在所有服务方法上使用属性(IOperationBehavior)

时间:2014-11-19 16:22:21

标签: wcf

我在[OperationContract]上使用以下[TrackingBehaviorAttribute]和自定义IOperationInvoker,一切都很好。

但我找到了一种方法,可以在接口级别([ServiceContract]级别)添加此属性。 我想避免在服务中的每个方法上添加属性的手动过程。

using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;    

public class TrackingBehaviorAttribute : Attribute, IOperationBehavior
    {
        #region IOperationBehavior Members
        public void AddBindingParameters(OperationDescription operationDescription,
                                         BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(OperationDescription operationDescription,
                                        ClientOperation clientOperation)
        {
        }

        public void Validate(OperationDescription operationDescription)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription,
                                          DispatchOperation dispatchOperation)
        {
            MethodInfo currMethodInfo = operationDescription.SyncMethod;
            CUSTOMOperationInvoker invoker = new CUSTOMOperationInvoker
                                          (dispatchOperation.Invoker, currMethodInfo);

            dispatchOperation.Invoker = invoker;
            invoker.OnInvokeEnded += new EventHandler<TrackingEventArgs>(/* logWriterMethod! */);
        }
        #endregion
    }
}

我尝试修改属性以包含IServiceBehavior,如下所示:

public class TrackingBehaviorAttribute : Attribute, IServiceBehavior, IOperationBehavior
{
    #region IServiceBehavior Members
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {

    }
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach ()
        {
            //Some loop to add this attribute to all service operation.
        }
    }
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    #endregion

但我似乎无法让它发挥作用。我接近这个错误吗?

更新

我在@ErnieL的帮助下获得了服务级别的属性,但现在应用于多个服务时,我在启动主机时遇到以下错误:

"The value could not be added to the collection, as the collection already contains
an item of the same type: 'Tracking.TrackingServiceBehaviorAttribute'.
This collection only supports one instance of each type."

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

您正在寻找的循环是这样的:

public virtual void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
    foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
    {
        foreach (OperationDescription operation in endpoint.Contract.Operations)
        {
            // TrackingBehaviorAttribute is your code that implements IOperationBehavior
            operation.Behaviors.Add(new TrackingBehaviorAttribute());
        }
    }
}

如果您需要更多示例Carlos Figueira Extensibility blog,请阅读。

答案 1 :(得分:1)

这次我尝试使用IContractBehavior,它似乎有效。

public class TrackingContractBehaviorAttribute : Attribute, IContractBehavior, IOperationBehavior
{
    #region IContractBehavior Members
    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
    }
    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {
    }
    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
    {
        foreach (OperationDescription operation in contractDescription.Operations)
        {
            operation.Behaviors.Add(new Tracking.TrackingContractBehaviorAttribute());
        }
    }
    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
    }
    #endregion

    #region IOperationBehavior Members
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

    public void Validate(OperationDescription operationDescription)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        MethodInfo currMethodInfo = operationDescription.SyncMethod;
        TrackingOperationInvoker invoker = new TrackingOperationInvoker(dispatchOperation.Invoker, currMethodInfo); 
//TrackingOperationInvoker is my own custom invoker to start some functions before default invoker.

        dispatchOperation.Invoker = invoker;
        invoker.OnInvokeEnded += new EventHandler<TrackingEventArgs>(logWriter);
    }