I have created a win service that has this method on start:
private String bamboo = "";
public String Baboon = "";
protected override void OnStart(string[] args)
{
this.bamboo = "bamboo";
this.baboon = "baboon";
}
after the service starts i have methods for returning the field and the property:
public String GetValueBamboo()
{
return this.bamboo;
}
public String GetValueBaboon()
{
return this.Baboon;
}
these methods return empty strings when i try to get the values from another app:
public void GetValues()
{
var binding = new NetNamedPipeBinding();
var epAddrs = new EndpointAddress("net.pipe://localhost/PipeReverse");
var pipeFactory =
new ChannelFactory<ITaskManager>(
binding,
epAddrs);
var proxy =
pipeFactory.CreateChannel();
Assert.AreEqual(proxy.GetValueBamboo(),"bamboo"); // returns false
Assert.AreEqual(proxy.GetValueBaboon(),"baboon"); // returns false
}
I have noticed that if i use the same proxy object to first set the values of the field/property(didn't write those methods, pretty straightforward), then the results come out as expected but every call after with a new proxy object again returns empty strings.
is there a way that i can set some properties and/or fields on the service and that they persist between calls to the service?
The solution that i ended up using is just to declare the fields static, and then it works.
I would still like to know why instanced fields in a service reset after reinitializing the client, so if anyone has any idea about this I would very much like to know.
Related
Having an issue with akka.net. I need to access an actor which I have already created with a specific name. I can retrieve the actor from IActorContext but I am struggling to access it from the ActorSystem.
I have created a method called GetOrCreateActor which attempts to get the actor using ActorSelection. If it doesn't exist, the catch creates a new actor with the name. If it does exist, I want it to return the reference. However, it never returns from '.Result'. Assuming this could be some sort of deadlocking issue.
public static IActorRef GetOrCreateActor<T>(this ActorSystem actorSystem, string actorPath, string name = null) where T : ActorBase
{
try
{
return actorSystem.ActorSelection(actorPath).ResolveOne(TimeSpan.FromSeconds(1)).Result;
}
catch
{
return actorSystem.ActorOf(actorSystem.DI().Props<T>(), name);
}
}
Edit
I've tried to include a simplified version of the calling code below.
The actor system is created in an IOC container using AutoFac (ExampleActor is the ReceiveActor I am trying to access):
containerBuilder.RegisterAssemblyTypes(typeof(ExampleActor).Assembly).Where(x => x.Name.EndsWith("Actor"));
var lazyContainer = new Lazy<IContainer>(() => containerBuilder.Build());
containerBuilder.Register(c =>
{
var system = ActorSystem.Create("ExampleActorSystem");
new AutoFacDependencyResolver(lazyContainer.Value, system);
return system;
}).As<ActorSystem>().SingleInstance();
return lazyContainer.Value;
ActorSystem is then injected into another class, where I call the GetOrCreateActor method (via the Execute method):
public class ExampleCommand : IExampleCommand
{
private readonly ActorSystem _actorSystem;
public ExampleCommand(ActorSystem actorSystem)
{
_actorSystem = actorSystem;
}
public void Execute()
{
SendMessage();
}
private void SendMessage()
{
string message = new Message();
_actorSystem.GetOrCreateActor<ExampleActor>("akka://ExampleActorSystem/user/ExampleActor", "ExampleActor").Tell(message);
}
}
The above command would be called from a RESTful endpoint
public ExampleGetModule(IExampleCommand exampleCommand)
{
Get["/api/createExample"] = parameters =>
{
exampleCommand.Execute();
};
}
Your deadlocking issue looks more like it has to do with how you're using your container than it does Akka.NET:
var lazyContainer = new Lazy<IContainer>(() => containerBuilder.Build());
containerBuilder.Register(c =>
{
var system = ActorSystem.Create("ExampleActorSystem");
new AutoFacDependencyResolver(lazyContainer.Value, system);
return system;
}).As<ActorSystem>().SingleInstance();
In terms of what can go wrong here, self-referential Lazy<T> types are an infamous source of race-conditions. You should not be calling lazyContainer.Value inside of this registration method if the output of containerBuilder.Build depends on the input of containerBuilder.Register.
Last thing is to use step-through debugging to make sure that your application actually calls into the ResolveOne method here - if you're not getting a timeout exception back then it means that your application is deadlocking on producing the actor system (because of how DI is configured).
Sorry if i dont explain myself clearly but I can't seem to wrap my head around how to present the problem at hand.
We have some utility classes used in web and windows forms development. We use the following pattern in order to dynamically call the corresponding methods depending on whether the code runs inside a web or in windows forms.
The following code is a stripped down version so you can observe the logic clearlier:
public static class Constants
{
private static ConstantsWinFormsWebCommonProvider _Provider;
public static ConstantsWinFormsWebCommonProvider Provider
{
get
{ /*in websites the static variables reset to null in case of Appdomain recycle
*so we check beforehand, this also serves for first time use in both: web and winforms */
//lazy loading, initializes when provider is required for the first time or if gets null because appdomain recycle...
if (_Provider != null) return _Provider;
_Provider = Fun.WebSite()? (ConstantsWinFormsWebCommonProvider)new ConstantsWebProvider() : new ConstantsWinFormsProvider();
Initialize();
return _Provider;
}
}
public static void Initialize()
{
Provider.Initialize();
}
public static string DataBaseName
{
get { return Provider.DataBaseName ; }
set { Provider.DataBaseName = value; }
}
}
public class ConstantsWinFormsWebCommonProvider
{
internal bool isInitialized { get; set; } //variable only used in the winform part for now, shouldnt affect the web part issue
internal string DataBaseName { get; set; }
}
public class ConstantsWebProvider: ConstantsWinFormsWebCommonProvider
{
public override void Initialize()
{
base.Initialize();
string errordetails= "";
if (!Fun.InitializeWeb(ref errordetails)) //fills all the Provider properties and connects, otherwise returns false
{
throw new Exception("Problem initializating web " + errordetails));
}
}
}
public class ConstantsWinFormsProvider: ConstantsWinFormsWebCommonProvider
{
public new string DataBaseName
{
get
{//lazy loading so it connects only when required
if (isInitialized) //(!string.IsNullOrEmpty(base.DataBaseName))
{
return base.DataBaseName ;
}
bool resul = Fun.InicializeWinForms();
if (resul) return base.DataBaseName ;
MessageBox.Show("Problem initializing");
return null;
}
set
{
Fun.WinFormsValueSavingSistemx(value); //example call, not related with the issue at hand
}
}
}
The problem is that occasionally in the case of the web we get errors because the properties inside the Provider variable are null, but the Provider itself is not null.
In theory it shouldn't be possible (in the case of the web we initialize all the Provider properties in the Initialize() function and if the appdomain recycles causing the properties to go null the Provider variable should be null too causing it to call Initialize() again when you try to access one of its properties).
What's the cause and recommended solution to this problem?
Edit:
In case this provides more hindsight, the problem for now has happened in the first page load of one aspx (isPostback = false, where it would access the Provider.DataBaseName for the first time in the first visit to that aspx or if coming again from another aspx). Also in the documented cases they where using IE8 and IE9...
So I am only a few days into learning about wcf services, specifically duplex, and I am starting with a test app. The goal is to have a Service that has an internal (static?) class which stores variables, and a Client that fetches for those variables.
Currently I have two variables in the Storage class, one which is a list of Subscribers (ObservableCollection<IMyContractCallBack>) and one which is an ObservableCollection<string>, where each string gets sent in the callback method to the client.
I would like to be able to have the client Fetch (which first Subscribes if not already, by adding its context to the collection on the server side) the strings in the collection on the server side. That part works as expected. However, I would also like to Push a string from the server to every client in the subscription list, as well as Add strings to the collection of strings. That's where my issues crop up.
Anytime I Fetch, it adds to string list "test1..." and "test2..." and sends them, then the client updates a textblock UI (wpa) so if I fetch twice I'll have "test1...","test2...","test1...","test2..." because right now there's no checking for duplicates. That proves that the collection can get updated and remembered on the server side from Fetch to Fetch. However, when I try to Add or Send a given text, all variables are forgotten, so the subscriber list is null, and the list-to-add-to is empty. Yet when I then Fetch again, the old list is back (now with 6 things, test1...,test2... etc...)
I have this before the class
[ServiceBehavior(InstanceContextMode= InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
and I also tried a Singleton context mode to no avail. Changing the ConcurrencyMode to Multiple doesn't do anything different either. Any ideas as to why my static data is being reset only when internal commands come from the server itself?
Here is the code for my Service:
namespace WcfService3
{
[ServiceBehavior(InstanceContextMode= InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service1 : IService1
{
public static event Action NullContext;
public static ObservableCollection<IMyContractCallBack> Subscriptions;
public void NormalFunction()
{
//Only sends to Subs that are STILL Open
foreach (IMyContractCallBack user in Subscriptions)
{
//Removes the Closed users, because they are hanging around from last session
if (((ICommunicationObject)user).State != CommunicationState.Opened)
{
Subscriptions.Remove(user);
}
else
{
ObservableCollection<string> holder = Storage.GetList();
foreach (string str in holder)
{
user.CallBackFunction(str);
}
}
}
}
public static void Send(string str)
{
try
{
foreach (IMyContractCallBack user in Subscriptions)
{
user.CallBackFunction(str);
}
}
catch
{
//For some reason 'Subscriptions' is always null
NullContext.Invoke();
}
}
public static void Add(string str)
{
//For some reason 'SendList' is always null here, too
Storage.AddToList(str);
if (Subscriptions != null)
{
//For same reason 'Subscriptions' is always null
foreach (IMyContractCallBack user in Subscriptions)
{
user.CallBackFunction(str);
}
}
}
public void Subscribe()
{
//Adds the callback client to a list of Subscribers
IMyContractCallBack callback = OperationContext.Current.GetCallbackChannel<IMyContractCallBack>();
if (Subscriptions == null)
{
Subscriptions = new ObservableCollection<IMyContractCallBack>();
}
if(!Subscriptions.Contains(callback))
{
Subscriptions.Add(callback);
}
}
and here is my code for the Storage class:
namespace WcfService3
{
public static class Storage
{
public static readonly ObservableCollection<string> SendList = new ObservableCollection<string>();
public static IMyContractCallBack callback;
public static ObservableCollection<string> GetList()
{
if (SendList.Count == 0)
{
AddToList("Test1...");
AddToList("Test2...");
}
return SendList;
}
public static void AddToList(string str)
{
SendList.Add(str);
}
}
}
I can provide more code if needed.
Are you using the ThreadStatic attribute anywhere? (just do a quick search) Thats a real long shot and probably not your issue.
You probably have a threading issue. Do all your clients connect at the same time (i really mean in close succession?) If yes, you are going to have threading issues with this code in your Subscribe method:
if (Subscriptions == null)
{
Subscriptions = new ObservableCollection<IMyContractCallBack>();
}
You should better constrain access to your Subscriptions method so you can see who modifies it and when and use Console statments to figure out where you're going wrong.
I have now something like this:
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string Method1()
{
SomeObj so = SomeClass.GetSomeObj(); //this executes very long time, 50s and more
return so.Method1(); //this exetus in a moment
}
[WebMethod]
public string Method2()
{
SomeObj so = SomeClass.GetSomeObj(); //this executes very long time, 50s and more
return so.Method2(); //this exetus in a moment
}
...
}
Is it possible to make stateful web service so that I can reuse SomeObj so and just call methods on the same object?
So the client which will use this service would first call web method which would create so object and return some ID.
And then in subsequent calls the web service would reuse the same so object based on ID.
EDIT
Here is my actual code:
[WebMethod]
public List<ProcInfo> GetProcessList(string domain, string machineName)
{
string userName = "...";
string password = "...";
TaskManager tm = new TaskManager(userName, password, domain, machineName);
return tm.GetRunningProcesses();
}
[WebMethod]
public bool KillProcess(string domain, string machineName, string processName)
{
string userName = "...";
string password = "...";
(new TaskManager(userName, password, domain, machineName);).KillProcess(processName);
}
Stateful web services are not scalable and I wouldn't recommend them. Instead you could store the results of expensive operations in the cache. This cache could be distributed through custom providers for better scalability:
[WebMethod]
public string Method1()
{
SomeObj so = TryGetFromCacheOrStore<SomeObj>(() => SomeClass.GetSomeObj(), "so");
return so.Method1(); //this exetus in a moment
}
[WebMethod]
public string Method2()
{
SomeObj so = TryGetFromCacheOrStore<SomeObj>(() => SomeClass.GetSomeObj(), "so");
return so.Method2(); //this exetus in a moment
}
private T TryGetFromCacheOrStore<T>(Func<T> action, string id)
{
var cache = Context.Cache;
T result = (T)cache[id];
if (result == null)
{
result = action();
cache[id] = result;
}
return result;
}
Option 1
You can use your HttpSession.
//this executes very long time, 50s and more, but only once.
private SomeObj SessionSomeObj {
get
{
var ret = (SomeObj)Session["SomeObjStore"] ?? SomeClass.GetSomeObj();
SessionSomeObj = ret;
return ret;
}
set { Session["SomeObjStore"] = value; }
}
[WebMethod(EnableSession = true)]
public string Method1()
{
return SessionSomeObj.Method1(); //this exetus in a moment
}
[WebMethod(EnableSession = true)]
public string Method2()
{
return SessionSomeObj.Method2(); //this exetus in a moment
}
Note that this will only work if one call per client is made at a time.
Option 2
You can leave the class as is but use the WebMethod differently. If you are calling from a .Net generated class, async methods are provided for these occurrences. Basically you invoke the Method1 begin request method and get a call back when the execution is finished. You might need to tweak the timeout parameter of the web service client class for this to work though.
Option 3
You can use the caching features of the SixPack library to do this effortlessly! ;-)
[Edited after comment] There are now two static fields in option 1 to allow two different instances, one per method, as requested.
[Edited after further explanation] Using Session to make the calls stateful.
See: http://msdn.microsoft.com/en-us/library/aa480509.aspx
Also added Option 3.
Change the ServiceContract of your interface into:
[ServiceContract(SessionMode = SessionMode.Required)]
And put the following attribute on your class:
[ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode.PerSession)]
See http://msdn.microsoft.com/en-us/library/system.servicemodel.sessionmode.aspx for more information and an example.
I have got an app I'm going to write in ASP.NET MVC and I want to create a DatabaseFactory object something like this:-
public class DatabaseFactory
{
private string dbConn get { return <gets from config file>; }
public IDatabaseTableObject GetDatabaseTable()
{
IDatabaseTableObject databaseTableObject = new SQLDatabaseObject(dbConn);
return databaseTableObject;
}
}
and this works fine, but I obviously have to instantiate the DatabaseFactory in every controller that needs it. If I made this static, so I could, in theory just call DatabaseFactory.GetDatabaseTable() it would cause a memory leak, wouldn't it?
---------edit-------
maybe I need to add in a bit more detail.
If I had the above code like this:-
public static class DatabaseFactory
{
private static string dbConn get { return <gets from config file>; }
public static IDatabaseTableObject GetDatabaseTable()
{
IDatabaseTableObject databaseTableObject = new SQLDatabaseObject(dbConn);
return databaseTableObject;
}
}
then instead of my controller code saying
DatabaseFactory databaseFactory = new DatabaseFactory();
var tableObject = databaseFactory.GetDatabaseTable();
List<DbRecord> records = tableObject.Table.ToList();
I just said
var tableObject = DatabaseFactory.GetDatabaseTable();
List<DbRecord> records = tableObject.Table.ToList();
wouldn't that result in the DB connection remaining open once the controller's action method had been GCed?
Since you don't store the object anywhere, this would not leak memory.
Apparently this will cause a memory leak.