为单个操作启用SOAP消息检查

时间:2011-09-21 15:07:42

标签: wcf

如果仅在调用特定操作时强制IMessageInspector触发,而不是在每次调用服务时触发?目前,我正在将自定义IEndpointBehavior应用于调用此IMessageInspector的端点,但这不是我想要做的...

1 个答案:

答案 0 :(得分:3)

消息检查器绑定到调度运行时对象,该对象是每个端点的单个对象,而不是操作。如果参数检查器工作,那么您可以使用它(它绑定到操作),但如果您需要消息检查器,则它不能绑定到单个操作。但是,您可以在检查器内检查操作是否符合您的预期(基于Action标头,每个操作是唯一的),如下面的代码所示。

public class StackOverflow_7502134
{
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        string Echo(string text);
        [OperationContract]
        int Add(int x, int y);
    }
    public class Service : ITest
    {
        public string Echo(string text)
        {
            return text;
        }
        public int Add(int x, int y)
        {
            return x + y;
        }
    }
    public class MyInspector : IEndpointBehavior, IDispatchMessageInspector
    {
        string[] operationNames;

        public MyInspector(params string[] operationNames)
        {
            this.operationNames = operationNames ?? new string[0];
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            // by default, action == <serviceContractNamespace>/<serviceContractName>/<operationName>
            string operationName = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf('/') + 1);
            if (this.operationNames.Contains(operationName))
            {
                Console.WriteLine("Inspecting request to operation {0}", operationName);
                Console.WriteLine(request);
                Console.WriteLine();
                return operationName;
            }
            else
            {
                return null;
            }
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            string operationName = correlationState as string;
            if (operationName != null)
            {
                Console.WriteLine("Inspecting reply from operation {0}", operationName);
                Console.WriteLine(reply);
                Console.WriteLine();
            }
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        MyInspector inspector = new MyInspector("Add"); // inspecting Add, not Echo
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "").Behaviors.Add(inspector);
        host.Open();
        Console.WriteLine("Host opened");

        ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        ITest proxy = factory.CreateChannel();

        Console.WriteLine("Calling Echo");
        Console.WriteLine(proxy.Echo("Hello world"));
        Console.WriteLine();

        Console.WriteLine("Calling Add");
        Console.WriteLine(proxy.Add(4, 5));

        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}