从WCF内

时间:2017-07-07 15:24:54

标签: c# .net wcf attributes

我在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

我完成日志记录后,我需要在IDisposable内关闭连接。我发现的选项是:

  1. WebServiceLogging课程上实施Dispose()并在那里SomeDatabaseConnection
  2. 直接从WebServiceLogger.BeforeSendReply()
  3. 处理IDispatchMessageInspectors

    我的问题是:

      传递到WebServiceLogger
    • dispatchRuntime.MessageInspectors(例如Attribute) - 我注意到每个请求都没有重新创建此对象,而是在我的服务的第一个请求中只重复一次。这些物品是如何处置的? WCF会对它们调用“Dispose()˙还是应该在这里使用其他方法?”
    • 由于我们正处于这种状态,我有一种唠叨的想法,即在c# attribute dispose中使用非托管资源可能并不是一个好主意。谷歌搜索FileSet没有产生任何结果(虽然析构函数有一个结果)。对这种方法有任何批评吗?

1 个答案:

答案 0 :(得分:2)

打开并关闭BeforeSendReply方法内的连接;即使它成为局部变量(带using - 块等)。

这样的事情:

public void BeforeSendReply {
    ... gather Request data.
    using (var conn = new SqlConnection(...)) {
        ... Log using ADO.NET
    }
}

开销通常无关紧要(因为ADO.NET使用连接池,并且不会真正打开/关闭全新的连接)。其次,最重要的是,您不必考虑如何在多线程(并行请求)场景中使用/调用拦截器实例。

这也更好地匹配工作单元模式,如果你在OperationContract的实现方法中做同样的事情,通常会使用它。如果你考虑一下,拦截器点(AfterReceiveRequestBeforeSendReply)实际上只是这种方法实现的扩展(类似AOP)。