<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>SGuy's MSDN Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/sguyge/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/sguyge/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:50:25 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Windows Fabric 1.0 installation failure on Italian (ITA) OS</title>
      <link>https://docs.microsoft.com/archive/blogs/sguyge/windows-fabric-1-0-installation-failure-on-italian-ita-os</link>
      <pubDate>Mon, 29 Jul 2013 11:53:59 GMT</pubDate>
      <dc:creator><![CDATA[SGuy Ge]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/sguyge/2013/07/29/windows-fabric-1-0-installation-failure-on-italian-ita-os/</guid>
      <description><![CDATA[If you’re trying to install Service Bus 1.0 for Windows Server, Workflow Manager for Windows Server,...]]></description>
      <content:encoded><![CDATA[<p>If you’re trying to install Service Bus 1.0 for Windows Server, Workflow Manager for Windows Server, you might run into an installation issue if you happen to be running on an Italian OS. The installation would fail because Windows Fabric, which Service Bus depends on, fails to install. If you inspect the installation log file you’ll find something like:</p>  <p>MSI (s) (DC:EC) [20:59:41:496]: Product: Windows Fabric -- Error 1722. There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor.&#160; Action DoFabricSetup, location: C:\Program Files\Windows Fabric\bin\Fabric\Fabric.Code.1.0\MSIHiddenAppLauncher.exe, command: FabricSetup /operation:install /gac /trace:&quot;C:\ProgramData\Windows Fabric\Fabric\log&quot; /fabricDataRoot:&quot;C:\ProgramData\Windows Fabric\\&quot; /traceBufferSizeInKB:128 /traceFileSizeInMB:128 /fabricPrincipal:&quot;domain\user&quot;</p>  <p>The cause of the failure is, in Italian, the time format is 00.00.00 instead of 00:00:00. This is a localization bug of Windows Fabric installer on Italian OS.</p>  <p>There’s no fix available, but there’re some easy workarounds to unblock the installation.</p>  <ol>   <li>Change the following registry setting to HH:MM:SS and install Windows Fabric (without restarting the services/machine). </li>    <ul>     <li>HKEY_CURRENT_USER\Control Panel\International\sTimeFormat = h:mm:ss tt</li>   </ul>    <li>Instead of messing up the registry, you should be able to achieve the same by changing the Date/Time format in control panel.</li> </ol>  <p>Note: Don’t forget to revert the change to the time format after the installation is done.</p>]]></content:encoded>
    </item>
    <item>
      <title>DO NOT set DataMember.Order property to Int32.MaxValue when using DataContractSerializer</title>
      <link>https://docs.microsoft.com/archive/blogs/sguyge/do-not-set-datamember-order-property-to-int32-maxvalue-when-using-datacontractserializer</link>
      <pubDate>Thu, 02 May 2013 19:46:00 GMT</pubDate>
      <dc:creator><![CDATA[SGuy Ge]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/sguyge/2013/05/02/do-not-set-datamember-order-property-to-int32-maxvalue-when-using-datacontractserializer/</guid>
      <description><![CDATA[The issue  Today I‘m investigating a WCF compatibility issue reported by a customer. The scenario...]]></description>
      <content:encoded><![CDATA[<h1>The issue</h1>  <p><font size="3">Today I‘m investigating a WCF compatibility issue reported by a customer. The scenario is: The customer has a WCF service running on a machine with .NET 4.0, and a WCF client running on another machine with .NET 4.0 and everything works fine. Then the customer upgrades the client machine to .NET 4.5 and all of a sudden the client and service are not able to communicate.</font></p>  <p><font size="3">Here is the DataContract being used:</font></p>  <p>&#160;</p>  <p>[DataContract(Namespace = &quot;https://temp/schemas&quot;)]</p>  <p>public abstract class BaseClass</p>  <p>{</p>  <p>&#160;&#160;&#160; [DataMember(IsRequired = false, EmitDefaultValue = false)]</p>  <p>&#160;&#160;&#160; private int _rowId;</p>  <p>&#160;&#160;&#160; [DataMember(IsRequired = false, EmitDefaultValue = false)]</p>  <p>&#160;&#160;&#160; private DateTime _addDate;</p>  <p>&#160;&#160;&#160; [DataMember(IsRequired = false, EmitDefaultValue = false)]</p>  <p>&#160;&#160;&#160; private string _developerNotes;</p>  <p>&#160;&#160;&#160; [DataMember(Order = int.MaxValue, IsRequired = true, Name = &quot;IsDirty&quot;, EmitDefaultValue = true)]</p>  <p>&#160;&#160;&#160; public bool IsDirty { get; set; }</p>  <p>}</p>  <p><font size="3">Looking at the XML serialization produced by WCF 4.0 and 4.5, we can see the members are ordered differently, no wonder the client and the service cannot talk to each other.</font></p>  <h3>XML serialization produced by WCF in .NET 4.0:</h3>  <p>&lt;BaseClass xmlns=&quot;https://temp/schemas&quot; xmlns:i=&quot;https://www.w3.org/2001/XMLSchema-instance&quot;&gt;</p>  <p>&lt;IsDirty&gt;true&lt;/IsDirty&gt;</p>  <p>&lt;_addDate&gt;2013-04-01T01:01:02&lt;/_addDate&gt;</p>  <p>&lt;_developerNotes&gt;DeveloperNotes&lt;/_developerNotes&gt;</p>  <p>&lt;_rowId&gt;1&lt;/_rowId&gt;</p>  <p>&lt;/BaseClass&gt;</p>  <h3>XML serialization produced by WCF in .NET 4.5:</h3>  <p>&lt;BaseClass xmlns=&quot;https://temp/schemas&quot; xmlns:i=&quot;https://www.w3.org/2001/XMLSchema-instance&quot;&gt;</p>  <p>&lt;_addDate&gt;2013-04-01T01:01:02&lt;/_addDate&gt;</p>  <p>&lt;_developerNotes&gt;DeveloperNotes&lt;/_developerNotes&gt;</p>  <p>&lt;_rowId&gt;1&lt;/_rowId&gt;</p>  <p>&lt;IsDirty&gt;true&lt;/IsDirty&gt;</p>  <p>&lt;/BaseClass&gt;</p>  <h1>The cause</h1>  <p><font size="3">My initial thought is there might be some changes in WCF that caused the member order to be changed, but I would also be surprised if that’s the case as this would be a big breaking change. It turned out to not be the case. But there must be something changed, right? Exactly! It turned out what has changed was the sort algorithm in BCL.</font></p>  <p><font size="3">Wait, you might ask, shouldn’t the sort algorithm change be transparent to upper level applications? Well, theoretically it should be, but there’re always situations when reality rear its ugly head.</font></p>  <p><font size="3">Before WCF serializes data contract classes into XML, it will sort the members according to <a href="https://msdn.microsoft.com/en-us/library/ms729813.aspx">its ordering rule</a>. In short, a member that has an order specified will appear after a member that doesn’t have an order specified. If both members have order specified, the one with smaller order will appear first. If both has the same order value, then alphabetic order will be used.</font></p>  <p><font size="3">In fact the ordering rule is a bit complicated, especially when a comparer is concerned. But WCF managed to implement one simple comparer that worked almost perfectly – until Int.MaxValue comes into the picture.</font></p>  <p><font size="3">Below is the comparer class that WCF implemented, to make sure members that has no order specified appear before members that have orders specified, it used a trick, i.e. to assign them an order of -1. In this way, it can treat all members in a unified way.</font></p>  <p>internal class DataMemberComparer : IComparer&lt;DataMember&gt;    <br />{     <br />&#160;&#160;&#160; public int Compare(DataMember x, DataMember y)     <br />&#160;&#160;&#160; {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; int num = x.Order - y.Order;     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (num != 0)     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; {     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return num;     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; return string.CompareOrdinal(x.Name, y.Name);     <br />&#160;&#160;&#160; }     <br /> }     <br /></p>  <p><font size="3">Now let’s look at what happens during sorting. Below is the first comparison that happens on .NET 4.0 and .NET 4.5. <font size="3">Can you see what’s wrong there? </font></font></p>  <table cellspacing="0" cellpadding="2" width="399" border="0"><tbody>     <tr>       <td valign="top" width="74">&#160;</td>        <td valign="top" width="88">x.Name /          <br />x.Order</td>        <td valign="top" width="79">y.Name /          <br />y.Order</td>        <td valign="top" width="91">x.Order - y.Order</td>        <td valign="top" width="65">CompareResult</td>     </tr>      <tr>       <td valign="top" width="74">.NET 4.0</td>        <td valign="top" width="88">IsDirty /          <br />2147483647</td>        <td valign="top" width="79">_rowId /          <br />-1</td>        <td valign="top" width="91">         <br />-2147483648</td>        <td valign="top" width="65">&lt; 0</td>     </tr>      <tr>       <td valign="top" width="74">.NET 4.5</td>        <td valign="top" width="90">_rowId /          <br />-1</td>        <td valign="top" width="84">IsDirty / 2147483647</td>        <td valign="top" width="95">         <br />-2147483648</td>        <td valign="top" width="78">&lt; 0</td>     </tr>   </tbody></table>  <p><font size="3">Can you see the difference? And can you see what’s wrong there? </font></p>  <p><font size="3">Actually there’re 2 issues here. </font><font size="3">The first issue is that the comparison WCF did in .NET 4.0 produces incorrect result, it’s a typical wrap around error that happens in boundary cases. Mathematically, Int.MaxValue - (-1) = Int.MaxValue + 1 = 2147483648, still a positive value, however, in reality, the maximum positive integer that a 32 bit integer can represent is 2147483647, adding 1 would cause overflow and the result becomes -2147483648 (Int.MinValue), which is negative and wrong.</font></p>  <p><font size="3">The second issue is that in .NET 4.5, the change of sort algorithm causing the 2 members to be passed in in the reverse order. This time because a 32 bit integer can represent 1 more negative value than positive value, the comparison produces the right result: -1 - Int.MaxValue = –2147483648 = Int.MinValue.</font></p>  <p><font size="3">The compatibility issue is caused by the combination of these 2 issues. Even if WCF in .NET 4.0 sorted members incorrectly, as long as it’s talking to .NET 4.0, everything is fine as the other side would be expecting the same (wrong) order. Same for .NET 4.5. But when .NET 4.0 and 4.5 are mixed, the problem arises as the two side are expecting different orders.</font></p>  <p><font size="3">Had WCF implemented the comparison correctly, it would be resilient to any sort algorithm changes. Had the sort algorithm not changed in .NET 4.5, WCF would continue to produce the same (incorrect) result and interact well across different versions.</font></p>  <h1>The options</h1>  <p><font size="3">OK, now we’ve understood the root cause, let’s have the joy of evaluating different options.</font></p>  <p><font size="3">The first option is to revert the change to the BCL sort algorithm. But in fact it didn’t do anything wrong, as long as you implement the comparer correctly, it will still produce the right sort result – and in a much faster way! The change to the BCL sort algorithm in .NET 4.5 is for the good, even if you don’t do anything to your application, your application would get a much faster sort for free when moving from .NET 4.0 to 4.5. In my specific case, the sort used to take 17 comparisons in .NET 4.0, but now it only takes 6 comparisons in .NET 4.5. That should give you a better idea regarding how faster it is. So 99.99% of the .NET 4.5 customers would benefit from this change. Does it make sense to revert it just for a few customers? This choice might not be too hard. Check out <a href="https://en.wikipedia.org/wiki/Introsort">here</a> if you are interested in the new sort algorithm implemented in .NET 4.5. </font></p>  <p><font size="3">The second option is to fix the comparer in WCF. However this isn’t an easy task for several reasons. First we can only fix the behavior in .NET 4.5 and later versions, as that’s where the behavior change happened. But on the other hand in our case the comparison is done correctly. So in order to make it produce the same result as 4.0, we’ll need to emulate the wrong behavior in 4.0. That indeed is a mission impossible as there’s simply no way to emulate the wrong behavior in 4.0, as the wrong behavior can also happen in .NET 4.5 – it depends on the initial order. The only possible way might be to have WCF duplicate the sort algorithm from .NET 4.0 into .NET 4.5, so that the comparison sequences remain unchanged, but obviously that’s not an easy task, let alone there’s no guarantee you can achieve 100% compatibility. Second, even worse, since .NET 4.5 has been released for a while and a lot of new applications could have been written based on the new behavior, reverting to 4.0 behavior means breaking these new applications. What a dilemma!</font></p>  <p><font size="3">The third option is to fix the application. Compare with the above 2 options, this might be the most straightforward option. Just change Int.MaxValue to another values (e.g. Int.MaxValue - 1) and you’re guaranteed to have the same member order across different .NET versions.</font></p>  <h1>Conclusion</h1>  <p><font size="3">If you run into this exact issue, you should already know what to do to solve this issue by reading this far.</font></p>  <p><font size="3">I think WCF should check the value of Order when validating data contracts and disallows the use of Int.MaxValue as Order, but unfortunately that didn’t happen and might never happen. That’s the whole point of this post: To raise people’s awareness of this issue and hopefully to prevent it from happening in the future.</font></p>  <p><font size="3"><strong>The only thing you should remember is, as the title says, if you’re using data contracts, don’t ever set DataMember.Order to Int.MaxValue, otherwise this issue will bite you some time later when your service are deployed on to different versions of .NET (4.0- vs. 4.5+).</strong></font></p>]]></content:encoded>
    </item>
    <item>
      <title>Running Service Bus Server on a legacy domain without a fully qualified domain name</title>
      <link>https://docs.microsoft.com/archive/blogs/sguyge/running-service-bus-server-on-a-legacy-domain-without-a-fully-qualified-domain-name</link>
      <pubDate>Mon, 29 Apr 2013 15:28:38 GMT</pubDate>
      <dc:creator><![CDATA[SGuy Ge]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/sguyge/2013/04/29/running-service-bus-server-on-a-legacy-domain-without-a-fully-qualified-domain-name/</guid>
      <description><![CDATA[If you’re trying to host a Service Bus Server in your own domain, you might run into an issue that’s...]]></description>
      <content:encoded><![CDATA[<p><font size="3">If you’re trying to host a Service Bus Server in your own domain, you might run into an issue that’s reported in <a href="https://social.msdn.microsoft.com/Forums/en-US/servbus/thread/688ada3c-bb95-488d-9ad0-aec297438e1c">this forum thread</a>. This post will talk about that issue and more importantly, how to workaround it.</font></p>  <h1>The Issue</h1>  <p><font size="3">First let’s briefly review the issue.</font></p>  <ol>   <li><font size="3">The installation of Service Bus was successful. This issue existed since Service Bus 1.0 RTM, so it doesn’t matter whether you’re installing RTM version or CU1.</font></li>    <li><font size="3">After the installation you try to configure Service Bus with either the wizard or PowerShell cmdlet, but that will never succeed. If you open Control Panel =&gt; Administrative Tools =&gt; Services, look at Service Bus Message Broker service, you’ll find that it’s always in Starting state and will never transition into Started state.</font></li>    <li><font size="3">Your domain name contains only one segment, or put it another way, your domain name doesn’t contain a dot. So your domain name looks like MyDomain and your fully qualified machine name looks like MyMachine.MyDomain, instead of MyDomain.com and MyMachine.MyDomain.com.</font></li> </ol>  <p><font size="3">If you meet all above 3 conditions, then read on. Otherwise you might be running into a different issue.</font></p>  <h1>The cause</h1>  <p><font size="3">The root cause of the issue is the domain name doesn’t qualify as a fully qualified domain name (FQDN), while the current implementation of Service Bus server requires a FQDN to be used. A FQDN must be in the form of Prefix.Suffix, where Prefix and Suffix cannot be empty strings.</font></p>  <p><font size="3">Service Bus supports Windows Server 2008 R2 and later OS, on which you won’t be able to create a domain with a name that only contains one segment. However, this is possible with Windows Server 2003. It will give you a warning but will still allow you to do so if you insist. I suppose Windows Server 2000 won’t even warn you.</font></p>  <h1>The solution</h1>  <p><font size="3">The solution is fairly straightforward, just put your Service Bus server in a domain with a FQDN. However, simple as it is, in reality it might be impossible to implement as normally domain name is something out of your control.</font></p>  <p><font size="3">I can’t imagine why someone would create a new domain without a FQDN, Windows Server 2008 R2 won’t let you do that anyway. But I can imagine corporates that had their domains created a decade ago and used it ever since – domain structure isn’t something that can be easily changed or is desirable to be changed in a corporate environment.</font></p>  <p><font size="3">So is there a way to make it work without a FQDN? The good news is there is!</font></p>  <h1>The workaround</h1>  <p><font size="3">The workaround is a bit complicated, so you’ll need to follow the steps carefully.</font></p>  <p><font size="3">To avoid getting you lost in the details, first let’s look at the outline of the workaround:</font></p>  <ol>   <li><font size="3">Create a new certificate with full machine name.</font></li>    <li><font size="3">Edit Window Fabric setting to use full machine names.</font></li>    <li><font size="3">Re-configure Service Bus farm.</font></li> </ol>  <p><font size="3">With the outline in mind, now let’s go into all the details. Let’s say the domain name is MyDomain and the machine name is MyMachine, replace them with your own domain name and machine name when applying the workaround.</font></p>  <h2>1. Create a new certificate with full machine name.</h2>  <p><font size="3">1.1 Make a copy of &quot;C:\Program Files\Service Bus\1.0\Scripts\GeneratedClusterCert.inf&quot; to another folder, let’s say C:\Temp.</font></p>  <p><font size="3">1.2 Modify the following 2 lines, replace CloudSpecificHostName and *.CloudSpecificDomainName with your full machine name.</font></p>  <ul>   <li><font size="3">Before change:</font></li>    <ul>     <li><font size="3">Subject = &quot;CN=CloudSpecificHostName&quot;</font></li>      <li><font size="3">_continue_ = &quot;DNS=*.CloudSpecificDomainName&quot;</font></li>   </ul>    <li><font size="3">After change:</font></li>    <ul>     <li><font size="3">Subject = &quot;CN=MyMachine.MyDomain&quot;</font></li>      <li><font size="3">_continue_ = &quot;DNS=MyMachine.MyDomain&quot;</font></li>   </ul> </ul>  <p><font size="3">1.3 Open an administrator command line prompt and go to C:\Temp, run the following command, this will generate a new certificate AppfabricSSL.cer in current directory.</font></p>  <ul>   <li><font size="3">certreq.exe -cert AppServerGeneratedSBCA -new GeneratedClusterCert.inf AppfabricSSL.cer</font></li> </ul>  <p><font size="3">1.4 Open the generated AppfabricSSL.cer, copy out the Thumbprint and remove any spaces in between, this will be used in step 3.</font></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/33/68/metablogapi/2061.Thumbprint_388C2AC2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-33-68-metablogapi/2061.Thumbprint_5F00_388C2AC2.png"><img title="Thumbprint" style="display: inline; background-image: none;" border="0" alt="Thumbprint" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/33/68/metablogapi/8360.Thumbprint_thumb_06285743.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-33-68-metablogapi/8360.Thumbprint_5F00_thumb_5F00_06285743.png" width="412" height="510" /></a></p>  <p><font size="3">1.5 [Optional] </font><a href="https://msdn.microsoft.com/en-us/library/ms788967.aspx"><font size="3">View the certificate store</font></a><font size="3"> and make sure the generated certificate has been installed. </font></p>  <h2>2. Edit Window Fabric setting to use full machine names.</h2>  <p><font size="3">2.1 Open &quot;C:\Program Files\Windows Fabric\bin\Fabric\Fabric.Config.1.0\Settings.xml&quot;</font></p>  <p><font size="3">2.2 Replace *.MyDomain in the following lines with full machine name.</font></p>  <ul>   <li><font size="3">Before change:</font></li>    <ul>     <li><font size="3">&lt;Parameter Name=&quot;ClusterAllowedCommonNames&quot; Value=&quot;*.MyDomain&quot; /&gt;</font></li>      <li><font size="3">&lt;Parameter Name=&quot;ClientAuthAllowedCommonNames&quot; Value=&quot;*.MyDomain&quot; /&gt;</font></li>      <li><font size="3">&lt;Parameter Name=&quot;ServerAuthAllowedCommonNames&quot; Value=&quot;*.MyDomain&quot; /&gt;</font></li>   </ul>    <li><font size="3">After change:</font></li>    <ul>     <li><font size="3">&lt;Parameter Name=&quot;ClusterAllowedCommonNames&quot; Value=&quot;MyMachine.MyDomain&quot; /&gt;</font></li>      <li><font size="3">&lt;Parameter Name=&quot;ClientAuthAllowedCommonNames&quot; Value=&quot;MyMachine.MyDomain&quot; /&gt;</font></li>      <li><font size="3">&lt;Parameter Name=&quot;ServerAuthAllowedCommonNames&quot; Value=&quot;MyMachine.MyDomain&quot; /&gt;</font></li>   </ul> </ul>  <p><font size="3">c. Save the file.</font></p>  <h2>3. Re-configure Service Bus farm by running the following commands in SB PowerShell.</h2>  <p><font size="3">3.1 Remove-SBHost</font></p>  <p><font size="3">3.2 Set-SBCertificate -EncryptionCertificateThumbprint {ThumPrint} -FarmCertificateThumbprint {ThumPrint}</font></p>  <ul>   <li><font size="3">The {ThumPrint} is what you write down in 1.4</font></li> </ul>  <p><font size="3">3.3 Add-SBHost</font></p>  <p><font size="3">After following the steps above, now SB Message Broker service should be started in a few minutes and you can send/receive messages to/from SB queues.</font></p>  <p><font size="3">Note: The workaround described here is for single machine farms only. It might also work for multi machine farms with a few modifications, but I haven’t tried that.</font></p>]]></content:encoded>
    </item>
    <item>
      <title>Customizing .NET XML serialization process</title>
      <link>https://docs.microsoft.com/archive/blogs/sguyge/customizing-net-xml-serialization-process</link>
      <pubDate>Fri, 12 Oct 2012 17:12:27 GMT</pubDate>
      <dc:creator><![CDATA[SGuy Ge]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/sguyge/2012/10/12/customizing-net-xml-serialization-process/</guid>
      <description><![CDATA[.NET XML serialization is very convenient and useful, it will generate a dynamic assembly to perform...]]></description>
      <content:encoded><![CDATA[<p>.NET XML serialization is very convenient and useful, it will generate a dynamic assembly to perform the serialization and deserialization, you can even create an XML serialization assembly by using SGen.exe in advance to improve the startup performance. </p>  <p>&#160;</p>  <p>However, in some rare cases you might want to fine tune the generated XML serialization assembly. This isn’t something officially supported, but the fact that an XML serialization assembly pre-created by SGen.exe is allowed leaves us with an extensibility point and makes this possible. In this post I’m going to show you how to do exactly this.</p>  <p>&#160;</p>  <p>There’re 3 key steps involved:</p>  <ol>   <li>Modifying the source code.</li>    <li>Naming the serialization assembly.</li>    <li>Setting ParentAssemblyId.</li> </ol>  <p>Let’s walk through these steps in detail.</p>  <h1>1. Modifying the source code</h1>  <p>This step is obvious, but the questions is how do you get the source code that would be used to compile the XML serialization assembly. This is well supported, just add the following snippet into your configuration file and run your application. </p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&lt;</font></span><font style="font-size: 9.5pt;"><span>configuration</span></font><span><font style="font-size: 9.5pt;">&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&#160; &lt;</font></span><font style="font-size: 9.5pt;"><span>system.diagnostics</span></font><span><font style="font-size: 9.5pt;">&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&#160;&#160;&#160; &lt;</font></span><font style="font-size: 9.5pt;"><span>switches</span></font><span><font style="font-size: 9.5pt;">&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&#160;&#160;&#160;&#160;&#160; &lt;</font></span><font style="font-size: 9.5pt;"><span>add</span><span> </span><span>name</span><span>=</span>&quot;<span>XmlSerialization.Compilation</span>&quot; <span></span><span>value</span><span>=</span>&quot;<span>1</span>&quot;</font><span><font style="font-size: 9.5pt;"> /&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&#160;&#160;&#160; &lt;/</font></span><font style="font-size: 9.5pt;"><span>switches</span></font><span><font style="font-size: 9.5pt;">&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&#160; &lt;/</font></span><font style="font-size: 9.5pt;"><span>system.diagnostics</span></font><span><font style="font-size: 9.5pt;">&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p lang="en-CA" style="margin: 0in; list-style-type: disc;"><span><font style="font-size: 9.5pt;">&lt;/</font></span><font style="font-size: 9.5pt;"><span>configuration</span></font><span><font style="font-size: 9.5pt;">&gt;</font></span></p> <font style="font-size: 11pt;"></font>  <p>By setting this switch you’re telling XML serialization to preserve the source code it uses to generate the dynamic assembly, and by running it you’re having XML serialization to generate the source code for you. The generated assembly and the source code can be found in %temp% folder. The name of the file looks like a combination of some random characters, such as x5n5uhgy.dll and x5n5uhgy.cs.</p>  <p>Now you have the source file and it’s straightforward to fine tune it to suit your need.</p>  <h1>2. Naming the serialization assembly</h1>  <p>In order to build the serialization assembly, you also need a project. Just create a class library project with Visual Studio and add the source file into the project. When naming the assembly, you’ll need to follow the name convention. Let’s say the type being serialized lies in YourApplication.exe (or YourLibrary.dll), then the serialization assembly should be named YourApplication.XmlSerializers.dll (or YourLibrary.XmlSerializers.dll). You got the idea.</p>  <p>Now you build the project and get the serialization assembly, and you cannot wait to test it. It might work sometimes, in this case you’re done. </p>  <p>But sometimes, to your frustration, it doesn’t work, you find out XML serialization is still generating and using dynamic assembly even you’ve provided your own. Why?</p>  <h1>3. Setting ParentAssemblyId</h1>  <p>To answer this question let’s take a look at the following scenario: You created an assembly MyDataContracts.dll, and pre-created a serialization assembly MyDataContracts.Serialzation.dll for it. Later on you made some modifications to the type being serialized and recompiles MyDataContracts.dll, now there is a mismatch between the type inside MyDataContracts.dll and the serialization code inside MyDataContracts.Serialzation.dll, you can imagine what will happen if this old MyDataContracts.Serialzation.dll is being used with the new MyDataContracts.dll.</p>  <p>To solve this problem XmlSerializerVersionAttribute is introduced, it’s defined in System.Xml, the purpose is to prevent outdated pre-generated XML serialization assembly from being used. XmlSerializerVersionAttribute is used in generated assembly to save the identity information of its parent assembly (where the type being serialized lies in), and during run time, XML serialization will check if the identity information saved in the generated assembly matches the parent assembly, if the attribute doesn’t exist or the ID or version doesn’t match, the pre-generated serialization assembly will be ignored and dynamic assembly will still be generated.</p>  <p>If you look at the source code generated by XML serialization, you’ll find one line similar to the below:</p>  <p>[assembly: System.Xml.Serialization.XmlSerializerVersionAttribute(ParentAssemblyId = @&quot;60d7b267-090e-4055-93a9-01d5489fa2ea,&quot;, Version = @&quot;4.0.0.0&quot;)]</p>  <p>Mostly the answer to the previous question is that it fails the check of ParentAssemblyId, this happens when you rebuild the parent assembly which causes ParentAssemblyId to be changed – even if you didn’t change a single line of code! </p>  <p>Its obvious and easy to fix if there is a version mismatch, but for ParentAssemblyId mismatch, how can you get the right one? Using Reflector on System.Xml.dll you can find a method named GenerateAssemblyId, it’s the one that XML serialization uses to generate the ParentAssemblyId. </p>  <table style="margin-bottom: 0px; list-style-type: disc;" cellspacing="0" cellpadding="0" width="100%"><tbody>     <tr>       <td style="padding: 4px 5px;" valign="top" colspan="2">         <pre style="margin-top: 14px; margin-bottom: 14px;"><font style="font-size: 11pt;"><font color="#1000a0">private</font> <font color="#1000a0">static</font> <a title="System.String" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.String">string</a> <b><a class="bold" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://System.Xml:4.0.0.0:b77a5c561934e089/System.Xml.Serialization.TempAssembly/GenerateAssemblyId(System.Type):String">GenerateAssemblyId</a></b>(<a title="System.Type" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Type">Type</a> type)
{
    <a title="System.Reflection.Module" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Reflection.Module">Module</a>[] <b>modules</b> = <a title="Type type; // Parameter" style="cursor: auto;">type</a>.<a title="Assembly System.Type.Assembly { ... }" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Type/property:Assembly:System.Reflection.Assembly">Assembly</a>.<a title="Module[] System.Reflection.Assembly.GetModules();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Reflection.Assembly/GetModules():System.Reflection.Module%5b%5d">GetModules</a>();
    <a title="System.Collections.ArrayList" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Collections.ArrayList">ArrayList</a> <b>list</b> = <font color="#1000a0">new</font> <a title="System.Collections.ArrayList.ArrayList();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Collections.ArrayList/.ctor()">ArrayList</a>();
    <font color="#1000a0">for</font> (<a title="System.Int32" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Int32">int</a> <b>i</b> = <font color="#800000">0</font>; <a title="int i // Local Variable" style="cursor: auto;">i</a> &lt; <a title="Module[] modules // Local Variable" style="cursor: auto;">modules</a>.<a title="int System.Array.Length { ... }" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Array/property:Length:Int32">Length</a>; <a title="int i // Local Variable" style="cursor: auto;">i</a>++)
    {
        <a title="ArrayList list // Local Variable" style="cursor: auto;">list</a>.<a title="int System.Collections.ArrayList.Add(object);" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Collections.ArrayList/Add(Object):Int32">Add</a>(<a title="Module[] modules // Local Variable" style="cursor: auto;">modules</a>[<a title="int i // Local Variable" style="cursor: auto;">i</a>].<a title="Guid System.Reflection.Module.ModuleVersionId { ... }" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Reflection.Module/property:ModuleVersionId:System.Guid">ModuleVersionId</a>.<a title="string System.Object.ToString();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Object/ToString():String">ToString</a>());
    }
    <a title="ArrayList list // Local Variable" style="cursor: auto;">list</a>.<a title="void System.Collections.ArrayList.Sort();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Collections.ArrayList/Sort()">Sort</a>();
    <a title="System.Text.StringBuilder" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Text.StringBuilder">StringBuilder</a> <b>builder</b> = <font color="#1000a0">new</font> <a title="System.Text.StringBuilder.StringBuilder();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Text.StringBuilder/.ctor()">StringBuilder</a>();
    <font color="#1000a0">for</font> (<a title="System.Int32" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Int32">int</a> <b>j</b> = <font color="#800000">0</font>; <a title="int j // Local Variable" style="cursor: auto;">j</a> &lt; <a title="ArrayList list // Local Variable" style="cursor: auto;">list</a>.<a title="int System.Collections.ArrayList.Count { ... }" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Collections.ArrayList/property:Count:Int32">Count</a>; <a title="int j // Local Variable" style="cursor: auto;">j</a>++)
    {
        <a title="StringBuilder builder // Local Variable" style="cursor: auto;">builder</a>.<a title="StringBuilder System.Text.StringBuilder.Append(string);" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Text.StringBuilder/Append(String):System.Text.StringBuilder">Append</a>(<a title="ArrayList list // Local Variable" style="cursor: auto;">list</a>[<a title="int j // Local Variable" style="cursor: auto;">j</a>].<a title="string System.Object.ToString();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Object/ToString():String">ToString</a>());
        <a title="StringBuilder builder // Local Variable" style="cursor: auto;">builder</a>.<a title="StringBuilder System.Text.StringBuilder.Append(string);" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Text.StringBuilder/Append(String):System.Text.StringBuilder">Append</a>(<font color="#800000">&quot;,&quot;</font>);
    }
    <font color="#1000a0">return</font> <a title="StringBuilder builder // Local Variable" style="cursor: auto;">builder</a>.<a title="string System.Object.ToString();" style="cursor: auto;" href="https://www.aisto.com/roeder/dotnet/Default.aspx?Target=code://mscorlib:4.0.0.0:b77a5c561934e089/System.Object/ToString():String">ToString</a>();
}
</font></pre>
      </td>
    </tr>
  </tbody></table>
<font style="font-size: 11pt;"></font><font style="font-size: 11pt;"></font><font style="font-size: 11pt;"></font><font style="font-size: 11pt;"></font>

<p>You can write a simple console application and use this method to calculate the right ParentAssemblyId. Once you’ve got the new ParentAssemblyId, set it in the XmlSerializerVersionAttribute and recompile the project. </p>

<p>With that, XML serialization will happily load you pre-generated assembly!</p>]]></content:encoded>
    </item>
  </channel>
</rss>