Serve Laurijssen
Serve Laurijssen

Reputation: 9733

WCF initializing code

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

Answers (4)

Chocolim
Chocolim

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

Anton
Anton

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

Vyacheslav Volkov
Vyacheslav Volkov

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

marc_s
marc_s

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

Related Questions