Am stuck on what am sure is a fundamental and easy to solve problem in WCF, just need to be guided towards the right way.
I have a large object (which is actually a trained text classifier) that I need to expose through a Web Service in C# .NET. The classifier object can be loaded from disk when the service initially starts, but I don't want to keep loading it from disk for every request (the object that services requests currently occupies about 6 GB in memory, and it takes a while to keep loading it from disk for every request), so instead I want to persist that object in memory throughout all requests to that web service, and the object should only be loaded when the service starts (instead of loading it when the first web request triggers it).
How would I go about doing that?
Thanks for any help!
Probably the easiest way is to create your service as a singleton. This involves specifying InstanceContextMode = InstanceContextMode.Single in a ServiceBehavior attribute on your service class definition.
However it is very questionable if sending a 6GB object over the wire using WCF is advisable. You can run into all sorts of service availability issues with this approach.
Additionally, singletons are not scalable within a host (can be only one instance per host), although you can host multiple singleton services and then load-balance the requests.
The way I've done this in projects that I've had the problem with in the past is to self host the WCF service inside a Windows Service.
I've then set the data storage object up inside the service as a singleton that persists for the life of the service. Each WCF service call then gets the singleton each time it needs to do something with the data.
I would avoid running in IIS simply because you don't have direct control of the service's lifetime and therefore don't have enough control of when things are disposed and instantiated.
Related
I have a WCF service that uses various config parameters that are located in a database, as well as a cache for better performance. Right now I have a Singleton that holds this information and is initialized on the first call to the Webservice in a lazy loading behavior.
The cache was exenteded lately and so the initialization takes some time, of course resulting in a longer response time on the first service request.
So what would be the most efficient way to do some kind of eager loading initialization of the service before the fist call occurs (probably on application pool start)?
Don't host the service in an asp.net application, but use a self-hosting process (i.e. a console application) or (even better) a WAS (Windows Activation Service) service within IIS.
This is much more reliable and you can initialize service BEFORE first clien call.
See MSDN for details.
What's the general rule of thumb to decide whether to use PerSession or PerCall?
I have a slightly heavy (I think..) WCF service, containing CRUD methods to about 80 tables.
I have separated the WCF service into 7 contracts within 1 service, (i.e., 7 end points within 1 service) such that each contract takes care of its own domain, for example I have a Sales contract, so all sales related tables, and its corresponding operations are within the sales "bounded context"
So my WCF service structure looks something like this:
public partial class ABCService : ISalesService
{
//CRUD methods of all tables related to Sales
}
public partial class ABCService : IMarketingService
{
//CRUD methods of all tables related to Marketing
}
public partial class ABCService : ICustomerService
{
//CRUD methods of all tables related to Customer
}
public partial class ABCService : IProductService
{
//CRUD methods of all tables related to Products
}
My concern with PerCall is that, because I have a fairly large DB/WCF service, I'm afraid that the amount of resources consumed by each call, multiplied by the number of users and the rate of which they call the service, would be far too great.
I do not know the fine details, but I have read that creating a Channel Proxies are expensive operations.
Oh, I'm using hand coded proxies instead of VS's Add service reference to consume my WCF service.
So, my question is, which should I use? PerSession or PerCall?
Update:
I do not need to maintain state between calls.
I'm using NetTCP bindings
In my opinion, to take a decision consider these two points
For going with InstanceContextMode.PerSession - If your users have some session values stored on the WCF service on the server.
For going with InstanceContextMode.PerCall - If your users have nothing stored in session on the WCF service on the server i.e. WCF service requires No per user settings required to store in memory. Requires scalability.
Some points regarding When-And-Why,
InstanceContextMode.PerCall
If your service is stateless and scalable, i.e. benefits are similar to HTTP as it is also stateless.
If service has light-weight initialization code (or none at all).
If your service is single threaded.
Example scenario: For any 1000 client requests in a given time period in a PerCall situation, there will only be 100 objects instantiated for 100 active calls. Secondly if server were to crash then in PerCall situation the only errors that would occur would be to the 100 actual requests that were in progress (assuming fast failover). The other 900 clients could be routed to another server on their next call.
InstanceContextMode.PerSession
If your service has to maintain some state between calls from the same client.
If your service has light-weight initialization code (or none at all). Even though you are only getting a new instance for each client proxy, you still want to be careful about having expensive initialization code in a constructor.
Example scenario: For any 1000 client requests in a given time period in a PerSession situation you may have 1000 objects instantiated on the server but only 100 are actually active in call at any moment. And thus instantiated PerSession objects could be a waste of resources and may impact the ability to serve requests under load. Secondly if server were to crash then in PerSession all 1000 clients who have a session on that server would lose their session and be unable to complete their work.
Reference links:
MSDN - WCF Instancing, Concurrency, and Throttling
SO - Per-Call vs Per-Session
MSDN - Using Sessions in WCF context
The reason you don't see many answers to this type of question online is that it depends. What I would do is try it out -- then open up perfmon on the server where you are hosting the service and add the counters for your service. Just google wcf performance manager counters if you aren't familiar.
The good news is that WCF makes changing the setup pretty easy.
If you are concerned with the cost of instantiating a proxy on the client side, remember that perCall is a service behavior, not a client behavior. Even if you set the service instance context to PerCall, you can still create one instance of your proxy and make a bunch of method calls from that proxy. All perCall means is that when you make a call, an instance of the service is created, your method is called, and the instance of the service is torn down again. If you don't have any expensive initialization on the service instance (i.e. if they're basically static methods) you're probably ok with per call.
My windows service is hosting WCF services.
From what I understand my wcf services can be a singleton or have it create new endpoints per client request.
And I understand from this, if it is singleton, any caching done inside a endpoint will behave different when compared to if the endpoints are generated per client request.
If I am wrong in the above setup, please correct me.
What caching options do I have?
Is it similar to the web where multiple requests which are new instances of web pages have a cache store that can be used application wide?
Take a look at
This Link
for your endpoint management.
It sums to:
Instance Management is a set of techniques helping us to bind all client requests to service instances governing which instance handles which request. In order to get familiar with all instance management modes we should take a brief overview on all of them. Basically there are three instance modes in WCF:
Per-Session instance mode
Per-Call instance mode
Singleton Instance Mode
What I've usually done in situations like this is an per-session instance-cache. (Of course it depends on what I'm trying to do).
I use a cache object as in the following:
Configuration GetCachedConfiguration()
{
// If there is no cached item, get it from the database first.
if (cachedConfiguration == null)
{
cachedConfiguration = ConfigurationData.GetConfigurationData();
}
return cachedConfiguration;
}
Where cachedConfiguration is my static cached object. This function acts as my accessor to configuration data (in this case).
The easiest thing to do is store cached data in static classes.
Can you please answer to the following questions to enlighten me about web services.
What is the lifecycle of web service ? When the class which represents my web service gets instanced and when it's start running (executing) ?
Is it there new instance created for every webMethod call ? And what happens if there are multiple simultaneous requests for same or different web method ?
When to open connection to remote resource, that the onnection is ready before any requests. And this connection must persist through whole lifetime of web service.
Thank you in advace for all answers.
Webservices are nothing more than ASP.NET pages communicating on the SOAP protocol (XML over HTTP). Each method have its own round-trip (like a page, so new instances are created by default). ASP.NET thread pool is used for running a webservice. As web programmer you don't have lot of control over how thread pool is used since it depends on many external factors (system resources, concurrent page requests...).
If you mean database connections by 'Opening connection to remote resources' these connections also are pooled by Connection Pool of ADO.NET and it will be managed automatically. If you external resources are heavy use Singleton webservice model and load external resources in constructor. Don't use singleton patteron on a database connection (It has its own pooling mechanism). You should take care of concurrency issues for your static variables if you are choosing Singleton pattern.
At the end I should say living in managed-world of programming is easier than ever. Most of the time somebody is caring about our doubts.
That depends; You have two instancation models.
"Single Call" (an instance is created for each call made to the service)
"Singleton" (an instance is created on the first call and reused as long as the process remains alive).
See answer 1; Eleboration; Yes, each call get's its own instance
I would seperate that away from the actual Web Service class. You can use another singleton approach to achieve this functionality.
Hope this helps,
I have a written a Windows Service in C#. It is functioning and performing well. I have added a WCF service to the Windows service to enable client applications to connect to the Windows service and obtain stateful information from the Windows service.
I configured the WCF service to be a singleton, so that the same service instance is used to handle all requests from all clients as follows:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
All clients are able to connect and have access to the same stateful information within the WCF service. However, I am running into the following peculiar behavior.
Revised:
I instantiate the WCF service contract within my Windows Service. Any stateful information assigned at the time of instantiation is available to all clients that connect to the service.
However, any stateful information added to the service contract instance later directly from the Windows Service (not by clients) is not visible to clients that connect to the service. It is as if there are two instances of the service contract: One for the Windows Service and one for the clients that connect to the WCF service.
What is the recommended (best) way to instantiate a WCF service and have it be able to access stateful information available within the Windows Service?
I would recommend doing an end-run around this by holding your state in a static member, so that it doesn't matter whether or not WCF is creating a new instance for each call or reusing one. This solves the problem and simplifies the code.
Why does the WCF service have to have stateful information? Couldn't that be stored in a database and accessed when needed?
WCF does allow Singleton instances for services - but it's usually discouraged to use this, unless you absolutely, positively have to. Typically, it's easier and scales much better if you can store the stateful info in e.g. a database table and let clients access that using a normal, per-call WCF service.
UPDATE:
OK, another idea: you'll always only gonna have a single ServiceHost anyway. If you choose the "per-call" instanciation mode (as recommended by all leading experts), the ServiceHost will allocate a thread pool of worker threads which will then service the incoming requests.
Why does the WCF service need to be a singleton? Couldn't you use "per-call" and still get at the stateful information in the NT Service?
A request comes in and an instance of your service object (the service class, implementing the service interface) is created. How do you access the stateful information in the NT service right now? Couldn't you do that from the newly created service instance, too - when you actually need it?
If you have stateful information being held in the NT Service, you'll need to make sure any concurrent access will be properly handled - that's totally independent of whether your WCF service class is a singleton or not.
UPDATE 2:
Using the 'OperationContext.Current.Host', you can access the ServiceHost that hosts a given service instance inside the service method being executed - not sure if you can access the actual NT service instance. But if you create your own custom ServiceHost descendant, which has an additional property "ListOfClients", you should be able to access that list at any time, from any service instance running.
MIND YOU: since there are possibly any number of service requests being processed at any given time, reading the list must be thread-safe, and updating the list from the Windows NT Service is even more "risky" and needs to take these concurrency issues into account! Lock the list if you need to update it - otherwise, you'll have unpredictable results.
Marc
Setting InstanceContextMode.Single will cause the ServiceHost to construct a single instance of your service and use that for all calls. But it sounds like you would like to construct the instance yourself, and populate it with a reference to some shared state. If so, that's called the "well-known instance" pattern and can be accomplished by passing the instance to the ServiceHost constructory, like so:
var svc = new MyServiceClass(state);
var host = new ServiceHost(svc, new Uri(..), ...);
...
ServiceHost will use the instance you pass in for all calls.
An important consideration when using the Single instance mode (whether the object is "well-known" or constructed by the ServiceHost) is threading. By default WCF will only allow one thread to execute concurrently per service instance. So in the PerCall instance mode, since you'll have multiple service instances, you can support multiple concurrent threads which will improve throughput under normal conditions. But with the Single instance mode you only have one service instance so you'd only run one thread at a time. It depends on the service, but it often makes sense then to switch the concurrency mode to Multiple, which will allow multiple concurrent threads into your service instance, but requires that your service implementation be thread-safe.
Some good docs here: http://msdn.microsoft.com/en-us/library/ms731193.aspx