I have some WCF services. These services run in ASP.NET. I want these services to be able to access a static variable. My problem is, I'm not sure where the appropriate server level storage mechanism is. I don't want to use the database because of speed. But, I want the static variables to stay in memory as long as possible. In fact, I'd like it to stay until I restart my server if it all possible.
Can anyone provide me with any ideas?
You could use static variables in WCF but you must properly synchronize the access to them because they can potentially be accessed from multiple threads concurrently. The values stored in static variables are accessible from everywhere in the AppDomain and remain in memory until the server is restarted.
You could have something like this
public static class StaticVariables
{
private static string _variable1Key = "variable1";
public static Object Variable1
{
get
{
return Application[_variable1Key];
}
set
{
Application[_variable1Key] = value;
}
}
}
The Application collection itself is thread safe but the stuff you add to it might not be; so keep that in mind.
If all the services are in a single ServiceContract and if all the member variables in your service can be shared across all sessions, then you could set the ServiceBehavior to have a single instance.
[ServiceBehavior( InstanceContextMode = InstanceContextMode.Single )]
public class MyService : IMyServiceContract
{
}
Related
I have a Windows service hosting multiple WCF services. All of it running on a local machine (using NamePipe).
Is there a simple way to have these WCF services share a property? (I would rather not have them sharing a file).
I need this as each session instantiated within each WCF service will be getting a hold on a given hardware and the other WCF services need to know what is still available in order to be able to instantiate another session.
Each WCF service implements a different protocol, which is why I did not merge the lot. There will be one proxy for each host.
I don't know of a super simple way of getting service instances to share a property, but you could create a custom host that derives from ServiceHost and have it implement a particular interface, say something like:
public interface ISharedStateContainer
{
SharedState State { get; set; }
}
This interface would have to be known your services. Then, in your windows service project, you could make a custom service host:
public class CustomServiceHost: ServiceHost, ISharedStateContainer
{
SharedState state;
public SharedState State{ get{ return state; } set{ state=value; } }
}
...and then when the windows service creates the wcf service host instances, it could inject the shared state:
var sharedState = new SharedState();
myServiceHost = new CustomServiceHost( typeof( MyService ) );
((ISharedStateContainer) myServiceHost).State = sharedState;
myOtherHost = new CustomServiceHost( typeof( OtherService ) );
((ISharedStateContainer) myOtherHost).State = sharedState;
myServiceHost.Open();
myOtherHost.Open();
...and then, in a running instance of a service, you could get to shared state like this:
var sharedState = ((ISharedStateContainer)OperationContext.Current.Host).State
Where I've got SharedState, you could make it any type you want...but making it a reference type that itself has properties means you can use it to share as many properties as you need. Note that with any shared state, you'll have race conditions to protect against.
I've done a windows service the same way (multiple different wcf service types)...and this is more-or-less how they share state.
EDIT:
I don't know why I didn't think about this sooner, but another nice way to share state is using a singleton. This is probably more straightforward than the earlier approach. I have this pattern going on, too...for a somewhat different reason, but it would serve for shared state, too:
public class SharedState
{
//--> singleton instance...
static readonly SharedState current;
//--> use static initializer to create the current instance...
static SharedState( )
{
current = new SharedState();
}
//--> hide ctor...
private SharedState(){}
public static SharedState Current
{
get { return current; }
}
//--> all your shared state instance methods and properties go here...
public string SomeString
{
get
{
return //...
}
}
}
...and then you can get to this object from anywhere in your service, even from code not running in the context of a client operation. I use this for long running background task that the service needs to perform periodically, but shared properties are super easy:
var someValue = SharedState.Current.SomeString;
I have used static variable which I hope it will persist in IIS. But for sometimes, it is cleared. Is that possible that IIS will clear the static variable?
public partial class Main : CustomPage
{
public static bool cachedCurrentYearDataInFile = false;
static variables live though the application cycle. If the application ends (chech application pool settings like idle and recycle) a new instance is generated and you would lose all static information of the now non-existant one. If you want persistence you should consider, actual persistence like file/database.
I am trying to access global.asax application variable from WCF, that's my goal at least. I've tried many type of solutions, but the one that I am trying now is using static variables.
I've created a StaticVariable.cs class like so:
public static class StaticVariables
{
private static string _Key = "name1";
public static Object someInfo
{
get
{
return HttpContext.Current.Application[_Key];
}
}
}
The Application["name1"] is initialized in the global.asax.cs. I can read it when I access my webservice but not in my WCF service.
In my WCF I call the StaticVariables someInfo to retrieve the data, but I get:
System.Web.HttpContext.Current is null error
My WCF is running asynchronously and its called from within a webservice using Task<int>.Factory.FromAsync. So I assume that the problem is that the WCF runs not on the main thread, but I am not sure.
So it seems that the Static class doesn't work in my case and I wanted to know how to solve this. Thanks
Why don't you simply use static variables ?
HttpContext is dependent on ASP.NET pipeline. In a host-agnostic model (OWIN or self-hosted) you don't have access to it.
Application storage in HttpApplicationState is only useful if you need to access the current HttpContext. If it's not necessary, you should simply use static properties.
Moreover, HttpApplicationState was initially created for backward compatibility with classic ASP.
public static class StaticVariables
{
public static object SomeInfo { get; set; }
}
See also Singleton and HttpApplicationState and http://forums.asp.net/t/1574797.aspx
My WCF service uses callbacks. To be able to call all clients, I'm using something like this:
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerSession)]
class Svc
{
// stores all connections
private static List<Svc> Connections = new List<Svc> ();
// callback for this instance
private ICallback Cb;
public Svc ()
{
Cb = OperationContext.Current.GetCallbackChannel<ICallback> ();
Connections.Add (this);
}
// ... lots of other code that uses or updates the list of connections
}
Is this the right way to do it?
I'm asking because I'm fighting with an apparent design problem in the above approach. I tried to move a lot of common code, including the static List<Svc> to a common base class that can be used by all my WCF services. But when deriving, this list is shared among all subclasses.
I then tried to avoid this undesirable sharing by making the base class generic (Svc<T>, meaning each subclass gets its own static members) but this leads to other annoyances and is not a clean design.
Yes, this is the right approach of storing references to your clients to send callbacks to all of them. I don't store the CallbackChannel objects but the OperationContext instances in my service.
To your other question: You could extract the code to administrate the list of connected clients to a separate class and use an instance of that class in your service.
Use the Singleton pattern when you need to store global state in a centralized manner.
In your case it could look like this:
public Svc()
{
this.CallbackChannel = OperationContext.Current.GetCallbackChannel<ICallback>();
// The static 'Instance' property returns the singleton
SvcActiveInstanceContainer.Instance.Add(this);
}
Related resources:
Singleton Design Pattern
I wrote a WCF service, but the data stored in the Service implementation doesn't persists between calls, not even if stored in a static variable. What can I do?
The service implementation is as follows:
public class Storage : IStorage
{
protected static object[] _data;
#region IStorage Members
public void Insert(object[] data)
{
lock (_data)
{
_data = _data.Concat(data).ToArray();
}
}
public object[] SelectAll()
{
lock (_data)
{
return (object[])_data.Clone();
}
}
#endregion
}
The service host is a console application:
static void Main(string[] args)
{
ServiceHost serviceHost =
new ServiceHost(typeof(TimeSpanStorage));
serviceHost.Open();
Console.WriteLine("Service running. Please 'Enter' to exit...");
Console.ReadLine();
}
By default WCF instanceMode is set to Per call, meaning data used in the service is specific to that client for that method call.
On your implementation try adding
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single)]
public class MyService: IService
This makes the service essentially a singleton.
What you are looking to do is create a durable service:
WCF Durable services are WCF services
in which the operations can remember
the values of private variables (=the
state of the service) inbetween
restarts of the serivcehost and/or
client.
Are you wanting to persist the data beyond the lifetime of your ServiceHost instance? If so, then I agree that a durable service makes sense.
However, if you are only wanting to persist data between calls to your WCF service while the service is alive, then a durable service is overkill in my humble opinion. Using static data is perfectly acceptable; it is precisely what I do in my WCF project. In fact, the code that you've shown should work, so something else is going on here.
Is the Main() method actually as you've shown it? If so, then that's a problem. As soon as your WCF-enabled console application starts up, it immediately shuts back down, taking the WCF service with it. You need to have some logic in there to keep the console application alive because the WCF service will only remain 'hosted' while the console application is running.
If this is not the problem, let me know, and I'll add the full code of a simple application that demonstrates how to do this.
Add:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
Above your class and you'll have a service that is a single instance (i.e. the class proterties remain the same) and allows multiple concurrent connections.
Now you have to take care of your property read/write, i.e. use locks as you've already done (or some other technique).