WCF服务主机何时销毁自定义IDispatchMessageInspector?

时间:2012-07-17 16:38:12

标签: c# wcf

我已经创建了IDispatchMessageInspector接口的自定义实现,我的代码工作正常99%。

我的问题是,当WCF服务主机被杀死和/或释放我的类的实例时,我需要释放一些托管对象。我的对象是自由实现IDisposable但它们没有被处置。我已经浏览过MSDN库(更加困惑)和SO档案,但是没有发现任何解决“WCF服务主机何时/何地销毁MessageInspectors?”的问题。

我是否需要在某个地方挂钩活动?我是否需要从ServiceModel命名空间实现更神秘的东西?

任何人都可以给我指向正确的方向吗?

修改1:澄清

目前,我使用自动网络服务器在IDE中运行。一旦投入生产,我最终无法控制主机,可能是任何有效的服务器主机选择。

MyCore.My和MyCore.MyProperties对象是我在WCF服务器主机被杀死/退回时试图处理的对象。

即使我已经杀死了网络服务器进程(任务栏中的那些东西),也永远不会调用Dispose()。

编辑2:添加了代码段。

using /* snip */
using MyCore = Acme.My;

namespace My.SOAP
{
    public class MyMessageInspector : IDispatchMessageInspector
    {
        protected static MyCore.My _My;
        protected static MyCore.MyProperties _MyProps;
        protected static ConcurrentDictionary<string, MyCore.AnotherSecretThing> _anotherSecretThings = new ConcurrentDictionary<string, MyCore.AnotherSecretThing>();

        protected static void InitMy()
        {
            if (_My != null) return;

            _MyProps = new MyCore.MyProperties();
            MyCore.MySqlDatabaseLogger logger = new MyCore.MySqlDatabaseLogger(_MyProps);
            _My = new MyCore.My(logger);
        }

        public MyMessageInspector()
        {
            InitMy();
        }

        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request,    System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            MyMessageHeader header = null;
            try
            {
                // find My header
                Int32 headerPosition = request.Headers.FindHeader(MyMessageHeaderKey.MyHeaderElementName, MyMessageHeaderKey.MyNamespace);
                // get reader
                XmlDictionaryReader reader = request.Headers.GetReaderAtHeader(headerPosition);
                // get My header object
                header = MyMessageHeader.ReadHeader(reader);
                // add to incoming messages properties dictionary
                OperationContext.Current.IncomingMessageProperties.Add(MyMessageHeaderKey.MyHeaderElementName, header);
            }
            catch (Exception ex)
            {
                // log via ExceptionHandlingBlock
            }

            MyCore.SecretThings SecretThings = CreateSecretThings(/* snip */);
            return SecretThings.Id;
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object  correlationState)
        {
             MyCore.SecretThings req = _My.GetSecretThingsOnThread();
            // if we didn't find the SecretThings, there is nothing to stop() and no data to put in the MessageHeaders
            if (req == null) return;

            MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
            reply = buffer.CreateMessage();

            var MyHeader = new MyMessageHeader(/* snip */);
            reply.Headers.Add(MyHeader);
            req.Stop(MyCore.Status.SUCCESS);
        }

        protected MyCore.SecretThings CreateSecretThings(string key, Dictionary<string, string> ids)
        {
            /* snip */
            return _My.GetSecretThings(/* snip */);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我一直在看DispatchMessageInspector以及它是如何实现的。

您可能知道使用IEndpointBehavior注册MessageInspectors(通过配置或代码添加端点行为)。您可以在EndpointBehaviour中创建DispatchMessageInspector的实例。

   public class MyBehaviour : IEndpointBehavior
{     

    public void AddBindingParameters(ServiceEndpoint endpoint,
       System.ServiceModel.Channels.BindingParameterCollection
                                            bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {

    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        var inspector = new SampleMessageInspector(); //register
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }

}

根据http://msdn.microsoft.com/en-us/magazine/cc163302.aspx端点行为由服务主机注册

  

在ServiceHost和ChannelFactory构建过程中,这些行为集合会自动填充在代码中(通过属性)或配置文件中的任何行为(稍后会详细介绍)。您还可以在构建后手动向这些集合添加行为。以下示例显示如何将ConsoleMessageTracing作为服务行为添加到主机:

     

ServiceHost host = new ServiceHost(typeof(ZipCodeService));   host.Description.Behaviors.Add(new ConsoleMessageTracing());

并进一步规定ServiceHost只有服务有一生......

  

ServiceHost扩展对象在ServiceHost的生命周期内保留在内存中,而InstanceContext和OperationContext扩展对象仅在服务器实例或操作调用的生命周期内保留在内存中。您的自定义调度程序/代理扩展可以使用这些集合在整个管道中存储(并查找)用户定义的状态。

我假设这就是为什么你的MessageInspectors中的对象永远不会被销毁的原因。

有些人会将其视为反模式,但我可能会建议您使用MessageInspectors来检索对象的ServiceLocator。然后,您可以查看设置其生命周期,只要其父使用?

    public class SampleMessageInspector : IDispatchMessageInspector
{             

    public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        var objectToDispose = ServiceLocator.Current.GetInstance<ObjectToDispose>();

        //do your work
        return null;
    }

    public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
        //do some other work
    }
}

继续我提到的内容......

作为一个例子,这篇文章提到使用Ninject作为IoC容器,并将对象的生命周期设置为WCF服务的生命周期

  

Bind(...)。To(...)。InScope(()=&gt; OperationContext.Current)

Ninject WCF Garbage Collection on repositories

然后,您可以通过ServiceLocator访问Ninject Kernal,并且对象(_MyProperties等...)将被处理掉