WCF InstanceContextMode.Single, Default Constructors, and Unity
During a refactoring of a WCF solution I was converting all the various services in the solution to use dependency injection with constructors. One of the services was configured as a singleton using the ServiceBehavior InstanceContextMode.Single. This particular service controls a resource that is best left for a singleton because it has an open socket listener that receives responses from our mainframe systems. The service was also configured for transactions and has the ReleaseServiceInstanceOnTransactionComplete explicitly set to false.
When the other developer on the project fired up the test harness for the services he was receiving the message “The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host. “. After testing a few theories I noticed that the service was marked up with the InstanceContextMode behavior. I removed the attribute and tested the service and it worked just fine which lead me to draw a conclusion about how WCF handles the InstanceContextMode attribute.
Because you are telling WCF to manage that service instances lifetime it makes sense that it would require a default constructor because WCF is going to be instantiating and disposing of the service instance. When I refactored the service with no default constructor that was a breaking change for the WCF infrastructure. So the question remains, can Unity handle a singleton service instance?
To test Unity with a Singleton service I followed the steps in my previous article on Unity and WCF and created an IInstanceProvider, IServiceBehavior, and a custom ServiceHost. The results were what I expected. Each call to the service was handled by the singleton instance of the service whose lifetime was being managed by the Unity container.
using System; namespace Service { //[System.ServiceModel.ServiceBehavior(InstanceContextMode=System.ServiceModel.InstanceContextMode.Single)] public class PersonService : Contracts.IPersonService { private Guid _instanceId; /// <summary> /// Initializes a new instance of the PersonService class. /// </summary> public PersonService() { _instanceId = Guid.NewGuid(); } #region IPersonService Members public Contracts.PersonResponse SavePersonRecord(Contracts.PersonRequest request) { return new Contracts.PersonResponse(_instanceId.ToString(), String.Format("Added Person - {0}", request.Person.Name)); } public Contracts.PersonResponse DeletePersonRecord(Contracts.PersonRequest request) { return new Contracts.PersonResponse(_instanceId.ToString(), String.Format("Deleted Person - {0}", request.Person.Name)); } #endregion } }
The client calls the SavePersonRecord method then subsequently the delete person method. As you can see the Instance Id returned by the service is the same for both calls. Removing the lifetime element from the Unity configuration results in two different instance Id’s returning from the service because the default behavior for WCF is to create a new instance per call to the service.
I ran one final test and that was to remove the default constructor and require the Instance Id to be passed to the constructor:
using System; namespace Service { //[System.ServiceModel.ServiceBehavior(InstanceContextMode=System.ServiceModel.InstanceContextMode.Single)] public class PersonService : Contracts.IPersonService { private Guid _instanceId; /// <summary> /// Initializes a new instance of the PersonService class. /// </summary> /// <param name="instanceId"></param> public PersonService(string instanceId) { _instanceId = new Guid(instanceId); } #region IPersonService Members public Contracts.PersonResponse SavePersonRecord(Contracts.PersonRequest request) { return new Contracts.PersonResponse(_instanceId.ToString(), String.Format("Added Person - {0}", request.Person.Name)); } public Contracts.PersonResponse DeletePersonRecord(Contracts.PersonRequest request) { return new Contracts.PersonResponse(_instanceId.ToString(), String.Format("Deleted Person - {0}", request.Person.Name)); } #endregion } }
The Unity configuration now looks like so:
<unity> <typeAliases> <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" /> <typeAlias alias="IPersonService" type="Contracts.IPersonService, Contracts" /> </typeAliases> <containers> <container> <types> <type type="IPersonService" mapTo="Service.PersonService, Service"> <lifetime type="singleton" /> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="instanceId" parameterType="System.String, mscorlib"> <value value="2423f423-a4da-4306-9ba1-452214c517d6"/> </param> </constructor> </typeConfig> </type> </types> </container> </containers> </unity>
Hopefully it is no surprise that the results of calling the service are the same as the screenshot posted above.
I still need to test this with transactions but I believe using the right set of options will prevent WCF from disposing your singleton and allow your custom Unity service host to handle that.
Comments are closed.


