MessageInspector消息:"此消息不支持该操作,因为它已被复制."

Pau*_*tos 2 .net wcf

这是事情:

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

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

然而,今天,有些事情变得糟透了,停止了工作.

我从头开始重新制作原型,一切正常.我整个下午都在丢失弹珠.

相关代码如下:

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;
  }
  // ...
}
Run Code Online (Sandbox Code Playgroud)

以下是服务的配置:

<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>
Run Code Online (Sandbox Code Playgroud)

类似地,客户端配置是:

<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>
Run Code Online (Sandbox Code Playgroud)

编辑添加

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

(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
Run Code Online (Sandbox Code Playgroud)

编辑添加

正如其中一条评论所述,我发布了一个可在此处运行的原型项目:ServiceModel.zip

我不能强调原型是有效的.我唯一不知道的是为什么我突然开始得到这个奇怪的信息.我不复制邮件,只处理标题,我搜索的任何地方都说阅读邮件是一个很大的禁忌.

我担心这样一个事实,即在WCF模型中有很多要点检查,甚至替换整个消息,建筑师设计了这样一个对象,即使你看它也会变得愚蠢.

如果您有机会进行检查,请制定一个可以维持任何想要检查它的人操纵的恐惧的坚实目标.

Sti*_*tif 7

使用Greg Sansoms解决方案,但将原始邮件替换为原始邮件的副本:

public object AfterReceiveRequest(ref Message request, 
                                IClientChannel channel, 
                                InstanceContext instanceContext)
{
MessageBuffer buffer = request.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

//make sure the orignal message is set to a value wich has not been copied nor read
request = buffer.createMessage();

return null;
Run Code Online (Sandbox Code Playgroud)

}

一定要通过ref传递请求对象