<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1208</guid>
      <link>https://shazwazza.com/post/asmx-soap-webservices-with-abstract-models-without-using-xmlinclude/</link>
      <category>ASP.Net</category>
      <title>ASMX SOAP Webservices with abstract models without using XmlInclude</title>
      <description>&lt;p&gt;I’m hoping this post might be useful to some folks out there that might be stuck using old ASMX/SOAP webservices in ASP.Net. If you’ve tried to return an abstract or superclass from an ASMX webservice without using XmlInclude or SoapInclude, you’ll get an error like:&lt;/p&gt;&lt;pre&gt;System.InvalidOperationException: There was an error generating the XML document. ---&amp;gt; System.InvalidOperationException: The type MyAwesomeClass was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write6_Item(String n, String ns, Item o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write10_Item(Object o)
   at Microsoft.Xml.Serialization.GeneratedAssembly.ItemSerializer.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
   at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
   at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()&lt;/pre&gt;
&lt;p&gt;The normal way to work around this is to attribute your ASMX class with &lt;em&gt;[XmlInclude(typeof(MyAwesomeClass)] &lt;/em&gt;and repeat this for every subclass that you might be returning. This essentially tells the SOAP handler what types it should expect to serialize so it can ‘warm’ up a list of XmlSerializers. &lt;/p&gt;
&lt;p&gt;The problem with this is that you need to know about all of these types up-front, but what if you have a plugin system where other developers can define their own types? There would be no way of knowing up-front what types to register so this approach will not work.&lt;/p&gt;
&lt;h2&gt;IXmlSerializer to the rescue&lt;/h2&gt;
&lt;p&gt;To work around this problem you can define a wrapper class for your abstract/superclass.&amp;nbsp; Working with &lt;em&gt;IXmlSerializer&lt;/em&gt; is pretty annoying and I highly recommend &lt;a href="http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly" target="_blank"&gt;this great article&lt;/a&gt; if you are going to use it since one mistake can cause all sorts of problems&lt;/p&gt;
&lt;p&gt;The following class should work for any object. Also note the usage of the static dictionary to store references to created XmlSerializer instances since these are expensive to create per type.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SerializedObjectWrapper : IXmlSerializable
{
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// The underlying Object reference that is being returned&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; Object { get; set; }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// This is used because creating XmlSerializers are expensive&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; ConcurrentDictionary&amp;lt;Type, XmlSerializer&amp;gt; TypeSerializers 
        = &lt;span class="kwrd"&gt;new&lt;/span&gt; ConcurrentDictionary&amp;lt;Type, XmlSerializer&amp;gt;();

    &lt;span class="kwrd"&gt;public&lt;/span&gt; XmlSchema GetSchema()
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReadXml(XmlReader reader)
    {
        reader.MoveToContent();

        &lt;span class="rem"&gt;//Get the Item type attribute&lt;/span&gt;
        var itemType = reader.GetAttribute(&lt;span class="str"&gt;"ItemType"&lt;/span&gt;);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (itemType == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"ItemType attribute cannot be null"&lt;/span&gt;);
            
        &lt;span class="rem"&gt;//Ensure the type is found in the app domain&lt;/span&gt;
        var itemTypeType = Type.GetType(itemType);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (itemTypeType == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"Could not find the type "&lt;/span&gt; + itemType);

        var isEmptyElement = reader.IsEmptyElement;
                    
        reader.ReadStartElement();

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (isEmptyElement == &lt;span class="kwrd"&gt;false&lt;/span&gt;)
        {
            var serializer = TypeSerializers.GetOrAdd(itemTypeType, t =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(t));
            Object = serializer.Deserialize(reader);
            reader.ReadEndElement();
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; WriteXml(XmlWriter writer)
    {
        var itemType = Object.GetType();
        var serializer = TypeSerializers.GetOrAdd(itemType, t =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(t));
            
        &lt;span class="rem"&gt;//writes the object type so we can use that to deserialize later&lt;/span&gt;
        writer.WriteAttributeString(&lt;span class="str"&gt;"ItemType"&lt;/span&gt;, 
            itemType.AssemblyQualifiedName ?? Object.GetType().ToString());

        serializer.Serialize(writer, Object);
    }
}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/p&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;Here’s an example of the usage of the &lt;em&gt;SerializedObjectWrapper&lt;/em&gt; class along with the example that would cause the above mentioned exception so you can see the difference:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyAbstractClass
{
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyAwesomeClass : MyAbstractClass
{
}

&lt;span class="rem"&gt;//WONT WORK&lt;/span&gt;
[WebMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; MyAbstractClass GetStuff()
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MyAwesomeClass();
}

&lt;span class="rem"&gt;//WILL WORK&lt;/span&gt;
[WebMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; SerializedObjectWrapper GetStuff()
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; SerializedObjectWrapper
    {
        Object = &lt;span class="kwrd"&gt;new&lt;/span&gt; MyAwesomeClass()
    };
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I know most people aren’t using AMSX web services anymore but in case your stuck on an old project or have inherited one, this might be of use :)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
  </channel>
</rss>