How to Add Xmlinclude Attribute Dynamically

How to add XmlInclude attribute dynamically

Two options; the simplest (but giving odd xml) is:

XmlSerializer ser = new XmlSerializer(typeof(AList),
new Type[] {typeof(B), typeof(C)});

With example output:

<AList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ListOfBs>
<B />
<B xsi:type="C" />
</ListOfBs>
</AList>

The more elegant is:

XmlAttributeOverrides aor = new XmlAttributeOverrides();
XmlAttributes listAttribs = new XmlAttributes();
listAttribs.XmlElements.Add(new XmlElementAttribute("b", typeof(B)));
listAttribs.XmlElements.Add(new XmlElementAttribute("c", typeof(C)));
aor.Add(typeof(AList), "ListOfBs", listAttribs);

XmlSerializer ser = new XmlSerializer(typeof(AList), aor);

With example output:

<AList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<b />
<c />
</AList>

In either case you must cache and re-use the ser instance; otherwise you will haemorrhage memory from dynamic compilation.

Adding XmlIncludeAttribute programmatically

The XmlSerializer constructor can accept an array of "extra types", like this:

var _xs = new XmlSerializer(typeof(Model.ISession), 
SerializationOverrides(), new Type[] { typeof(Model.Session),
new XmlRootAttribute("Session"), "");

Doing that as well as adding additional XmlElements to the overrides seems to be doing the trick:

private static XmlAttributeOverrides SerializationOverrides()
{
var overrides = new XmlAttributeOverrides();

overrides.Add(typeof(Model.ISession), XmlInclude("Session", typeof(Model.Session)));

return overrides;
}

private static XmlAttributes XmlInclude(string name, Type type)
{
var attrs = new XmlAttributes();
attrs.XmlElements.Add(new XmlElementAttribute(name, type));
return attrs;
}

XmlSerializer, XmlArray with dynamic content... how?

The KnownTypesAttribute does not work for XmlSerializer. It's only used by a DataContractSerializer. I'm quite sure that you can exchange the serializer in WCF, because I have done that for the DataContractSerializer. But if that's not an option, you have to implement IXmlSerializable yourself and handle type lookup there.

Before disqualifying this solution: You just have to implement IXmlSerializable just for a special class which replaces Item[]. Everything else can be handled by the default serializer.

How to use XmlInclude to specify types dynamically?

It's because your response.GetType() actually returns List<object> type and then you tried to serialize non expected type. Object don't know anything about your types and serializer for Object can't serialize your unknown types.

You can use BaseClass for your reports and XmlInclude to solve this exception:

[XmlInclude(typeof(Report01)]
[XmlInclude(typeof(Report02)]
public class BaseClass { }
public class Report01 : BaseClass { ... }
public class Report02 : BaseClass { ... }

List<BaseClass> objs = new List<BaseClass>();
List<BaseClass> objs2 = new List<BaseClass>();
// fill collections here
ObjectToXml(objs, "c:\\12\\objs.xml");
ObjectToXml(objs2, "c:\\12\\objs2.xml");

Use the XmlInclude or SoapInclude attribute to specify types that are not known statically

Just solved the issue. After digging around for a while longer, I found this SO post which covers the exact same situation. It got me in the right track.

Basically, the XmlSerializer needs to know the default namespace if derived classes are included as extra types. The exact reason why this has to happen is still unknown but, still, serialization is working now.

Serialize collection of base class to XML dynamically

Found a soultion, during serialization u can pretty much insert item attributes directly

So first you collect attributes like

    XmlAttributeOverrides xOver = new XmlAttributeOverrides();
XmlAttributes xAttrs = new XmlAttributes();
foreach (var cls in BaseDerived.DerivedClasses)
{
var attr = new XmlArrayItemAttribute(cls);
xAttrs.XmlArrayItems.Add(attr);
}
xOver.Add(this.GetType(), BaseDerived.GetMemberName((Wrapper x) => x.Entities), xAttrs);

Btw:

public static string GetMemberName<T, TValue>(Expression<Func<T, TValue>> memberAccess)
{
return ((MemberExpression)memberAccess.Body).Member.Name;
}

and then you just mention it in serialization:

    XmlSerializer cs = new XmlSerializer(this.GetType(), xOver);


Related Topics



Leave a reply



Submit