gpt4 book ai didi

c# - 如何将具有多态性的 c# 对象序列化为具有覆盖的 soapattributes 的 soapmessage,类似于 XmlAttributeOverrides?

转载 作者:太空宇宙 更新时间:2023-11-03 11:59:55 24 4
gpt4 key购买 nike

我有一个动态创建的类型,所以我无法更改它的实现。我无法应用类似

的解决方案
[SoapInclude()] 

想象一下,如果我有这样的类(class):

public class BaseClass{}
public class DerivedClass:BaseClass{}
public class AnotherDerivedClass:BaseClass{}

public class RequestClass
{
public BaseClass item{get;set;}
}

如果我们尝试简单地序列化,我们会得到未找到 DerivedClass 的异常,因此我们必须覆盖 xml 属性。我已经设法覆盖我的类型并使用 XmlAttributeOverrides 将其序列化,如下所示:

var requestObject = new RequestClass() {item = new DerivedClass()};
XmlAttributes attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute
{
ElementName = "DerivedClass",
Type = typeof(DerivedClass)
};
attrs.XmlElements.Add(attr);
XmlAttributeOverrides attoverrides = new XmlAttributeOverrides();
attoverrides.Add(typeof(RequestClass), "item", attrs);
XmlSerializer sr = new XmlSerializer(typeof(RequestClass), attoverrides);
StringWriter writer = new StringWriter();
sr.Serialize(writer, requestObject);
var xml = writer.ToString();

现在上面的工作正常,但我想要的是将我的对象序列化为 SOAP 消息。我发现了与上面类似的类 Like SoapAttributeOverrides 并且我尝试用这些类覆盖它但它似乎不起作用。我已经试过了:

var requestObject = new RequestClass(){item = new DerivedClass()};
SoapAttributeOverrides ovr = new SoapAttributeOverrides();
SoapAttributes soapAtts = new SoapAttributes();
SoapElementAttribute element = new SoapElementAttribute();
element.ElementName = "DerivedClass";
ovr.Add(typeof(RequestClass), "item", soapAtts);
var sr = new XmlSerializer(new SoapReflectionImporter(ovr).ImportTypeMapping(typeof(RequestClass)));
StringWriter writer = new StringWriter();
sr.Serialize(writer, requestObject);
var xml = writer.ToString();
writer.Close();

我再次遇到异常 DerivedClass was not found。如何为 SoapElementAttribute 提供类似于 XmlElementAttribute.Type 的类型,以便可以进行序列化以通过覆盖支持 BaseClass 的多态性?

最佳答案

.Net 中的 SOAP 编码 XML 序列化通过 included type 支持多态性机制。为了在运行时将包含的类型添加到 SoapReflectionImporter,请使用:

因此您可以按如下方式制造您的XmlSerializer:

public static XmlSerializer RequestClassSerializer { get; } 
= CreateSoapSerializerWithBaseClassIncludedTypes(typeof(RequestClass), typeof(DerivedClass), typeof(AnotherDerivedClass));

static XmlSerializer CreateSoapSerializerWithBaseClassIncludedTypes(Type rootType, params Type [] includedTypes)
{
var importer = new SoapReflectionImporter();
foreach (var type in includedTypes)
importer.IncludeType(type);
return new XmlSerializer(importer.ImportTypeMapping(rootType));
}

然后引入如下扩展方法:

public static partial class XmlSerializationHelper
{
public static string GetSoapXml<T>(this T obj, XName wrapperName, XmlSerializer serializer = null)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
{
xmlWriter.WriteStartElement(wrapperName.LocalName, wrapperName.NamespaceName);
(serializer ?? GetDefaultSoapSerializer(obj.GetType())).Serialize(xmlWriter, obj);
xmlWriter.WriteEndElement();
}
return textWriter.ToString();
}
}

static readonly Dictionary<Type, XmlSerializer> cache = new Dictionary<Type, XmlSerializer>();

public static XmlSerializer GetDefaultSoapSerializer(Type type)
{
lock(cache)
{
if (cache.TryGetValue(type, out var serializer))
return serializer;
return cache[type] = new XmlSerializer(new SoapReflectionImporter().ImportTypeMapping(type));
}
}
}

您将能够按如下方式序列化您的requestObject:

var requestObject = new RequestClass(){item = new DerivedClass()};

var xml = requestObject.GetSoapXml("wrapper", RequestClassSerializer);

注意事项:

  • 为避免严重的内存泄漏,您应该静态缓存任何不是使用 XmlSerializer(Type)XmlSerializer(Type, String) 创建的 XmlSerializer 构造函数。为什么,请参阅 the documentation还有 Memory Leak using StreamReader and XmlSerializer .

    如果您动态生成类型族,您可能需要将它们的序列化器缓存在受 lock 语句保护的静态字典中。

  • 中所述Extension method to serialize generic objects as a SOAP formatted stream InvalidOperationException while SOAP serialization of complex type 在使用 SOAP XML 序列化程序直接序列化为 XML 之前,您需要手动编写信封或其他包装元素。

    如果出于某种原因您只想将 SOAP XML 主体作为一系列 XML 片段,您可以这样做:

    public static string GetSoapBodyXml<T>(this T obj, XmlSerializer serializer = null)
    {
    using (var textWriter = new StringWriter())
    {
    var settings = new XmlWriterSettings() { Indent = true, ConformanceLevel = ConformanceLevel.Fragment }; // For cosmetic purposes.
    using (var xmlWriter = XmlWriter.Create(textWriter, settings))
    {
    xmlWriter.WriteWhitespace(""); // Hack to prevent an error about WriteStartDocument getting called for ConformanceLevel.Fragment
    (serializer ?? GetDefaultSoapSerializer(obj.GetType())).Serialize(xmlWriter, obj);
    }
    return textWriter.ToString();
    }
    }

演示 fiddle here .

关于c# - 如何将具有多态性的 c# 对象序列化为具有覆盖的 soapattributes 的 soapmessage,类似于 XmlAttributeOverrides?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57509260/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com