2012-07-17 61 views
2

我已经创建了IDispatchMessageInspector接口的自定义实现,并且我的代码工作得很好。WCF服务主机何时销毁自定义IDispatchMessageInspector?

我的问题是,当WCF服务主机被终止和/或释放我的类的一个实例时,我需要释放一些托管对象。我的对象免费实现IDisposable,但它们不会被丢弃。我已经通过MSDN库(更困惑)和SO归档,但没有发现任何解决“WCF服务主机销毁MessageInspectors的时间/地点?”问题的任何内容。

我需要在某处挂钩事件吗?我是否需要从ServiceModel名称空间实现更加神秘的东西?

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

编辑1:澄清

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

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

即使我杀死了web服务器进程(任务栏中的那些东西),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 */); 
     } 
    } 
} 
+0

可我们看到的例子吗?你想要在你的DispatchMessageInspector中处理你的对象吗? – Mike 2012-07-17 20:24:05

回答

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中的对象永远不会被销毁。

有些人会认为它是反模式,但我可能会推荐一个ServiceLocator,MessageInspectors可以用它来检索对象。只要父母的用法,你可以考虑设置他们的一生?

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服务

绑定(...)。向(...)。InScope(()=> OperationContext.Current)

Ninject WCF Garbage Collection on repositories

然后,您可以打通的服务定位和对象访问Ninject籽粒(_MyProperties等)将被处理掉

+0

我喜欢这个答案,@Mike。非常全面,并提供有关所提及主题的其他信息的链接。这需要我花一点时间来消化,并尝试应用于我的确切场景。 – JohnKeller 2012-07-18 12:54:44

+0

让我知道你是否想要更多的帮助。 – Mike 2012-07-18 13:50:03