我已经创建了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 */);
}
}
}
答案 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等...)将被处理掉