我有一个在 IIS 中承载的 WCF 服务:
[WebServiceLogging]
public class ComplaintService : IComplaintService
此服务具有WebServiceLogging
属性,该属性直接将请求/响应登录到数据库:
public class WebServiceLoggingAttribute : Attribute, IServiceBehavior {
SomeDatabaseConnection connection; // unmanaged resource
... interface implementations
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) {
IDispatchMessageInspector messageInspector = new WebServiceLogger(connection, _operations);
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
{
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
dispatchRuntime.MessageInspectors.Add(messageInspector); // pass the logger into WCF.
}
}
}
}
日志记录工作是从WebServiceLogger
完成的,它使用SomeDatabaseConnection
非托管资源:
public class WebServiceLogger : IDispatchMessageInspector {
public object AfterReceiveRequest {
... gather Request data.
}
public void BeforeSendReply {
... gather Request data.
... Log using ADO.NET
... Dispose of Command object. No Connection closing!
}
}
完成日志记录后,我需要在WebServiceLogger
内关闭连接。我确定的选项是:
- 在
WebServiceLogging
类上实现IDisposable
并在那里执行Dispose()
或 - 直接从
WebServiceLogger.BeforeSendReply()
处理SomeDatabaseConnection
我在这里的问题是:
IDispatchMessageInspectors
(例如WebServiceLogger
(传递到dispatchRuntime.MessageInspectors
- 我注意到此对象不是每个请求都重新创建,而是仅在对我的服务的第一个请求中重新创建一次。如何处理这些物品?WCF 是否对它们调用 'Dispose(( ̇,或者我应该在这里使用其他方法?- 既然我们在这里,我有一个唠叨的想法,也许在
Attribute
中使用非托管资源不是一个好主意。谷歌搜索c# attribute dispose
没有产生任何结果(不过,析构函数有一个结果(。对这种方法有什么批评吗?
在BeforeSendReply
方法中打开和关闭连接;即使其成为局部变量(带有using
块等(。
像这样:
public void BeforeSendReply {
... gather Request data.
using (var conn = new SqlConnection(...)) {
... Log using ADO.NET
}
}
开销通常是无关紧要的(因为 ADO.NET 使用连接池,并且不会真正打开/关闭全新的连接(。其次,也是最重要的一点,这样您就不必考虑在多线程(并行请求(场景中如何使用/调用拦截器实例。
这也更好地匹配了工作单元模式,如果您在 OperationContract 的实现方法中执行相同的操作,通常会使用这种模式。如果你考虑一下,拦截器点(AfterReceiveRequest
和BeforeSendReply
(实际上只是这种方法实现(一种AOP(的扩展。