【问题标题】:How to get the invoked operation name within a IClientMessageInspector?如何在 IClientMessageInspector 中获取调用的操作名称?
【发布时间】:2013-04-16 06:06:04
【问题描述】:

我在我的应用程序中实现了一个IClientMessageInspector 来“拦截”传出 Web 服务调用。是否可以从BeforeSendRequest 和AfterReceiveReply 内部找出正在调用的操作?

这里有一个类似的问题,How do i get the invoked operation name within a WCF Message Inspector,是针对服务端(接收请求的一方)。我试图做类似的事情,例如

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var v = OperationContext.Current.OutgoingMessageProperties["HttpOperationName"];
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        var v = OperationContext.Current.OutgoingMessageProperties["HttpOperationName"];
    }

但在发出请求期间,OperationContext.Current 似乎为空,所以我不能使用它。知道如何得到它吗?知道如何干净地做到这一点(而不是说,解析 SOAP xml)吗?

【问题讨论】:

  • 这很难,因为您在客户端堆栈中的位置非常低,以至于您真正需要的信息都包含在消息对象中。你有机会使用不同的检查员吗?例如,每个操作都会应用一个 IParameterInspector,因此是直截了当的。它还可以让您避免绑定特定的解决方案,例如 HTTPOperationName。
  • 参数检查器如何工作?

标签: c# .net wcf soap iclientmessageinspector


【解决方案1】:

从您询问如何使用IParameterInspector 完成此操作的 cmets。操作名称是 Before/AfterCall 方法的一部分。

只是添加到我的 cmets 上使用哪个检查员。来自Carlos Figueira's blogs:

本系列上一篇文章中描述的消息检查器, 允许您完全控制通过 WCF 的消息 堆。他们很强大,但你必须知道如何处理 Message 对象,这不是最理想的方式 编程。如果 WCF 中的服务模型隐藏了所有消息传递 框架允许我们定义我们的服务 强类型操作(即,使用漂亮的原语和用户定义的 types),应该有一种拦截请求/响应的方法 经过所有处理以从传入的参数中提取这些参数 消息(或在它们被打包到传出消息中之前)完成。 IParameterInspector 正是如此——在每次调用之前和之后, 检查员有机会检查操作输入、输出 和返回值,与操作定义的类型相同 合同,不需要转换(唯一需要的是演员,因为 参数作为对象传递)。

这是一个完整的命令行程序,演示:

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

namespace WCFClientInspector
{
    public class OperationLogger : IParameterInspector
    {
        public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
        {
            Console.WriteLine("Completed operation:" + operationName);
        }

        public object BeforeCall(string operationName, object[] inputs)
        {
            Console.WriteLine("Calling operation:" + operationName);
            return null;
        }
    }

    public class OperationLoggerEndpointBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            foreach (ClientOperation operation in clientRuntime.ClientOperations)
            {
                operation.ClientParameterInspectors.Add(new OperationLogger());
            }
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }
    }


    [ServiceContract]
    public interface ISimple
    {
        [OperationContract]
        void DoSomthing(string s);
    }

    public class SimpleService : ISimple
    {
        public void DoSomthing(string s)
        {
            Console.WriteLine("Called:" + s);
        }
    }

    public static class AttributesAndContext
    {
        static void Main(string[] args)
        {
            ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple"));
            simpleHost.Open();

            ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]);
            factory.Endpoint.EndpointBehaviors.Add(new OperationLoggerEndpointBehavior());
            ISimple proxy = factory.CreateChannel();

            proxy.DoSomthing("hi");

            Console.WriteLine("Press ENTER to close the host.");
            Console.ReadLine();

            ((ICommunicationObject)proxy).Shutdown();

            simpleHost.Shutdown();
        }
    }

    public static class Extensions
    {
        static public void Shutdown(this ICommunicationObject obj)
        {
            try
            {
                obj.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Shutdown exception: {0}", ex.Message);
                obj.Abort();
            }
        }
    }
}

它应该给出输出:

  Calling operation:DoSomthing 
  Called:hi 
  Completed operation:DoSomthing
  Press ENTER to close the host.

【讨论】:

    【解决方案2】:

    reply.Headers.Action 和 request.Headers.Action 怎么样。当然,其余的与所链接的问题一样棘手。所以完整的代码是:

    var action = reply.Headers.Action.Substring(reply.Headers.Action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1);
    

    或

    var action = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1);
    

    【讨论】:

    • 奇怪..当我测试这段代码时request.Headers.Action是一个空字符串""和reply.Headers.Action是空的
    • 很可能是因为在这个阶段,要执行的操作还没有决定msdn.microsoft.com/en-us/magazine/cc163302.aspx#S2
    • 问题是 request.Headers.Action 可能未指定。据我了解,这取决于 WSDL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 2016-02-01
    相关资源
    最近更新 更多