Reputation: 9733
I have created a WCF service which reads from a database and sends back results. For performance reasons I'd like to cache the tables on service startup (which happens in a windows service OnStart). But there's no such thing as constructors in WCF (right?) so best thing I came up with is create an Init() function and call that like the following:
protected override void OnStart(string[] args)
{
mServiceHost = new ServiceHost(typeof(DLSService.DLSService), new Uri("http://localhost:8000/DLS"));
mServiceHost.AddServiceEndpoint(typeof(DLSService.IDLSService), new BasicHttpBinding(), "ServicesHost");
((DLSService.DLSService)mServiceHost.SingletonInstance).Init();
mServiceHost.Open();
}
But using SingletonInstance and casting to the correct type does not seem all that elegeant to me. Are there more elegant ways to achieve constructor like functionality in WCF?
Upvotes: 4
Views: 4765
Reputation: 56
With framework 4.5 you can use a configuration's function in your service implementation code:
http://msdn.microsoft.com/en-us/library/hh205277(v=vs.110).aspx.
Upvotes: 0
Reputation: 1386
This can be solved with a memoization library, like MbCache. We are doing exactly what you are looking for; on application start-up we call each service operation that we want to cache, and MbCache caches the result for consecutive calls (i.e. no database round-trip to get results) until the cache expires.
MbCache does come with its on fair share of complexity, but once it is running it works very well and handles all the cache logic for us.
Upvotes: 3
Reputation: 4742
You can use the IInstanceProvider
interface to create your service, read this article for more information.
Here's an example of code:
public class CustomInstanceProvider:IInstanceProvider
{
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
{
return new DLSService.DLSService();
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
var mServiceHost = new ServiceHost(typeof(DLSService.DLSService), new Uri("http://localhost:8000/DLS"));
mServiceHost.AddServiceEndpoint(typeof(DLSService.IDLSService), new BasicHttpBinding(), "ServicesHost");
foreach (var channelDispatcher in mServiceHost.ChannelDispatchers.OfType<ChannelDispatcher>())
{
foreach (var endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.InstanceProvider = new CustomInstanceProvider();
}
}
mServiceHost.Open();
Upvotes: 1
Reputation: 754348
The recommended best practice is to use the per-call activation model in WCF and keep the services totally stateless.
This means: every time the client makes a request, on the server-side, an instance of your service implementation class will be created, the requested service call will be made, and then the service class will be destroyed again.
So putting your initialization code into the service implementation class constructor would be a really bad idea - it would be executed for each and every single request.
What you could do is have some kind of logic (either in your service class, or some support code, e.g. some kind of an admin interface) that would load those tables you want to cache into a persistent cache, e.g. something like the AppFabric cache. Once done, multiple service instances handling requests could use that common cache to get better performance.
Upvotes: 3