【问题标题】:How can I deserialize a custom SOAP header in WCF?如何反序列化 WCF 中的自定义 SOAP 标头?
【发布时间】:2014-08-19 17:10:48
【问题描述】:

我正在尝试通过 WCF 向所有 SOAP 请求添加自定义标头。我找到了this fantastic article,了解如何做到这一点。我的MessageHeader 类如下所示:

public class OperatorNameMessageHeader : MessageHeader
{
    private string opName;

    public const string HeaderName = "OperatorNameMessageHeader";
    public const string HeaderNamespace = "http://schemas.microsoft.com/scout";

    public override string Name { get { return HeaderName; } }
    public override string Namespace { get { return HeaderNamespace; } }

    public string OperatorName
    {
        get { return opName; }
        set { opName = value; }
    }

    public OperatorNameMessageHeader()
    {
    }

    public OperatorNameMessageHeader(string operatorName)
    {
        opName = operatorName;
    }

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

文章没有说的一件事是如何读取服务器上的值。根据this post,您可以使用OperationContext.Current.IncomingMessageHeaders 来读取这些标头。当我在调试器下查看这些MessageHeaders 时,我看到了 3 个标题,包括我的自定义标题。因此,它肯定会出现在 SOAP 数据中。但是,当我打电话给GetHeader

OperatorNameMessageHeader test = msgHeaders.GetHeader<OperatorNameMessageHeader>(OperatorNameMessageHeader.HeaderName, OperatorNameMessageHeader.HeaderNamespace);

那么test.OperatorName 为空。基本上,我只是取回一个尚未从 SOAP 中的数据反序列化的空 OperatorNameMessageHeader 对象。

我的下一步是运行 WCF 跟踪工具。当我这样做时,我可以验证自定义标头确实是通过网络发送的:

<MessageHeaders>
   <ActivityId CorrelationId="66a7c5b6-3548-4f3c-9120-4484af76b64b" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">f9bef03b-4e7b-4e84-b327-5e79814d9933</ActivityId>
   <OperatorNameMessageHeader xmlns="http://schemas.microsoft.com/scout">
      <OperatorName>Correct Operator Name</OperatorName>
   </OperatorNameMessageHeader>
   <To d4p1:mustUnderstand="1" xmlns:d4p1="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:90/IRolesAndResourcesManager</To>
   <Action d4p1:mustUnderstand="1" xmlns:d4p1="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IRolesAndResourcesManager/Authenticate</Action>
</MessageHeaders>

所以,服务器数据,我只是无法获取它。有什么办法解决这个问题?

【问题讨论】:

  • 我现在遇到了这个问题,您找到解决方案了吗?
  • @Declan - 从来没有!不过,我最终找到了一种使用 HTTP 标头做同样事情的方法。该信息不在 SOAP 中,仅适用于 HTTP,因此对某些人来说可能会破坏交易。
  • @MikeChristensen 我遇到了同样的问题。你应该在这个问题上悬赏:)

标签: c# .net wcf soap


【解决方案1】:

我遇到了完全相同的问题,并且能够使其工作如下:

[DataContract(Namespace = OperatorNameMessageHeader.HeaderNamespace)]
public class OperatorNameMessageHeader
{
    public const string HeaderName = "OperatorNameMessageHeader";
    public const string HeaderNamespace = "http://schemas.microsoft.com/scout";

    [DataMember]
    public string OperatorName { get; set; }
}

这样,我可以读取标题如下:

public static OperatorNameMessageHeader DeserializeSoap(string xml)
{
    using (var reader = XmlReader.Create(new StringReader(xml)))
    {
        var m = System.ServiceModel.Channels.Message.CreateMessage(reader, int.MaxValue, MessageVersion.Soap11);
        var operatorNameHeader = m.Headers.GetHeader<OperatorNameMessageHeader>(OperatorNameMessageHeader.HeaderName, OperatorNameMessageHeader.HeaderNamespace);

        return operatorNameHeader;
    }
}

请注意,我正在使用 WCF 反序列化 XML 字符串,因此需要使用 [DataContract][DataMember] 属性 - 没有它们,它将无法工作。不确定您是否需要实际从 MessageHeader 派生您的情况,但对我而言,读取自定义标头不是必需的。

希望这会有所帮助。

【讨论】:

  • 你的建议对我有帮助。但是由于某种原因,我只能从肥皂标题中反序列化 1 个属性。为了反序列化 3 个属性,我必须将标题定义分成 3 个部分并反序列化 3 次。不知道为什么。
【解决方案2】:

我遇到了类似的问题。我必须从标题中读取用户名和密码。我找到了一个临时解决方案,我正在使用 XmlDictionaryReader。但是使用此代码,我只查找名称,我仍然可以改进它,但暂时可以使用。我有它用于 VB,将类似于 C#

        Dim username As String = ""
        Dim password As String = ""
        Dim usernameTokenId As String = ""
        Dim passwordType As String = ""

        For i As Integer = 0 To OperationContext.Current.IncomingMessageHeaders.Count - 1
            Dim mhi As Channels.MessageHeaderInfo = OperationContext.Current.IncomingMessageHeaders.Item(i)
            Dim headers As Channels.MessageHeaders = OperationContext.Current.RequestContext.RequestMessage.Headers
            If mhi.Name.Equals("Security") Then
                Dim xr As XmlDictionaryReader = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(i)
                xr.MoveToContent()
                While xr.MoveToNextAttribute()
                    Console.Write(" {0}='{1}'", xr.Name, xr.Value)
                End While
                Do
                    Select Case xr.NodeType
                        Case XmlNodeType.Element
                            If xr.LocalName.Equals("Username") Then
                                username = xr.ReadElementContentAsString()
                            End If
                            If xr.LocalName.Equals("Password") Then
                                password = xr.ReadElementContentAsString()
                            End If

                            While xr.MoveToNextAttribute()
                                If xr.LocalName.Equals("Id") Then
                                    usernameTokenId = xr.Value
                                End If
                                If xr.LocalName.Equals("Type") Then
                                    passwordType = xr.Value
                                End If
                            End While
                        Case XmlNodeType.Attribute

                            'Case XmlNodeType.Text
                            '    Console.Write(xr.Value)
                            'Case XmlNodeType.EndElement
                            '    Console.Write("</{0}>", xr.Name)
                    End Select
                Loop While xr.Read()
            End If


            Dim name As String = mhi.Name
        Next

【讨论】:

    猜你喜欢
    • 2011-01-04
    • 1970-01-01
    • 2012-01-20
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 2021-03-08
    相关资源
    最近更新 更多