Understanding WCF Self-Hosting approach using ServiceHost class and its constructors - c#

I have some doubts regarding service hosting in WCF.
I want to host a service using the self-hosting approach.
ServiceHost class comes to the rescue.
By using it, it is possible to host a service having a direct access to the Windows Hosting Framework.
Well, consider the following approaches:
0) COMMON ASSUMPTIONS: All cases assume that configuration file App.config is used in order to set endpoints' ABC. So in the following codes no mention about endpoint, just do not bother about it.
We will consider this services too:
[ServiceContract]
public interface IMyService {
[OperationContract]
string MyOp1(int myint);
[OperationContract]
string MyOp2(int myint);
}
public class MyService : IMyService {
// This service needs to be constructed providing at least a string or an integer, if an attempt to construct it wothout passing any of these is done, the service should raise an error.
MyService(string strparam) { ... }
MyService(int intparam) { ... }
MyService(string strparam, int intparam) { ... }
public string MyOp1(int myint) { ... }
public string MyOp2(int myint) { ... }
}
public class MyStandaloneService : IMyService {
// This service does not need to be constructed.
MyStandaloneService() { ... }
public string MyOp1(int myint) { ... }
public string MyOp2(int myint) { ... }
}
1) CASE 1: It is possible to host a service using this overload of the ServiceHost class:
public ServiceHost(
Type serviceType,
params Uri[] baseAddresses
)
By using it, it is possible to let the framework manage the service instantiation because simply the service type is required. Of course the construction is the base contruction if the service. The no parameter constructor will be called. This overload is good when handling services that do not need special construction... some kind of standalone services:
using (ServiceHost host = new ServiceHost(typeof(MyStandaloneService))) {
host.Open();
...
host.Close();
}
2) CASE 2: It is possible to host a service using this overload of the ServiceHost class:
public ServiceHost(
Object singletonInstance,
params Uri[] baseAddresses
)
By using it, it is possible to instantiate a service and then host it without letting the framework handle this... this approach is good when dealing with services that need special treatment and are not completely standalone:
MyService MS = new MyService("the string");
using (ServiceHost host = new ServiceHost(MS)) {
host.Open();
...
host.Close();
}
Well I would like to understand the following:
A) In CASE 1 it is possible to host a service automatically by providing the type. If I attempt to create another service of the same type (MyStandaloneService), does it result in an error because trying to create two same services? Probably I should hardcode, in this case, endpoint configurations because using the config file will result in two same services hosted n the same address.
B) In CASE 2 the MSDN documentation says this creates a singleton instance of the service. So If I attempt to host another service in this way:
MyService MS = new MyService("the string");
MyService MS2 = new MyService(23);
ServiceHost host = new ServiceHost(MS));
ServiceHost host2 = new ServiceHost(MS2));
host.Open();
host2.Open();
...
host.Close();
host2.Close();
Would I get an error?
C) If I wanted to avoid singleton instantiation what should I do?
Thanks

First of all, you probably need to check out the ServiceBehaviorAttribute MSDN article.
I don't go into details here, but you can either create one instance of the service object to handle ALL requests (sequentially, that is, one after the other), or let the ServiceHost object create one service object per request and handle them simultaneously in different threads.
Once you decide what approach suits you best in your application, you will understand which one of the ServiceHost constructor overloads to use. Your CASE 1 corresponds to multiple-instances simultaneous handling approach, and CASE 2 corresponds to 'one instance to handle them all' approach.
The ServiceHost overloads must go hand-to-hand with [ServiceBehavior] attribute on your MyService class. So, please check out the link I gave above.
EDIT: now responding to your questions:
A) If I attempt to create another service of the same type (MyStandaloneService), does it result in an error because trying to create two same services?
No, it is what will be done by ServiceHost: it will create one instance of the service per request (in fact, per session, but again read MSDN)
B) In CASE 2 the MSDN documentation says this creates a singleton instance of the service. So If I attempt to host another service in this way (...) Would I get an error?
You can't host two services with the same ABC at once, so yes. If you host them on different endpoints, it's OK. The 'singleton' here means that one single service instance will handle all requests.
C) If I wanted to avoid singleton instantiation what should I do?
Use CASE 1 approach :)

To get a non-default constructor called for each instance of a non-singleton service, you should look at IInstanceProvider. You can use ServiceBehaviorAttribute with InstanceContextMode = PerCall to get a new service object for each call, and your IInstanceProvider will be used to get that object, so you can do whatever setup you need to do.

Related

How to call a method of the ServiceHost from the hosting process in WCF C#

I have a publisher / subscriber pattern WCF Duplex ServiceHost that is hosted by a Windows Service. The Windows Service receives events from a separate process. OnEvent I would like to force my WCF Host to publish that data to all subscribed clients. Typically if a Client is calling this is straight forward. But when my Service Host needs to do this - I can't get my head around HOW to do that.
I have 2 questions:
1: I do not know how to create a Channel in WCFHost from my Windows Service so that it can use to publish to the Subscribers.
2: I read Creating WCF ChannelFactory so I do know I am creating a DuplexChannelFactory (2 per second ) which might be too much overhead.
Any help examples, hints are greatly appreciated. I am not a WCF expert and currently know more about it than I thought I should have to know in order to use it.
I had read on SO
Can I call a Method in a self hosted wcf host locally?
So then I have created a method inside my WCFHost like so:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
AutomaticSessionShutdown = false,
IncludeExceptionDetailInFaults = true)]
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServerHost<TService> : ServiceHost where TService : class
{
public T GetDuplexClientChannel<T, Cback>(BindingType bindingType, EndpointAddress endPointAddress) where T : class
{
ServiceEndpoint sep = GetContractServiceEndPoint<T>(bindingType, endPointAddress);
lock (_syncRoot)
{
DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(typeof(Cback), sep);
return factory.CreateChannel(endPointAddress);
}
}
}
I get an error of course that there is no InstanceContext because I am constructing using typeof(Cback) ..
"This CreateChannel overload cannot be called on this instance of DuplexChannelFactory, as the DuplexChannelFactory was initialized with a Type and no valid InstanceContext was provided."
So I am not sure how I can go about performing this ?
And for those that say read the error : yes I read the error.
Now how to do that with an InstanceContext that does not exist as OperationContext.Current does not exist at this point as I am calling this method form my Hosting Process into my WCFHost.
So if I could have a nice example of how to do this - even if I must use the code example on the 2nd link (of course implementing the DuplexChannelFactory) I would greatly appreciate it.
EDIT
Basically the windows Service is doing some heavy work monitoring other services, about 2 times a second it then must publish that to "Subscribed" Clients via WCF.
I think you have got very confused about how everything is wired together and are mixing concepts from the client in with the service. You haven't provided much concrete information about your scenario to go on so I'm going to provide a small example and hopefully you will be able to apply the ideas to your problem.
[ServiceContract(CallbackContract=typeof(IMyServiceCallback))]
public interface IMyService
{
[OperationContract]
void Register();
}
public interface IMyServiceCallback
{
[OperationContract]
void ReceiveData(string data);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
static HashSet<IMyServiceCallback> s_allClients = new HashSet<IMyServiceCallback>();
static object s_lockobj = new object();
public void Register()
{
lock(s_lockobj)
{
_allClients.Add(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>());
}
}
public static void SendDataToClients(string data)
{
HashSet<IMyServiceCallback> tempSet;
lock(s_lockobj)
{
tempSet = new HashSet<IMyServiceCallback>(_allClients);
}
foreach(IMyServiceCallback cb in tempSet)
{
try
{
cb.ReceiveData(data);
}
catch(Exception)
{
lock(s_lockobj)
{
_allClients.Remove(cb);
cb.Abort();
cb.Dispose();
}
}
}
}
}
In your OnEvent method, you would call something similar to this inside your event method.
MyService.SendDataToClients(mydata);
This uses static data to store the list of clients. If you wanted to do something like segment your clients for different endpoints, you would need to do something different. There is a potential out of order message and scaling problem with this code if your OnEvent method can be called again while the previous call hasn't completed. For example, if you receive 2 messages, the first being large and the second being small, you could potentially send the second smaller message to clients later in the HashSet iteration order before they have been sent the first message. Also this won't scaled to a large number of clients as you could block timing out on one client holding up messages being sent to other clients. You could use something similar to Task's to dispatch multiple message deliveries. If this needs to scale, I would suggest looking at Reactive Extensions for .Net

How to invoke WCF service with own constructor using my InstanceProvider

I am kind of new in implementing and using WCF services and extremely new (and apparently clueless) in DI.
I have WCF Services which are having constructors. The parameters of the constructors could only come in runtime from the Client application (Web server).
Something like this:
In Application server:
public class MyService : IMyService {
private IUserContext userContext;
public MyService(IUserContext uContext) {
this.userContext = uContext;
}
public DoWork() {
... // uses uContext
}
}
In Web server can only see IMyService and not the implementation of the MyService. The code would be something like this (oversimplified console app):
class Program {
static void Main(string[] args) {
var factory = new ChannelFactory<IMyService>("MyServiceEndpoint"); // MyServiceEndpoint correctly defined in config file
var client = factory.CreateChannel();
client.DoWork();
((IClientChannel)client).Close();
factory.Close();
}
}
First WCF "forced" me to use parameter-less constructor in the implementation of MyService in order to test it I added that by initializing the UserContext object. Of course I don't have the necessary info to create the object in compile time so this won't help me.
I proceeded with using this solution creating my own ServiceHostFactory, ServiceHost and IInstanceProvider where IDependency is an interface IUserContext which is implemeted by my UserContext class.
This works as expected, I registered in my svc file the custom factory, I don't need parameter-less constructor anymore. However since I don't know how to pass my UserContext to the InstanceProvider I only get a default UserContext object.
Now my noviceness comes in. I don't know how to invoke MyService by passing in the UserContext which lives in the web server. Do I also need own ChannelFactory?
Can someone direct me in the right way by updating the web server dummy code?
Thanks!
Remark: I don't want UserContext to be a parameter of the DoWork() method, because that would mean changing the parameter list of all my services and all calls...
The notion of constructors does not exist on the wire (no matter what transport you are using). For that reason you will never be able to make the client invoke a particular constructor. This is simply not part of the design of WCF (also not part of SOAP).
Don't use constructor parameters that are provided by the client. Or, make the service class have a parameterless ctor and make all service methods accepts the former constructor parameters as normal parameters.
You can also transmit common parameters as SOAP headers. That saves you changing the signature of all service methods.

Self hosted WCF service - confusing behavior

I'm in the process of learning WCF, and as a practical exercise I've decided to write generic wrapper for the ServiceHost class. The idea is to have a class like the one below :
public class Host<I(nterface), S(ervice)>
where S : I, new()
{
/**/
ServiceHost mServiceHost;
S mServiceInstance = new S();
}
Where the I type is the interface with the [ServiceContract] attribute & the S type is the Service that's implementing the forementioned interface.
I've created an auxiliary hello-world type service in the mean time to test my class on the go.
In the Host's constructor I've instantiated the internal ServiceHost like this :
mServiceHost = new ServiceHost(mServiceInstance);
I've added a service endpoint :
mServiceHost.AddServiceEndPoint(typeof(I), new BasicHttpBinding(), new Uri("http://localhost:40000/MyTestService"));
a bit later I've opened the host, launched my application and attempted to see if my browser will indicate a service present under the "http://localhost:40000/MyTestService" - I got a blank page and all attempts to add a service reference failed.
I've later added the same Uri to the ServiceHost's constructor :
mServiceHost = new ServiceHost(mServiceInstance, new Uri("http://localhost:40000/MyTestService"));
That constructor's 2nd argument is either :
params string[] baseAddresses
or
params Uri[] baseAddresses
In any case, the presence of the "params" keyword tells me that this parameter is OPTIONAL.
I've reacitvated my app, and (using the browser) navigated to the uri. The service page popped up. All in all - it's working but not the way I expected, I seem to be missing something.
Questions :
Why did the service fail when I did not supply the optional baseAddresses parameter in the ServiceHost constructor - while attempting to feed the addresses while adding service endpoints?
Can I achieve my goal "the way I initially wanted it to be" ?
Best regards, and hoping to hear from any WCF experts soon(tm).
Greg Sansom answered your first question.
As for the second it can be done: please get a look at Juval Lowy's ServiceModelEx classes (especially ServiceHost) download here it contains several useful classes for WCF

WCF service returning another service (service factory?)

We are using WCF for communication between a client and a server application. The client application has many features that requires communication to the server - and we have chosen to implement this in multiple classes (seperation of responsability)
For the time, we are creating new WCF endpoints and service contracts for each object - Invoicing, Accounting, Content Management, etc. This causes a lot of endpoint configuration both on the client and server (with potential misconfiguration problems when moving into the test and production platforms).
I would like to know if I can define a single WCF endpoint that can deliver multiple service contact implementations. Our configuration files would then contain a single endpoint (to the service factory) and I can request different services by specifying the interface of the service I am interested in.
e.g.
using (IServiceClientFactory serviceClientFactory = new RealProxyServiceClientFactory())
{
// This is normal WCF proxy object creation.
IServiceFactory serviceFactory = serviceClientFactory.CreateInstance<IServiceFactory>("");
// This is what we would like to do
IInvoiceService invoiceService = serviceFactory.getService(typeof(IInvoiceService));
invoiceService.executeOperation(data);
}
The clue being a single endpoint configuration per client/server pair, instead of an endpoint configuration per service contact I would like to make available.
Is this possible?
I'm not 100% clear on what you're trying to do, but if you just want to be able to host different contracts on the same address with the implementation inside one service class, this is completely possible. To share an endpoint address, you must ensure that you use the same binding instance for each service endpoint.
Here is a complete sample which defines 3 contracts, 1 service class which implements all of them, and a ServiceHost with the 3 contract endpoints at the exact same address:
using System;
using System.ServiceModel;
[ServiceContract]
interface IContractA
{
[OperationContract]
void A();
}
[ServiceContract]
interface IContractB
{
[OperationContract]
void B();
}
[ServiceContract]
interface IContractC
{
[OperationContract]
void C();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Service : IContractA, IContractB, IContractC
{
public Service()
{
}
public void A()
{
Console.WriteLine("A");
}
public void B()
{
Console.WriteLine("B");
}
public void C()
{
Console.WriteLine("C");
}
}
class Program
{
public static void Main(string[] args)
{
Uri address = new Uri("net.pipe://localhost/Service/");
ServiceHost host = new ServiceHost(new Service(), address);
NetNamedPipeBinding binding = new NetNamedPipeBinding();
host.AddServiceEndpoint(typeof(IContractA), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractB), binding, string.Empty);
host.AddServiceEndpoint(typeof(IContractC), binding, string.Empty);
host.Open();
IContractA proxyA = ChannelFactory<IContractA>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyA.A();
((IClientChannel)proxyA).Close();
IContractB proxyB = ChannelFactory<IContractB>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyB.B();
((IClientChannel)proxyB).Close();
IContractC proxyC = ChannelFactory<IContractC>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));
proxyC.C();
((IClientChannel)proxyC).Close();
host.Close();
}
}
I doubt that this would work. Xml serialization might be the biggest problem here.
Also I don't think you actually need it. If I was in your shoes I would try and abstract my communication with the service. Basically you would always send a "Message" to the service, which has a "Target" being one of the classes you wanted to access. The service would always reply with a "Response", of which the contents would be filled by the class the "Message" was send to.
Another approach would be to route all these messages trough a service that would echo the request to the appropriate service. This way you keep scalability up, but it does still have a large configuration burden.
HTH.
Sounds like you want to keep your seperate services but have some kind of bus that routes is throught. MSMQ maybe, then you can have one services that takes every message pops it onto a specific queue and then a dedicated service can read that off that particular queue.
Not really a WCF based solution though admittedly.
The notion of a single interface(read as ServiceContract) implemented by multiple classes wont work. So you'd need one 'monster' service that implements all and routes through to the correct service. Facade pattern springs to mind.

Stop/start WCF MEX service at runtime

Is it possible/how do I stop and start the HTTP MEX listener of a self hosted WCF service at runtime without affecting the primary WCF service?
(Please don't ask why I want to do this. It is a hack to get around artificial limitations imposed by someone else.)
*****[Re-added this answer after re-test and code cleanup] This is actual code that I have added to my generic WCF-based service development framework and it is fully tested.*****
Assuming that you start with MEX enabled on the ServiceHost...
The following solution is written in
terms of a ServiceHost subclass
(WCFServiceHost<T>) that implements
a special interface (IWCFState) for
storing an instance of the MEX
EndpointDispatcher class.
First, add these namespaces...
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
Secondly, define the IWCFState interface...
public interface IWCFState
{
EndpointDispatcher MexEndpointDispatcher
{
get;
set;
}
}
Thirdly, create a static class for some ServiceHost extension methods (we'll fill them in below)...
public static class WCFExtensions
{
public static void RemoveMexEndpointDispatcher(this ServiceHost host){}
public static void AddMexEndpointDispatcher(this ServiceHost host){}
}
Now let's fill in the extension methods...
Stopping MEX on a ServiceHost at Runtime
public static void RemoveMexEndpointDispatcher(this ServiceHost host)
{
// In the simple example, we only define one MEX endpoint for
// one transport protocol
var queryMexChannelDisps =
host.ChannelDispatchers.Where(
disp => (((ChannelDispatcher)disp).Endpoints[0].ContractName
== "IMetadataExchange"));
var channelDisp = (ChannelDispatcher)queryMexChannelDisps.First();
// Save the MEX EndpointDispatcher
((IWCFState)host).MexEndpointDispatcher = channelDisp.Endpoints[0];
channelDisp.Endpoints.Remove(channelDisp.Endpoints[0]);
}
Then call it like this...
// WCFServiceHost<T> inherits from ServiceHost and T is the Service Type,
// with the new() condition for the generic type T. It encapsulates
// the creation of the Service Type that is passed into the base class
// constructor.
Uri baseAddress = new Uri("someValidURI");
WCFServiceHost<T> serviceImplementation = new WCFServiceHost<T>(baseAddress);
// We must open the ServiceHost first...
serviceImplementation.Open();
// Let's turn MEX off by default.
serviceImplementation.RemoveMexEndpointDispatcher();
Starting MEX (again) on a ServiceHost at Runtime
public static void AddMexEndpointDispatcher(this ServiceHost host)
{
var queryMexChannelDisps =
host.ChannelDispatchers.Where(
disp => (((ChannelDispatcher)disp).Endpoints.Count == 0));
var channelDisp = (ChannelDispatcher)queryMexChannelDisps.First();
// Add the MEX EndpointDispatcher
channelDisp.Endpoints.Add(((IWCFState)host).MexEndpointDispatcher);
}
Then call it like this...
serviceImplementation.AddMexEndpointDispatcher();
Summary
This design allows you to use some messaging methods to send a command to the service itself or to code that is hosting the service and have it carry out the enabling or disabling of a MEX EndpointDispatcher, effectively turning off MEX for that ServiceHost.
Note: This design assumes that the code will support MEX at startup, but then it will use a config setting to determine if the service will disable MEX after calling Open() on the ServiceHost. This code will throw if you attempt to call either extension method before the ServiceHost has been opened.
Considerations: I would probably create a special service instance with management operations that did not support MEX at startup and establish that as service control channel.
Resources
I found the following two resources indispensable while figuring this out:
.NET Reflector: class browser, analyzer & decompiler for inspecting assemblies like System.ServiceModel.dll: http://www.red-gate.com/products/reflector/
Extending Dispatchers (MSDN): provides a fantastic high-level diagram of the class composition of a WCF service: http://msdn.microsoft.com/en-us/library/ms734665.aspx

Categories