How can I make a variable (object) available for the whole lifetime of the webservice?
Static variable seem to work but is there an other way to do it?
Static variables exist for the lifetime of the App Domain that contains them. In the case of a web service, this is usually the ASP.Net Worker Process. What that means is that when IIS decides to cycle the worker process, your static variable will be gone. This may be what you want, in which case it is probably a good choice. (Putting asside discussions of whether or not static variables are proper in a given context).
Within the scope of a web service you also have access to the HttpApplicationState via the Application property (this would be an asmx service...not sure if WCF is the same or not), so this could also be a good choice for stashing something needed for the lifetime of a service.
A singleton utilizing HttpApplicationState should work a treat
probably, but if static variable works then move on to the next problem ! :)
Related
I am creating a web API in ASP.Net with IIS. However, I have been storing class members statically so that they can be accessed across different classes. This is obviously bad practice and I am noticing that every time a request is being made for the API, the same values are being returned due to the members not being cleared. How would I clear the members every request while also being able to access them across classes?
You should almost never use static variables in a web application. Even if you want to share variables across requests, access to statics is not thread-safe in many cases, and that can result in corrupt memory, incorrect system behavior, and even total system failure (if you're unlucky).
If you have variables that need to be shared, use an application variable instead. If you need to have a common cache, use one of the established caching techniques.
As for your specific question
How would I clear the members every request while also being able to access them across classes?
I think there is a misunderstanding here. There is no absolutely no reason to re-use a variable if it is being reset every time. I am guessing you think there is a performance cost to allocating new variables with each request; this is false. It is actually less efficient to use shared variables as multiple threads will experience false sharing and have to wait for each other as each request completes. If you use a new set each time, each thread has its own sandbox to work in and can complete the request much more quickly.
Instead, store your variables locally or as member variables in an object that is discarded at the end of the request. If you need some common location across all modules within a request, you can use HttpContext.Item or one of its alternatives.
Is it advisable to use singleton pattern in wcf application?. I have ServiceResponse class which will take care the response and errordetail and almost all the details of the wcf current request. When i first hit the service, lets say i have 5 properties in ServiceResponse class and which got filled with respective values and some error details in errordetail property. For the next hit, lets say i dont get any error details and all other 4 properties got filled up.
But the thing here is, the errordetail property is still populated with the previous values which i assume the singleton object doesnt get created even after the subsequent hits. So only changed values got affected but untouched property still holds the previous value for the subsequent hits.
is it because the appdomain never get unloaded to release the object to allow the next sinleton object to get created for the other imm. request? How to acheive the singleton pattern in wcf otherwise. Appreciate the help.
The singleton pattern implies that the object is only instantiated once and lives for the entire lifetime of the AppDomain. You should not store data that is specific to a given request in static objects because all of them will share the same data which might not be what you are looking for.
Whether it is a good idea or not to use static objects in a WCF application is a question that will entirely depend on your scenario and what you need to store there. Since WCF is a multithreaded environment where multiple threads could access this shared data you will have to take special care to ensure that this data is thread safe by using the proper synchronization mechanisms.
is it because the appdomain never get unloaded to release the object
to allow the next sinleton object to get created for the other imm.
request?
There's a single AppDomain that gets created when your application starts. Don't expect to get a different AppDomain on each request. Requests will all be served from the same AppDomain until the application gets recycled by IIS.
...almost all the details of the wcf current request.
This is not a singleton. A singleton will per definition be shared between all requests. You want to create an instance that lives through the whole requets or connection context. Create an instance of your object and store it in the relevant request/connection cache the first time it is needed.
If you have a windows service and a windows forms application that uses the same static object, is it the same object in both applications? In other words if I update the object in the service will it also be updated in the forms application as well if both are running at the same time?
They run on different processes so they don't share the static object.
Not exaclty related with your question but threads created on the same application is a different story. They will share the static variable unless is marked with ThreadStatic attribute
No. Unless you do something specific to achieve this objects are not shared between different processes.
The simple answer to this is is that each process has its own static so no, it will not be shared between the service and desktop process.
The complicated part is that there may even be multiple instances of a static in a single process.
In Java there is one instance of the static object for each ClassLoader that loads the class. I checked for equivalent functionality in C#. I found this question on SO that suggests that there is indeed something similar to multiple classloaders in in C# (I guess actually in CLR) and though I did not find any specific reference to multiple instances of a static I am sure that would be the case.
Simply put no,
static is 'static per AppDomain' (and you could have multiple domains per process), so not even for one process is safe to assume that your static variables will be 'shared' (normally is true unless you create new domains by hand, e.g. see What is AppDomain?) - e.g. web apps typically break the 'static' singletons etc.
In other words you need to use some sort of persistence to be able to share your data in between different applications. Or use remoting, WCF to communicate over application (domain) boundaries.
I think each application runs in its own Process. I really doubt that updating a static object in Windows service have any effect on static object running as Windows forms application.
Windows service runs under system account where as a Windows forms application runs under User account.
As others have pointed out in the comments, the processes run in different memory. Each process has
its own address space.
Windows service responds to Service control Manager commands.
They are completely two different things.
I will go ahead and preface this by saying: I am somewhat new to WCF.
I'm working on a server-side routine that's responsible for doing a great deal of business logic. It's accessible from a client via WCF.
My main WCF method calls off to several other private methods. Instead of passing around all of the "lookup data" I need for the business logic to each private method, I decided to use a singleton instance of a class named DataProvider that contains all of this "lookup data".
At the end of the routine, I "release" the DataProvider's lookup data so the next time the routine is executed, the latest lookup data will be used.
So, here's a simplified example:
public void Generate()
{
try
{
//populate singleton DataProvider with it's lookup data...
DataProvider.Instance.LoadLookupData();
//do business logic...
}
finally
{
//release provider's lookup data...
DataProvider.Release();
}
}
This works great until I have two different clients that execute the method at (or near) the same time. Problems occur because they share the same singleton instance and the task who finishes first will release the DataProvider before the other completes.
So...
What are my options here?
I'd like to avoid passing around all of the lookup data so the singleton pattern (or some derivative) seems like a good choice. I also need to be able to support multiple clients calling the method at the same time.
I believe the WCF service is configured as "Per-Call". I'm not sure if there's a way to configure a WCF service so that the static memory is not shared between service invocations.
Any help would be appreciated.
By default WCF is using "Per-Call", which means new instance of the WCF service is created for each client's call. Now since you implemented singleton even though new instance of the WCF is created it still calls your singleton.
If you would like to create lookup that is created for each call (like you have now) you should not do it as singleton. This way each client that calls your method will have new instance of the lookup, I think that was your intention.
However if you have lookup that is not changing that fast, I would recommend to share it between all calls, this will improve performance of your WCF service. You will need to declare your WCF service as
InstanceContextMode = InstanceContextMode.Single
ConcurrencyMode = ConcurrencyMode.Multiple
What this does is creating Singleton automatically for you by WCF, so you don't have to do it yourself, second it will support > 1 concurrent user (ConcurrencyMode.Multiple).
Now if you have your lookup that is changing and it needs to be reloaded after some period of time, I still would recommend using
InstanceContextMode = InstanceContextMode.Single
ConcurrencyMode = ConcurrencyMode.Multiple
but inside in your code cache it and then expire your cache at specific time or relative time (1 hours).
Here are some links that might help you:
3 ways to do WCF instance management (Per call, Per session and Single)
Hope this will help.
The static variables in a WCF service are always shared between instances regardless of the WCF InstanceContextMode setting. It seems you would be better off using a caching pattern for your look up data. The answers to this caching question provide some alternatives to rolling your own although they are a bit dated.
Also, if you decide that making the whole service instance a singleton (InstanceContextMode=Single) is the easiest solution be aware that you'll generally kill service scalability unless you also make your code multi-threaded (ConcurrencyMode=Multiple). If you can knock out thread-safe code in your sleep then a singleton service might be for you.
simplest is to use a synchronization mechanism - have you looked at lock(...) - this will act as a gatekeeper a lot like a critical section (if you have come across those in windows programming)
define a static object in your class
i.e.
static object lockObject = new object();
and use it in Generate method
i.e.
void Generate()
{
lock(lockObject)
{
...
}
}
On an ASP.NET website, are static classes unique to each web request, or are they instantiated whenever needed and GCed whenever the GC decides to disposed of them?
The reason I ask is because I've written some static classes before in C# and the behavior is different than I would have expected. I would have expected static classes to be unique to each request, but it doesn't seem like that is the case.
If they are not unique to each request, is there a way to allow them to be?
UPDATE:
The answer driis gave me was exactly what I needed. I was already using a singleton class, however it was using a static instance and therefore was being shared between requests even if the users were different which in this case was a bad thing. Using HttpContext.Current.Items solves my problem perfectly. For anyone who stumbles upon this question in the future, here is my implementation, simplified and shortened so that it easy to understand the pattern:
using System.Collections;
using System.Web;
public class GloballyAccessibleClass
{
private GloballyAccessibleClass() { }
public static GloballyAccessibleClass Instance
{
get
{
IDictionary items = HttpContext.Current.Items;
if(!items.Contains("TheInstance"))
{
items["TheInstance"] = new GloballyAccessibleClass();
}
return items["TheInstance"] as GloballyAccessibleClass;
}
}
}
Your static classes and static instance fields are shared between all requests to the application, and has the same lifetime as the application domain. Therefore, you should be careful when using static instances, since you might have synchronization issues and the like. Also bear in mind, that static instances will not be GC'ed before the application pool is recycled, and therefore everything that is referenced by the static instance, will not be GC'ed. This can lead to memory usage problems.
If you need an instance with the same lifetime as a request, I would suggest to use the HttpContext.Current.Items collection. This is by design meant to be a place to store stuff that you need througout the request. For nicer design and readability, you can use the Singleton pattern to help you manage these items. Simply create a Singleton class that stores its instance in HttpContext.Current.Items. (In my common library for ASP.NET, I have a generic SingletonRequest class for this purpose).
Static members have a scope of the current worker process only, so it has nothing to do with requests, because different requests may or may not be handled by the same worker process.
In order to share data with a specific user and across requests, use HttpContext.Current.Session.
In order to share data within a specific request, use HttpContext.Current.Items.
In order to share data across the entire application, either write a mechanism for that, or configure IIS to work with a single process and write a singleton / use Application.
By the way, the default number of worker processes is 1, so this is why the web is full of people thinking that static members have a scope of the entire application.
Since the types are contained in an app domain, I would expect static classes to be present as long as the app domain is not recycled, or if the request gets served by a different app domain.
I can think of several ways to make objects specific to a particular request depends on what you want to do, for e.g. you could instantiate the object in Application.BeginRequest and then store it in HttpRequest object so that it can be accessed by all objects in the request processing pipeline.
If they are not unique to each request, is there a way to allow them to be?
Nope. Static members are owned by the ASP.NET process and shared by all users of the Web app. You'll need to turn to other session management techniques such as session variables.
Normally static methods, properties and classes are common at the Application level. As long as the application lives, they are shared.
You can specify a different behaviour by using the ThreadStatic attribute. In that case they will be specific to the current thread, which, I think, is specific for each request.
I would not advise this though as it seems overcomplicated.
You can use HttpContext.Current.Items to set stuff up for one request, or HttpContext.Current.Session to set stuff up for one user (across requests).
In general though, unless you have to use things like Server.Transfer, the best way is basically creating things once and then passing them explicitly via method invocation.