在运行时停止/启动WCF MEX服务

时间:2021-03-15 20:29:26

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?

是否可以/如何在运行时停止并启动自托管WCF服务的HTTP MEX侦听器而不影响主WCF服务?

(Please don't ask why I want to do this. It is a hack to get around artificial limitations imposed by someone else.)

(请不要问我为什么要这样做。这是一个克服其他人施加的人为限制的黑客。)

1 个解决方案

#1


*****[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.*****

***** [重新测试和代码清理后重新添加了这个答案]这是我添加到基于WCF的通用服务开发框架的实际代码,并且已经过全面测试。*****

Assuming that you start with MEX enabled on the ServiceHost...

假设您在ServiceHost上启用MEX启动...

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.

以下解决方案是根据ServiceHost子类(WCFServiceHost )编写的,该子类实现了用于存储MEX EndpointDispatcher类实例的特殊接口(IWCFState)。

First, add these namespaces...

首先,添加这些命名空间......

using System.ServiceModel;
using System.ServiceModel.Dispatcher;

Secondly, define the IWCFState interface...

其次,定义IWCFState接口......

public interface IWCFState
{
    EndpointDispatcher MexEndpointDispatcher
    {
        get;
        set;
    }
}

Thirdly, create a static class for some ServiceHost extension methods (we'll fill them in below)...

第三,为一些ServiceHost扩展方法创建一个静态类(我们将在下面填写)...

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.

此设计允许您使用某些消息传递方法向服务本身或托管服务的代码发送命令,并使其执行MEX EndpointDispatcher的启用或禁用,从而有效地关闭该ServiceHost的MEX。

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.

注意:此设计假定代码在启动时将支持MEX,但随后它将使用配置设置来确定服务是否在ServiceHost上调用Open()后禁用MEX。如果在ServiceHost打开之前尝试调用任一扩展方法,则会抛出此代码。

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.

注意事项:我可能会创建一个特殊的服务实例,其管理操作在启动时不支持MEX并将其建立为服务控制通道。

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/

    .NET Reflector:类浏览器,分析器和反编译器,用于检查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

    扩展调度程序(MSDN):提供了WCF服务的类组合的精彩高级图表:http://msdn.microsoft.com/en-us/library/ms734665.aspx

#1


*****[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.*****

***** [重新测试和代码清理后重新添加了这个答案]这是我添加到基于WCF的通用服务开发框架的实际代码,并且已经过全面测试。*****

Assuming that you start with MEX enabled on the ServiceHost...

假设您在ServiceHost上启用MEX启动...

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.

以下解决方案是根据ServiceHost子类(WCFServiceHost )编写的,该子类实现了用于存储MEX EndpointDispatcher类实例的特殊接口(IWCFState)。

First, add these namespaces...

首先,添加这些命名空间......

using System.ServiceModel;
using System.ServiceModel.Dispatcher;

Secondly, define the IWCFState interface...

其次,定义IWCFState接口......

public interface IWCFState
{
    EndpointDispatcher MexEndpointDispatcher
    {
        get;
        set;
    }
}

Thirdly, create a static class for some ServiceHost extension methods (we'll fill them in below)...

第三,为一些ServiceHost扩展方法创建一个静态类(我们将在下面填写)...

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.

此设计允许您使用某些消息传递方法向服务本身或托管服务的代码发送命令,并使其执行MEX EndpointDispatcher的启用或禁用,从而有效地关闭该ServiceHost的MEX。

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.

注意:此设计假定代码在启动时将支持MEX,但随后它将使用配置设置来确定服务是否在ServiceHost上调用Open()后禁用MEX。如果在ServiceHost打开之前尝试调用任一扩展方法,则会抛出此代码。

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.

注意事项:我可能会创建一个特殊的服务实例,其管理操作在启动时不支持MEX并将其建立为服务控制通道。

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/

    .NET Reflector:类浏览器,分析器和反编译器,用于检查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

    扩展调度程序(MSDN):提供了WCF服务的类组合的精彩高级图表:http://msdn.microsoft.com/en-us/library/ms734665.aspx