4
votes

I have developed a WCF service for consumption within the organization's Ethernet.
The service is currently hosted on a windows-service and is using net.tcp binding.
There are 2 operation contracts defined in the service.
The client connecting to this service is a long running windows desktop application.
Employees(>30,000) usually have this client running throughout the week from Monday morning to Friday evening straight.

During this lifetime there might be a number of calls to the wcf service in question depending on a certain user action on the main desktop client. Let us just say 1 in every 3 actions on the main desktop application would trigger a call to our service.

Now we are planning to deploy this window service on each employee's desktop
I am also using `autofac` as the dependency resolver container.
My WCF service instance context is `PerSession`, but ideally speaking we have both the client and service running in the same desktop (for now) so I am planning to inject the same service instance for each new session using `autofac` container.
Now am not changing the `InstanceContext` attribute on the service implementation because in future I might deploy the same service in a different hosting environment where I would like to have a new service object instance for each session.

Like mentioned earlier the client is a long running desktop application and I have read that it is a good practise to `Open` and `Close` the proxy for each call but if I leave the service to be PerSession it will create a new service instance for each call, which might not be required given the service and client have a 1-1 mapping.
Another argument is that I am planning to inject the same instance for each session in this environment, so Open & Close for each service call shouldn't matter ?
So which approach should I take, make the service `Singleton` and Open Close for each call or Open the client-side proxy when the desktop application loads/first service call and then Close it only when the desktop application is closed ?

1
when I mean by injecting the same singleton instance, I am talking about injecting the same service instance for each time Open is called by a client proxy, I am not injecting a singleton instance of the client proxy.Vignesh.N

1 Answers

5
votes

My WCF service instance context is PerSession, but ideally speaking we have both the client and service running in the same desktop (for now) so I am planning to inject the same service instance for each new session using autofac container

Generally you want to avoid sharing a WCF client proxy because if it faults it becomes difficult to push (or in your case reinject) a new WCF to those parts of the code sharing the proxy. It is better to create a proxy per actor.

Now am not changing the InstanceContext attribute on the service implementation because in future I might deploy the same service in a different hosting environment where I would like to have a new service object instance for each session

I think there may be some confusion here. The InstanceContext.PerSession means that a server instance is created per WCF client proxy. That means one service instance each time you new MyClientProxy() even if you share it with 10 other objects being injected with the proxy singleton. This is irrespective of how you host it.

Like mentioned earlier the client is a long running desktop application and I have read that it is a good practise to Open and Close the proxy for each call

Incorrect. For a PerSession service that is very expensive. There is measurable cost in establishing the link to the service not to mention the overhead of creating the factories. PerSession services are per-session for a reason, it implies that the service is to maintain state between calls. For example in my PerSession services, I like to establish an expensive DB connection in the constructor that can then be utilised very quickly in later service calls. Opening/closing in this example essentially means that a new service instance is created together with a new DB connection. Slow!

Plus sharing a client proxy that is injected elsewhere sort of defeats the purpose of an injected proxy anyway. Not to mention closing it in one thread will cause a potential fault in another thread. Again note that I dislike the idea of shared proxies.

Another argument is that I am planning to inject the same instance for each session in this environment, so Open & Close for each service call shouldn't matter ?

Yes, like I said if you are going to inject then you should not call open/close. Then again you should not share in a multi-threaded environment.

So which approach should I take

Follow these guidelines

  1. Singleton? PerCall? PerSession? That entirely depends on the nature of your service. Does it share state between method calls? Make it PerSession otherwise you could use PerCall. Don't want to create a new service instance more than once and you want to optionally share globals/singletons between method calls? Make it a Singleton

  2. Rather than inject a shared concrete instance of the WCF client proxy, instead inject a mechanism (a factory) that when called allows each recipient to create their own WCF client proxy when required.

  3. Do not call open/close after each call, that will hurt performance regardless of service instance mode. Even if your service is essentially compute only, repeated open/close for each method call on a Singleton service is still slow due to the start-up costs of the client proxy

  4. Dispose the client proxy ASAP when no longer required. PerSession service instances remain on the server eating up valuable resources throughout the lifetime of the client proxy or until timeout (whichever occurs sooner).

  5. If your service is localmachine, then you consider the NetNamedPipeBinding for it runs in Kernel mode; does not use the Network Redirector and is faster than TCP. Later when you deploy a remote service, add the TCP binding

I recommend this awesome WCF tome

enter image description here