2011-12-29 327 views
1

我有定制IClientMessageFormatter,目前增加归因于指定的XML元素消息:无法获得IClientMessageFormatter工作

public class GetOrdersMessageFormatter : IClientMessageFormatter 
{ 
    readonly IClientMessageFormatter original; 

    public GetOrdersMessageFormatter(IClientMessageFormatter actual) 
    { 
     original = actual; 
    } 

    public void AddArrayNamespace(XmlNode node) 
    { 
     if (node != null) 
     { 
      var attribute = node.OwnerDocument.CreateAttribute("test"); 
      attribute.Value = "test"; 
      node.Attributes.Append(attribute); 
     } 
    }  

    public object DeserializeReply(Message message, object[] parameters) 
    { 
     return original.DeserializeReply(message, parameters); 
    } 

    public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 
    { 
     Message newMessage = null; 

     var message = original.SerializeRequest(messageVersion, parameters); 

     if (message.Headers.Action == "urn:Mage_Api_Model_Server_HandlerAction") 
     { 
      var doc = new XmlDocument(); 

      using (var reader = message.GetReaderAtBodyContents()) 
      { 
       doc.Load(reader); 
      } 

      if (doc.DocumentElement != null) 
      { 
       switch (doc.DocumentElement.LocalName) 
       { 
        case "call": 
         AddArrayNamespace(doc.SelectSingleNode("//args")); 
         break; 
       } 
      } 

      using (var ms = new MemoryStream()) 
      { 
       using (var xw = XmlWriter.Create(ms)) 
       { 
        doc.Save(xw);      

        ms.Position = 0; 
        using (var xr = XmlReader.Create(ms)) 
        { 
         newMessage = Message.CreateMessage(message.Version, null, xr); 
         newMessage.Headers.CopyHeadersFrom(message); 
         newMessage.Properties.CopyProperties(message.Properties); 
        } 
       } 
      } 
     } 

     return newMessage; 
    }  
} 

它给例外

System.ArgumentException:该用于消息正文的XmlReader必须位于元素上。 参数名:读者

服务器堆栈跟踪:在在System.ServiceModel.Channels System.ServiceModel.Channels.BodyWriter.WriteBodyContents(的XmlDictionaryWriter作家) 在System.ServiceModel.Channels.XmlReaderBodyWriter.OnWriteBodyContents(的XmlDictionaryWriter作家) .BodyWriterMessage.OnWriteBodyContents(的XmlDictionaryWriter作家) 在System.ServiceModel.Channels.Message.OnWriteMessage(的XmlDictionaryWriter作家) 在System.ServiceModel.Channels.Message.WriteMessage(的XmlDictionaryWriter作家) 在System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(消息消息,BufferManager bufferManager,Int32 initialOffset,Int32 maxSizeQuota) 在System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(消息消息的Int32 maxMessageSize,BufferManager bufferManager,的Int32 messageOffset) 在System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(消息信息) 在System.ServiceModel.Channels.HttpOutput 。发送(时间跨度超时) 在System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.SendRequest(消息消息,时间跨度超时) 在System.ServiceModel.Channels.RequestChannel.Request(消息消息,时间跨度超时) 在系统。 ServiceModel.Dispatcher.RequestChannelBinder.Request(消息消息,TimeSpan超时) at System.ServiceModel.Channels.ServiceChannel.Call(String action,Boolean oneway,ProxyOperationRuntime operation,Object [] ins ,对象[]奏,时间跨度超时) 在System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage包括MethodCall,ProxyOperationRuntime操作) 在System.ServiceModel.Channels.ServiceChannelProxy.Invoke(即时聊天消息)

我想,这可能是我需要使用message.CreateBufferedCopy()创建邮件副本并使用该副本来加载XmlDocument,但这也没有奏效。 可能有人知道我做错了什么,或知道例子,这是做了非常相同的事情(我的意思是在发送之前影响消息xml)。

回答

3

格式化程序中的问题在于,您正在使用在消息消耗之前放置的阅读器(和流)创建消息。从创建流和阅读器中删除“使用”语句后,请求就会经过 - 请参阅下面的代码。

public class StackOverflow_8669406 
{ 
    public class GetOrdersMessageFormatter : IClientMessageFormatter 
    { 
     readonly IClientMessageFormatter original; 

     public GetOrdersMessageFormatter(IClientMessageFormatter actual) 
     { 
      original = actual; 
     } 

     public void AddArrayNamespace(XmlNode node) 
     { 
      if (node != null) 
      { 
       var attribute = node.OwnerDocument.CreateAttribute("test"); 
       attribute.Value = "test"; 
       node.Attributes.Append(attribute); 
      } 
     } 

     public object DeserializeReply(Message message, object[] parameters) 
     { 
      return original.DeserializeReply(message, parameters); 
     } 

     public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 
     { 
      Message newMessage = null; 

      var message = original.SerializeRequest(messageVersion, parameters); 

      if (message.Headers.Action == "urn:Mage_Api_Model_Server_HandlerAction") 
      { 
       var doc = new XmlDocument(); 

       using (var reader = message.GetReaderAtBodyContents()) 
       { 
        doc.Load(reader); 
       } 

       if (doc.DocumentElement != null) 
       { 
        switch (doc.DocumentElement.LocalName) 
        { 
         case "call": 
          AddArrayNamespace(doc.SelectSingleNode("//args")); 
          break; 
        } 
       } 

       var ms = new MemoryStream(); 

       XmlWriterSettings ws = new XmlWriterSettings 
       { 
        CloseOutput = false, 
       }; 

       using (var xw = XmlWriter.Create(ms, ws)) 
       { 
        doc.Save(xw); 
        xw.Flush(); 
       } 

       Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray())); 

       ms.Position = 0; 
       var xr = XmlReader.Create(ms); 
       newMessage = Message.CreateMessage(message.Version, null, xr); 
       newMessage.Headers.CopyHeadersFrom(message); 
       newMessage.Properties.CopyProperties(message.Properties); 
      } 

      return newMessage; 
     } 
    } 

    [ServiceContract(Namespace = "")] 
    public interface ITest 
    { 
     [OperationContract(Action = "urn:Mage_Api_Model_Server_HandlerAction")] 
     int call(string args); 
    } 
    public class Service : ITest 
    { 
     public int call(string args) 
     { 
      return int.Parse(args); 
     } 
    } 
    class MyBehavior : IOperationBehavior 
    { 
     public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
     { 
     } 

     public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
     { 
      clientOperation.Formatter = new GetOrdersMessageFormatter(clientOperation.Formatter); 
     } 

     public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
     { 
     } 

     public void Validate(OperationDescription operationDescription) 
     { 
     } 
    } 
    public static void Test() 
    { 
     string baseAddress = "http://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); 
     host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), ""); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress)); 
     foreach (OperationDescription operation in factory.Endpoint.Contract.Operations) 
     { 
      operation.Behaviors.Add(new MyBehavior()); 
     } 

     ITest proxy = factory.CreateChannel(); 
     Console.WriteLine(proxy.call("4455")); 

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

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