Custom ServiceHost with DI and InstanceContextMode.Percall - c#

In my Managed Application, I currently have my WCF services running as:
SomeService service = new SomeService(container) //IUnityContainer
ServiceHost serviceHost = new ServiceHost(service, serviceAddress);
Whats the catch ? SomeService defined with:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single
This is not good anymore, I need to make it InstanceContextMode.PerCall.
When trying to .Open() If changing the InstanceContextMode to "PerCall" - it will throw:
System.InvalidOperationException: In order to use one of the ServiceHost constructors that takes a service instance, the InstanceContextMode of the service must be set to InstanceContextMode.Single. This can be configured via the ServiceBehaviorAttribute. Otherwise, please consider using the ServiceHost constructors that take a Type argument
Is this the solution to my problem ? How do I pass values to the constructor on my wcf service?
My Main concern:
I run different types of services inside this managed application, It seems that this solution is good only if i run one type of service.

When more than one service instance will be needed (PerCall or PerSession) then passing a single service instance into the ServiceHost isn’t enough... which is the exception.
Controlling instance creation is managed by the IInstanceProvider.
Is this the solution to my problem ? How do I pass values to the constructor on my wcf service?
This only answers half your question. You are using Unity. The management of creating the container needs to be part of the implementation. The most common solution is to use Unity.WCF which is also available as a NuGet package.
Note that Unity.WCF doesn’t support object lifetimes based WCF OperationContexts. There are multiple (more complicated) implementations like this that do.

Related

How to inject parameters for a Single WCF Service without the default parameter-less constructor

I'm using SimpleInjector and I get the following error when I try to call SimpleInjectorServiceHostFactory-->CreateServiceHost(Type serviceType, Uri[] baseAddresses). This error appear only for the WCF services marked as [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)].
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.
For the services marked as [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] the SimpleInjectorServiceHostFactory-->CreateServiceHost(Type serviceType, Uri[] baseAddresses) method works perfectly even if the service doesn't have a default parameter-less constructor.
Any idea how to have an injection of the parameters for [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] services just like it happens with [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] services without the default parameter-less constructor ?
Thanks
After some digging I found that this is a bug in Simple Injector, or at least a misinterpretation in the way WCF handles this.
The ServiceHost class needs the singleton object in its ctor instead of the type. If the type is supplied the ServiceHost will try to create the instance and it therefore needs a default constructor.
I created a issue on GitHub for this.
but why this default constructor is not required for the "PerCall" WCF Service
Because in that case WCF will call back into the container for creating the type and Simple Injector offcourse can handle the parameters in the constructor.
A possible workaround would be to indeed configure your service as PerCall and assuming you want Single for some caching, refactor the cache out of the WCF implementation into its own class and register this as a singleton in Simple Injector.
You have to have a default constructor which is what WCF service calls to create your instance. You can take over this process by using your own IInstanceProvider and inject what you need.
If you are using Singleton (Single) then ServiceHost expects that you pass an already created instance (which you can create with any kind of constructor). I am not sure what your DI fx does to constructing this kind of instance. See this answer WCF ConcurrencyMode Single and InstanceContextMode PerCall as well.

wcf instances not correct instanciated

I read this Article and I thought I write a little ping Service (Both Service and Client can ping).
however, when I use
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession,
ConcurrencyMode = ConcurrencyMode.Multiple)]
My ping service only creates one instance. But I want multiple instances. My callback interface is saved in a private but it is overwritten because when the clients register, they register to one instance and not different.
Is that Bad design in my case or why does wcf only create one instance?
The problem was with the Windsor Container.
When I instanciate a Component with ´.AsWcfService´ Windsor doesn't care about the ServiceBehavior. So I need to set the lifestile to transient for this case.

Created WCF service, Hosted in window service, Trying to consume within that service. How to do?

I created a WCF service library. Then I created a Windows service to host this WCF service.
Now I want to call a function defined in WCF service library within same window service.
protected override void OnStart(string[] args)
{
if (serviceHost != null)
serviceHost.Close();
// Create a ServiceHost for the Registration type and
// provide the base address.
serviceHost = new System.ServiceModel.ServiceHost(typeof(Registration));
// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
Registration r = new Registration();
System.Threading.Thread t = new System.Threading.Thread(r.ReadAttempt);
Object passParameterToCallback = null;
t.IsBackground = false;
t.Start(passParameterToCallback);
}
If you just need to call a method on the same class, then you are already doing that in your code by just creating a new Registration() and calling a method on it. There is no reason to call through WCF.
If for some reason you do want to call your service through WCF to yourself, then you should construct a client instead of the actual class.
If you need to call the same instance of your WCF service object, then you will have to have your WCF service set to Single, and then call your WCF client.
Or use this constructor for ServiceHost that takes in a singleton object, then call methods on the same object instance, or then use the ServiceHost.SingletonInstance property to get back that instance that was passed to the constructor.
ServiceHost class should also be able to take in an singleton instance of the service instead of a type, according to this:
http://msdn.microsoft.com/en-us/library/ms585487.aspx
So, try instantiating the class of type Registration, and pass that to ServiceHost. This only works like I said though, with a singleton type WCF service, or more specifically one where you have InstanceContextMode set to Single.
That way you should be left with a reference to the class, and should be able to access it fine.
It might be worth thinking of it all in another way though. If your problems is just notifying the windows service about things happening in the WCF service, how about defining an event inside your WCF service your windows service could subscribe to and receive events from your WCF service in that way?
If it is logic that you need to use inside your WCF service, how about extracting that logic to an external class or making it static, so you can use it anywhere.
Good luck

Persisting a WCF service hosted within a windows service? (i.e. instantiating once and only once)

I have the following problem. There is a WCF service hosted within a windows service like this:
sHost = new ServiceHost(typeof(DataService));
_thread = new Thread(new ThreadStart(sHost.Open));
_thread.Start();
Where DataService is a WCF Service Contract in the solution.
Several layers below the WCF service is a cache in a seperate assembly. But, every time a new connection/proxy to the WCF service is made, a new instance of the service is created. This results in a new instance of the cache being created in the DAL. So what I would like to do is have the WCF service and therefore all classes down the stack instanced once and only once (with some exceptions due to multiplicity requirements). So, the WCF service should be instanced and listen for new connections, rather than have DataService instanced every single time a new connection is made.
I hope this makes sense. How do I do this?
Many thanks,
Fugu
Instantiate DataService yourself and pass the instance to the ServiceHost constructor:
sHost = new ServiceHost(new DataService());
I think alexdej answer is correct, but without seeing your code cannot comment to why you get a Null reference exception.
I can however point you to these videos', I completed these only 2 days ago to help learn WCF and I am sure they will answer your question.
Self hosting WCF - http://channel9.msdn.com/shows/Endpoint/Endpoint-Screencasts-Self-hosting-WCF-Services/
Hosting WCF as a windows service - http://channel9.msdn.com/shows/Endpoint/endpointtv-Screencast-Hosting-WCF-Services-in-Windows-Services/

WCF Web/ServiceHost - Singletons and initialisation

I have some Service class which is defined as InstanceContextMode.Single, and is well known in the hosting application. (The host creates an instance, and passes that to the WebServiceHost)
Hosting app:WebServiceHost host = null;
SomeService serviceInstance = new SomeService("text", "more text");
host = new WebServiceHost(serviceInstance, baseUri);
Problem:
When I go to use the variables initialised when the service is created (ie, when a call is made to the service), they are either null or empty...
Am I wrong in assuming that as the instance being initialised in the hosting application is used for each request to the WebServiceHost?
Any pointers here would be great.
Your assumption seems correct to me.
Did you put the right code in the service constructor?

Categories