请求拦截器(RequestInterceptor)和消息检查器(MessageInspector)有什么区别?

7

我这里有两个问题:

1)Microsoft.ServiceModel.Web.RequestInterceptorSystem.ServiceModel.Dispatcher.DispatchRuntime.MessageInspectors(IdispatchMessageInterceptor)之间的基本区别是什么?

两者都似乎是可用于实现请求管道中的自定义验证/拦截器的请求/消息拦截器。

何时使用一个而非另一个?

2)还有如何将RequestInterceptor插入到RouteTable.Routes.Add(new ServiceRoute())

我有这样的一个类 -

public class AuthenticationInterceptor : RequestInterceptor
{
   //Authentication logic goes here......
}

一个像下面这样的路由定义:

RouteTable.Routes.Add(new ServiceRoute(routePrefix, new MyServiceHostFactory(container, (sh) => {
                foreach (System.ServiceModel.Dispatcher.ChannelDispatcher cd in sh.ChannelDispatchers)
                {
                    foreach (System.ServiceModel.Dispatcher.EndpointDispatcher ed in cd.Endpoints)
                    {
                        ed.DispatchRuntime.MessageInspectors.Add(new AuthenticationInterceptor());
                    }
                }
                return sh; })));

这里是 MyServiceHostFactory 的定义:-
public MyServiceHostFactory(IocContainer container, Func<ServiceHost, ServiceHost> createservicehost = null);

现在它会抛出以下错误:-
在这一行:-,'System.Collections.Generic.SynchronizedCollection<System.ServiceModel.Dispatcher.IDispatchMessageInspector>.Add(System.ServiceModel.Dispatcher.IDispatchMessageInspector)'的最佳重载方法匹配有一些无效参数。
ed.DispatchRuntime.MessageInspectors.Add(new AuthenticationInterceptor());

我知道原因,是因为我正在尝试在MessageInspector中连接RequestInterceptor。它们都属于不同的接口层次结构。
那么我应该怎么做呢?
编辑:还要注意的是,我无法更改AuthenticationInterceptor逻辑,因为代码不在我的控制范围内。

我这里没有太多可以补充的。这个链接对你有帮助吗?(https://dev59.com/FE_Ta4cB1Zd3GeqPCqm-) - shahkalpesh
@shahkalpesh,不,那并没有帮助,因为它使用的是WebServiceHost2,而我不是。 - Anil Purswani
1个回答

10

以下是您问题的答案(要理解拦截器和检查器,您需要阅读第2点):

1. 解决方案(您需要将代码逻辑添加到其中)

在下面的代码中实现IDispatchMessageInspector接口。请注意,以下类的名称应更改为inspector,但正如您所提到的,您无法更改它,因此应在此处实现接口。否则,建议创建另一个带有匹配检查器后缀和实现的类。

public class AuthenticationInterceptor : RequestInterceptor, IDispatchMessageInspector
{
    //Authentication logic goes here......
    object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
    {
        //Your code here.
    }
    void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
        //Your code here.
    }
}

2. RequestInterceptor和MessageInspectors之间的区别

在任何客户端与服务器之间的通信中,有两个重要的通信阶段。第一阶段是客户端建立连接,第二阶段是双方进行通信。

在建立连接时,试图建立连接的客户端不一定是有效的客户端。它可能是未经授权的请求,也可能是有效但不打算连接到目标服务器的请求,需要授权或连接重定向。

一个重定向的很好的例子是:

  1. 您希望区域客户端/服务器避免跨区域通信,但其中一个客户端(有效的)却试图连接到不同地区的服务器。

  2. 您希望服务器有选择地决定是否允许一些特殊用户进行跨区域客户端 - 服务器通信。

还可以有更复杂的重定向场景,超出了本答案的范围。

因此,在WCF中,Rest starter kit提供了在连接建立阶段拦截请求的额外能力。 拦截器(在您的情况下为AuthenticationInterceptor)应该验证这些请求,如果请求无效,则可以记录必要的条目并拒绝进一步处理来自此被拒绝的客户端/会话的任何通信。

有许多具有RequestInterceptor的好处:

  1. 它帮助我们在非常早期的阶段验证传入请求。

  2. 它可以帮助我们构建自定义认证器或重定向组件。

  3. 它阻止了在请求阶段期间进行任何进一步的消息处理,这对于让WCF服务/服务器远离不必要的负载非常重要。

Message Inspectors:

MessageInspectors 可以被视为第二个阶段的一部分,即当请求经过验证并且连接已经建立时,客户端和服务器开始通过彼此传递消息。现在,在您的应用环境中,消息可能使用二进制、XML或JSON序列化格式传递。可能会应用加密。

例如,可能会从客户端A接收消息,并将其交给服务器B,然后服务器队列它到另一个等待来自另一台服务器D的更多信息的服务器C。一旦Server D提供了信息,将队列中的消息与来自Server B和Server D的原始消息进一步组合起来,交给另一个服务进行反序列化和转换为某些有意义的内容,可返回给Server B,B再将其返回给客户端A。

相当复杂,对吧?但是使用移动PIN进行信用卡支付的多服务器认证工作方式类似,尽管可能并非完全相同,但更加复杂。

在WCF中,Interceptors和Inspectors可以一起工作,它们的职责不同。 拦截器验证最终用户/连接/重定向,检查员验证/处理消息。

几点说明:

  1. ...
  2. 你可以通过实现IClientMessageInspector接口来构建自己的消息检查器,用于客户端;或是在服务器端实现IDispatchMessageInspector接口。

    如果你拥有客户端和服务器组件,也可以将这两个接口都实现在同一个类中。

    在这种情况下,你需要实现IDispatchMessageInspector接口。

    IDispatchMessageInspector接口并不像上述提到的那样进行拦截,而是用于“检查”传入的消息和任何传出的消息。当消息从客户端到达时,可以使用配置来挂钩此检查器。

    请注意,在检查器级别,任何到达的消息都已经在各种信道堆栈级别上得到处理,并分配给将处理此请求的WCF服务。如果在中间使用了任何加密,则消息已经被解密。但是,消息尚未反序列化。

    自定义检查器的用途是:可能系统实现了定制的序列化格式(例如银行业务中的SWIFT / FIX协议)或另一级压缩/解压缩编码等。

    该自定义检查器可以反序列化数据并将其传递给实际用于处理反序列化数据的COMP组件。

    IDispatchMessageInspector接口有两个必须实现的方法:

    a) AfterReceiveRequest 和

    b) BeforeSendReply(ref Message,Object)。

    AfterReceiveRequest方法可以将数据反序列化并将其传递给COMP,而BeforeSendReply方法则可以重新序列化数据并对消息执行任何操作。

    你可以使用行为(behaviors)将MessageInspectors附加到Web服务接收的每个消息上。

    自定义拦截器和检查器主要用于企业平台或高度可定制的平台。

    希望这个答案能够帮助你。你可以在以下链接上阅读更多相关内容(可能你已经访问过第一个链接):

    http://msdn.microsoft.com/en-us/library/ee391967.aspx

    http://msdn.microsoft.com/en-us/library/aa717047(v=vs.110).aspx

    此致, Kajal


我通过使用自定义的MessageInspector解决了我的问题,感谢你提供的简洁明了的说明。这是一个精确的答案,应该得到数百个赞。 - Anil Purswani
确实是非常有用的答案。 - Anton Krouglov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接