How can I host multiple Service Fabric Actor Types inside a single service? - actor

I've read here that is should be possible to host tightly coupled ActorTypes within the same service but I can't seem to find any documentation on exactly how to do it.
I thought it might I need to create my own instance of the ActorService and pass the context into it but I don't seen to be able to find the right API's from the document.
Does anyone have an example they could share ?

Sort of but not really. You can have multiple actor types in the same application. It looks like they're in the same service in Visual Studio, but they're actually deployed as separate services. Bear with me for a minute if you will..
So you can register multiple actors like this:
internal static class Program
{
private static void Main()
{
ActorRuntime.RegisterActorAsync<Actor1>().GetAwaiter().GetResult();
ActorRuntime.RegisterActorAsync<Actor2>().GetAwaiter().GetResult();
Thread.Sleep(Timeout.Infinite);
}
}
Great, I have multiple actor types. This works and you can just do that.
But you want know how it works! Well, that's just a simplified version of this:
internal static class Program
{
private static void Main()
{
ActorRuntime.RegisterActorAsync<Actor1>(
(context, actorType) => new ActorService(context, actorType, () => new Actor1())).GetAwaiter().GetResult();
ActorRuntime.RegisterActorAsync<Actor2>(
(context, actorType) => new ActorService(context, actorType, () => new Actor2())).GetAwaiter().GetResult();
Thread.Sleep(Timeout.Infinite);
}
}
This is more telling of what's actually happening, because you see here I now have two services. So what's going on?
The secret is in the ActorRuntime. It does a little more work than ServiceRuntime (where you register Reliable Services normally). The Actor framework build process does some magic on your behalf to configure a service type and a default service instance inside your application for each actor type. You can see this in your ApplicationManifest.xml, where the build tools sets up default services for you:
<DefaultServices>
<Service Name="Actor1ActorService" GeneratedIdRef="3262c188-3eee-44c5-9d1e-d2c2a2685f89|Persisted">
<StatefulService ServiceTypeName="Actor1ActorServiceType" TargetReplicaSetSize="[Actor1ActorService_TargetReplicaSetSize]" MinReplicaSetSize="[Actor1ActorService_MinReplicaSetSize]">
<UniformInt64Partition PartitionCount="[Actor1ActorService_PartitionCount]" LowKey="-9223372036854775808" HighKey="9223372036854775807" />
</StatefulService>
</Service>
<Service Name="Actor2ActorService" GeneratedIdRef="1bc66d2c-0479-4bb2-a9aa-3254030506f1|Persisted">
<StatefulService ServiceTypeName="Actor2ActorServiceType" TargetReplicaSetSize="[Actor2ActorService_TargetReplicaSetSize]" MinReplicaSetSize="[Actor2ActorService_MinReplicaSetSize]">
<UniformInt64Partition PartitionCount="[Actor2ActorService_PartitionCount]" LowKey="-9223372036854775808" HighKey="9223372036854775807" />
</StatefulService>
</Service>
As an example, if I take the two actor types I have defined above and deploy that application, here is the result:
These are actually separate service instances in the application, and each is of a different service type, all of which is automatically generated for you:
And of course, because they're different service instances, they'll be distribute across the cluster as you would normally expect:
I'll go update that doc.

Related

NET Core Server Side multiple session Blazor

I'm trying to host my Blazor application on my server.
I spent all the summer on it and I just realized every time I open my website on new device it doesn't create a new session restarting from zero, but continues where I left it. The worst part is there is a login system behind it, so I feel super dumb at the moment.
I really need a big hint on how to fix this "not little" issue.
Is there a way to make server create new session every time someone open the website (without making it loose to other users)?
The solution should be use a Client Template instead, but the performance are really to slow.
UPDATE:
Accounts "user password" are:
- user user
- test test
Download project sample (requires Net Core 3.0)
[SOLUTION] itminus found the solution to my issue.
You have also to add in ConfigureServices in Startup.cs this services.AddScoped<Storage>();
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<Storage>();
}
every time I open my website on new device it doesn't create a new session restarting from zero, but continues where I left it.
I checkout your code and find that you're using Singleton Pattern to initialize the Storage. If I understand it correctly, this Storage singleton instance will be shared across different users (also across different devices). As this instance will be used to render the Main.razor page, there will be concurrency problems that you're experiencing now .
To fix that issue, the Storage instance should be limited within some specific connection. As you're using Blazor Server Side, you could register the Storage as a Scoped Service:
In Blazor Server apps, a scoped service registration is scoped to the connection. For this reason, using scoped services is preferred for services that should be scoped to the current user, even if the current intent is to run client-side in the browser.
Firstly, remove the static singleton instance :
public class Storage
{
private static Storage instance;
private Storage()
{
}
public static Storage GetInstance()
{
if (Storage.instance == null)
Storage.instance = new Storage();
return Storage.instance;
}
public List<Items>list {get;set;} = new List<Items>();
public string password {get;set;}
}
Register this Class as a scoped service:
services.AddScoped<Storage>();
And then inject this service in your Login.razor and Main.razor :
#inject project.Storage Storage
Finally, you need change all the Storage.GetInstance(). to Storage.:
Storage.list = Order;
...
Storage.password = password;
I notice that you're also creating the Importer/Additional instance using the Singleton Pattern. I would suggest you should refactor them to use Service Injection in a similar way.

How to set FiddlerCore up to monitor all system traffic?

We are evaluating FiddlerCore for a use-case. Basically, for now we just want to catch all of the endpoints/urls being requested on a system. This works fine in Fiddler, no issues. But we only want to catch them while a certain vendor software is open. So we want to write a plugin to that software that will run when it launches, and then exit when it exits. Hence, using FiddlerCore (hopefully).
As proof-of-concept, I just made a simple app, one form with a textbox, that it should just append each url into the textbox. Simple as simple can be. However, it's not doing anything. I run the app, then refresh a page in my browser, and ... nothing.
Here is the entire (non-generated) code of my program...
using Fiddler;
using System;
using System.Windows.Forms;
namespace ScratchCSharp {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
FiddlerApplication.AfterSessionComplete += FiddlerApplication_AfterSessionComplete;
FiddlerApplication.Startup(8888, FiddlerCoreStartupFlags.Default);
}
private void FiddlerApplication_AfterSessionComplete(Session s) {
textBox1.Invoke((Action)delegate () {
AddText(s.fullUrl);
});
}
public void AddText(string text) {
textBox1.Text += $"{text}\n";
}
}
}
After a little more poking around, I see that FiddlerApplication.IsSystemProxy is returning false. Seems to have to do with that the Startup flag to set as system proxy is no longer honored, and it tells you now to use the Telerik.NetworkConnections.NetworkConnectionManager to set it as the system proxy. But I can't find anywhere that actually says how to do that. The closest thing I could find is this thread which seems to be their official answer to this question. However, it only goes into a lot of talk about WHY they deprecated the flag, and what their thinking was in how they designed its replacement, but not actually into HOW TO USE the replacement. The Demo app also does NOT use these libraries (probably why it doesn't catch anything either).
The biggest problem though, is that the NetworkConnectionsManager class has no public constructor, so you can't create an instance. It is not inheritable, so you can't make a subclass instance. All of the methods on it are instance methods, not static/shared. And there seems to be no method in the libraries which will create an instance of NetworkConnectitonsManager for you.
So while the class is clearly designed to be used as an instance (hence the methods not being static/shared, there doesn't actually seem to be any way to create an instance.
Any help on how to set this thing up to catch all the outgoing URLs on the system?
You can use the following code for starting Fiddler Core and registering it as a system proxy:
FiddlerCoreStartupSettings startupSettings =
new FiddlerCoreStartupSettingsBuilder()
.ListenOnPort(fiddlerCoreListenPort)
.RegisterAsSystemProxy()
.ChainToUpstreamGateway()
.DecryptSSL()
.OptimizeThreadPool()
.Build();
FiddlerApplication.Startup(startupSettings);
Some of the methods are obsolete for now, but I would recommend to stick with them until the NetworkConnectionManager API is improved and finalized.
Also, there is a sample application (that FiddlerCore installer installs on the Desktop), which is useful for a starting point with the development.

Background service confusion

I'm trying to find out how to keep an Android service running after the starting app is closed. I've tried looking at samples for background services (e.g this one, and some on the Xamarin site) but in every case the service stops running if the minimised app is 'swiped' off the screen. I don't want the service to accidently stop like this, it should run continually until a confirmed stop is requested. The service does not consume much in the way of resources, just gets a GPS location and posts it to a website every 2 minutes.
By way of background, I am a newbie to Xamarin/Android, but have in the past created several successful services in Windows with C#
(Later)
One sample I tried did leave an item in the Settings list of running apps, but didn't actually perform any service tasks once swiped off the screen. Additionally there was no icon in the status bar. After doing some reading it seems that my androidmanifest file is missing a 'service' attribute (although none of the samples I tried have this); what I have now tried is this
<service
android:name=".LocationService"
android:icon="#drawable/icon"
android:label="#string/service_name"
>
<intent-filter>
<action android:name="android.service.LocationService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
...but still no luck.
Have you had a look at the Xamarin sample here the source is here
They create a service like so:
[Service]
public class SimpleService : Service
{
System.Threading.Timer _timer;
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
Log.Debug ("SimpleService", "SimpleService started");
DoStuff ();
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
base.OnDestroy ();
_timer.Dispose ();
Log.Debug ("SimpleService", "SimpleService stopped");
}
public void DoStuff ()
{
_timer = new System.Threading.Timer ((o) => {
Log.Debug ("SimpleService", "hello from simple service");}
, null, 0, 4000);
}
public override Android.OS.IBinder OnBind (Android.Content.Intent intent)
{
throw new NotImplementedException ();
}
}
And start and stop it with this:
StartService (new Intent (this, typeof(SimpleService)));
StopService (new Intent (this, typeof(SimpleService)));
Also it sounds like you want a Sticky service Docs
When the system is under memory pressure, Android may stop any running services. The exceptions to this rule are services explicitly started in the foreground, which are discussed later in this article.
When a service is stopped by the system, Android will use the value returned from OnStartCommand to determine how or if the service should be restarted. This value is of type StartCommandResult, which can be any of the following:
Sticky – A sticky service will be restarted, and a null intent will be delivered to OnStartCommand at restart. Used when the service is continuously performing a long-running operation, such as updating a stock feed.
RedeliverIntent – The service is restarted, and the last intent that was delivered to OnStartCommand before the service was stopped by the system is redelivered. Used to continue a long-running command, such as the completion of a large file upload.
NotSticky – The service is not automatically restarted.
StickyCompatibility – Restart will behave like Sticky on API level 5 or greater, but will downgrade to pre-level 5 behavior on earlier versions.
Hope this helps.
Solved it now. The confusion was mainly due to many samples being out-of-date (using deprecated methods) and different suggestions for 'pure' Android projects and Xamarin ones. Certainly don't need to modify the androidmanifest file as I suggested above.
If anyone is trying to find something similar, my project is here.
Solving the initial issue has now raised some new questions, of course, but I will post separately about that if needed.

Multiple Facebook Canvas Applications within same web application - CanvasAuthorizeAttribute

I am having a problem with running multiple Facebook applications under a single Web application.
Similar to this problem:
Multiple facebook apps under one web application
I do like the solution suggested here, however the CanvasAuthorizeAttribute uses the FacebookApplication.Current internally and this is a static instance of the FB application within the Web application.
I can't call the .SetApplication method within the controller as I will have concurrency issues.
It would be nice if the FacebookApplication.Current called the Func that is passed into the .SetApplication instead of just calling inside of the .SetApplication.
That way I could pass a function that does my logic for retrieving the correct FB application.
Am I missing something that is already in the SDK?
You can always have your own logic at http://facebook.stackoverflow.com/questions/4931240/multiple-facebook-apps-under-one-web-application/4936703#4936703
private IFacebookApplication Current
{
get
{
var url = HttpContext.Current.Request.Url;
var app = GetSettingsForUrl(url);
// put your custom logic here and return the appropriate IFacebookApplication
return app;
}
}
But you should do this during Application_Start where it is still running on a single thread and not in Controller.

How to speed up Azure deployment from Visual Studio 2010

I have Visual Studio 2010 solution with an Azure Service and an ASP.NET MVC 3 solution that serves as a Web Role for the Azure service. No other roles attached to the service other than that.
Every deployment to the Azure staging (or production, for that matter) environment takes up to 20 minutes to complete, form the moment I click publish on Visual Studio until all instances (2) are started.
As you can imagine this makes it a PITA to publish often, or to quick-fix some bugs. Is there a way to speed the process up? Would it be faster to upload the package to de Blob storage and upgrade from there? How would I go about achieving that?
I feel on-line docs on Azure leave a lot to be desired. Particularly when it comes to troubleshooting by the way.
Thanks.
One idea for reducing the need (and frequency) for redeploying is to move static content into blob storage, external to the package. For instance, move your css and javascript to blob storage, along with images. Once this is done, you'd only have to recompile / redeploy for .NET code changes. You can upload updated css, at any time, to blob storage. If you want to test this in staging first, you could always have a staging vs. production container name for your static content and store that container name in a config setting.
This doesn't change the deployment time when you do need to redeploy, but at least you can reduce how often you go through that process...
You should enable Web Deploy in your Azure project. It works this way :
1/ Create a RDP account (don't forget, you need to upload a certificate with its private key so that Azure can decipher the password). That is hidden in the Deploy Dialog Box for your Azure deployment project.
2/ Enable Web Deployment - same place
Once you've published the app that way, right-click in the web application (not the azure deployment project) and select Publish. The pop-up has everything defined except the password, enter that as well and you'll upload your changes to Azure in a matter of seconds.
CAVEAT : this is meant for single-instance web apps, definitely not the way to go for a production upgrade strategy, and the Blob storage answer already mentioned is the best option in that case.
Pierre
My solution to this problem is only to push a new package when I am changing code in the RoleEntryPoint or with the Service Definition. In Azure 1.3 you now have the ability to use Remote Desktop Connection. Using RDC, I will compile my code locally and use copy/paste to place it on the Azure server in the appropriate directory. Once the production code is running correctly, I can then push the fully tested version to staging and then do a VIP swap. This limits the number of times I actually have to deploy a package.
You actually have quite a long window in which you can keep modifying your code in Azure before you have to publish a new package. The new package is only really needed for those cases where Azure has to shutdown/restart your role instance.
It's a nice idea to try uploading your project to blob storage first, but unfortunately this is what Visual Studio is doing for you behind the scene anyway. As has been pointed out elsewhere, most of the time in doing the deploy is not the upload itself, but the stopping and starting of all of your update domains.
If you're just running this site in a development environment, then the only way I know to speed it up is to run just one instance. If this is the live environment, then... sorry, I think you're out of luck.
So that I don't have to deploy to the cloud to test minor changes, what I've found works quite well is to engineer the site so that it works when running in local IIS just like any other MVC site.
The biggest barrier to this working are settings that you have in the cloud config. The way we get around this is to make a copy of all of the settings in your cloud config and put them in your web.config in the appSettings. Then rather than using RoleEnvironment.GetConfigurationSettingValue() create a wrapper class that you call instead. This wrapper class checks RoleEnvironment.IsAvailable to see if it is running in the Azure fabric, if it is, it calls the usual config function above, if not, it calls WebConfigurationManager.AppSettings[].
There are a few other things that you'll want to do around getting the config setting change events which hopefully you can figure out from the code below:
public class SmartConfigurationManager
{
private static bool _addConfigChangeEvents;
private static string _configName;
private static Func<string, bool> _configSetter;
public static bool AddConfigChangeEvents
{
get { return _addConfigChangeEvents; }
set
{
_addConfigChangeEvents = value;
if (value)
{
RoleEnvironment.Changing += RoleEnvironmentChanging;
}
else
{
RoleEnvironment.Changing -= RoleEnvironmentChanging;
}
}
}
public static string Setting(string configName)
{
if (RoleEnvironment.IsAvailable)
{
return RoleEnvironment.GetConfigurationSettingValue(configName);
}
return WebConfigurationManager.AppSettings[configName];
}
public static Action<string, Func<string, bool>> GetConfigurationSettingPublisher()
{
if (RoleEnvironment.IsAvailable)
{
return AzureSettingsGet;
}
return WebAppSettingsGet;
}
public static void WebAppSettingsGet(string configName, Func<string, bool> configSetter)
{
configSetter(WebConfigurationManager.AppSettings[configName]);
}
public static void AzureSettingsGet(string configName, Func<string, bool> configSetter)
{
// We have to store these to be used in the RoleEnvironment Changed handler
_configName = configName;
_configSetter = configSetter;
// Provide the configSetter with the initial value
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
if (AddConfigChangeEvents)
{
RoleEnvironment.Changed += RoleEnvironmentChanged;
}
}
private static void RoleEnvironmentChanged(object anotherSender, RoleEnvironmentChangedEventArgs arg)
{
if ((arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(change => change.ConfigurationSettingName == _configName)))
{
if ((_configSetter(RoleEnvironment.GetConfigurationSettingValue(_configName))))
{
RoleEnvironment.RequestRecycle();
}
}
}
private static void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
{
// If a configuration setting is changing
if ((e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)))
{
// Set e.Cancel to true to restart this role instance
e.Cancel = true;
}
}
}
The uploading itself takes a bit more than a minute most of the time. It's the starting up of the instances that take up most of the time.
What you can do is to deploy your fixes to staging first (note that it costs money so don't let it be there for too long). Swapping from staging to production only takes a couple of seconds. So while your application's still running you can upload the patched version, let your testers test it on staging and when they give the go then simply swap it to production.
I haven't tested your possible alternative approach by first uploading to blob storage first. But I think that's overhead as it doesn't speed up starting up the instances.

Resources