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
Related
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.
I have a WCF Host with something like this:
[ServiceContract]
public interface IMountToOs
{
[OperationContract]
char GetMountDriveLetter();
[OperationContract]
MyTestClass MyTest();
}
public class MyTestClass
{
public string A { get; set; }
public string B { get; set; }
}
Client
private IMountToOs _proxy;
public IMountToOs Proxy
{
get
{
if (_proxy == null)
{
NetTcpBinding binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 2147483647;
binding.OpenTimeout = TimeSpan.FromMilliseconds(50000);
EndpointAddress address = new EndpointAddress("net.tcp://localhost:1234/MountToOsHost");
//_proxy = new MountToOsClient(binding, address);
ChannelFactory<IMountToOs> factory = new ChannelFactory<IMountToOs>(binding);
_proxy = factory.CreateChannel(address);
}
return _proxy;
}
}
While I can access
MessageBox.Show("Okay - " + Proxy.GetMountDriveLetter());
I can't call this method:
MessageBox.Show("Okay - " + Proxy.MyTest().A);
The complete extension is not working. But only while using it in an extension. Even if I insert a Messagebox in the first line of the extension it is not hit. I don't know why. It seems to run a pre-check and find the call of the custom class which is refused or so...
If I use a winform or so there is no problem.
.net 3.5
curious is that I have a break-point and a message of the hosts side. So I see that the method is not called
Update
now I moved the wcf-call in the Load Method of the extension and get a exception:
System.MissingMethodException: method not found:
"Contracts.Interfaces.MyTestClass
Contracts.Interfaces.IMountToOs.MyTest()".
My winform test and this extension use the same interface so that the method should known from both. no contract or so is outdated
According to what I found here and in the comments of the post: "For creating dynamic service proxy using client channel factory method, you will need datacontracts of the service. If you don't have datacontracts but you have the service URL, then you could use reflection to create proxy at runtime and call the service method."
Seems that the MyTestClass type is not known on the client side, so I think you could use reflection, or share the class between the client and server or much more simple, use the datacontract attribute.
Also, found something on MSDN that says something like this:
"When to use a proxy?
We create proxy using svcutil.exe. The output of this tool gives a proxy class and makes corresponding changes to the application configuration file. If you have a service that you know is going to be used by several applications or is generic enough to be used in several places, you'll want to continue using the generated proxy classes. We use proxy in WCF to be able to share the service contract and entities with the client. Proxies have several restrictions like they need to have gets and sets , contructors can't be exposed , methods other than the service contract cannot be exposed, repetition of code, everytime that we add/modify a service contract/data contract/message contract we need to re-generate the proxy for the client.
When to use ChannelFactory
The other option is using the ChannelFactory class to construct a channel between the client and the service without the need of a proxy . In some cases, you may have a service that is tightly bound to the client application. In such a case, it makes sense to reference the Interface DLL directly and use ChannelFactory to call your methods using that. One significant advantage of the ChannelFactory route is that it gives you access to methods that wouldn't otherwise be available if you used svcutil.exe..
When to use a ChannelFactory vs Proxy class?
A DLL is helpful if the client code is under you control and you'd like to share more than just the service contract with the client -- such as some utility methods associated with entities and make the client & the service code more tightly bound. If you know that your entities will not change much and the client code is less, then a DLL would work better than a proxy. If the client to your service is external to the system, such as API, it makes sense to use a proxy, because it makes sharing the contract easier by giving a code file rather than a DLL."
We cant see the class
MountToOsClient: IMountToOs
So we can only assume it is ok.
[DataContract] // Missing
public class MyTestClass
{
[DataMember] // Missing
public string A { get; set; }
[DataMember] // Missing
public string B { get; set; }
}
MountToOsClient can not expose Mytestclass without these attributes.
my application is composed by a lot of different windows service. Each of them creates programmatically a WCF service. I tried to configure my service with a "per-call" instancecontextmode but it seems to process one request at time.
What should I do?
The class implementing the service interface is decorated with this attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
While the service is instantiated like this:
ServiceHost _host = new ServiceHost(typeof(IMultiMarketBatchNotification));
_host.AddServiceEndpoint(typeof(IMultiMarketBatchNotification), binding, myAddress);
where:
IMultiMarketBatchNotification is the service interface
binding is the instance of the binding (NetTcpBinding)
myAddress is a string containing the service url (like net.tcp://...)
Isn't that enough?
Thanks,
Marco
You need to add those lines of code after instating your ServiceHost, but before opening it:
// look for the "ServiceBehavior"
ServiceBehaviorAttribute srvBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
if (srvBehavior == null)
{
// if we didn't find the service behavior - create one and add it to the list of behaviors
srvBehavior = new ServiceBehaviorAttribute();
srvBehavior.InstanceContextMode == InstanceContextMode.PerCall;
host.Description.Behaviors.Add(srvBehavior);
}
else
{
// if we found it - make sure the InstanceContextMode is set up properly
srvBehavior.InstanceContextMode == InstanceContextMode.PerCall;
}
That should do it.
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.
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.