2012-07-17 64 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