c# - 如何在 WCF 服务响应中正确实现自定义 soap 1.2 header 和 WS-Addressing

标签 c# wcf soap

我是 WCF 新手。我正在托管一个由第三方应用程序 (TPA) 调用的 WCF 服务。 TPA 要求 wcf 服务响应具有自定义 header ,并且响应 soap 信封应如下所示:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
               xmlns:stan="http://client/schema/framework/header/standardheaderresponse"
               xmlns:sys="http://client/schema/framework/common/systemidentifier"  >

  <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <stan:StandardHeaderResponse>
      <stan:From>
        <sys:Identifier>BUS</sys:Identifier>
        <sys:Name>BuildingEvent</sys:Name>
        <sys:Version>1</sys:Version>
      </stan:From>
      <stan:Timestamp>2013-03-15T03:05:41.000</stan:Timestamp>
      <stan:CorrelationID>uuid:c12c9e48-8164-4074-9c8c-2b979804dbd2</stan:CorrelationID>
    </stan:StandardHeaderResponse>

    <wsa:Action> 
      http://client/service.buildingloc.event.BuildingEvent.SendEvent
    </wsa:Action>
    <wsa:MessageID>uuid:ab4c4001-f089-721c-aae6-f51ec37d3501</wsa:MessageID>
    <wsa:To>http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
    <wsa:RelatesTo>uuid:de9a7007-f056-431c-aae6-f51ec37d3488</wsa:RelatesTo>
  </soap:Header>

  <soap:Body>
    …
  </soap:Body>

</soap:Envelope>

我的服务使用自定义 wcf 绑定(bind),如下所示:

var binding     = new CustomBinding();   
binding.Elements.Add( new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap12WSAddressing10 } );
binding.Elements.Add( new HttpTransportBindingElement() );

为了向我的响应添加自定义 soap header ,我使用了 IDispatchMessageInspector,它看起来如下所示:

   public void BeforeSendReply(ref Message reply, object correlationState)
        {
            reply.Headers.Add(new StandardHeaderResponse());
        }

和 MessageHeader 如下:

[MessageContract]
    public class StandardHeaderResponse : MessageHeader
    {
        #region Overrides of MessageHeaderInfo

        public override string Name
        {
            get { return GetType().Name; }
        }

        public override string Namespace
        {
            get { return "client/schema/framework/header/standardheaderresponse"; }
        }

        #endregion

        #region Overrides of MessageHeader

        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteElementString("Key", "Value");
        }

        #endregion
    }

但是当我运行该服务并从我的测试客户端发出请求时,我在 Fiddler 中得到以下输出

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
    <a:RelatesTo>urn:uuid:953e0b5b-44c6-4994-aae2-7710c31cb8f0</a:RelatesTo>
    <StandardHeaderResponse>
      <Key>Value</Key>
    </StandardHeaderResponse>
  </s:Header>
  <s:Body> 
   ...   
  </s:Body>
</s:Envelope>

这与 TPA 的预期完全不同。我需要做什么才能使 fiddler 输出看起来更像 TPA 所期望的。为什么不是所有 WS-Address 元素都像 <wsa:Action> , <wsa:MessageID><wsa:RelatesTo>作为标题的一部分呈现。任何帮助将不胜感激。

最佳答案

这是一个例子。我已经使用适当的命名空间和 DataMembers 创建了 DataContract 类。然后我将根类的实例添加到消息头中。为了填充 WSA 元素,我使用了 Message.Headers 集合的属性。

 class Program
{
    [DataContract( Namespace = "http://client/schema/framework/header/standardheaderresponse" )]
    public class StandardHeaderResponse
    {
        [DataMember( Order = 1 )]
        public FromHeaderResponse From { get; set; }

        [DataMember( Order = 2 )]
        public DateTime Timestamp { get; set; }

        [DataMember( Order = 3 )]
        public Guid CorrelationID { get; set; }
    }

    [DataContract( Namespace = "http://client/schema/framework/common/systemidentifier" )]
    public class FromHeaderResponse
    {
        [DataMember( Order = 1 )]
        public string Identifier { get; set; }

        [DataMember( Order = 2 )]
        public string Name { get; set; }

        [DataMember( Order = 3 )]
        public int Version { get; set; }
    }

    static void Main( string[] args )
    {
        Message message = Message.CreateMessage( MessageVersion.Default, "http://client/service.buildingloc.event.BuildingEvent.SendEvent", "Message body" );

        var header = new StandardHeaderResponse()
        {
            CorrelationID = Guid.NewGuid(),
            Timestamp = DateTime.Now,
            From = new FromHeaderResponse()
            {
                Identifier = "BUS",
                Name = "BuildingEvent",
                Version = 1
            }
        };

        message.Headers.Add( MessageHeader.CreateHeader( "StandardHeaderResponse", "http://client/schema/framework/header/standardheaderresponse", header ) );
        message.Headers.Action = @"http://client/service.buildingloc.event.BuildingEvent.SendEvent";
        message.Headers.To = new Uri( @"http://www.w3.org/2005/08/addressing/anonymous" );
        message.Headers.MessageId = new System.Xml.UniqueId( Guid.NewGuid() );
        message.Headers.RelatesTo = new System.Xml.UniqueId( Guid.NewGuid() );

        Console.WriteLine( message.ToString() );
        Console.WriteLine( "Press any key to exit..." );
        Console.ReadKey();
    }
}

生成的消息如下所示:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://client/service.buildingloc.event.BuildingEvent.SendEvent</a:Action>
    <StandardHeaderResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://client/schema/framework/header/standardheaderresponse">
      <From xmlns:d4p1="http://client/schema/framework/common/systemidentifier">
        <d4p1:Identifier>BUS</d4p1:Identifier>
        <d4p1:Name>BuildingEvent</d4p1:Name>
        <d4p1:Version>1</d4p1:Version>
      </From>
      <Timestamp>2013-04-10T00:17:13.8001086+02:00</Timestamp>
      <CorrelationID>6fa83bf3-95f2-4101-aa78-b271a9e96aae</CorrelationID>
    </StandardHeaderResponse>
    <a:To s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/anonymous</a:To>
    <a:MessageID>urn:uuid:88bc7f91-1de6-4c08-84bc-de75e029337d</a:MessageID>
    <a:RelatesTo>urn:uuid:6dd90731-5ca3-4c83-949b-194ee9da4b6c</a:RelatesTo>
  </s:Header>
  <s:Body>
    <string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Message  body</string>
  </s:Body>
</s:Envelope>

它的格式不完全相同,但它是相同的消息。

希望这对您有所帮助。

关于c# - 如何在 WCF 服务响应中正确实现自定义 soap 1.2 header 和 WS-Addressing,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15808852/

相关文章:

c# - 使用 Simple Injector 注册泛型类型的实例创建者

c# - 在 Caliburn Micro 中进行多个窗口的正确方法?

c# - WCF 客户端 : Forcing Global Namespaces

c# - WCF 使用、关闭和扩展

WCF 服务向后兼容性检查

ruby-on-rails - 基于 GMT 的 SOAP4R SOAPDateTime 格式

c# - 如何从后面的 c# 代码打开 jQuery UI 对话框?

c# - 划掉文字文本

java - 不同环境使用不同的 WSDL

tomcat - 在 Tomcat 上部署 JAX-WS Web 服务