如何将具有多态性的c#对象序列化为具有重写的soapattributes的soapmessage,类似于XmlAttributeOverrides?
我有一个动态创建的类型,因此无法更改它的实现。我不能应用像这样的解决方案如何将具有多态性的c#对象序列化为具有重写的soapattributes的soapmessage,类似于XmlAttributeOverrides?,c#,serialization,soap,C#,Serialization,Soap,我有一个动态创建的类型,因此无法更改它的实现。我不能应用像这样的解决方案 [SoapInclude()] 想象一下,如果我有这样的课程: public class BaseClass{} public class DerivedClass:BaseClass{} public class AnotherDerivedClass:BaseClass{} public class RequestClass { public BaseClass item{get;set;} } 如果我
[SoapInclude()]
想象一下,如果我有这样的课程:
public class BaseClass{}
public class DerivedClass:BaseClass{}
public class AnotherDerivedClass:BaseClass{}
public class RequestClass
{
public BaseClass item{get;set;}
}
如果我们尝试简单地序列化,我们会得到一个异常,即找不到DerivedClass,因此我们必须重写xmlattributes。
我已经成功地覆盖了我的类型,并用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消息。我发现了类似于上面的类,比如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未找到异常。如何给
SoapElementAttribute
一个类似于XmlElementAttribute.type
的类型,以便通过重写使序列化支持基类的多态性?在.Net中,SOAP编码的XML序列化通过一种机制支持多态性。要在运行时将包含的类型添加到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));
}
var requestObject = new RequestClass(){item = new DerivedClass()};
var xml = requestObject.GetSoapXml("wrapper", RequestClassSerializer);
然后介绍以下扩展方法:
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));
}
}
}
注:
- 为了避免严重的内存泄漏,您应该静态缓存任何未使用
XmlSerializer(Type)
或XmlSerializer(Type,String)
构造函数创建的XmlSerializer
。有关原因,请参见和
如果要动态生成类型族,可能需要将其序列化程序缓存在受lock
语句保护的静态字典中
- 如中所述,在使用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();
}
}
public静态字符串GetSoapBodyXml(此T对象,XmlSerializer序列化程序=null)
{
使用(var textWriter=new StringWriter())
{
var settings=new XmlWriterSettings(){Indent=true,ConformanceLevel=ConformanceLevel.Fragment};//用于修饰目的。
使用(var xmlWriter=xmlWriter.Create(textWriter,设置))
{
xmlWriter.WriteWhitespace(“”;//Hack以防止为ConformanceLevel.Fragment调用WriteStartDocument时出错
(序列化程序??GetDefaultSoapSerializer(obj.GetType()).Serialize(xmlWriter,obj);
}
返回textWriter.ToString();
}
}
演示小提琴。是的,我做了类似的事情。我知道soap格式在我的案例中应该是什么样子的。所以我只是做了一件我可以静态地做的事情,其余的都很好,这是我要弄清楚的。还是要谢谢你的努力。我会将您的答案标记为正确,因为显然没有办法,我用xmlattributesoverrides序列化了c#对象本身,并将其插入soap主体中。