MessageInspector消息:“此消息不支持该操作,因为它已被复制." [英] MessageInspector message: "This message cannot support the operation because it has been copied."

查看:41
本文介绍了MessageInspector消息:“此消息不支持该操作,因为它已被复制."的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是东西:

出于跟踪和安全原因,我有一个业务请求,要求所有WCF消息都应具有特定的标头.

I have a business request that all WCF messages should have a specific header, for tracking and security reasons.

无论如何,我在客户端和服务上都设置了 MessageInspector 的实现-到目前为止,我们都控制了两端-并且在原型阶段都运行良好.

Anyway, I setup an implementation of MessageInspector on both the client and the service -- we control both ends so far -- and all worked well on the prototype phase.

但是,今天,有些事情消失了,并停止了工作.

However, today, something went awire and stopped working.

我从头开始重做原型,一切正常.整个下午我都在弹大理石.

I redid the prototype from scratch and things works just fine. I'm loosing my marbles over it for the entire afternoon.

相关代码如下:

public class DispatchEndpointBehavior : IEndpointBehavior
{
  public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
                                    EndpointDispatcher endpointDispatcher)
  {
    var mi = new MessageInspector();
    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(mi);
  }
  // ...
}

public class DispatchMessageInspector : IDispatchMessageInspector
{
  public object AfterReceiveRequest(ref Message request, 
                                        IClientChannel channel, 
                                        InstanceContext instanceContext)
  {
    var index = request.Headers.FindHeader("name", "");
    if (index == -1)
      throw new MessageSecurityException("...");

    var value = request.Headers.GetHeader<Guid>(index);

    // do something with the value

    return null;
  }
  // ...
}

public class ClientEndpointBehavior : IClientEndpointBehavior
{
  public void ApplyClientBehavior(ServiceEndpoint endpoint, 
                                  ClientRuntime clientRuntime)
  {
    var mi = new ClientSecurityMessageInspector();
    clientRuntime.MessageInspectors.Add(mi);
  }
  // ...
}

public class ClientSecurityMessageInspector : IClientMessageInspector
{
  public object BeforeSendRequest(ref Message request, 
                                  IClientChannel channel)
  {
    request.Headers.Add(MessageHeader.CreateHeader("name", "", Guid.NewGuid()));
    return null;
  }
  // ...
}

以下是该服务的配置:

<system.serviceModel>
  <services>
    <service behaviorConfiguration="Default" name="[Service Name]">
      <endpoint 
           address="" 
           binding="basicHttpBinding" 
           behaviorConfiguration="headerBehavior"
           contract="[Service Contract]"/>
      <endpoint address="mex" ... />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="Default">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="headerBehavior">
        <headerBehavior headerName="token" />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add name="headerBehavior" type="[Implementation Type]" />
    </behaviorExtensions>
  </extensions>
</system.serviceModel>

类似,客户端配置为:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="[Service name]" ... >
                <readerQuotas ... />
                <security mode="None">
                    <transport 
                         clientCredentialType="None" 
                         proxyCredentialType="None"
                         realm=""/>
                    <message 
                         clientCredentialType="UserName" 
                         algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint 
            address="http://.../MyService.svc"
            binding="basicHttpBinding" 
            bindingConfiguration="Default"
            contract="[Service Contract]"
            name="[Service Name]"
            behaviorConfiguration="headerBehavior" />
    </client>
    <behaviors>
        <endpointBehaviors>
            <behavior name="headerBehavior">
                <headerBehavior
                    headerName="prosper-security-token"
                    securityTokenValueService="[Implementation Type]"
                    securityTokenValueGetterMethodName="[Method Name]" />
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <extensions>
        <behaviorExtensions>
            <add name="headerBehavior" type="[Implementation Type]" />
        </behaviorExtensions>
    </extensions>
</system.serviceModel>

已修改为添加

根据请求,异常堆栈跟踪如下:

As requested, the exception stack trace is as follows:

(System.ServiceModel.FaultException) This message cannot support the operation because it has been copied.

Server stack trace: 
   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at ConsoleApplication1.UserManagementService.IUserManagement.CreateUser(String username, String password, String[] systemCodes)
   at ConsoleApplication1.UserManagementService.UserManagementClient.CreateUser(String username, String password, String[] systemCodes) in C:\Users\Paulo Santos\Documents\Visual Studio 2008\Projects\PJonDevelopment\ConsoleApplication1\ConsoleApplication1\Service References\UserManagementService\Reference.cs
   at ConsoleApplication1.Program.Main(String[] args) in C:\Users\Paulo Santos\Documents\Visual Studio 2008\Projects\PJonDevelopment\ConsoleApplication1\ConsoleApplication1\Program.cs

已修改为添加

我在其中的一条评论中指出,我已经发布了一个可在此处运行的原型项目: ServiceModel.zip

As told in one of the comments I've posted a prototype project that works here: ServiceModel.zip

我对原型的工作压力还不够.我唯一不知道的是为什么我突然开始收到这个奇怪的消息.我不复制邮件,仅处理邮件头,在我搜索的所有地方都说,阅读邮件是一个很大的禁忌.

I can't stress enough that the prototype works. The only thing I don't know is why I suddenly started getting this weird message. I don't copy the message and only deal with headers, and everywhere I search say that reading the message is a big no-no.

我怕一个事实,即要在 WCF 模型中检查,甚至替换整个消息,架构师都设计了这样一个对象,即使您看了它也会觉得很po.

I dread the fact that with so many points to inspect, even replace, the entire message within WCF model, the architects designed with such an object that even if you look at it it goes poof.

如果您有机会进行检查,请创建一个可靠的对象,以承受想要检查的人所操纵行为的艰辛.

If you're giving the opportunity to inspect, make a solid objec that can sustain the hardships of behing manipulated by anyone who wants to inspect it.

推荐答案

这是因为Message对象只能被读取一次.尝试使用缓冲副本:

This is because a Message object can only be read once. Try using a buffer copy:

public object AfterReceiveRequest(ref Message request, 
                                    IClientChannel channel, 
                                    InstanceContext instanceContext)
{
MessageBuffer buffer = reply.CreateBufferedCopy(MaxMessageSize);
    Message requestCopy = buffer.CreateMessage();
    var index = requestCopy.Headers.FindHeader("name", "");
    if (index == -1)
        throw new MessageSecurityException("...");

    var value = requestCopy.Headers.GetHeader<Guid>(index);

    // do something with the value

    return null;
}

有关更多信息,请查看 MSDN .

For more info, check out MSDN.

这篇关于MessageInspector消息:“此消息不支持该操作,因为它已被复制."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆