0

AuthenticateUserOutput我们从 WCF Web 服务返回类的实例。

所以我们有这个方法:

public override AuthenticateUserOutput AuthenticateUser(AuthenticateUserInput AuthenticateUserInput)

AuthencateUserOutput 是自动生成的:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.5420")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="xxxx")]
public partial class AuthenticateUserOutput : WS2MethodOutput
{

    private bool authenticationResultField;

    private UserContext userContextField;

    /// <remarks/>
    public bool AuthenticationResult
    {
        get
        {
            return this.authenticationResultField;
        }
        set
        {
            this.authenticationResultField = value;
        }
    }

    /// <remarks/>
    public UserContext UserContext
    {
        get
        {
            return this.userContextField;
        }
        set
        {
            this.userContextField = value;
        }
    }
}

我们需要能够反序列化为AuthenticateUserOutput,但它不起作用。

作为测试,我实例化了一个AuthenticateUserOutput,序列化它并尝试反序列化它。

它因 InvalidOperationException 而失败。

这是序列化的 XML:

<?xml version="1.0" encoding="utf-16"?>
<AuthenticateUserOutput xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="xxxx">
  <Response xmlns="xxxx">
    <IsValid>true</IsValid>
    <Success>true</Success>
  </Response>
  <AuthenticationResult xmlns="xxxx">true</AuthenticationResult>
  <UserContext xmlns="xxxx">
  </UserContext>
</AuthenticateUserOutput>

下面是序列化和反序列化代码:

    public static string ToXml(this object input)
    {
        string output;
        XmlSerializer serializer = new XmlSerializer(input.GetType());
        StringBuilder sb = new StringBuilder();
        using (TextWriter textWriter = new StringWriter(sb))
        {
            serializer.Serialize(textWriter, input);
        }
        output = sb.ToString();
        return output;
    }

和:

    public static T FromXml<T>(this string input)
    {
        T output;

        XmlSerializer serializer = new XmlSerializer(typeof(T));

        output = (T)serializer.Deserialize(new StringReader(input));

        return output;
    }

异常的具体细节:

System.InvalidOperationException occurred
  Message="<AuthenticateUserOutput xmlns='xxxx'> was not expected."
  Source="qkxd8dd-"
  StackTrace:
       at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderAuthenticateUserOutput.Read31_AuthenticateUserOutput()
  InnerException: 

所以它不能反序列化它自己的序列化 Xml。

有人能看出为什么吗?

谢谢,

J1M。

更新:这是测试代码:

        AuthenticateUserOutput test = new AuthenticateUserOutput();

        test.AuthenticationResult = true;
        test.Response = new ResponseType();
        test.Response.Exception = null;
        test.Response.IsValid = true;
        test.Response.Success = true;
        test.Response.ValidationErrors = null;
        test.UserContext = new UserContext();

        string serializedXml = test.ToXml();

        AuthenticateUserOutput deserializedString = serializedXml.FromXml<AuthenticateUserOutput>();

UPDATE2 : 多亏了 Mark Gravell,反序列化器才能工作

好的,我忘了我已经添加了这个来让命名空间在反序列化时正确出现:

public partial class WS2MethodInput
{
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces _xmlns;

    /// <summary>
    /// Constructor for WS2MethodInput that sets up default namespaces
    /// </summary>
    public WS2MethodInput()
    {
        _xmlns = new XmlSerializerNamespaces();
        _xmlns.Add("", "xxxx");
    }
}

有了这个,序列化的 Xml 就像在这条消息的顶部一样。没有它,反序列化程序可以工作,但 AuthenticateUserOutput 缺少命名空间:

<?xml version="1.0" encoding="utf-16"?>
<AuthenticateUserOutput xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="xxxx">
  <Response xmlns="xxxx">
    <IsValid>true</IsValid>
    <Success>true</Success>
  </Response>
  <AuthenticationResult xmlns="xxxx">true</AuthenticationResult>
  <UserContext xmlns="xxxx">
  </UserContext>
</AuthenticateUserOutput>

注意xmlns="xxxx"末尾的AuthenticateUserOutput

问题是,现在我不能在没有其他代码的情况下使用该 Xml:

1)将其加载到 XDocument 中并添加命名空间并在我需要对其进行反序列化时将其删除 2)对正则表达式的字符串替换或其他内容执行相同操作

我真的不喜欢这两个。事实上,这太可怕了!8X

4

1 回答 1

0

问题是设置 XmlSerializerNamespaces 以强制根元素上的 xmlns。

把它拿走,它就起作用了。

但是,现在我不能在其他任何地方使用序列化的 Xml,因为它缺少命名空间。

我将开始一个新的问题,关注这个问题。

谢谢,

J1M。

更新:

好的,我想通了,所以我不打算写一个新问题。

给定以下 XSD:

<xs:schema xmlns="urn:www-test-com:testservice" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:www-test-com:testservice" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="AuthenticateUserInput">
        <xs:annotation>
            <xs:documentation>Used to provide user credentials to the AuthenticateUser method</xs:documentation>
        </xs:annotation>
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Username" type="xs:string"/>
                <xs:element name="Password" type="xs:string"/>
                <xs:element name="Method" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

svcutil 会生成类似这样的东西,尽管我想有很多工具会为 XSD 吐出类似的东西:

[Serializable()]
[XmlType(AnonymousType = true, Namespace = "urn:www-test-com:testservice")]
public class AuthenticateUserInput
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string Method { get; set; }
}

现在,使用“默认”XmlSerializer代码:

    static string ToXml(object input)
    {
        string output;

        XmlSerializer serializer = new XmlSerializer(input.GetType());
        StringBuilder sb = new StringBuilder();

        using (XmlWriter xw = XmlWriter.Create(sb))
        {
            serializer.Serialize(xw, input);
        }
        output = sb.ToString();
        return output;
    }

您将获得以下 XML:

<AuthenticateUserInput xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Username xmlns="urn:www-test-com:testservice">sa</Username>
    <Password xmlns="urn:www-test-com:testservice">Password1</Password>
    <Method xmlns="urn:www-test-com:testservice">Plain</Method>
</AuthenticateUserInput>

哪个不符合模式(验证失败,这就是目前正在杀死我们的原因)

[XmlType]好的,所以,我找到了更改为的参考,[XmlRoot]并且粗略的测试有效,如果我更改生成的类,我现在得到以下一致的 Xml:

<AuthenticateUserInput xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:www-test-com:testservice">
    <Username>sa</Username>
    <Password>Password1</Password>
    <Method>Plain</Method>
</AuthenticateUserInput>

但我不想手动更改所有自动生成的类。所以过了一段时间我找到了以下解决方案:

    static string ToXml(object input)
    {
        string output;

        XmlSerializer serializer = CreateSerializer(input.GetType());
        StringBuilder sb = new StringBuilder();

        var settings = new XmlWriterSettings() { OmitXmlDeclaration = true, Encoding =  Encoding.UTF8, Indent = true };

        using (XmlWriter xw = XmlWriter.Create(sb, settings))
        {
            serializer.Serialize(xw, input);
        }
        output = sb.ToString();
        return output;
    }

    static T FromXml<T>(string input)
    {
        T output;

        XmlSerializer serializer = CreateSerializer(typeof(T));

        output = (T)serializer.Deserialize(new StringReader(input));

        return output;
    }

    private static XmlSerializer CreateSerializer(Type incomingType)
    {
        XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
        XmlAttributes newAttributes = new XmlAttributes();

        newAttributes.XmlRoot = new XmlRootAttribute();
        newAttributes.XmlRoot.Namespace = ((XmlTypeAttribute)incomingType.GetCustomAttributes(typeof(XmlTypeAttribute), true)[0]).Namespace;
        attrOverrides.Add(incomingType, newAttributes);

        XmlSerializer serializer = new XmlSerializer(incomingType, attrOverrides);
        return serializer;
    }

如您所见,您可以创建一个XmlAttributeOverrides并添加一个XmlAttributes实例化XmlRoot属性,而不是仅使用 XmlSerializer 的默认构造函数。为了使这个更好和通用,它将命名空间从传入的类型中剔除,((XmlTypeAttribute)incomingType.GetCustomAttributes(typeof(XmlTypeAttribute), true)[0]).Namespace如果类型没有该属性,则会失败,所以这个解决方案需要更多的工作,但你明白了一般的想法。

问候,

J1M

于 2012-11-21T16:15:44.727 回答