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
*****[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 MEXEndpointDispatcher
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...
ServiceHost
at Runtimepublic 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();
ServiceHost
at Runtimepublic 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();
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.
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