<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Andrew Arnott : .NET</title><link>http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx</link><description>Tags: .NET</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>GZip encoder for Compact WCF</title><link>http://blogs.msdn.com/andrewarnottms/archive/2008/10/01/gzip-encoder-for-compact-wcf.aspx</link><pubDate>Wed, 01 Oct 2008 05:13:07 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8971022</guid><dc:creator>andarno</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/8971022.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=8971022</wfw:commentRss><description>&lt;p&gt;The GZip encoder is not included in NetCF as it is on the desktop WCF, but it isn't hard to build yourself and in fact we have released a sample of exactly how to add your own GZip encoder to NetCF:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://go.microsoft.com/fwlink/?LinkId=108652"&gt;http://go.microsoft.com/fwlink/?LinkId=108652&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;So many people have asked me for it lately I thought I'd better just post the link.&amp;#160; Have fun!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8971022" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/Mobile+devices/default.aspx">Mobile devices</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/NetCF/default.aspx">NetCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/WCF/default.aspx">WCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item><item><title>OpenID and ASP.NET web sites</title><link>http://blogs.msdn.com/andrewarnottms/archive/2008/04/14/openid-and-asp-net-web-sites.aspx</link><pubDate>Tue, 15 Apr 2008 01:21:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8395098</guid><dc:creator>andarno</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/8395098.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=8395098</wfw:commentRss><description>&lt;p&gt;If you are a web developer I hope you've considered accepting &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; credentials for logging in your users.&amp;#160; If you have an ASP.NET web site, the process of adding OpenID support to your web site &lt;a href="http://blog.nerdbank.net/2008/04/how-to-add-openid-to-your-aspnet-web.html"&gt;couldn't be easier&lt;/a&gt; when you use the free C# &lt;a href="http://dotnetopenid.googlecode.com"&gt;DotNetOpenId&lt;/a&gt; library.&amp;#160; &lt;/p&gt;  &lt;p&gt;Supporting OpenID is a great idea:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;No more &amp;quot;I forgot my username/password&amp;quot; pages. &lt;/li&gt;    &lt;li&gt;No more &amp;quot;Change Password&amp;quot; pages. &lt;/li&gt;    &lt;li&gt;Your users have one less username/password to make-up/reuse when they join your site. &lt;/li&gt;    &lt;li&gt;Users who prefer greater security than a username/password provides can choose an OpenID Provider that provides that assurance, without you having to enhance your site. &lt;/li&gt;    &lt;li&gt;It's free.&amp;#160; And so are &lt;a href="http://wiki.openid.net/Libraries"&gt;the libraries&lt;/a&gt; that you can drop in to add support for it. &lt;/li&gt; &lt;/ol&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8395098" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/Identity/default.aspx">Identity</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item><item><title>Workaround for XmlSerializer T[] and List&lt;T&gt; bug</title><link>http://blogs.msdn.com/andrewarnottms/archive/2007/11/05/workaround-for-xmlserializer-t-and-list-t-bug.aspx</link><pubDate>Tue, 06 Nov 2007 00:34:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5919435</guid><dc:creator>andarno</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/5919435.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=5919435</wfw:commentRss><description>&lt;p&gt;The XmlSerializer in NetCF 2.0 has a bug where if a single serialization requires reflecting into types that use a mixture of Collection&amp;lt;T&amp;gt;-like types for the same T the XmlSerializer will throw an exception.&amp;#xA0; Here an example where CF 2.0 would crash:&lt;/p&gt;  &lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt; &lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SerializingType1 {
   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] FirstNames;
   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; PhoneNumbers;
}&lt;/pre&gt;

&lt;p&gt;This type would fail to serialize under NetCF 2.0 because T = string would appear in two kinds of collections.  This next example would also fail if you were serializing TypeA, because it contains a TypeB instance which has the another kind of T collection.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TypeA {
   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] FirstNames;
   &lt;span class="kwrd"&gt;public&lt;/span&gt; TypeB b;
}
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TypeB {
   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; PhoneNumbers;
}&lt;/pre&gt;

&lt;p&gt;If you can change the public API to use all T[] or List&amp;lt;T&amp;gt; and avoid the mixture, you've worked around the problem. So this would be the simplest workaround:&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SerializingType1 {
   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; FirstNames;
   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; PhoneNumbers;
}&lt;/pre&gt;

&lt;p&gt;If you can't change the public API to maintain compatibility for your customers, here's another workaround that will eliminate the mixture for the XmlSerializer but keep the mixture for your customers.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SerializingType1 {
   [XmlIgnore]
   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] FirstNames {
      get { &lt;span class="kwrd"&gt;return&lt;/span&gt; firstNamesHiddenList != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? firstNamesHiddenList.ToArray() : &lt;span class="kwrd"&gt;null&lt;/span&gt;; }
      set { firstNamesHiddenList = &lt;span class="kwrd"&gt;value&lt;/span&gt; != &lt;span class="kwrd"&gt;null&lt;/span&gt; ? &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;(&lt;span class="kwrd"&gt;value&lt;/span&gt;) : &lt;span class="kwrd"&gt;null&lt;/span&gt;; }
   }
   [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
   [XmlArray(&lt;span class="str"&gt;"FirstNames"&lt;/span&gt;)]
   [Obsolete(&lt;span class="str"&gt;"This member is for internal use only."&lt;/span&gt;)]
   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; firstNamesHiddenList;
   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; PhoneNumbers;
}&lt;/pre&gt;

&lt;p&gt;This will make the XmlSerializer work, and the API to the customer appear to be the same, except for a public member that they should never use directly that is only there (and public) because the XmlSerializer requires it.&amp;#xA0; EditorBrowsableAttribute and ObsoleteAttribute are there to help the customer to not run into that member and use it when you didn&amp;#x2019;t intend them to.&amp;#xA0; &lt;/p&gt;

&lt;p&gt;This bug is fixed in .NET Compact Framework 3.5.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5919435" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/Mobile+devices/default.aspx">Mobile devices</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/NetCF/default.aspx">NetCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item><item><title>What do you think of the new WCF 'Store and forward' Mail Transport?</title><link>http://blogs.msdn.com/andrewarnottms/archive/2007/10/29/what-do-you-think-of-the-new-wcf-store-and-forward-mail-transport.aspx</link><pubDate>Mon, 29 Oct 2007 22:53:53 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5770194</guid><dc:creator>andarno</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/5770194.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=5770194</wfw:commentRss><description>&lt;p&gt;With the .NET Compact Framework 3.5 release which comes with Visual Studio 2008, a new Windows Communication Foundation transport is introduced that uses email as the communication mechanism.&lt;/p&gt;  &lt;p&gt;Others have already blogged about this new transport including &lt;a href="http://blogs.msdn.com/romanbat/archive/2006/10/21/windows-communication-foundation-compact-edition-and-the-story-of-the-lunch-launcher.aspx"&gt;Roman Batoukov&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/davidklinems/"&gt;David Kline&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I'd like to take a poll of the audience to see how you like the transport, including the documentation and samples that we ship with it.&amp;#xA0; Can you think of uses for an email transport?&amp;#xA0; Do you have any trouble figuring out how to use it?&amp;#xA0; Will you use it exclusively on desktop machines, mobile devices or both?&lt;/p&gt;  &lt;p&gt;Please comment below and let me know what you're doing with it! We'd like to know about any pain points you run into so we can fix it in the next version.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5770194" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/Mobile+devices/default.aspx">Mobile devices</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/NetCF/default.aspx">NetCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/WCF/default.aspx">WCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item><item><title>Calling WCF services from NetCF 3.5 using Compact WCF and NetCFSvcUtil.exe</title><link>http://blogs.msdn.com/andrewarnottms/archive/2007/09/13/calling-wcf-services-from-netcf-3-5-using-compact-wcf-and-netcfsvcutil-exe.aspx</link><pubDate>Thu, 13 Sep 2007 02:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4885642</guid><dc:creator>andarno</dc:creator><slash:comments>16</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/4885642.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=4885642</wfw:commentRss><description>&lt;P&gt;The &lt;A href="http://msdn2.microsoft.com/en-us/netframework/aa497273.aspx" mce_href="http://msdn2.microsoft.com/en-us/netframework/aa497273.aspx"&gt;.NET Compact Framework&lt;/A&gt; 3.5 adds a subset of the &lt;A href="http://msdn2.microsoft.com/en-us/netframework/aa663324.aspx" mce_href="http://msdn2.microsoft.com/en-us/netframework/aa663324.aspx"&gt;Windows Communication Foundation&lt;/A&gt; (WCF or "Indigo") to smart devices, allowing them to communicate with desktop WCF components with all the flexibility of multiple, interchangeable service bindings and endpoints.&amp;nbsp; Although it ships out of the box only with support for message-level communication (no service calls, per se), we have a code generation tool that will allow you to call WCF or other WSDL-publishing services.&lt;/P&gt;
&lt;P&gt;Desktop has an &lt;A href="http://msdn2.microsoft.com/en-us/library/aa347733.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa347733.aspx"&gt;svcutil.exe&lt;/A&gt; tool that generates client proxy code, but the source code it generates cannot compile against NetCF libraries because NetCF does not include all the classes referenced from that source code.&amp;nbsp; While you can modify the code by hand to eventually get it to work with NetCF, we offer an easier way.&lt;/P&gt;
&lt;P&gt;The NetCFSvcUtil.exe tool that ships as part of the &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;amp;displaylang=en"&gt;Power Toys for .NET Compact Framework 3.5&lt;/A&gt;&amp;nbsp;supports many of the same command-line switches that svcutil.exe does, but performs a few additional/modified steps:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Verifies that the service being consumed&amp;nbsp;offers endpoints compatible&amp;nbsp;with the feature subset included in NetCF 3.5. 
&lt;LI&gt;Generates the client proxy class in C# or VB&amp;nbsp;that compiles against NetCF or desktop WCF. 
&lt;LI&gt;Generates code for a CFClientBase class that fills in where NetCF doesn't support calling WCF services. 
&lt;LI&gt;Does &lt;EM&gt;not&lt;/EM&gt; generate a .config file to store the endpoint information.&amp;nbsp; This information is stored in the client proxy code.&amp;nbsp; If an X509 certificate required by the endpoint, that must be passed into the proxy class' constructor by your code.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Assuming that you have a service running at http://localhost/service/service.svc&amp;nbsp;on your desktop computer and a device application in your C:\deviceapp directory, you could generate the code to call the service from NetCF using the following command line.&amp;nbsp; Be sure NetCFSvcUtil.exe is in your path.&amp;nbsp; Also be sure to use a machine name that can be reached from your device.&amp;nbsp; If you use "http://localhost/..." as your argument to the tool, your device will look for localhost (which is the device itself!) and not find the service that is running on your Windows box.&lt;/P&gt;
&lt;DIV class=command&gt;C:\deviceapp&amp;gt;netcfsvcutil.exe http://&amp;lt;machinename&amp;gt;/service/service.svc&lt;/DIV&gt;
&lt;P&gt;The tool will generate and list two source files.&amp;nbsp; The source file named after your service will be the one that contains the proxy class you'll use from your app.&amp;nbsp; You can use it just like you would the svcutil.exe-generated code, except for the provision of secure endpoints made in my numbered list above.&lt;/P&gt;
&lt;P&gt;To use these source files in your application, add them to your Visual Studio project and be sure you have System.ServiceModel.dll and System.Runtime.Serialization.dll in your project's Referenced Assemblies list in Solution Explorer.&amp;nbsp; Calling your service from your device application can be as simple as a couple of lines of code:&lt;/P&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;PRE class=csharpcode&gt;CalculatorServiceClient client = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; CalculatorServiceClient();
MessageBox.Show(client.Add(3, 5));&lt;/PRE&gt;
&lt;P&gt;Some features that WSDLs and the desktop .NET WCF supports are not supported by the .NET Compact Framework 3.5.&amp;nbsp; Although NetCFSvcUtil.exe generates code to enable some of these features,&amp;nbsp;here is a list of features that remain &lt;EM&gt;unavailable&lt;/EM&gt; for our first version of Compact WCF when calling a WCF service on desktop:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Fault contracts (they are not automatically deserialized for you, but you get the raw xml that you can parse manually) 
&lt;LI&gt;Custom message headers (including peer hop counts) 
&lt;LI&gt;Callback contracts 
&lt;LI&gt;Sessions 
&lt;LI&gt;Mandatory transactions&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;And the only desktop binding&amp;nbsp;NetCF 3.5&amp;nbsp;supports is basicHttpBinding, with optional WS-Security (X.509 only) and no support for WS-ReliableMessaging.&amp;nbsp; NetCF 3.5 adds the new mail transport as well, but NetCFSvcUtil does not support generating proxies for services exposed only on the mail transport.&lt;/P&gt;
&lt;P&gt;It's worthwhile to note that any service or client that supports WSDL contracts should be able to intercommunicate, regardless of underlying implementation.&amp;nbsp; This means that if you have a desktop WCF service that you want to call from NetCF, you may also use the already-existing &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxtskaddingremovingwebreferences.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxtskaddingremovingwebreferences.asp"&gt;Add Web Reference&lt;/A&gt; in Visual Studio to generate code for your client proxy class (the command line equivalent is &lt;A href="http://msdn2.microsoft.com/en-us/library/7h3ystb6(VS.80).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/7h3ystb6(VS.80).aspx"&gt;wsdl.exe&lt;/A&gt;).&amp;nbsp; The resulting proxy class may not have as friendly of a public API for you to use, and it won't use the WCF stack, but it is a valid alternative that will work in&amp;nbsp;many cases.&lt;/P&gt;
&lt;P&gt;The reverse is also true: you can use WCF to call into old-style .asmx web services.&amp;nbsp; It is not necessary to even know which web service implementation is used on a server.&amp;nbsp; So long as it publishes a WSDL, you're in luck.&amp;nbsp; If it doesn't publish a WSDL, you may still be able to generate a client proxy for it as long as it uses WCF service model and you have access to the managed service assemblies.&amp;nbsp; But that's another topic.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4885642" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/Mobile+devices/default.aspx">Mobile devices</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/NetCF/default.aspx">NetCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/WCF/default.aspx">WCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item><item><title>Power Toys for .NET Compact Framework 3.5 CTP released</title><link>http://blogs.msdn.com/andrewarnottms/archive/2007/09/13/power-toys-for-net-compact-framework-3-5-ctp-released.aspx</link><pubDate>Thu, 13 Sep 2007 02:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4885367</guid><dc:creator>andarno</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/4885367.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=4885367</wfw:commentRss><description>&lt;P&gt;The .NET Compact Framework team just released the Consumer Technology Preview (CTP) of the Power Toys for .NET Compact Framework 3.5.&amp;nbsp; These Power Toys are tools to help you build, debug and optimizie your NetCF 3.5 applications.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;My personal favorite is the NetCF ServiceModel Metadata Tool (NetCFSvcUtil.exe) which allows NetCF clients to call web services using the Compact WCF stack.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8174C14-A27D-4148-BF01-86C2E0953EAB&amp;amp;displaylang=en"&gt;Download it and check it out&lt;/A&gt;!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4885367" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/Mobile+devices/default.aspx">Mobile devices</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/WCF/default.aspx">WCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item><item><title>How to (not) write an especially precarious app on .NET (Compact Framework)</title><link>http://blogs.msdn.com/andrewarnottms/archive/2007/07/02/how-to-write-an-especially-precarious-app-on-net-compact-framework.aspx</link><pubDate>Tue, 03 Jul 2007 01:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3664734</guid><dc:creator>andarno</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/andrewarnottms/comments/3664734.aspx</comments><wfw:commentRss>http://blogs.msdn.com/andrewarnottms/commentrss.aspx?PostID=3664734</wfw:commentRss><description>&lt;P&gt;As the .NET Compact Framework developers work to add features, fix bugs, and refactor code, we often have to determine whether a given change could break existing customer code.&amp;nbsp; The ideal is that NetCF 3.5 will run all apps that ran on NetCF 2.0 and 1.0.&amp;nbsp; We run hundreds of apps and many, many tests before shipping each product to check backward compatibility.&amp;nbsp; The .NET Framework (both desktop and CF) makes heavy use of internal classes to allow us the freedom to change the internals of the framework without breaking customer code.&amp;nbsp; But there are still ways that customers can write apps that may break on future versions.&lt;/P&gt;
&lt;H3&gt;Compare on exception text&lt;/H3&gt;
&lt;P&gt;Some exception types are very general and don't tell you much about the error.&amp;nbsp; One of these is InvalidOperationException, which can be thrown for a wide variety of reasons for many classes in our BCLs.&amp;nbsp; Developers usually look at the Exception.Message property to get an idea of what went wrong.&amp;nbsp; This is by design.&amp;nbsp; What is &lt;EM&gt;not&lt;/EM&gt; by design is for developers to write code in their apps that looks at the Message property and makes code path decisions based on it.&amp;nbsp; Here is an example: (highly contrived, admittedly)&lt;/P&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Program {
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Main(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] args) {
            &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt; {
                XmlSerializer serializer = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; XmlSerializer(&lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(MailAddress));
            } &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt; (InvalidOperationException ex) {
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (ex.Message == &lt;SPAN class=str&gt;"System.Net.Mail.MailAddress cannot be serialized because it does not have a parameterless constructor."&lt;/SPAN&gt;) {
                    &lt;SPAN class=rem&gt;// Print message to user saying he chose a bad type to serialize&lt;/SPAN&gt;
                }
            }
            &lt;SPAN class=rem&gt;// Success!&lt;/SPAN&gt;
        }
    }

&lt;/PRE&gt;
&lt;P&gt;This can break in at least two instances: &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The text in Exception.Message is localized to the computer running your app, so this code will break if it was run on, say a Spanish computer for example. 
&lt;LI&gt;A subsequent version of .NET Framework may change the Exception.Message text to be more descriptive, accurate or whatever.&amp;nbsp; &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Either one of these likely cases may cause your code path to take a wrong turn (in this case to assume success).&amp;nbsp; Instead, you should write code that can analyze exceptions based primarily on exception type and/or error code (enumerable or integer) where available.&lt;/P&gt;
&lt;P&gt;Note: It is generally ok to display the Exception.Message to a user of an app in the form of a MessageBox or a log file (there are security considerations in doing this, however) and let the user choose how to proceed.&lt;/P&gt;
&lt;H3&gt;Compare on Exception type&lt;/H3&gt;
&lt;P&gt;Another bad way of doing exception handling is to do absolute equality checking on exception types.&amp;nbsp; Here's another bad (and contrived) example:&lt;/P&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Program {
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; ThrowBadArgument(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; positiveValue) {
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (positiveValue &amp;lt;= 0)
                &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ArgumentException(&lt;SPAN class=str&gt;"Must be positive"&lt;/SPAN&gt;, &lt;SPAN class=str&gt;"positiveValue"&lt;/SPAN&gt;);
        }
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Main(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] args) {
            &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt; {
                ThrowBadArgument(-5);
            } &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt; (Exception ex) {
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (ex.GetType() == &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(ArgumentException)) {
                    &lt;SPAN class=rem&gt;// Oops, the user provided a non-positive number!&lt;/SPAN&gt;
                }
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;Now suppose that the developer (or vendor) supplying you with your ThrowBadArgument method decided it was more appropriate to throw an ArgumentOutOfRange exception.&amp;nbsp; This would break your code and again cause your program to inappropriately assume success.&lt;/P&gt;
&lt;P&gt;Here is a corrected example:&lt;/P&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Program {
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; ThrowBadArgument(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; positiveValue) {
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (positiveValue &amp;lt;= 0)
                &lt;SPAN class=kwrd&gt;throw&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ArgumentOutOfRangeException(&lt;SPAN class=str&gt;"Must be positive"&lt;/SPAN&gt;, &lt;SPAN class=str&gt;"positiveValue"&lt;/SPAN&gt;);
        }
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Main(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] args) {
            &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt; {
                ThrowBadArgument(-5);
            } &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt; (ArgumentException ex) {
                &lt;SPAN class=rem&gt;// Oops, the user provided a non-positive number!&lt;/SPAN&gt;
            }
        }
    }
&lt;/PRE&gt;
&lt;P&gt;Note in this latter example how the throwing method is using the derived class.&amp;nbsp; But catching the base class in this way allows us to catch either ArgumentException or ArgumentOutOfRangeException equally well.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;And if you need to check the exception type using an if statement (to check the type of Exception.InnerException for example) be sure to use the &lt;STRONG&gt;is&lt;/STRONG&gt; keyword rather than Exception.GetType() == typeof(...).&amp;nbsp; For example:&lt;/P&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;// good example&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (ex.InnerException &lt;SPAN class=kwrd&gt;is&lt;/SPAN&gt; ArgumentException) {
    &lt;SPAN class=rem&gt;// do stuff based on inner exception&lt;/SPAN&gt;
}
&lt;SPAN class=rem&gt;// Another good example (albeit harder to read)&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(ArgumentException).IsInstanceOfType(ex.InnerException)) {
}

&lt;SPAN class=rem&gt;// BAD example&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (ex.InnerException.GetType() == &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(ArgumentException)) {
    &lt;SPAN class=rem&gt;// do stuff based on inner exception&lt;/SPAN&gt;
}
&lt;/PRE&gt;
&lt;H3&gt;Finding public methods using reflection and parameter names&lt;/H3&gt;
&lt;P&gt;There's no good way to do this.&amp;nbsp; You should only find methods based on the parameter &lt;EM&gt;types&lt;/EM&gt;, not parameter &lt;EM&gt;names&lt;/EM&gt;.&amp;nbsp; The reflection API makes it easy to do it right, and harder to do it wrong.&amp;nbsp; Here is an example on how to do it right, and wrong:&lt;/P&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;PRE class=csharpcode&gt;    &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Program {
        &lt;SPAN class=kwrd&gt;static&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Main(&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;[] args) {
            &lt;SPAN class=rem&gt;// Good example&lt;/SPAN&gt;
            MethodInfo m = &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;).GetMethod(&lt;SPAN class=str&gt;"ToString"&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Type[] { &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(CultureInfo) });
            Console.WriteLine(m.Invoke(3, &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt;[] { CultureInfo.CurrentCulture }));
            
            &lt;SPAN class=rem&gt;// Bad example&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (MethodInfo method &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;typeof&lt;/SPAN&gt;(&lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt;).GetMethods()) {
                ParameterInfo[] parameters = method.GetParameters();
                &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (parameters.Length == 1 &amp;amp;&amp;amp; parameters[0].Name == &lt;SPAN class=str&gt;"provider"&lt;/SPAN&gt;) {
                    m = method;
                    &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
                }
            }
            Console.WriteLine(m.Invoke(3, &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt;[] { CultureInfo.CurrentCulture }));
        }
    }
&lt;/PRE&gt;
&lt;P&gt;You should not take a dependency on parameter names of methods you call.&amp;nbsp; The .NET compilers take care of this for you, but if you go around them by using reflection and use parameter names rather than parameter types to find the method overload you want, you're asking to be broken if those method parameter names ever change (and they can!)&lt;/P&gt;
&lt;H3&gt;Finding internal-only methods or types&amp;nbsp;using reflection&lt;/H3&gt;
&lt;P&gt;Again, there is no right way to do this.&amp;nbsp; Getting into the internals of a library by using reflection requires full trust and means you're just asking for your app to break in the next version of the library when those internals get changed.&lt;/P&gt;
&lt;H3&gt;In conclusion...&lt;/H3&gt;
&lt;P&gt;If you follow these tips, your apps will be more likely to perform well on current and future versions of the .NET Framework, on your own as well as your customers' locales.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3664734" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/NetCF/default.aspx">NetCF</category><category domain="http://blogs.msdn.com/andrewarnottms/archive/tags/.NET/default.aspx">.NET</category></item></channel></rss>