我们从WCF Web服务返回类AuthenticateUserOutput
的实例。
所以我们有这个方法:
public override AuthenticateUserOutput AuthenticateUser(AuthenticateUserInput AuthenticateUserInput)
AuthenicateUserOutput是自动生成的:
[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 :Deserializer的工作得益于Mark Gravell
OK, I forgot I'd added this to get the namespaces to come out correctly when de-serializing:
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
答案 0 :(得分: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
而不是仅使用XmlSerializer的默认构造函数,并在其上添加一个XmlAttributes
,您可以在其上实例化XmlRoot
属性。
为了使这个更好和通用,它使用((XmlTypeAttribute)incomingType.GetCustomAttributes(typeof(XmlTypeAttribute), true)[0]).Namespace
将传入类型的名称空间移出,如果类型没有该属性,则会失败,因此这个解决方案需要更多的工作,但你会得到一般的想法。 / p>
此致
J1M