<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0QERH07eip7ImA9WhBbFU4.&quot;"><id>tag:blogger.com,1999:blog-6894552</id><updated>2013-05-14T06:48:25.302-07:00</updated><category term="Reviews" /><category term="Immutability" /><category term="Performance" /><category term="OAuth" /><category term="Javascript" /><category term="Async" /><category term="Windows" /><category term="MSBuild" /><category term="DotNetOpenAuth" /><category term="ASP.NET" /><category term="OpenID" /><category term="Windows.Forms" /><category term="WCF" /><category term="Far sighted" /><category term="Ruby" /><category term="Linux" /><category term="Smart devices" /><category term="NHibernate" /><category term="GC" /><category term="Hardware" /><category term="Mono" /><category term="WPF" /><category term="InfoCard" /><category term=".NET" /><category term="Silverlight" /><title>JMPInline</title><subtitle type="html">Read up on .NET news, tips, cautions... and other areas of technological interest.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.nerdbank.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>153</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/Jmpinline" /><feedburner:info uri="jmpinline" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>47.71828</geo:lat><geo:long>-122.197026</geo:long><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><entry gd:etag="W/&quot;DkIGRn86fSp7ImA9WhBWFEU.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-1542315103882317832</id><published>2012-12-18T07:46:00.001-08:00</published><updated>2013-04-08T22:15:27.115-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-08T22:15:27.115-07:00</app:edited><title>The Demand For Computer Science Graduates</title><content type="html">Today, Olivia Leonardi is contributing a post about the growing demand for computer science graduates and the new, open source programs designed to help meet this need. This article is meant to help those who stumble across the &lt;a href="http://blog.nerdbank.net/2011/07/c-await-for-msbuild.html"&gt;posts regarding the technicalities of C# found on NerdBank&lt;/a&gt; a way to break into the industry and join in the conversation. Typically Leonardi is a writer for a &lt;a href="http://www.onlinecomputersciencedegree.com/certificates/"&gt;website offering information about computer science certification&lt;/a&gt;.&lt;br /&gt;
&lt;h4&gt;
The Demand For Computer Science Graduates&lt;/h4&gt;
Trained computer programmers are needed now more than ever. Modern society has experienced an exponential growth of technology that has revolutionized the economy and the workforce and the education system is struggling to keep up. Based on current figures, there are simply not enough individuals who have been properly trained to design and implement these various programs. However, this deficit may improve as a result of web-based programs that allow students to bypass brick-and-mortar university studies, most of which are extremely competitive and drop the majority of students who apply to them, and learn various aspects of computer programming online. Often times, for free. &lt;br /&gt;
&lt;a href="http://www.bls.gov/ooh/computer-and-information-technology/computer-programmers.htm#tab-2"&gt;According to the US Bureau of Labor Statistics&lt;/a&gt;, trained computer programmers essentially act as intermediaries between software engineers and &lt;a href="http://www.devry.edu/degree-programs/college-engineering-information-sciences/computer-information-systems-about.jsp"&gt;computer systems&lt;/a&gt;. Many of them are fluent in multiple code languages; the most widely used languages today include Java, C, C++ and HTML. As new software is developed, programmers must test it and, if necessary, debug programs by correcting errors in the code. This all-important task has implications in virtually every area of web-based development; from corporate websites and online business journals to blogs and social media. Project lengths vary; smartphone apps, for instance, take days to develop and optimize, while complex systems may take more than a year to finish.&lt;br /&gt;
Programmers are well compensated for their expertise, and also for their relative rarity in the job market.&lt;a href="http://www.bls.gov/ooh/computer-and-information-technology/computer-programmers.htm#tab-5"&gt; The BLS reported in 2010&lt;/a&gt; that the median wage for computer programmers was $71,380 – one of the highest in the nation, and&lt;a href="http://www.forbes.com/pictures/efkk45ifij/no-2-best-masters-degree-for-jobs-computer-science/"&gt; according to Forbes&lt;/a&gt;, the mid-career median salary for those who earn a master’s degree in computer science is $109,000. These high paying jobs are also not few and far between as associated employment opportunities are projected to grow by 22.3 percent.&lt;br /&gt;
The problem,&lt;a href="http://sciencecareers.sciencemag.org/career_magazine/previous_issues/articles/2012_03_16/caredit.a1200030"&gt; according to a recent article in Science&lt;/a&gt;, stems from shortcomings in computer science education programs. Technology is evolving at a much more rapid rate than the curricula taught to college-level computer science students. As a result, most receive a very generalized education without learning supplementary skills, such as specific code languages or complex systems programming. Fortunately, aspiring programmers now have access to several web-based outlets if they wish to learn these supplementary skills. Some of these programs include:&lt;br /&gt;
&lt;a href="http://www.codecademy.com/"&gt;&lt;strong&gt;Codecademy&lt;/strong&gt;&lt;/a&gt; | Launched in August 2011, this startup offers free lessons for programmers. Current courses include JavaScript Fundamentals, Python, JQuery and Code Year.&lt;a href="http://www.forbes.com/sites/jjcolao/2012/06/19/codecademy-raises-10-million-to-conquer-the-world/"&gt; According to Forbes&lt;/a&gt;, the site received 200,000 visitors within 72 hours of launching – and to date has logged more than 50 million completed exercises.&lt;br /&gt;
&lt;a href="http://www.c-sharpcorner.com/UploadFile/mahesh/csp08202007084545AM/csp.aspx"&gt;&lt;strong&gt;C# Corner&lt;/strong&gt;&lt;/a&gt; | This step-by-step tutorial trains students how to “write and compile C# programs, understand C# syntaxes” and perform other functions related to this commonly used language. The course is free, though previous code experience (such as C#, Pascal or Java) is recommended.&lt;br /&gt;
&lt;strong&gt;Coursera&lt;/strong&gt; | Launched in April 2012, this educational platform has served more than 1 million students to date. The site aggregates free courses offered by a number of prominent institutions, including Massachusetts Institute of Technology, Stanford University, Duke University, and Johns Hopkins University. &lt;a href="https://www.coursera.org/category/cs-programming"&gt;Upcoming courses&lt;/a&gt; related to programming include Functional Programming Principles in Scala (offered by École Polytechnique Fédérale de Lausanne) and Heterogeneous Parallel Programming (offered by University of Illinois at Urbana-Champaign).&lt;br /&gt;
&lt;strong&gt;University of Oklahoma Online&lt;/strong&gt; | The OU Supercomputing Center for Education &amp;amp; Research currently offers an&lt;a href="http://www.oscer.ou.edu/education.php"&gt; online tutorial&lt;/a&gt; that introduces principles of supercomputing. Though the concepts are complex, the course is designed to approach topics in a user-friendly manner that, with diligent study, will be digestible for students.&lt;br /&gt;
Online courses like these allow computer scientists to fill any gaps left by limited high education programs. If they prove to be effective, then the deficit of trained programmers stands to improve considerably in the coming years.&amp;nbsp; &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wLYSrZ90j2U:ZH8GOax0ygI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=wLYSrZ90j2U:ZH8GOax0ygI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wLYSrZ90j2U:ZH8GOax0ygI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wLYSrZ90j2U:ZH8GOax0ygI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=wLYSrZ90j2U:ZH8GOax0ygI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wLYSrZ90j2U:ZH8GOax0ygI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=wLYSrZ90j2U:ZH8GOax0ygI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wLYSrZ90j2U:ZH8GOax0ygI:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/wLYSrZ90j2U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/1542315103882317832/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2012/12/the-demand-for-computer-science.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/1542315103882317832?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/1542315103882317832?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/wLYSrZ90j2U/the-demand-for-computer-science.html" title="The Demand For Computer Science Graduates" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2012/12/the-demand-for-computer-science.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMCQHg7fyp7ImA9WhJSFEw.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5932171450555278629</id><published>2012-07-04T07:34:00.001-07:00</published><updated>2012-07-04T07:34:21.607-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-07-04T07:34:21.607-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DotNetOpenAuth" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><title>DotNetOpenAuth ships with Visual Studio 2012</title><content type="html">&lt;p&gt;Some of you may have already heard the &lt;a href="http://www.dotnetrocks.com/default.aspx?showNum=773"&gt;announcement on .NET Rocks (time index 41:30)&lt;/a&gt;, but in case you haven't: Visual Studio 2012 will include DotNetOpenAuth in all its ASP.NET project templates.&amp;nbsp; Woot!&amp;nbsp; Yes, my friends, it has finally happened. &lt;h3&gt;Q&amp;amp;A&lt;/h3&gt; &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;With the announcement, Scott Hunter mentions being able to hack into a site that accepted Twitter logins, and may have suggested that the site used DotNetOpenAuth.&amp;nbsp; He also mentioned that Microsoft "hardened" the library to fix some security issues.&amp;nbsp; Does DotNetOpenAuth have security holes? &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;Please don't be alarmed.&amp;nbsp; I worked closely with the Microsoft ASP.NET team who added DotNetOpenAuth to VS2012, and they never found any security holes in the library.&amp;nbsp; I don't actually know what Scott is referring to here.&amp;nbsp; Since a web site can certainly use DNOA improperly, security holes in web sites certainly are possible, but not likely from a fault in the library. &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;Is DotNetOpenAuth a Microsoft project now? &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;No.&amp;nbsp; DotNetOpenAuth continues to be independently owned and developed, although Microsoft has begun making source contributions to it.&amp;nbsp; Another example of this is jQuery, which Microsoft ships with ASP.NET as well, but Microsoft doesn't own or directly control it. &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;Will DotNetOpenAuth continue to get regular releases, or are they now tied to Visual Studio releases? &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;DotNetOpenAuth will continue to ship independently of VS.&amp;nbsp; The copy of DotNetOpenAuth that ships with Visual Studio 2012 is actually one of DotNetOpenAuth's own past releases.&amp;nbsp; The way the ASP.NET project templates bundle it is as a NuGet package, so if you create a web project based on these templates, NuGet can help you upgrade to the latest version of DotNetOpenAuth right away. &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;Is Microsoft contributing to DotNetOpenAuth now? &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;Yes.&amp;nbsp; You may have noticed the new &lt;a href="https://nuget.org/packages/DotNetOpenAuth.AspNet"&gt;DotNetOpenAuth.AspNet package&lt;/a&gt; available on NuGet.&amp;nbsp; This is Microsoft's contribution to the DotNetOpenAuth library.&amp;nbsp; Whereas the rest of DotNetOpenAuth is strictly a protocol library (no specific APIs for individual popular online services), the DotNetOpenAuth.AspNet package adds an assembly which &lt;i&gt;does&lt;/i&gt; target all the popular identity providers explicitly, making it easier to add buttons for "log in with Google", "log in with LinkedIn", etc.&amp;nbsp; &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;What is DotNetOpenAuth.AspNet?&amp;nbsp; &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;DotNetOpenAuth.AspNet is Microsoft's front-end to DotNetOpenAuth that the ASP.NET project templates use instead of DotNetOpenAuth directly. Internally, DotNetOpenAuth.AspNet uses DotNetOpenAuth so you're still using the time-tested library underneath.&amp;nbsp; So if you create a new ASP.NET project in VS2012, you'll be able to switch on DotNetOpenAuth.AspNet by uncommenting a few lines of code.&amp;nbsp;&amp;nbsp; &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;How does DotNetOpenAuth.AspNet compare with the core DotNetOpenAuth library?&amp;nbsp; Should I switch my existing code to use DotNetOpenAuth.AspNet? &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;To keep things simple, the ASP.NET team decided to conceal the core DotNetOpenAuth API behind theirs and they set several DotNetOpenAuth settings to their simple or "stateless" mode values.&amp;nbsp; This means that things are more likely to work in web farms right out of the box if you're using the DotNetOpenAuth.AspNet frontend, at the cost of a slightly less secure set of defaults.&amp;nbsp; Some settings are harder to reach if you're using the DotNetOpenAuth.AspNet frontend.&amp;nbsp; If you have existing code by all means keep it.&amp;nbsp; The library you're using is still active developed and what DotNetOpenAuth.AspNet uses behind the scenes so you're by no means going to be using obsolete code in the foreseeable future.&amp;nbsp; If you're writing new code, DotNetOpenAuth is still a fine choice, but if you're just acting as a relying party and want a simpler API to use against only popular identity providers, then DotNetOpenAuth.AspNet is a reasonable choice. &lt;p&gt;&lt;b&gt;Q: &lt;/b&gt;How else is DotNetOpenAuth.AspNet different than the rest of the library? &lt;p&gt;&lt;b&gt;A: &lt;/b&gt;It is less configurable than the rest of the library.&amp;nbsp; In particular it doesn't offer any way to be configured via your web.config file.&amp;nbsp; Although since the core DotNetOpenAuth is still active underneath the API, the normal web.config settings you use for DNOA may still apply in some cases.&amp;nbsp; Also, I don't actively support DotNetOpenAuth.AspNet myself.&amp;nbsp; Any feedback or issues filed against it I forward to the ASP.NET team, who maintains that project. &lt;p&gt;&lt;strong&gt;Q: &lt;/strong&gt;So… this is a Good Thing, right? &lt;p&gt;&lt;strong&gt;A: &lt;/strong&gt;Absolutely. It has never been easier for ASP.NET developers to build web sites that delegate authentication responsibilities to popular identity providers.&amp;nbsp; This is a boon for web developers, and especially a boon for all our web visitors out there that are now more likely to be able to reuse a few Internet identities instead of maintaining dozens of accounts on all the web sites they visit.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=yjOIBgse3u0:hW0lXlKoGXE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=yjOIBgse3u0:hW0lXlKoGXE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=yjOIBgse3u0:hW0lXlKoGXE:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=yjOIBgse3u0:hW0lXlKoGXE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=yjOIBgse3u0:hW0lXlKoGXE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=yjOIBgse3u0:hW0lXlKoGXE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=yjOIBgse3u0:hW0lXlKoGXE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=yjOIBgse3u0:hW0lXlKoGXE:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/yjOIBgse3u0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5932171450555278629/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2012/07/dotnetopenauth-ships-with-visual-studio.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5932171450555278629?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5932171450555278629?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/yjOIBgse3u0/dotnetopenauth-ships-with-visual-studio.html" title="DotNetOpenAuth ships with Visual Studio 2012" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2012/07/dotnetopenauth-ships-with-visual-studio.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMHSXc_eip7ImA9WhJTFUg.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-7334274102792345850</id><published>2012-06-24T07:11:00.001-07:00</published><updated>2012-06-24T10:03:58.942-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-24T10:03:58.942-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GC" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Performance" /><title>GC pressure series: hidden boxing</title><content type="html">&lt;h2&gt;&lt;/h2&gt; &lt;p&gt;Last time we talked about &lt;a href="http://blog.nerdbank.net/2012/06/gc-pressure-series-introduction-and.html"&gt;GC pressure from enumerating collections using their interfaces rather than their concrete types&lt;/a&gt;.&amp;nbsp; It turns out that the garbage produced by using the interfaces is directly caused by boxing, which we’ll explore more in depth and in a broader context here.&lt;/p&gt; &lt;p&gt;Before diving into boxing and when it can implicitly occur, let’s first review some terminology.&amp;nbsp; If you’re already fluent in value types vs. reference types, feel free to skip to the &lt;a href="#boxing"&gt;boxing section&lt;/a&gt;.&lt;/p&gt; &lt;h3&gt;Value types&lt;/h3&gt; &lt;p&gt;In C#, value types are structs.&amp;nbsp; Primitives you’re very familiar with like integer, float, and Guid are structs, as well as the ones you may define yourself.&amp;nbsp; If you pass a struct as a parameter to another method, that method gets a &lt;em&gt;copy&lt;/em&gt; of that struct – not the original struct.&amp;nbsp; Consider this example:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void Main() {
   int seeds = 5;
   AddOneSeed(5);
   Debug.Assert(seeds == 5);
}

static void AddOneSeed(int seeds) {
   seeds++;
}&lt;/pre&gt;
&lt;p&gt;The AddOneSeed method received a copy of the integer, which is a struct.&amp;nbsp; Therefore any changes it made do not propagate back to the caller.&amp;nbsp; Note that if a “ref” keyword is added to the parameter in the method’s signature that the method accesses the caller’s original struct instead of a copy, allowing the method to modify its caller’s value.&lt;/p&gt;
&lt;p&gt;Value types store their data directly in their container.&amp;nbsp; In the above case, the value types appear as local variables within methods, so the data of these value types is stored directly on the stack of the thread executing these methods.&amp;nbsp; This also means that value types can vary in size, and the container must know exactly how large the value type is so that enough memory can be allocated for it.&lt;/p&gt;
&lt;h3&gt;Reference types&lt;/h3&gt;
&lt;p&gt;In C#, reference types are classes.&amp;nbsp; Reference types store their data on the heap, and anyone holding a reference type is actually just holding a reference: a memory pointer to that object on the heap.&amp;nbsp; Classes may contain structs as fields.&amp;nbsp; This means that value types may actually appear on the heap.&amp;nbsp; Consider this simple example:&lt;/p&gt;&lt;pre class="prettyprint"&gt;class Fruit {
   int seeds;
}&lt;/pre&gt;
&lt;p&gt;Fruit is a reference type that contains a field that is a value type.&amp;nbsp; This value type always appears on the heap because it’s within an object on the heap.&amp;nbsp; The memory allocated on the heap by the Fruit object actually includes the value type directly.&amp;nbsp; In the case of Fruit above, the object on the heap is 12 bytes in size: 8 for the CLR header that exists for every object, and 4 more bytes for the seeds field.&lt;/p&gt;&lt;a name="boxing"&gt;&lt;/a&gt;
&lt;h3&gt;Boxing: When a value type becomes a reference type&lt;/h3&gt;
&lt;p&gt;Sometimes a value type must be represented as a reference type.&amp;nbsp; The CLR allows &lt;em&gt;anything&lt;/em&gt; to be represented as a System.Object.&amp;nbsp; But System.Object is a reference type.&amp;nbsp; Anyone with a reference to Object expects it to be a pointer to an object on the heap, and the size of Object to the holder of the reference is &lt;em&gt;always&lt;/em&gt; 4 bytes regardless of the size of that object on the heap (or 8 bytes in a 64-bit process).&amp;nbsp; How can a value type, which may vary in size, be assigned to a System.Object, which is always exactly 4 bytes?&amp;nbsp; Boxing.&lt;/p&gt;
&lt;p&gt;Boxing happens when the compiler has to assign a value-type to a reference type.&amp;nbsp; When boxing, the CLR allocates a new object on the heap just large enough to store the particular value type being boxed, and copies the value type into that object.&amp;nbsp; Now the reference to that object can be passed around simply as System.Object without anyone knowing how large the object really is. To actually look at the value type again, it must be &lt;em&gt;un&lt;/em&gt;boxed, where the value is copied back onto the stack, and possibly into a field typed as the matching value type.&lt;/p&gt;
&lt;p&gt;Let’s consider the simplest example of boxing.&amp;nbsp; We have an integer value type on the stack as a local variable in this method.&amp;nbsp; Then we assign this value type to a reference type.&amp;nbsp; IComparable is an interface.&amp;nbsp; Value types can implement interfaces.&amp;nbsp; But as soon as you refer to the value type by an interface it implements it gets boxed.&amp;nbsp; Check this out:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void Main() {
   int number = 5;
   IComparable comparable = number;
}&lt;/pre&gt;
&lt;p&gt;The C# compiler compiles the above code to the below IL:&lt;/p&gt;&lt;pre class="prettyprint"&gt;.locals init (
        [0] int32 number,
        [1] class [mscorlib]System.IComparable comparable)
nop 
ldc.i4.5 
stloc.0 
ldloc.0 
box int32
stloc.1&lt;/pre&gt;
&lt;p&gt;It’s not important that you understand all the IL, but notice the box instruction.&amp;nbsp; This tells the CLR to allocate an object and copy the value at the top of the stack into it, and then push a reference to that object onto the stack in its place.&amp;nbsp; The last instruction then assigns that object reference into the local variable typed as an IComparable.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;But wait… if a struct implements an interface already, why does it have to be boxed when it is assigned to a variable typed as that interface?&amp;nbsp; The answer lies in its size.&amp;nbsp; Anything can implement an interface (struct or class), and sizes can vary.&amp;nbsp; But folks holding a reference to an interface have to know in advance how much space to allocate for that reference.&amp;nbsp; Since value types vary in size, value types don’t qualify.&amp;nbsp; Instead, when you’re dealing with interfaces you’re always dealing with reference types, meaning that value types get boxed inside an object on the heap as a reference type.&lt;/p&gt;
&lt;p&gt;The important thing to realize here is that although the C# code did not have a &lt;em&gt;new&lt;/em&gt; keyword anywhere, an object was allocated anyway.&amp;nbsp; This is under-the-covers magic by C# and the CLR so that things just work, and normally it’s a good thing.&amp;nbsp; But this is a post on GC pressure, so of course we’re going to study how boxing can work against you, and how you can avoid it.&lt;/p&gt;
&lt;h3&gt;How to avoid boxing&lt;/h3&gt;
&lt;p&gt;The easiest way to avoid boxing is to always refer to a value type by its concrete type rather than by System.Object or an interface the value type implements.&amp;nbsp; You can still call methods on that struct that implement interfaces just by calling those methods directly.&amp;nbsp; For example, consider these two calls to CompareTo:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void Main() {
   int number = 5;

   // CompareTo is found on the IComparable interface
   IComparable comparable = number; // box number
   int result = comparable.CompareTo(8); // box 8

   // CompareTo is also a public method on int directly.
   // In fact two overloads of CompareTo are available
   // on int, one that takes System.Object and another
   // that takes an int, so the C# compiler will choose
   // to call the one that takes int, avoiding both 
   // boxes that the above example causes.
   int result2 = number.CompareTo(8);
}&lt;/pre&gt;
&lt;p&gt;The example demonstrates two things.&amp;nbsp; First is the discrete &lt;em&gt;second&lt;/em&gt; boxing that can happen.&amp;nbsp; Once we’ve boxed the int to an IComparable, there is only one CompareTo method for the compiler to choose from: CompareTo(object).&amp;nbsp; That means that in addition to having already boxed the 5, the 8 must also be boxed in order to call CompareTo(object).&amp;nbsp; On the other hand, leaving 5 as an integer avoids the first box, and allows the CompareTo(8) method to bind to int.CompareTo(int), which means the 8 can also remain as a value type.&amp;nbsp; To better understand what is happening, consider how the Int32 and IComparable types are defined:&lt;/p&gt;&lt;pre class="prettyprint"&gt;public struct Int32 : IComparable, IFormattable, IConvertible, IComparable&lt;int&gt;, IEquatable&lt;int&gt; {
   public int CompareTo(int value);
   public int CompareTo(object value);
}

public interface IComparable {
   int CompareTo(object obj);
}&lt;/pre&gt;
&lt;p&gt;As you can see, when you have an IComparable reference, all the compiler can do is call CompareTo(object). But when you have an Int32, you also can call CompareTo(int) and avoid both boxes.&lt;/p&gt;
&lt;p&gt;Keep in mind as well that returning a value type from a method whose signature returns an interface also boxes:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static IComparable GetNumber() {
   return 5; // boxed!
}&lt;/pre&gt;
&lt;h3&gt;Some pathological cases&lt;/h3&gt;
&lt;p&gt;An occasional box here and there isn’t going to hurt the performance of your app.&amp;nbsp; But there are some things you can do that can lead to enough boxing to really hurt in frequently called code.&lt;/p&gt;
&lt;h5&gt;Boxing in a loop&lt;/h5&gt;
&lt;p&gt;Suppose you have no choice but to box a value type to call a method that takes an interface.&amp;nbsp; If you were calling that method in a loop with the same value type each time, you can take care to avoid boxing for each iteration of the loop.&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void BoxEachIteration() {
   int number = 5;
   for (int i = 0; i &amp;lt; 500; i++) {
      Work(number, i);
   }
}

static void BoxJustOnce() {
   int number = 5;
   IComparable boxedNumber = number;
   for (int i = 0; i &amp;lt; 500; i++) {
      Work(boxedNumber, i);
   }
}

static void Work(IComparable number, int iteration) {
}&lt;/pre&gt;
&lt;h5&gt;Boxing in non-mutating methods&lt;/h5&gt;
&lt;p&gt;When you implement public methods that don’t mutate state, you should generally be very careful not to box at all.&amp;nbsp; For example, folks expect that retrieving a value from a dictionary should have no side effects including not allocating memory.&amp;nbsp; This is important because your cheap, non-mutating methods are often the ones that end up being called in loops which may end up being perf critical to the application.&lt;/p&gt;
&lt;p&gt;Earlier this week I investigated a performance problem that I found was due to GC pressure caused by a hashtable-like collection that boxed in its Get method.&amp;nbsp; Ouch.&amp;nbsp; Here was the Get method:&lt;/p&gt;&lt;pre class="prettyprint"&gt;public T Get(string key)
{
    return this.Get(new KeyedObject(key));
}&lt;/pre&gt;
&lt;p&gt;There's a &lt;em&gt;new&lt;/em&gt; keyword there, but KeyedObject was a struct, so supposedly no heap allocations there. But it gets more subtle. Take a look at how the struct is defined, and how the Get overload that is being called is defined:&lt;/p&gt;&lt;pre class="prettyprint"&gt;private struct KeyedObject : IKeyed
{
    private string name;
    internal KeyedObject(string name);
    string IKeyed.Key { get; }
}

public T Get(IKeyed item)
{
  // ...
}&lt;/pre&gt;
&lt;p&gt;Do you see the problem? Although the Get(string) method creates a struct, which doesn’t cause GC pressure, it then passes that struct to a method that accepts an interface.&amp;nbsp; That struct implements that interface, so while the C# compiler allows it, it first has to box the struct, which means all the work the authoring developer went to by using a struct to avoid allocations didn’t actually avoid the allocation after all.&amp;nbsp; Since this Get(string) method was being called thousands of times in this perf critical scenario, we were generating garbage like crazy and the GC had to keep interrupting the app to clean up.&lt;/p&gt;
&lt;p&gt;One possible fix to this is to add a Get(KeyedObject) overload that does the work directly with the value type.&amp;nbsp; Then the C# compiler would call that one instead of the one taking the interface, and the boxing would disappear.&lt;/p&gt;
&lt;h5&gt;Non-generic collections&lt;/h5&gt;
&lt;p&gt;Generic collections aren’t just sugar.&amp;nbsp; They can help performance tremendously.&amp;nbsp; Consider a table of value type pairs.&amp;nbsp; If you use the non-generic &lt;a href="http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx"&gt;Hashtable&lt;/a&gt; collection, where keys and values are typed as System.Object, each key and value must get boxed before storage.&amp;nbsp; That at least is a somewhat fixed cost – it’s not directly garbage because the box is persistent for as long as that entry is in the collection.&amp;nbsp; But now think about every lookup operation.&amp;nbsp; Let’s say you have a hashtable where the keys and values are both integers.&amp;nbsp; You have a key and you want to look up the value.&amp;nbsp; You are compelled to box the key first, making it impossible to query for values without allocating memory.&lt;/p&gt;&lt;pre class="prettyprint"&gt;var table = new Hashtable();
table[5] = 8; // boxes 5 and 8
int value = (int)table[5]; // box 5 (again)&lt;/pre&gt;
&lt;p&gt;If on the other hand you use Dictionary&amp;lt;int, int&amp;gt;, all the internal storage mechanisms and methods are strongly typed to take and return integers rather than System.Object, so no boxing occurs. This can have a dramatic impact on performance due to GC pressure as well as memory availability since each integer takes only 4 bytes in memory instead of the minimum 12 bytes required by every GC heap allocated object.&lt;/p&gt;
&lt;h3&gt;Should I define my type as struct or class?&lt;/h3&gt;
&lt;p&gt;That’s a broad question and there is more to consider than GC pressure when making this decision.&amp;nbsp; In my personal experience, almost every time I’ve nobly started with a struct I’ve ended up converting it to a class.&amp;nbsp; So my personal default is to use class unless struct is required.&amp;nbsp; There are several reasons for this, but most pertinent to this post are two things to consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Structs &lt;em&gt;allow &lt;/em&gt;you to allocate and pass around the values without allocating memory on the heap.&amp;nbsp; Classes &lt;em&gt;must&lt;/em&gt; always be allocated on the heap. 
&lt;li&gt;Structs can be boxed many times, but classes will only allocate memory &lt;em&gt;once&lt;/em&gt;.&amp;nbsp; &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Every time you assign a struct such that boxing is required, a &lt;em&gt;new&lt;/em&gt; object is allocated.&amp;nbsp; So the same struct can actually end up acquiring lots of memory and producing lots of garbage.&amp;nbsp; Whereas if you’d just chosen to use a class, the memory is allocated once and shared across all who reference it.&amp;nbsp; So be careful when you define structs and ask yourself how folks with that struct will use it.&amp;nbsp; If the likelihood is high that most instances of the struct will get boxed sometime in their lifetime, consider making it a class instead to help keep the GC pressure down.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=tCtIJR2FpyQ:4JSY5vUm8rc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=tCtIJR2FpyQ:4JSY5vUm8rc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=tCtIJR2FpyQ:4JSY5vUm8rc:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=tCtIJR2FpyQ:4JSY5vUm8rc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=tCtIJR2FpyQ:4JSY5vUm8rc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=tCtIJR2FpyQ:4JSY5vUm8rc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=tCtIJR2FpyQ:4JSY5vUm8rc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=tCtIJR2FpyQ:4JSY5vUm8rc:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/tCtIJR2FpyQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/7334274102792345850/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2012/06/gc-pressure-series-hidden-boxing.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/7334274102792345850?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/7334274102792345850?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/tCtIJR2FpyQ/gc-pressure-series-hidden-boxing.html" title="GC pressure series: hidden boxing" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.nerdbank.net/2012/06/gc-pressure-series-hidden-boxing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cNSHc_fSp7ImA9WhVaEUQ.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5552729507194930293</id><published>2012-06-08T14:50:00.001-07:00</published><updated>2012-06-08T15:38:19.945-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-08T15:38:19.945-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GC" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Performance" /><title>GC pressure series: Introduction and enumerators</title><content type="html">&lt;p&gt;As you may already know, I’m a Microsoft developer who works on Visual Studio.&amp;nbsp; Improved performance and responsiveness is a major goal for the 2012 release.&amp;nbsp; As much of the new code in Visual Studio 2012 was written in C#, I learned a lot about how much GC pressure can degrade performance.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q: Wait.&amp;nbsp; What is GC pressure?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A: &lt;/strong&gt;GC pressure happens when your .NET application produces lots of “garbage” by allocating and releasing memory.&amp;nbsp; .NET has to “collect” all this garbage periodically by walking your application’s memory graph to determine which objects are still used and which have become garbage, then the memory for the garbage is freed.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q: Right.&amp;nbsp; That’s what garbage collection is all about.&amp;nbsp; So what’s the problem?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A: &lt;/strong&gt;Normally the CLR’s heuristics for finding good times to pause your application to perform GC gives your application a lean memory footprint and high responsiveness.&amp;nbsp; The problem comes when you’re in a performance critical section of code in your application, perhaps in a loop of some kind, and within that section you’re producing &lt;em&gt;and discarding &lt;/em&gt;lots of managed objects. This causes “GC pressure” which leads .NET to interrupt your perf critical code to run the GC in order to keep your application from running up its memory use, which besides potentially slowing down the machine overall, can eventually lead to an OutOfMemoryException.&amp;nbsp; The heuristics of .NET’s GC are complex and beyond the scope of my blog.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q: How do I know if GC pressure is responsible for my performance problems?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;A: &lt;/strong&gt;Like most performance investigations, you find out that GC pressure is your problem by measuring using some profiler tool and noticing that native callstacks are executing while you’re allocating memory that include GC code.&amp;nbsp; &lt;/p&gt; &lt;p&gt;For instance, some large Visual Studio solutions I measured were spending around 30% of the time simply running the GC.&amp;nbsp; Imagine if I could wave a wand and make VS 30% faster.&amp;nbsp; That would be significant, right?&amp;nbsp; The good news is that GC pressure is very often a solvable problem.&amp;nbsp; In several upcoming blog posts, I’ll review several discrete sources of GC pressure that are easily solvable, and which allowed us to greatly improve solution load performance (and other scenarios) significantly.&lt;/p&gt; &lt;h3&gt;Enumerator structures vs. IEnumerable&amp;lt;T&amp;gt;&lt;/h3&gt; &lt;p&gt;It’s often good design to use types that are only as specific as needed.&amp;nbsp; For instance, your public methods should typically take IList&amp;lt;T&amp;gt; instead of List&amp;lt;T&amp;gt;.&amp;nbsp; This allows others to call you with a custom list implementation if they need to.&amp;nbsp; But this can actually cause GC pressure if you use a C# foreach to enumerate the list.&amp;nbsp; Consider the following:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void Main() {
   var numbers = new List&amp;lt;int&amp;gt;(new[] { 1, 2, 3, 4, 5, 6, 8 });
   foreach (var number in numbers) {
   }
}
&lt;/pre&gt;
&lt;p&gt;In this case, the C# compiler knows that foreach is enumerating the List&amp;lt;int&amp;gt; type.&amp;nbsp; The public List&amp;lt;T&amp;gt;.GetEnumerator() method returns a List&amp;lt;T&amp;gt;.Enumerator, which is a &lt;em&gt;struct&lt;/em&gt; rather than a class.&amp;nbsp; This means that C# can generate IL that enumerates the collection without allocating any new objects on the heap: no garbage.&amp;nbsp; But now consider a only slightly different case:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void Main() {
   IList&amp;lt;int&amp;gt; numbers = new List&amp;lt;int&amp;gt;(new[] { 1, 2, 3, 4, 5, 6, 8 });
   foreach (var number in numbers) {
   }
}&lt;/pre&gt;
&lt;p&gt;The only different is that I’ve explicitly typed the List&amp;lt;int&amp;gt; into an IList&amp;lt;int&amp;gt; local variable.&amp;nbsp; Now when C# enumerates the list with foreach, the only GetEnumerator() method available to call is the one on IList&amp;lt;T&amp;gt;, which returns an IEnumerator&amp;lt;T&amp;gt;.&amp;nbsp; This is typed as an interface, not a struct.&amp;nbsp; Although the underlying List&amp;lt;T&amp;gt;.GetEnumerator() will still be invoked, the struct it returns will now have to be boxed so that it is addressible via its IEnumerator&amp;lt;T&amp;gt; interface. This boxing allocates an object on the heap, which will be discarded after the enumeration is over.&amp;nbsp; If this foreach was itself in a perf critical loop then this could be a significant source of GC pressure.&lt;/p&gt;
&lt;p&gt;To wrap up with a final comprehensive example, here are two methods you might define:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void GarbageProducer(IEnumerable&amp;lt;int&amp;gt; numbers) {
   // numbers.GetEnumerator() can only returned a (boxed)
   // instance of IEnumerator&amp;lt;int&amp;gt;, forcing this method to
   // allocate one object each time this method is invoked.
   foreach (var number in numbers) {
   }
}

static void NoGarbageProducer(List&amp;lt;int&amp;gt; numbers) {
   // numbers.GetEnumerator() will return the stack allocated
   // List&amp;lt;int&amp;gt;.Enumerator struct, so no allocations are required.
   foreach (var number in numbers) {
   }
}&lt;/pre&gt;
&lt;p&gt;In the above snippet, GarbageProducer allocates memory, but its parameter is typed for maximum portability, whereas NoGarbageProducer never allocates memory but requires a very specific collection type to be passed in.&amp;nbsp; Which is better?&amp;nbsp; That depends, of course.&amp;nbsp; If the method is private, and you’re passing in a List&amp;lt;int&amp;gt; anyway, by all means keep the parameter typed as List&amp;lt;int&amp;gt; and avoid the allocation (in perf critical code anyway).&amp;nbsp; If the method is public you should probably use IEnumerable&amp;lt;T&amp;gt;.&amp;nbsp; Yes, it almost guarantees an allocation will be required, but on the other hand it allows virtually any type of collection to be passed in.&amp;nbsp; If you take List&amp;lt;T&amp;gt; and the caller only has a T[] array, the caller would first have to convert the array to a List&amp;lt;T&amp;gt; instance and then pass it in, and that’s much more costly to memory.&lt;/p&gt;
&lt;p&gt;I did say “almost guarantees” an allocation.&amp;nbsp; Can it be avoided?&amp;nbsp; Yes, actually.&amp;nbsp; With some extra work within the method:&lt;/p&gt;&lt;pre class="prettyprint"&gt;static void NoGarbageProducer(IEnumerable&amp;lt;int&amp;gt; numbers) {
   List&amp;lt;int&amp;gt; optimizedCase = numbers as List&amp;lt;int&amp;gt;;
   if (optimizedCase != null) {
      foreach (var number in optimizedCase) {
         DoWork(number);
      }
   } else {
      foreach (var number in numbers) {
         DoWork(number);
      }
   }
}

private static void DoWork(int number) {
}&lt;/pre&gt;
&lt;p&gt;Obviously this is more code to write and maintain, so it should only be done where measuring performance proves it is worthwhile.&amp;nbsp; Note that it only makes the enumerating alloc-free when the collection passed in is actually a List&amp;lt;T&amp;gt;, otherwise it falls back to the one-allocation code path.&amp;nbsp; This is an example of how you might discover you have a very popular method in a perf critical path, and perhaps you observe that you tend to be called with List&amp;lt;T&amp;gt; so you optimize for that case.&amp;nbsp; You could even optimize for multiple specific collection types, so long as each of them implement the alloc-free struct GetEnumerator pattern.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=dK2pCo3RtBQ:F_-D-ds7iHk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=dK2pCo3RtBQ:F_-D-ds7iHk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=dK2pCo3RtBQ:F_-D-ds7iHk:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=dK2pCo3RtBQ:F_-D-ds7iHk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=dK2pCo3RtBQ:F_-D-ds7iHk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=dK2pCo3RtBQ:F_-D-ds7iHk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=dK2pCo3RtBQ:F_-D-ds7iHk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=dK2pCo3RtBQ:F_-D-ds7iHk:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/dK2pCo3RtBQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5552729507194930293/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2012/06/gc-pressure-series-introduction-and.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5552729507194930293?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5552729507194930293?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/dK2pCo3RtBQ/gc-pressure-series-introduction-and.html" title="GC pressure series: Introduction and enumerators" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://blog.nerdbank.net/2012/06/gc-pressure-series-introduction-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4GRHY_eip7ImA9WhVbEk8.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-4567955313025830829</id><published>2012-05-28T10:58:00.001-07:00</published><updated>2012-05-28T10:58:45.842-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-28T10:58:45.842-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><title>A brief survey of the various .NET unit test frameworks</title><content type="html">&lt;p&gt;In summary, someone please fix NUnit to support async task methods.&lt;/p&gt; &lt;h3&gt;MSTest&lt;/h3&gt; &lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Best IDE experience for VS2010 and earlier (VS 2012 supports MSTest and other frameworks equally).&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Cons: &lt;/strong&gt;It requires an expensive product to develop and run.&amp;nbsp; ExpectedExceptionAttribute considered harmful.&lt;/p&gt; &lt;h3&gt;NUnit&lt;/h3&gt; &lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Supports Fluent syntax.&amp;nbsp; Attributes can specify that tests require STA, MTA, etc.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; No support for “async Task”.&amp;nbsp; Reuses test class instance for all tests within that class.&lt;/p&gt; &lt;h3&gt;xUnit&lt;/h3&gt; &lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;: Very few attributes keeps it simple.&amp;nbsp; Straightforward use of constructors and Dispose methods to wrap tests.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; Assert.Equals doesn’t allow accepting a formattable message to provide a more useful failure message.&amp;nbsp; No Assert.Inconclusive.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h9Q97tnSdKk:M-mcAmMywkg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=h9Q97tnSdKk:M-mcAmMywkg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h9Q97tnSdKk:M-mcAmMywkg:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h9Q97tnSdKk:M-mcAmMywkg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=h9Q97tnSdKk:M-mcAmMywkg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h9Q97tnSdKk:M-mcAmMywkg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=h9Q97tnSdKk:M-mcAmMywkg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h9Q97tnSdKk:M-mcAmMywkg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/h9Q97tnSdKk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/4567955313025830829/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2012/05/brief-survey-of-various-net-unit-test.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/4567955313025830829?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/4567955313025830829?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/h9Q97tnSdKk/brief-survey-of-various-net-unit-test.html" title="A brief survey of the various .NET unit test frameworks" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2012/05/brief-survey-of-various-net-unit-test.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ANSHo7cCp7ImA9WhVaEUQ.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5102660196131774609</id><published>2011-10-02T15:24:00.001-07:00</published><updated>2012-06-08T15:49:59.408-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-06-08T15:49:59.408-07:00</app:edited><title>How to get meld working with git on Windows</title><content type="html">&lt;p&gt;Inspired by &lt;a href="http://live.gnome.org/Meld/Windows"&gt;these instructions&lt;/a&gt;, I followed these steps:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Install &lt;a href="http://python.org/ftp/python/2.6.2/python-2.6.2.msi"&gt;Python 2.6&lt;/a&gt;&lt;br&gt; &lt;li&gt;Install &lt;a href="http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.22/pygtk-all-in-one-2.22.6.win32-py2.6.msi"&gt;PyGTK All-in-one installer&lt;/a&gt;&lt;br&gt; &lt;li&gt;Install &lt;a href="http://ftp.gnome.org/pub/GNOME/sources/meld/1.5/meld-1.5.2.tar.bz2"&gt;meld&lt;/a&gt;&lt;br&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Then you need to configure git to be able to find and invoke meld.&amp;nbsp; If you’re using the git bash shell, this can be done with these commands:&lt;/p&gt;&lt;pre class="prettyprint lang-bsh"&gt;PATH=$PATH:/c/python26
git config --global merge.tool meld
git config --global mergetool.meld.path /c/Users/andarno/Downloads/meld-1.5.2/bin/meld&lt;/pre&gt;
&lt;p&gt;Of course you may want to set your PATH to include Python permanently rather than the above command which only works for your active window.&amp;nbsp; The two git config commands have a persistent effect already, however.&lt;/p&gt;
&lt;p&gt;Finally, you’re now ready to use meld to resolve merge conflicts.&amp;nbsp; I haven’t found a way to get “git gui” to invoke the merge tool correctly, but this command from the git bash shell works great:&lt;/p&gt;&lt;pre class="prettyprint lang-bsh"&gt;git mergetool &lt;/pre&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=f2R8vcxGoxs:hdSZXM3gPyA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=f2R8vcxGoxs:hdSZXM3gPyA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=f2R8vcxGoxs:hdSZXM3gPyA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=f2R8vcxGoxs:hdSZXM3gPyA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=f2R8vcxGoxs:hdSZXM3gPyA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=f2R8vcxGoxs:hdSZXM3gPyA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=f2R8vcxGoxs:hdSZXM3gPyA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=f2R8vcxGoxs:hdSZXM3gPyA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/f2R8vcxGoxs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5102660196131774609/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2011/10/how-to-get-meld-working-with-git-on.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5102660196131774609?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5102660196131774609?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/f2R8vcxGoxs/how-to-get-meld-working-with-git-on.html" title="How to get meld working with git on Windows" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://blog.nerdbank.net/2011/10/how-to-get-meld-working-with-git-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYCRHs7fCp7ImA9WhdXFko.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-2391546129462032299</id><published>2011-08-29T20:49:00.001-07:00</published><updated>2011-08-29T20:49:25.504-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-29T20:49:25.504-07:00</app:edited><title>Immutable collections with mutable performance</title><content type="html">&lt;p&gt;In my &lt;a href="http://blogs.msdn.com/b/andrewarnottms/archive/2011/08/22/read-only-frozen-and-immutable-types-and-collections.aspx"&gt;last post&lt;/a&gt;, I detailed the differences among read/write, read only, frozen and immutable collection types.&amp;nbsp; I described how immutable collections come with a hit to the garbage collector due to the garbage they generate during mutations.&amp;nbsp; I have a very positive update on that topic.&lt;/p&gt; &lt;p&gt;See my &lt;a href="http://blogs.msdn.com/b/andrewarnottms/archive/2011/08/30/immutable-collections-with-mutable-performance.aspx"&gt;update on my Microsoft blog&lt;/a&gt; for the update.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=GGYVLOSHYzs:RZLoInT1c1g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=GGYVLOSHYzs:RZLoInT1c1g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=GGYVLOSHYzs:RZLoInT1c1g:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=GGYVLOSHYzs:RZLoInT1c1g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=GGYVLOSHYzs:RZLoInT1c1g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=GGYVLOSHYzs:RZLoInT1c1g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=GGYVLOSHYzs:RZLoInT1c1g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=GGYVLOSHYzs:RZLoInT1c1g:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/GGYVLOSHYzs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/2391546129462032299/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2011/08/immutable-collections-with-mutable.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2391546129462032299?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2391546129462032299?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/GGYVLOSHYzs/immutable-collections-with-mutable.html" title="Immutable collections with mutable performance" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2011/08/immutable-collections-with-mutable.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQERHg7fip7ImA9WhdXFko.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-3091549095084692718</id><published>2011-08-21T16:15:00.001-07:00</published><updated>2011-08-29T20:51:45.606-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-29T20:51:45.606-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Immutability" /><category scheme="http://www.blogger.com/atom/ns#" term="Async" /><title>Read only, frozen, and immutable collections</title><content type="html">&lt;p&gt;[Update: &lt;a href="http://blogs.msdn.com/b/andrewarnottms/archive/2011/08/30/immutable-collections-with-mutable-performance.aspx"&gt;a more recent post with new data on attainable performance of immutable collections&lt;/a&gt;]&lt;/p&gt; &lt;p&gt;The topics of immutability and functional programming has fascinated me lately.&amp;nbsp; Mostly because of my work on the Visual Studio Common Project System (CPS) which is a large, highly multi-threaded code base that only remains sane because of its reliance on immutable types in many areas.&lt;/p&gt; &lt;p&gt;In my research and conversations on this topic, I’ve learned to appreciate the differences between several adjectives often used interchangeably among programmers that I’d like to share with you, detailing the differences including some pros and cons of each.&amp;nbsp; At the bottom of the post I include a summary table and my own personal verdict for what kinds of collections (mutable and immutable) I prefer.&lt;/p&gt; &lt;p&gt;Although the principles here apply to any type in any language and platform, I’ll be using for some references and examples the collection types in the .NET base class library.&lt;/p&gt; &lt;p&gt;First a little terminology as I will use it in this post:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Mutable (a.k.a read/write): a collection or type that allows for in-place updates that anyone with a reference to that object may observe.  &lt;li&gt;Immutable: a collection or type that cannot be changed at all, but can be efficiently mutated by allocating a new collection that shares much of the same memory with the original, but has new memory describing the change.  &lt;li&gt;Freezable: a collection or type that is mutable until some point in time when it is frozen, after which it cannot be changed.  &lt;li&gt;Read only: a reference whose type does not permit mutation of the underlying data, which is usually &lt;em&gt;mutable&lt;/em&gt; by another reference. &lt;/li&gt;&lt;/ol&gt; &lt;h4&gt;The de facto read only standards in .NET&lt;/h4&gt; &lt;p&gt;There are not yet any freezable or immutable collections included in the&amp;nbsp; .NET base class library.&amp;nbsp; But we have a couple of read-only views of data, as outlined below.&amp;nbsp; &lt;/p&gt; &lt;h5&gt;De facto standard #1: IEnumerable&amp;lt;T&amp;gt;&lt;/h5&gt; &lt;p&gt;Often considered a convenient way to express data in a read-only way, IEnumerable&amp;lt;T&amp;gt; actually provides very few, if any, guarantees and almost no protections. &lt;/p&gt; &lt;ul&gt; &lt;li&gt;NO thread-safety to issuer or receiver. If the underlying collection changes while being enumerated from another thread, data corruption may result or exceptions may be thrown.  &lt;li&gt;NO immutability guarantee to the receiver. The underlying collection may be changed.  &lt;li&gt;NO immutability guarantee to the issuer. The receiver may cast the enumerable to ICollection or some other read/write type and may mutate the data through that interface if the underlying object allows it.  &lt;li&gt;NO performance guarantee to the receiver. The enumerable may represent a deferred execution query (LINQ for example) that may incur significant cost including network overhead with each enumeration. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Avoiding these shortcomings usually requires enumerating exactly once into a cloned collection, which comes with a perf and memory hit, and doesn’t entirely protect you from thread-safety issues that may occur during that one enumeration.&lt;/p&gt; &lt;h5&gt;De facto standard #2: ReadOnlyCollection&amp;lt;T&amp;gt;&lt;/h5&gt; &lt;p&gt;Somewhat misleadingly named, this collection is neither immutable nor a general collection. It is merely a wrapper around a mutable list.&amp;nbsp; Perhaps a more accurate name would be ReadOnlyListFacade&amp;lt;T&amp;gt;.&amp;nbsp; &lt;/p&gt; &lt;p&gt;This collection type is better than IEnumerable&amp;lt;T&amp;gt; in several ways, but still deficient in others:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;YES, immutable guarantee to the issuer.&amp;nbsp; The collection owner never releases a reference to the mutable collection, as the ReadOnlyCollection&amp;lt;T&amp;gt; is a genuine &lt;em&gt;wrapper&lt;/em&gt; around the mutable data, making it impossible for a receiver of the collection to mutate the data.  &lt;li&gt;YES, thread safety to the issuer, since the receiver cannot mutate the data, the underlying collection may be mutated without fear that the issuer with throw an exception or corrupt its own data.  &lt;li&gt;YES, reasonable performance guarantee to the receiver.&amp;nbsp; The IList&amp;lt;T&amp;gt; that the ReadOnlyCollection&amp;lt;T&amp;gt; wraps is virtually never populated via deferred execution.&amp;nbsp; Therefore enumerating the ReadOnlyCollection&amp;lt;T&amp;gt; repeatedly can generally be done with high performance and without side effects.  &lt;li&gt;NO thread-safety to the receiver.&amp;nbsp; If the receiver is reading the ReadOnlyCollection&amp;lt;T&amp;gt; while the issuer is mutating the underlying collection, the client may get an exception or perhaps even incorrectly perceive the contents of the collection.  &lt;li&gt;NO immutability guarantee to the receiver. The underlying collection may be changed. &lt;/li&gt;&lt;/ul&gt; &lt;h4&gt;Considerations among collections&lt;/h4&gt; &lt;h5&gt;Thread-safety&lt;/h5&gt; &lt;p&gt;Collections that are not thread-safe cannot be made thread-safe in a shareable way.&amp;nbsp; For example, although you can put lock { } statements around all uses of a collection to make it thread-safe, you cannot share references to your collection or any part of it outside your class because outside holders of that reference will not synchronize access to it with the same lock object you do (and ICollection.SyncRoot seems increasingly unpopular if it were ever known at all).&amp;nbsp; This suggests the importance of thread-safety built into collection classes.&lt;/p&gt; &lt;h5&gt;Freezable collections&lt;/h5&gt; &lt;p&gt;There are no freezable collection types in .NET (yet anyway).&amp;nbsp; So a discussion on them is somewhat speculative.&amp;nbsp; If the traditional List&amp;lt;T&amp;gt; class were to pick up a “Freeze()” method and an “IsFrozen” property, there would still be missing a type-safe way of communicating that a method expects or returns a frozen collection. You would have to perform a runtime check to see what is allowed or provided. Collection types that guarantee immutability are preferable for this purpose. If a method accepts an immutable collection parameter or returns an immutable collection, you have 100% confidence that that collection cannot ever change, period. If a List&amp;lt;T&amp;gt;.Freeze() method returned a FrozenList&amp;lt;T&amp;gt; object, and both the original List&amp;lt;T&amp;gt; and the FrozenList&amp;lt;T&amp;gt; pointed to the same data structure that could no longer be changed, that would provide a type-safe way of requiring or guaranteeing immutable data, however.&lt;/p&gt; &lt;p&gt;While one might consider that guarantee more theoretically aesthetic than practically useful, I can speak from some experience now that I avoid a lot of collection cloning code (and the perf problems that showed up as a result) because I &lt;em&gt;know&lt;/em&gt; that a collection I just received cannot possibly be changed. It’s gotten to the point that when I see a method accepting an IList&amp;lt;T&amp;gt; I ask myself “Why? Is that method expecting the caller to further mutate that list during or after its invocation and that the method will need to see that mutation?” Call me a functional programming geek, but if a method does not expect the caller the tamper with a collection that it passes to the method, I now greatly prefer to see IImmutableList&amp;lt;T&amp;gt; as the method parameter.&lt;/p&gt; &lt;p&gt;Before freezing, freezable collections offer the high construction performance and compact memory utilization of traditional mutable collections.&amp;nbsp; After freezing, any further mutation requires shallow cloning of the entire collection, with the perf and memory hit that comes with it.&amp;nbsp; &lt;/p&gt; &lt;p&gt;One possible danger of using a collection that is freezable (but unfrozen) is that someone you share a reference to the collection with might want an immutable copy of the collection and may freeze the collection behind your back, not realizing that your class still “owns” the collection and thus expects it to not be frozen.&lt;/p&gt; &lt;h5&gt;Performance&lt;/h5&gt; &lt;p&gt;The performance of mutable collections, particularly when they are initially sized adequate for their contents, can’t be beat by immutable collections.&amp;nbsp; However the performance of immutable collections can be remarkably good.&amp;nbsp; Much better than one might expect, and certainly good enough for due consideration in your design.&lt;/p&gt; &lt;p&gt;Immutable collections primary shortcoming is that raw add performance tends to be 2-3X slower than the amortized cost of its mutable collection counterparts.&amp;nbsp; This is chiefly due to the mandatory “spine rewrite” of the binary tree and the memory allocations that go along with it.&amp;nbsp; I just compared against &lt;em&gt;amortized&lt;/em&gt; cost of mutable collections because mutable collections have the shortcoming of occasionally breaking the bounds of their pre-allocated memory, which usually means allocating twice as much and then copying all the data from the old location to the new location.&lt;/p&gt; &lt;p&gt;Before you write off mutable collections due to their perf impact on initialization, keep in mind that this may rarely be where the performance problems in apps come from.&amp;nbsp; In my experience the perf problems never come from creating a new collection, but rather from cloning a collection within a lock to provide immutability and thread-safety guarantees, which completely vanish when you switch to genuinely immutable collections.&amp;nbsp; Also, the spine rewrite that leads to the slower fill performance can be avoided by using an immutable collection that optimizes around that scenario, as described in the below discussion on garbage collection.&lt;/p&gt; &lt;h5&gt;&lt;/h5&gt; &lt;h5&gt;Memory efficiency&lt;/h5&gt; &lt;p&gt;When dealing with collections, there’s no tighter data structure than an array, which is the underlying data structure of choice for must flat collections.&amp;nbsp; It has almost no overhead beyond the data stored, and that’s hard to beat.&amp;nbsp; On the other hand, since arrays have fixed size, it usually means there is memory wasted in the slack between the last element in the collection and the last slot in the preallocated array.&amp;nbsp; And when you have more elements than you have slots in the array, the array growth algorithm tends to be to allocate a new array of double the length and move all the data over, which means even more slack space wasting your memory.&lt;/p&gt; &lt;p&gt;Immutable collections can’t afford (in memory or performance) to use arrays because changing the collection would require cloning the array every time.&amp;nbsp; Instead, performant immutable collections can use binary trees that allow for incremental, non-mutating updates to the collection.&amp;nbsp; Without going deep into the theory of it, it allows (for example) an immutable collection of 500 elements to be mutated into a &lt;em&gt;new&lt;/em&gt; collection with one element added or removed while sharing almost all the memory between the two collections.&amp;nbsp; But because binary tree data structures require a heap-allocated “node” to represent each element in the array, with references to two other nodes in the tree, there is an overhead of at least 12 bytes per element in immutable collections.&lt;/p&gt; &lt;h5&gt;Garbage generation and collection&lt;/h5&gt; &lt;p&gt;Garbage generation is also an important concern when considering the memory impact of immutable collections.&amp;nbsp; Every mutation of an immutable collection necessarily allocates more memory.&amp;nbsp; And while most memory is shared across the different versions of the collection, when a particular version of a collection is no longer referenced, it automatically gets garbage collected.&amp;nbsp; This is a convenient feature of immutable collections in that they optimally share and automatically free memory.&amp;nbsp; However, since each mutation of the collection makes the last version of the collection uninteresting and thus available for garbage collection, it generally means that more garbage is produced than for the mutable counterpart.&amp;nbsp; &lt;/p&gt; &lt;p&gt;What’s the problem with allocating objects if they are freed as soon as they are not used any more?&amp;nbsp; The problem comes at garbage collection time. The more memory you allocate and release, the more frequently the garbage collector has to run, which usually suspends all other threads in your .NET application, potentially causing perf problems during or sometime after all that memory had been allocated and freed.&amp;nbsp; &lt;/p&gt; &lt;p&gt;This garbage collection pain is usually most poignantly felt when initializing very large immutable collections.&amp;nbsp; Without appropriate optimizations for this scenario, a large immutable collection will produce many times as much garbage during construction as its own final size in memory at completion.&amp;nbsp; So if you built a collection that requires 1MB of RAM just for the collection itself, you might have just blown through 4MB of RAM during its construction (freeing 3MB immediately after).&amp;nbsp; A well-written immutable collection class could optimize for this initialization case by allowing itself to reuse (i.e. mutate) tree nodes during initialization only, when such reuse could never be detectable outside as a “mutation”, which would solve the garbage generation problem for immutable collections, unless your collections tend to mutate very rapidly even after initial construction.&lt;/p&gt; &lt;h4&gt;Summary&lt;/h4&gt; &lt;table border="0" cellspacing="0" cellpadding="2" width="483"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="116"&gt;Read only&lt;/td&gt; &lt;td valign="top" width="97"&gt;Frozen&lt;/td&gt; &lt;td valign="top" width="131"&gt;Immutable&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;&lt;strong&gt;Capabilities&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="116"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="97"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="131"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Thread-safe&lt;/td&gt; &lt;td valign="top" width="116"&gt;No&lt;/td&gt; &lt;td valign="top" width="97"&gt;Yes&lt;/td&gt; &lt;td valign="top" width="131"&gt;Yes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Type-safe declaration&lt;/td&gt; &lt;td valign="top" width="116"&gt;Yes&lt;/td&gt; &lt;td valign="top" width="97"&gt;TBD&lt;/td&gt; &lt;td valign="top" width="131"&gt;Yes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Immutable guarantee&lt;/td&gt; &lt;td valign="top" width="116"&gt;No&lt;/td&gt; &lt;td valign="top" width="97"&gt;Yes&lt;/td&gt; &lt;td valign="top" width="131"&gt;Yes&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Allows mutation&lt;/td&gt; &lt;td valign="top" width="116"&gt;Yes, shared&lt;/td&gt; &lt;td valign="top" width="97"&gt;No&lt;/td&gt; &lt;td valign="top" width="131"&gt;Yes, isolated&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;&lt;strong&gt;CPU&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="116"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="97"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="131"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Isolated mutations performance&lt;/td&gt; &lt;td valign="top" width="116"&gt;Poor&lt;/td&gt; &lt;td valign="top" width="97"&gt;Poor&lt;/td&gt; &lt;td valign="top" width="131"&gt;Great&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Shared mutation performance&lt;/td&gt; &lt;td valign="top" width="116"&gt;Great, except when underlying data structure is outgrown and must be cloned.&lt;/td&gt; &lt;td valign="top" width="97"&gt;N/A.&amp;nbsp; No mutations allowed.&lt;/td&gt; &lt;td valign="top" width="131"&gt;N/A. All mutations are isolated.&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt; &lt;td valign="top" width="116"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="97"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="131"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Storage data structure&lt;/td&gt; &lt;td valign="top" width="116"&gt;Array&lt;/td&gt; &lt;td valign="top" width="97"&gt;Array&lt;/td&gt; &lt;td valign="top" width="131"&gt;Binary tree&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Memory across isolated versions&lt;/td&gt; &lt;td valign="top" width="116"&gt;Full duplication&lt;/td&gt; &lt;td valign="top" width="97"&gt;Full duplication&lt;/td&gt; &lt;td valign="top" width="131"&gt;Efficient sharing&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="137"&gt;Garbage generation &lt;/td&gt; &lt;td valign="top" width="116"&gt;Low&lt;/td&gt; &lt;td valign="top" width="97"&gt;Low&lt;/td&gt; &lt;td valign="top" width="131"&gt;Potentially high [&lt;a href="http://blogs.msdn.com/b/andrewarnottms/archive/2011/08/30/immutable-collections-with-mutable-performance.aspx"&gt;update&lt;/a&gt;]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;If you enjoyed this post, you may enjoy &lt;a href="http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/"&gt;Eric Lippert’s blog posts tagged Immutability&lt;/a&gt;.&amp;nbsp; Eric Lippert wrote &lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx"&gt;a good post on different kinds of immutability&lt;/a&gt; back in 2007.&lt;/p&gt; &lt;p&gt;And please let me know if you found this post useful or interesting.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=s2Jy-_nAbU8:hlq6cYg6Q_U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=s2Jy-_nAbU8:hlq6cYg6Q_U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=s2Jy-_nAbU8:hlq6cYg6Q_U:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=s2Jy-_nAbU8:hlq6cYg6Q_U:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=s2Jy-_nAbU8:hlq6cYg6Q_U:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=s2Jy-_nAbU8:hlq6cYg6Q_U:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=s2Jy-_nAbU8:hlq6cYg6Q_U:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=s2Jy-_nAbU8:hlq6cYg6Q_U:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/s2Jy-_nAbU8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/3091549095084692718/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2011/08/read-only-frozen-and-immutable-types.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/3091549095084692718?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/3091549095084692718?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/s2Jy-_nAbU8/read-only-frozen-and-immutable-types.html" title="Read only, frozen, and immutable collections" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.nerdbank.net/2011/08/read-only-frozen-and-immutable-types.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQNQ3wycSp7ImA9WhdTGE4.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-8588622561739490768</id><published>2011-07-16T08:33:00.001-07:00</published><updated>2011-07-16T08:33:12.299-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-16T08:33:12.299-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Async" /><title>C# await for MSBuild</title><content type="html">&lt;p&gt;The async CTP that adds the C# await keyword doesn’t include an awaitable MSBuild.&amp;nbsp; It’s easy to add yourself.&amp;nbsp; Just copy and paste the the BuildSubmissionAwaitExtensions class from the code below somewhere in your project and you’ll be able to await on MSBuild.&amp;nbsp; Also included below is a sample of what it might look like.&lt;/p&gt;&lt;script src="https://gist.github.com/1084850.js?file=MSBuildAwaiterSample.cs"&gt;&lt;/script&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=x9K4JeTp3v0:Iq3-ddAvT4E:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=x9K4JeTp3v0:Iq3-ddAvT4E:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=x9K4JeTp3v0:Iq3-ddAvT4E:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=x9K4JeTp3v0:Iq3-ddAvT4E:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=x9K4JeTp3v0:Iq3-ddAvT4E:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=x9K4JeTp3v0:Iq3-ddAvT4E:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=x9K4JeTp3v0:Iq3-ddAvT4E:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=x9K4JeTp3v0:Iq3-ddAvT4E:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/x9K4JeTp3v0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/8588622561739490768/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2011/07/c-await-for-msbuild.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8588622561739490768?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8588622561739490768?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/x9K4JeTp3v0/c-await-for-msbuild.html" title="C# await for MSBuild" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2011/07/c-await-for-msbuild.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0IBQXczeip7ImA9WhdTF0g.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-8260776574728675982</id><published>2011-07-15T10:37:00.001-07:00</published><updated>2011-07-15T10:39:10.982-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-15T10:39:10.982-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Async" /><title>C# await for WaitHandle</title><content type="html">&lt;p&gt;The async CTP that adds the C# await keyword doesn’t include an awaitable WaitHandle.&amp;nbsp; It’s easy to add yourself.&amp;nbsp; Just copy and paste the following code somewhere in your project and you’ll have an awaitable WaitHandle.&lt;/p&gt;&lt;script src="https://gist.github.com/1084951.js?file=WaitHandlerAwaitable.cs"&gt;&lt;/script&gt; &lt;p&gt;Warning: don't use this on AutoResetEvents, or the behavior may not be what you expect.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wTQIZ1X4L98:aCdrJr9YCpA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=wTQIZ1X4L98:aCdrJr9YCpA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wTQIZ1X4L98:aCdrJr9YCpA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wTQIZ1X4L98:aCdrJr9YCpA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=wTQIZ1X4L98:aCdrJr9YCpA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wTQIZ1X4L98:aCdrJr9YCpA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=wTQIZ1X4L98:aCdrJr9YCpA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=wTQIZ1X4L98:aCdrJr9YCpA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/wTQIZ1X4L98" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/8260776574728675982/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2011/07/c-await-for-waithandle.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8260776574728675982?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8260776574728675982?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/wTQIZ1X4L98/c-await-for-waithandle.html" title="C# await for WaitHandle" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2011/07/c-await-for-waithandle.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MAR3k4fSp7ImA9WhZUGUo.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-8291100173126770062</id><published>2011-06-13T08:22:00.002-07:00</published><updated>2011-06-13T08:37:26.735-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-13T08:37:26.735-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OAuth" /><title>What is 2-legged OAuth?</title><content type="html">&lt;p&gt;Although there is an &lt;a href="http://trac.tools.ietf.org/html/rfc5849"&gt;official spec for OAuth 1.0&lt;/a&gt;, the spec only outlines what the community refers to as "3-legged OAuth". &amp;nbsp;An alternative form of OAuth is loosely referred to as "2-legged OAuth", and there are far too many variants of this and not a single finalized spec to conform to. &amp;nbsp;As a result, there are various ways and forms to achieve what people, correctly or incorrectly, refer to as 2-legged OAuth. &amp;nbsp;In this post, I will attempt to clarify what (at least in my mind) 2-legged OAuth really means.&lt;/p&gt;
&lt;p&gt;I will not delve into the gritty details of the spec, but I will outline the flows and explain a bit. &lt;/p&gt;

&lt;h3&gt;3-legged OAuth&lt;/h3&gt;
&lt;p&gt;First, let's start with the spec's description of the OAuth flow (3-legged). &amp;nbsp;Here is an illustration:&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://bit.ly/mln2yP?r=bb" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="184" src="http://bit.ly/mln2yP?r=bb" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can clearly see the 3 "legs" of this flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The consumer (the application that wants to access data) creates an OAuth session by obtaining an &lt;i&gt;un&lt;/i&gt;authorized request token from the Service Provider (the host of the data).&lt;/li&gt;
&lt;li&gt;The consumer directs the user to the service provider, with the unauthorized request token in hand, so the service provider can ask the user to release the protected data to the consumer. &amp;nbsp;The user logs in as necessary, and grants the requested permission. &amp;nbsp;The service provider redirects the user back to the consumer.&lt;/li&gt;
&lt;li&gt;The same request token the consumer held before is now&amp;nbsp;&lt;i&gt;authorized&lt;/i&gt;. &amp;nbsp;The consumer submits it to the service provider in a direct web request to exchange it for an access token. &amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The access token may now be used by the consumer to submit requests to the service provider that will access the user's private data.&lt;/p&gt;&lt;p&gt;
By the way: notably absent from this 3-legged flow is the consumer obtaining its own "consumer key" and "consumer secret". &amp;nbsp;The process of obtaining these is explicitly outside the scope of the OAuth spec altogether, and is therefore defined by each service provider. &amp;nbsp;This process is only completed once per application, usually by the application developer him/herself, and is&amp;nbsp;&lt;i&gt;not&lt;/i&gt;&amp;nbsp;considered one of the legs of OAuth.&lt;/p&gt;
&lt;h3&gt;2-legged OAuth&lt;/h3&gt;
&lt;p&gt;
In 2-legged OAuth, the consumer tends to be installed on the user's machine, or is perhaps a widget embedded in a web page. &amp;nbsp;The key scenario difference as you step into 2-legged OAuth is that the consumer is&lt;i&gt; not&lt;/i&gt; requesting access to any &lt;i&gt;user&lt;/i&gt;&amp;nbsp;data. &amp;nbsp;Instead, it is merely establishing an account with the service provider with no previous data in it at all, which it can subsequently use to store and later retrieve data. 
&lt;/p&gt;&lt;p&gt;
However, since this particular installation or widget has its own "space" on the service provider to store data, the consumer can obtain user data directly from the user him/herself, and send that to the service provider, and later retrieve it. So we see that although 2-legged OAuth doesn't &lt;i&gt;start&lt;/i&gt;&amp;nbsp;with any user data, it may end up with user data that the consumer itself puts there.
&lt;/p&gt;&lt;p&gt;
Because no pre-existing user data is ever shared with the consumer, there is no need for the service provider to obtain authorization from the user. &amp;nbsp;Therefore the second of the three legs can be entirely skipped. &amp;nbsp;The modified flow is illustrated here:&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://bit.ly/lezeHC?r=bb" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="147" src="http://bit.ly/lezeHC?r=bb" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;&lt;p&gt;
Note that the "6.2" section is absent, and the User role has absolutely no interaction, leaving only two legs. &amp;nbsp;Section 6.1 is also slightly different: instead of the service provider issuing the consumer with an &lt;i&gt;un&lt;/i&gt;authorized request token, this request token is &lt;i&gt;pre-&lt;/i&gt;authorized. &amp;nbsp;The consumer can then immediately exchange it for an access token and discard the request token.&lt;/p&gt;&lt;p&gt;
At this point you may be saying to yourself: "That's silly -- why doesn't the service provider just issue the access token instead of a request token, and save another leg?" &amp;nbsp;Well, it could, but then that wouldn't be OAuth any more. &amp;nbsp;You could make the case that the above 2-legged flow is still OAuth because all the existing APIs and flows work as spec'd... the skipped legs doesn't alter the remaining legs so it requires little or no changes in a standard OAuth implementation to support 2-legged as well.&lt;/p&gt;
&lt;h3&gt;
What's &lt;i&gt;not&lt;/i&gt; 2-legged OAuth&lt;/h3&gt;
&lt;p&gt;
I've recently seen a list of links that all claim to describe "2 legged OAuth", but are nothing like what I just described. &amp;nbsp;Instead, what they describe is what I would refer to as &lt;i&gt;0 &lt;/i&gt;legged OAuth. &amp;nbsp;That's right: &lt;i&gt;none&lt;/i&gt;&amp;nbsp;of the 3 legs are preserved in the flow they describe. &amp;nbsp;Here is what they describe, in a nutshell:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The consumer's developer obtains a consumer key and secret.&lt;/li&gt;
&lt;li&gt;(skips the entire OAuth 3-legged flow here)&lt;/li&gt;
&lt;li&gt;Consumer accesses protected resources by submitting OAuth signed requests for resources using its consumer key, an empty access token, and signs the request with the consumer secret and an empty access token secret.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember from the 3-legged discussion above, that #1 in this list is not considered one of the three legs: it's a one-time step taken by the app developer. &amp;nbsp;Nor is #3 in this list considered one of the 3 legs, as it is simply the actual request for the protected resource, and is alone repeated at each request.&lt;/p&gt;&lt;p&gt;
Also consider that whereas genuine 2-legged OAuth can end up with the consumer storing &lt;i&gt;user&lt;/i&gt;&amp;nbsp;data in a private consumer-user data store at the service provider, this &lt;i&gt;0&lt;/i&gt;-legged OAuth cannot end up with user data in its service provider account, because all instances of the consumer share exactly the same account, and that would mix all the users' data together.&lt;/p&gt;&lt;p&gt;
This 0-legged OAuth should look remarkably similar to username/password authentication, and in flow that's exactly what it is, where the consumer app is the owner of the username/password instead of the user. &amp;nbsp;Why would someone go to the trouble of using/inventing 0-legged OAuth instead of just using username/password then? &amp;nbsp;Two reasons: 1) it may be easier to leverage existing OAuth-supporting code than adding support for username/password, and 2) OAuth provides signatures that mitigates against replay attacks that HTTP basic authentication can be vulnerable to.&lt;/p&gt;
&lt;h3&gt;
What's else is&amp;nbsp;&lt;i&gt;not&lt;/i&gt;&amp;nbsp;2-legged OAuth&lt;/h3&gt;
&lt;p&gt;Twitter has an interesting special case of OAuth as well, which also entirely skips the 3-legged flow, yet it is still &lt;i&gt;per user&lt;/i&gt;. &amp;nbsp;The user navigates his/her browser to twitter.com, and obtains an access token directly, with no request token preliminary step. &amp;nbsp;The user copies and pastes (manually!) this access token into the consumer app, which then simply access the user's private data without ever going through any of the 3-legged flow. &amp;nbsp;This also has been (incorrectly) referred to by some as "2 legged OAuth", but I hope this discussion can help you see this is a misconception.&lt;/p&gt;
&lt;h3&gt;
Summary&lt;/h3&gt;
&lt;p&gt;
Let's summarize terms and use cases then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3-legged OAuth: includes user authorization through a web browser for the consumer to access the end user's previously established private user data with a service provider.&lt;/li&gt;
&lt;li&gt;2-legged OAuth: skips user authorization, but still has non-empty request and access tokens. &amp;nbsp;Consumers gain access to an empty account that they may then fill with user data the consumer obtains directly from the user.&lt;/li&gt;
&lt;li&gt;0-legged OAuth: skips all three legs by having consumers simply access their own protected resources at the service provider using OAuth signatures based on a private consumer key and secret. &amp;nbsp;Analogous to username/password for the consumer app.&lt;/li&gt;
&lt;li&gt;Twitter access token option: also skips all three legs, but still provides access to a user's pre-existing data via a non-empty, manually obtained access token.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Please comment with your thoughts, and indicate whether you agree or disagree. &amp;nbsp;With so many application-specific half-specs out there claiming to describe "2-legged OAuth", I expect some comments to this post telling me I'm wrong. &amp;nbsp;That's fine. &amp;nbsp;I'd be interested in hearing you make a logical case for how you reduce OAuth 3-legs to 2-legs then. &amp;nbsp;And to reiterate, I'm not invalidating the use cases of what these 0-legged flows are doing, I'm merely suggesting we call it like it is: "&lt;i&gt;0-legged OAuth&lt;/i&gt;". &amp;nbsp;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=pXGVv8zAs7k:GO-1aYsZe1Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=pXGVv8zAs7k:GO-1aYsZe1Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=pXGVv8zAs7k:GO-1aYsZe1Y:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=pXGVv8zAs7k:GO-1aYsZe1Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=pXGVv8zAs7k:GO-1aYsZe1Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=pXGVv8zAs7k:GO-1aYsZe1Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=pXGVv8zAs7k:GO-1aYsZe1Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=pXGVv8zAs7k:GO-1aYsZe1Y:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/pXGVv8zAs7k" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/8291100173126770062/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2011/06/what-is-2-legged-oauth.html#comment-form" title="19 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8291100173126770062?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8291100173126770062?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/pXGVv8zAs7k/what-is-2-legged-oauth.html" title="What is 2-legged OAuth?" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>19</thr:total><feedburner:origLink>http://blog.nerdbank.net/2011/06/what-is-2-legged-oauth.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08FRXY7fyp7ImA9Wx5UEEs.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5752960676594216280</id><published>2010-10-14T07:10:00.000-07:00</published><updated>2010-10-14T07:16:54.807-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-14T07:16:54.807-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Reviews" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><title>.NET Obfuscator Product Review</title><content type="html">&lt;h3&gt;&lt;a href="http://www.secureteam.net/"&gt;CliSecure .NET Obfuscator Product Review&lt;/a&gt;&lt;/h3&gt;  &lt;h5&gt;&lt;/h5&gt;  &lt;h5&gt;Forward&lt;/h5&gt;  &lt;p&gt;.NET assemblies are (in general) remarkably easy to decompile and obtain reasonably intelligible source code.&amp;#160; A .NET obfuscator can be run as a post-build step to make decompiling the assembly much less useful to thieves who are trying to steal your intellectual property.&amp;#160; There are many .NET obfuscators out there.&amp;#160; &lt;/p&gt;  &lt;p&gt;In this post, I review the &lt;a href="http://www.secureteam.net/"&gt;SecureTeam CliSecure&lt;/a&gt; tool, version 5.2.0.7.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Introducing the test case&lt;/h4&gt;  &lt;p&gt;My “test case” DLL is not a simple “Hello, World!” app.&amp;#160; It’s dotnetopenauth.dll, which is just over 1MB in size and pushes the limits of the .NET Framework enough that a few bugs in the CLR, compiler and build tools were discovered while this assembly was written.&amp;#160; It defines its own .NET configuration sections, compiles with Code Contracts’ IL rewriter and ILMerge’s IL rewriter and is strong-name (delay) signed.&amp;#160; It also &lt;em&gt;very&lt;/em&gt; carefully uses log4net.dll when present, but doesn’t whine when the log4net is not present (defying most people’s assumptions about .NET’s runtime dependency rules).&amp;#160; This DLL is enough to make most obfuscators fail in some way or another.&lt;/p&gt;  &lt;p&gt;That said, the disclaimer is that this is just one test case, and is not intended to warrant or otherwise guarantee results on your own assemblies.&amp;#160; Your mileage may vary.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Usability&lt;/h4&gt;  &lt;p&gt;Since in course of this review I was a relatively new user to this software, and usability most impacts a new user, I’ll start with usability.&amp;#160; If you care more about functionality than usability, just skip this section.&amp;#160; (Does anyone buy an obfuscator because it’s user-friendly?)&lt;/p&gt;  &lt;p&gt;I find CliSecure easier than most obfuscators that I’ve tried, but it still has its oddities.&amp;#160; Launching CliSecure opens a non-intimidating GUI application with few enough controls that it looks like something a newbie can get a handle on, and it sports the new Ribbon UI that’s been so hot lately.&amp;#160; &lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh5.ggpht.com/_hfiLRSZPvmE/TLcPhtuLW5I/AAAAAAAAEeg/JGf2VUo6Zr0/s1600-h/image3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_hfiLRSZPvmE/TLcPiMFRoUI/AAAAAAAAEek/8blldk6EtaI/image_thumb1%5B1%5D.png?imgmax=800" width="402" height="279" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;But the first two buttons on the toolbar, New and Open, &lt;em&gt;don’t&lt;/em&gt; apply to a first-timer.&amp;#160; The app opens with a “New” project, so the New button is a no-op, and “Open” opens CliSecure projects, &lt;em&gt;not&lt;/em&gt; DLLs to obfuscate.&amp;#160; The next buttons, Save and Options, didn’t seem to apply either.&amp;#160; Finally a small button called “Add” on the Ribbon suggests maybe that’s the one I was looking for.&amp;#160; Bingo! &lt;/p&gt;  &lt;p&gt;There’s a field at the bottom that displays a derived a sub-path where the obfuscated DLL goes.&amp;#160; Cool.&amp;#160; But when I changed the DLL I was obfuscating, the sub-path didn’t change with it automatically.&amp;#160; &lt;/p&gt;  &lt;p&gt;The Options button led to a dialog box with a grid and an explanatory paragraph for each configurable setting.&amp;#160; Most of the explanations were adequate, although the most interesting one to me (Control Flow Obfuscation: Basic or Advanced) didn’t explain one over the other.&amp;#160; The help documentation did include this detail including the the pros and cons of each option.&lt;/p&gt;  &lt;p&gt;I found the Help documentation quite decent – complete with screenshots and explanation of the high level concepts needed to make informed obfuscation decisions.&amp;#160; &lt;/p&gt;  &lt;h4&gt;Noteworthy features&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;Support for strong-name and delay signing. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;Whirlwind obfuscation run&lt;/h4&gt;  &lt;p&gt;CliSecure has a whole array of powerful obfuscation options.&amp;#160; But beware: they’re all &lt;em&gt;off &lt;/em&gt;by default.&amp;#160; When obfuscating with the default settings in CliSecure the assemblies selected are not obfuscated at all but success is still reported.&amp;#160; &lt;/p&gt;  &lt;p&gt;After setting some reasonable obfuscation options, clicking “Build” (the button isn’t called “Obfuscate”) resulted in a few seconds of obfuscation during which there was an accurate progress bar.&amp;#160; When it was done, there was no output window, no warnings or errors, and the “building” window just disappeared.&amp;#160; Fortunately, near the button of the CliSecure window is a field that says where the “secured” assembly will be saved to, and it’s conveniently a read-only text field so I can copy the path out into Windows Explorer to open that folder (a click button to open the folder would have been a bonus though).&lt;/p&gt;  &lt;p&gt;While the CliSecure UI was up after obfuscating my DLL, I was pleased to see it didn’t have any open file handles to the input or output DLLs, so I could run builds in another process without having to close CliSecure first.&lt;/p&gt;  &lt;h5&gt;&lt;/h5&gt;  &lt;h4&gt;&lt;a href="http://www.secureteam.net/Obfuscator.aspx"&gt;CliSecure obfuscation settings&lt;/a&gt;&lt;/h4&gt;  &lt;p&gt;There is a plethora of options offered in the GUI app (all off by default):&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;Input&lt;/strong&gt;.&amp;#160; You can obfuscate several assemblies at once.&amp;#160; Besides just batching for convenience, this should &lt;font style="background-color: #ffff00"&gt;&lt;/font&gt;allow you to obfuscate internal members without breaking other assemblies with privileged InternalsVisibleTo allowing them to call these internal members. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Code Protection&lt;/strong&gt;. This is probably the most unique obfuscation feature in CliSecure, and truly worth your careful consideration.&amp;#160; It actually encrypts your IL and makes it completely invisible to .NET Reflector, only decrypting the IL at execution time at a per-method level.&amp;#160; But this decryption requires that your app run with Full Trust, which means you can’t use it on assemblies you send up to a shared host web server, among other things.&amp;#160; But it should be fine for an assembly that you ship to a customer.&amp;#160; This comes with a performance hit to the app, however. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Renaming&lt;/strong&gt;. This performs the most basic obfuscation function: renaming of types and members.&amp;#160; CliSecure even will rename your “public” API and fix up any assemblies that call into that assembly.&amp;#160; A great way to protect your own “internal” class libraries used by your multi-assembly application.&amp;#160; It helps you get away from InternalsVisibleTo, which some argue encourages bad design. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Control Flow. &lt;/strong&gt;Changes the idioms that compilers use for looping constructs, breaking a decompiler’s ability to reconstruct for and while loops. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Method Call Obfuscation&lt;/strong&gt;. This feature protects the public APIs that your assembly calls in other assemblies.&amp;#160; Depending on what you’re trying to obfuscate, this feature can be &lt;em&gt;very&lt;/em&gt; important.&amp;#160; Without it, every call to a method in .NET’s base class library will be apparent when people decompile your code, making it easier to figure out what you’re doing.&amp;#160; CliSecure will replace these discoverable calls with dynamically generated delegates so a static analyzer or decompiler cannot discover them.&amp;#160; This comes with a performance hit to the app, however. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Merging&lt;/strong&gt;. CliSecure comes with ILMerge-like behavior built-in, allowing you to conceal even more code by merging your helper library .dll with your application .exe and thus removing all the public surface area your library would have otherwise left exposed.&amp;#160; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For my next test, I turned on everything except Code Protection or Method Call Obfuscation so I could still use .NET Reflector to see what obfuscation had taken place (and because DotNetOpenAuth.dll runs in shared hosting web servers and requiring Full Trust isn’t an option).&amp;#160; I also didn’t use the Merging feature.&amp;#160; Although DotNetOpenAuth uses ILMerge and could therefore possibly benefit from this feature, not every SKU of DotNetOpenAuth would be obfuscated, so making every SKU take a dependency on running CliSecure doesn’t make sense.&lt;/p&gt;  &lt;h5&gt;Obfuscation quality&lt;/h5&gt;  &lt;p&gt;With so many protections turned on, obfuscation took a few seconds to complete this time.&amp;#160; In .NET Reflector I saw just the public namespaces, and within those just the public types and members.&amp;#160; All the obfuscated stuff was under the default (empty) namespace in a flat structure.&amp;#160; Not only is this good for obfuscation, it’s good for the stuff that you &lt;em&gt;want&lt;/em&gt; to be discoverable because all the obfuscated stuff doesn’t clutter up the stuff you want to be discoverable.&amp;#160; Extra points for clean discoverability of public stuff.&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh5.ggpht.com/_hfiLRSZPvmE/TLcPjDbZI1I/AAAAAAAAEeo/JjVt_NhCVw0/s1600-h/image4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_hfiLRSZPvmE/TLcPjR-K-4I/AAAAAAAAEes/-8qCJwArgZg/image_thumb1.png?imgmax=800" width="467" height="371" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;The internal types were mostly obfuscated, with the necessary exception of the members that implemented public interfaces, and some internal types that are used to implement .NET .config file sections.&amp;#160; I think these could have been obfuscated and were not, but configuration section types aren’t typically where people store their sensitive intellectual property anyway.&amp;#160; Some of the types and members had such weird names that .NET Reflector crashed a few times as I was looking through the assembly.&amp;#160; That’s just a bonus (since it discourages those snoopers).&lt;/p&gt;  &lt;p align="left"&gt;Some methods were so obfuscated that .NET Reflector gave up on their implementations:&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/_hfiLRSZPvmE/TLcPjworHOI/AAAAAAAAEew/ycaMD0snj9I/s1600-h/image14.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_hfiLRSZPvmE/TLcPkb5rpcI/AAAAAAAAEe0/UKStOc1nGGg/image_thumb6.png?imgmax=800" width="528" height="229" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;Others were decompiled, but quite uselessly so:&lt;/p&gt;  &lt;p align="center"&gt;&lt;a href="http://lh6.ggpht.com/_hfiLRSZPvmE/TLcPktiYoRI/AAAAAAAAEe4/aG-tSE5_2aY/s1600-h/image19.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_hfiLRSZPvmE/TLcPlU1rYnI/AAAAAAAAEe8/cCh9FJi9mt4/image_thumb9.png?imgmax=800" width="488" height="212" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p align="left"&gt;While most of this is unintelligible, I did manage to read that an HtmlLink object is instantiated here, which is puzzling since I turned on Method Call Obfuscation and thought that this type of thing would be hidden.&amp;#160; I also found some internal strings that didn’t appear to have the obfuscated/encrypted values I expected since I turned on “String Obfuscation”.&amp;#160; That said, .NET Reflector was unable to analyze where these strings were used, so that’s a half-win.&lt;/p&gt;  &lt;p align="left"&gt;The bizarrely named methods were no more intelligible when you use .NET Reflector’s click-through to see the method implementation: the method “implementation” is merely a static field that holds a delegate and is initialized somewhere else that isn’t evident.&amp;#160; &lt;/p&gt;  &lt;p align="left"&gt;&lt;strong&gt;I’d give the obfuscator effectiveness a rating of 9.5/10.&lt;/strong&gt;&amp;#160; Yes, there were a couple words I could read here and there and the unobfuscated configuration section types, but it seems impossible to reverse engineer, and it obfuscated the names of properties, which other obfuscators say cannot be done.&amp;#160; And remember, I haven’t even turned on Code Protection, which presumably would give it, what, a score of 15/10? &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh6.ggpht.com/_hfiLRSZPvmE/TLcPlzFXttI/AAAAAAAAEfA/pvdBDEZ6a5Q/wlEmoticonsmile2.png?imgmax=800" /&gt;&lt;/p&gt;  &lt;h5&gt;Verifiable Code&lt;/h5&gt;  &lt;p&gt;This is the trip cord for almost every obfuscator.&amp;#160; If “peverify.exe” reports no errors on the original assembly, an obfuscator &lt;em&gt;must&lt;/em&gt; produce a verifiable obfuscated assembly.&amp;#160; Also, if the obfuscator injects code into the assembly that generates and executes IL at runtime, this code must also be verifiable (although peverify.exe cannot validate this unfortunately).&lt;/p&gt;  &lt;p&gt;CliSecure passed this test by generating verifiable code when Renaming, Control Flow and String Obfuscation were turned on.&amp;#160; But it generated 32 peverify errors when Method Call Obfuscation was turned on, and 2 more peverify errors when Code Protection was added.&amp;#160; Since these two protections also impact performance and require the protected app to run with full trust, leaving these two protections off anyway makes sense for me.&amp;#160; But for apps that would like to use these protection mechanisms the peverify errors they cause could cause verification/test issues at best and runtime failures at worst.&lt;/p&gt;  &lt;h4 align="left"&gt;Does it run?&lt;/h4&gt;  &lt;p align="left"&gt;So although CliSecure passed the peverify.exe test, would the assembly actually run when dropped in-place of a non-obfuscated DLL?&amp;#160; I had to find out.&lt;/p&gt;  &lt;p align="left"&gt;I built the entire solution of DotNetOpenAuth and all its samples.&amp;#160; Since CliSecure didn’t rename public types and members, a post-build in-place obfuscation should theoretically keep the sites working.&amp;#160; Some of these sites are configured for only ASP.NET Medium Trust, so it would help validate that the obfuscator continues to run under this permission level as well.&lt;/p&gt;  &lt;p align="left"&gt;Verdict: the obfuscated assembly appears to work.&amp;#160; I qualify with “appears” to work because it’s a very complex assembly with many code paths and I haven’t finished testing all of them.&amp;#160; But the core scenario works.&lt;/p&gt;  &lt;h4&gt;Debugging support&lt;/h4&gt;  &lt;p&gt;Any time you obfuscate an assembly you make debugging more difficult.&amp;#160; The end user may report callstacks that are totally useless both to your user and to you!&amp;#160; A good obfuscator will provide a way for you as the code owner to de-obfuscate stack traces, or even interactively debug your assembly with a reasonably similar experience to an unobfuscated assembly (provided you have the source code).&lt;/p&gt;  &lt;p&gt;Amazingly enough, the obfuscated DLL was still debuggable using the original .pdb symbols file.&amp;#160; The callstacks were obfuscated but stepping through the code still worked when the source code is available.&amp;#160; Not all the breakpoints seemed to fire which &lt;em&gt;may&lt;/em&gt; be a VS2010 bug or a bug in the obfuscation I don’t know.&amp;#160; But stepping over and stepping into worked great once the debugger was stopped.&amp;#160; &lt;/p&gt;  &lt;p&gt;The callstack de-obfuscator failed, in that the callstack it generated was still illegible.&amp;#160; That’s a real bummer when customer reports come in with a callstack that you then need to decipher.&lt;/p&gt;  &lt;h4&gt;Command line obfuscation support&lt;/h4&gt;  &lt;p&gt;CliSecure comes with a command-line version of their tool that takes all parameters at the command line, or takes a convenient single parameter that is the CliSecure project file that contains all the details within it.&amp;#160; While there is no MSBuild task included, the command line syntax seems simple enough that an MSBuild “Exec” task could easily handle kicking off the process as part of an automated build.&lt;/p&gt;  &lt;h3&gt;Summary&lt;/h3&gt;  &lt;p&gt;This is by far the most feature rich .NET obfuscation tool I’ve seen.&amp;#160; Its obfuscation protections are superb, even with the couple of semi-faulty options turned off.&amp;#160; Debugging is pretty good, although de-obfuscating callstacks needs some work.&amp;#160; During this review the SecureTeam behind the product were very responsive and fixed many bugs I reported rapidly, so I fully expect a new version coming near you will fix the remaining issues.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=VU4OWZHWToA:cTXz5pTwdCI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=VU4OWZHWToA:cTXz5pTwdCI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=VU4OWZHWToA:cTXz5pTwdCI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=VU4OWZHWToA:cTXz5pTwdCI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=VU4OWZHWToA:cTXz5pTwdCI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=VU4OWZHWToA:cTXz5pTwdCI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=VU4OWZHWToA:cTXz5pTwdCI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=VU4OWZHWToA:cTXz5pTwdCI:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/VU4OWZHWToA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5752960676594216280/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2010/10/net-obfuscator-product-review.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5752960676594216280?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5752960676594216280?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/VU4OWZHWToA/net-obfuscator-product-review.html" title=".NET Obfuscator Product Review" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_hfiLRSZPvmE/TLcPiMFRoUI/AAAAAAAAEek/8blldk6EtaI/s72-c/image_thumb1%5B1%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2010/10/net-obfuscator-product-review.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEADQH87eip7ImA9WxFbEEU.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-4632580049400478264</id><published>2010-07-02T06:54:00.001-07:00</published><updated>2010-07-02T07:59:31.102-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-02T07:59:31.102-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Reviews" /><category scheme="http://www.blogger.com/atom/ns#" term="Hardware" /><title>Review on the Dell Studio 15 laptop</title><content type="html">&lt;p&gt;So I bought a new laptop from Dell two weeks ago.&amp;#160; Here are the highlights:&lt;/p&gt;  &lt;h4&gt;The good&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;Very speedy (of course I paid for that). &lt;/li&gt;    &lt;li&gt;Sleep/wake &lt;em&gt;finally&lt;/em&gt; works well.&amp;#160; Waking is very fast, and actually reliable! &lt;/li&gt;    &lt;li&gt;The propping back legs on the laptop are conveniently placed and the heat on the underside of the laptop are also lending to holding the laptop on your lap without getting hot spots on your legs. &lt;/li&gt;    &lt;li&gt;The face recognition auto-login feature is cool, but I suspect a photo of me would log me in, which makes it more of a toy than a tool. &lt;/li&gt;    &lt;li&gt;I like the backlit keyboard.&amp;#160; And the touchpad has two-finger zoom (which can be disabled) and a scroll circle feature which is pretty cool (although I haven’t used it). &lt;/li&gt;    &lt;li&gt;It’s remarkably lightweight, especially considering how souped up the hardware is. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;The Bad&lt;/h4&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;ol&gt;   &lt;li&gt;When left on for long periods, the mouse touch pad grows to be burning hot, making it unusable. &lt;/li&gt;    &lt;li&gt;It didn’t come with a TPM chip.&amp;#160; These things were invented and shipping in laptops years ago.&amp;#160; What’s up with that? &lt;/li&gt;    &lt;li&gt;No room for a smart card slot, that combined with no TPM chip, means I have to use a flimsy USB card reader to remote into work.&amp;#160; &lt;/li&gt;    &lt;li&gt;It doesn’t come with a Windows DVD, or software to burn a recovery DVD based on the backup partition on the hard drive. &lt;/li&gt;    &lt;li&gt;No hardware lights for disk access, or caps lock or anything else.&amp;#160; The lack of classic feedback for whether the computer is busy is a little unnerving. &lt;/li&gt;    &lt;li&gt;When the caps lock key is pressed, a small display appears that permanently steals focus from the active window (at least when you’re in Remote Desktop), so you’re typing away, press caps lock, and suddenly your typing isn’t going anywhere.&amp;#160; Whoops. &lt;/li&gt;    &lt;li&gt;The face recognition auto-login feature (and webcam) remains active while the screensaver is on.&amp;#160; This keeps the CPU hotter than it needs to be, and it means if you approach your laptop (perhaps to see your loved ones in your photo screensaver) the screen saver exits and you get logged in.&amp;#160; Where the real problem here though is that if the screen saver reduced your screen resolution and the face recognition auto-login exits the screen saver to log you in automatically, the screen resolution isn’t restored to normal, and the desktop is wacked.&lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;&lt;/h2&gt;  &lt;h4&gt;The Ugly&lt;/h4&gt;  &lt;ol&gt;   &lt;li&gt;The WiFi is very unreliable.&amp;#160; It frequently drops the connection entirely and can’t find any hotspots.&amp;#160; I have to disable/re-enable the Wireless Connection to get back online. &lt;/li&gt;    &lt;li&gt;Bluetooth is even more unreliable.&amp;#160; Pairing with my Bluetooth mouse was an exercise in patience.&amp;#160; And it keeps losing the mouse, requiring a restart.&amp;#160; In the meantime, most Bluetooth dialogs/windows hang, making troubleshooting the problem virtually impossible. &lt;/li&gt;    &lt;li&gt;YouTube HD videos hang in the middle for &lt;em&gt;minutes&lt;/em&gt; with a black screen mid-movie, and the video driver can otherwise randomly crash the machine for no apparent reason at all. &lt;/li&gt; &lt;/ol&gt;  &lt;h4&gt;Verdict&lt;/h4&gt;  &lt;p&gt;I really like this laptop, but for me, the Ugly bits are deal-breakers.&amp;#160; I rely on the Internet for most of my work, and my Bluetooth mouse is much more usable than a touch pad.&amp;#160; When neither work well or reliably, the laptop is of very limited use.&amp;#160; Tech support suggested I upgrade the drivers on my brand new laptop to resolve the problems, which doesn’t make sense to me anyway given they should have put the latest drivers on when they shipped it, but that didn’t help anyway.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-eZykFHgwRk:q6P3kdnEdpA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=-eZykFHgwRk:q6P3kdnEdpA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-eZykFHgwRk:q6P3kdnEdpA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-eZykFHgwRk:q6P3kdnEdpA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=-eZykFHgwRk:q6P3kdnEdpA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-eZykFHgwRk:q6P3kdnEdpA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=-eZykFHgwRk:q6P3kdnEdpA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-eZykFHgwRk:q6P3kdnEdpA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/-eZykFHgwRk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/4632580049400478264/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2010/07/review-on-dell-studio-15-laptop.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/4632580049400478264?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/4632580049400478264?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/-eZykFHgwRk/review-on-dell-studio-15-laptop.html" title="Review on the Dell Studio 15 laptop" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://blog.nerdbank.net/2010/07/review-on-dell-studio-15-laptop.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEHQnk9eSp7ImA9WhRaF0U.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-2640453341360821021</id><published>2010-04-13T21:50:00.001-07:00</published><updated>2012-02-20T16:20:33.761-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-02-20T16:20:33.761-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DotNetOpenAuth" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>DotNetOpenAuth v3.4.3 released</title><content type="html">&lt;p&gt;DotNetOpenAuth has just seen a minor release to v3.4.3.&amp;#160; Fixes center around corner case interoperability issues that cause a very small percentage (&amp;lt;0.5%) of &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; users to be unable to log into your relying party web sites.&amp;#160; A few other random fixes as well.&amp;#160; &lt;/p&gt;&lt;p&gt;Go &lt;a href="http://sourceforge.net/projects/dnoa/files/releases/"&gt;download it now&lt;/a&gt;.&lt;/p&gt;&lt;h4&gt;&lt;/h4&gt;&lt;h5&gt;The OpenID “dot bug”&lt;/h5&gt;&lt;p&gt;The most noteworthy fix was a very difficult one to pull off, namely the bug where OpenIDs with trailing dots being unsupported.&amp;#160; Back in the 1990s, classic ASP had &lt;a href="http://insecure.org/sploits/ms.personal_web_server.dotbug.html"&gt;the infamous “dot bug”&lt;/a&gt; where a trailing dot appended to a URL path would reveal the source code of the server-side script, which was a fatal security hole that was (of course) patched.&amp;#160; I think that this might have inspired the .NET Framework’s Uri class design to include automatically removing trailing dots from each path segment in a Uri instance.&amp;#160; Since FAT and NTFS file systems don’t support trailing dots on filenames, this doesn’t cause any issue if the web is run by Windows file systems.&amp;#160; &lt;/p&gt;&lt;p&gt;But when these URLs are actually OpenIDs, and those OpenIDs contain path segments that are base64 encoded where one of the two assignable characters is a period (ala Yahoo’s pseudonymous OpenIDs), then approximately 1.5% of base64-encoded OpenIDs have trailing periods.&amp;#160; So what’s the problem?&amp;#160; When an OpenID positive assertion comes into an OpenID relying party web site based on .NET with a claimed_id that ends with a period, .NET will quietly strip the period from the claimed_id, causing the login to fail or (arguably worse) to succeed but with OpenID discovery misdirected to the wrong URL (one where the trailing dot is stripped).&amp;#160; &lt;/p&gt;&lt;p&gt;The .NET Framework provides no (supported) way to turn off this dot-stripping behavior.&amp;#160; If your relying party web site is running with Full Trust you can set some internal flags using reflection to suppress the behavior, but it has some nasty side-effects.&amp;#160; If you’re on medium trust, you’re sunk.&lt;/p&gt;&lt;p&gt;But I’m pleased to say that DotNetOpenAuth has a solution, handling both medium and full trust, that is as good as the .NET Framework will allow until a fix in the platform is made.&amp;#160; I won’t bore you with all the gory details on this post, but suffice it to say, that if you just download and use the new version, you’ll be working with OpenIDs even with trailing dots.&amp;#160; Phew.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=romn_pyFgqo:lXlFqynielA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=romn_pyFgqo:lXlFqynielA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=romn_pyFgqo:lXlFqynielA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=romn_pyFgqo:lXlFqynielA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=romn_pyFgqo:lXlFqynielA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=romn_pyFgqo:lXlFqynielA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=romn_pyFgqo:lXlFqynielA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=romn_pyFgqo:lXlFqynielA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/romn_pyFgqo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/2640453341360821021/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2010/04/dotnetopenauth-v343-released.html#comment-form" title="15 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2640453341360821021?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2640453341360821021?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/romn_pyFgqo/dotnetopenauth-v343-released.html" title="DotNetOpenAuth v3.4.3 released" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>15</thr:total><feedburner:origLink>http://blog.nerdbank.net/2010/04/dotnetopenauth-v343-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMCQ3o9fCp7ImA9WxBbF00.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5453365124440130994</id><published>2010-03-09T20:07:00.001-08:00</published><updated>2010-03-15T19:27:42.464-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-03-15T19:27:42.464-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>How to upgrade your Blogger OpenID to a decent one</title><content type="html">&lt;p&gt;If you host your blog on Google’s &lt;a href="http://www.blogger.com/"&gt;Blogger&lt;/a&gt; service you may have discovered that your blog is an &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; you can use to log into various web sites that act as OpenID relying parties.&amp;#160; But Blogger’s support for OpenID is limited to OpenID 1.1, which is very old and not supported by many relying parties nowadays.&lt;/p&gt;  &lt;p&gt;You can upgrade your Blogger hosted OpenID to the new OpenID 2.0 version and log into many more web sites, all while still using your Google account to log in, thanks to &lt;a href="http://www.google.com/profiles"&gt;Google Profiles&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Here’s how to upgrade your Blogger OpenID to OpenID 2.0:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Create a &lt;a href="http://www.google.com/profiles"&gt;Google Profiles&lt;/a&gt; profile if you haven’t already done so. &lt;/li&gt;    &lt;li&gt;Visit &lt;a href="http://www.blogger.com/"&gt;http://www.blogger.com/&lt;/a&gt;, logging in if necessary. &lt;/li&gt;    &lt;li&gt;On the blog you use for an OpenID click &lt;strong&gt;Layout&lt;/strong&gt;. &lt;/li&gt;    &lt;li&gt;Click &lt;strong&gt;Edit HTML.&lt;/strong&gt; &lt;/li&gt;    &lt;li&gt;In the Edit Template area, add the following HTML within the &amp;lt;HEAD&amp;gt; tag of your template:      &lt;pre class="html:nogutter" name="code"&gt;&amp;lt;link rel='openid2.provider' href='https://www.google.com/accounts/o8/ud?source=profiles' /&amp;gt;&amp;#160;
&amp;lt;link rel='openid2.local_id' href='http://www.google.com/profiles/YOURGOOGLEPROFILE' /&amp;gt;
&amp;lt;link rel='openid.server' href='http://www.blogger.com/openid-server.g' /&amp;gt;&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;Click Save Template. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you add OpenID endpoints to your blog, Blogger will automatically deactivate its own OpenID 1.1 support.  Since Google Profiles only supports OpenID 2.0 RPs, the above instructions also re-asserts Blogger as the OpenID 1.1 Provider so that 1.1 RPs still work.  So what we have is the best of both worlds now.&lt;/p&gt;

&lt;p&gt;Thanks to Breno de Medeiros of Google for the tip on how to keep OpenID 1.1 RPs working.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=CosZVuMxU4U:a2YYHzXHUrU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=CosZVuMxU4U:a2YYHzXHUrU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=CosZVuMxU4U:a2YYHzXHUrU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=CosZVuMxU4U:a2YYHzXHUrU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=CosZVuMxU4U:a2YYHzXHUrU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=CosZVuMxU4U:a2YYHzXHUrU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=CosZVuMxU4U:a2YYHzXHUrU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=CosZVuMxU4U:a2YYHzXHUrU:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/CosZVuMxU4U" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5453365124440130994/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2010/03/how-to-upgrade-your-blogger-openid-to.html#comment-form" title="15 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5453365124440130994?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5453365124440130994?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/CosZVuMxU4U/how-to-upgrade-your-blogger-openid-to.html" title="How to upgrade your Blogger OpenID to a decent one" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>15</thr:total><feedburner:origLink>http://blog.nerdbank.net/2010/03/how-to-upgrade-your-blogger-openid-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICQn05cSp7ImA9WxBQFks.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-4643078507506158768</id><published>2010-01-16T08:49:00.001-08:00</published><updated>2010-01-16T08:49:23.329-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-16T08:49:23.329-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OAuth" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNetOpenAuth" /><category scheme="http://www.blogger.com/atom/ns#" term="InfoCard" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>DotNetOpenAuth’s “call home” reporting</title><content type="html">&lt;p&gt;A few months ago I asked how people would feel if DotNetOpenAuth collected feature statistics and sent them back to the library's authors so we get a better feel for what features are used, errors that are common.&amp;#160; The feedback I got was positive, so v3.4 has reporting turned on by default, but you can opt out either entirely or just omit certain details from the report by adding some simple tags to your web.config file.&amp;#160; &lt;/p&gt;  &lt;p&gt;This turns it completely off:&lt;/p&gt;  &lt;pre class="xml:nogutter" name="code"&gt;&amp;lt;dotNetOpenAuth&amp;gt;
  &amp;lt;reporting enabled=&amp;quot;false&amp;quot; /&amp;gt;
&amp;lt;/dotNetOpenAuth&amp;gt;&lt;/pre&gt;

&lt;p&gt;This makes the reporting pseudonymous, in that no URLs from your own web site are sent back in the report, but a random GUID is still included in your report so that we know that the origin of the report is the same across multiple reports.&lt;/p&gt;

&lt;pre class="xml:nogutter" name="code"&gt;&amp;lt;dotNetOpenAuth&amp;gt;
  &amp;lt;reporting includeLocalRequestUris=&amp;quot;false&amp;quot; /&amp;gt;
&amp;lt;/dotNetOpenAuth&amp;gt;&lt;/pre&gt;

&lt;h5&gt;How is the report sent?&lt;/h5&gt;

&lt;p&gt;There’s an adjustable frequency that defaults to once daily.&amp;#160; When certain features in DotNetOpenAuth are accessed, a quick time check is made, and if it’s time to send a report, a thread pool thread is queued to generate and HTTP POST the report to &lt;a href="https://reports.dotnetopenauth.net/"&gt;https://reports.dotnetopenauth.net/&lt;/a&gt;.&amp;#160; We use a thread pool thread to minimize the performance impact this reporting has on your web site.&amp;#160; In fact the entire reporting feature is finely tuned to have virtually no impact on your site’s performance.&lt;/p&gt;

&lt;p&gt;If your site isn’t running for at least one reporting interval, a report will not be sent.&amp;#160; So most of your self-hosted “localhost” sites run by Personal Web Server in Visual Studio will not generate these reports.&lt;/p&gt;

&lt;h5&gt;What’s in the report?&lt;/h5&gt;

&lt;p&gt;So what all information is actually in this report anyway? Well, here's a sample: &lt;/p&gt;

&lt;pre&gt;{be791692-2573-41b4-bd6f-6f4760cf186c}
DotNetOpenAuth, Version=3.3.4.10015, Culture=neutral, PublicKeyToken=2780ccd10d57b246 (official)
.NET Framework 2.0.50727.4927
====================================
requests.txt
﻿http://localhost:4856/login.aspx
http://localhost:54347/User/Authenticate
====================================
cultures.txt
﻿en-US
====================================
features.txt
﻿OpenIdLogin
OpenIdButton
AXFetchAsSregTransform
OpenIdRelyingParty StandardRelyingPartyApplicationStore StandardRelyingPartyApplicationStore
ClaimsRequest
FetchRequest
ClaimsResponse
XrdsPublisher
====================================
event-Yadis.txt
4	XRDS referenced in HTTP header
8	XRDS referenced in HTML
1	XRDS in initial response
====================================
event-PositiveAuthenticationResponse.txt
2	https://www.myopenid.com/server
2	http://localhost:45235/provider
====================================
event-NegativeAuthenticationResponse.txt&lt;/pre&gt;

&lt;p&gt;At the top of the file is a self-identifying GUID.&amp;#160; It means nothing, except that the GUID is the same for all reports that come from your web site, allowing the reporting database to update the records for your web site (whether we even know the URL of your web site or not) with the latest report.&amp;#160; &lt;/p&gt;

&lt;p&gt;Then we have the DotNetOpenAuth version and CLR you’re using.&amp;#160; It turns out that we not only use this for statistical purposes, but it allows the reporting server that receives the report to check whether the version you’re using is on a list of versions with known exploitable security holes.&amp;#160; Since for many web sites authentication is a feature that’s completed and never considered again, someone using an old version of an authentication library may be exposed to security holes that a newer version would correct.&amp;#160; So what happens if the version of DotNetOpenAuth that’s reporting in is one with known security holes?&amp;#160; Not much.&amp;#160; But if you have DotNetOpenAuth error logging (usually via log4net) enabled, an ERROR is logged with a message describing the problem and warning the web developer to upgrade.&amp;#160; In the meantime the library on the web site continues functioning.&amp;#160; I actually debated with myself whether to install a kill-switch, since perhaps disabling authentication on a web site altogether is better than leaving the site operational with a nasty security hole.&amp;#160; But decided against that… and I suspect most web site owners would agree that it’s not my decision to make whether to shut down your web site. :)&amp;#160; So I leave it at emitting a warning in your ERROR log.&lt;/p&gt;

&lt;p&gt;The requests.txt section gives just the first few URLs on the site that either host DotNetOpenAuth’s &lt;a href="http://openid.net"&gt;ASP.NET&lt;/a&gt; controls or programmatically process &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt;/&lt;a href="http://oauth.net"&gt;OAuth&lt;/a&gt;/InfoCard messages.&amp;#160; Currently the longest this list of URLs can get is &lt;strong&gt;3&lt;/strong&gt;, since some sites like blogs may have login controls on every one of their blog post pages and I mostly just want to get an idea of who’s using the library.&amp;#160; Note that these URLs have their query strings stripped off before being included in the report to try to avoid accidental private information disclosure.&amp;#160; You can omit this section in your reports by setting the &amp;lt;reporting&amp;gt; element’s includeLocalRequestUris=”false” attribute.&lt;/p&gt;

&lt;p&gt;The cultures.txt section just reports what the browser that’s accessing your web site says is its primary culture.&amp;#160; This will help me know which languages to offer localized error messages for.&amp;#160; Each report is limited to only reporting 20 cultures.&amp;#160; You can omit this section in your reports by setting the &amp;lt;reporting&amp;gt; element’s includeCultures=”false” attribute.&lt;/p&gt;

&lt;p&gt;The features.txt section lists which parts of the DotNetOpenAuth library have been used by your web site.&amp;#160; Pretty straightforward.&amp;#160; You can omit this section in your reports by setting the &amp;lt;reporting&amp;gt; element’s includeFeatureUsage=”false” attribute.&lt;/p&gt;

&lt;p&gt;The event-Yadis.txt section is just some random statistics on how OpenID identifier pages are constructed.&amp;#160; You can omit this section in your reports by setting the &amp;lt;reporting&amp;gt; element’s includeEventStatistics=”false” attribute.&lt;/p&gt;

&lt;p&gt;The event-*AuthenticationResponse.txt sections tell me which remote parties DotNetOpenAuth is able to successfully interop with and which ones have issues.&amp;#160; Note that &lt;em&gt;no&lt;/em&gt; user information is collected or reported.&amp;#160; You can omit this section in your reports by setting the &amp;lt;reporting&amp;gt; element’s includeEventStatistics=”false” attribute.&lt;/p&gt;

&lt;p&gt;Please comment with your thoughts, including any questions or concerns you may have.&amp;#160; &lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=fmSVnuT69dY:rACK6h3yHpo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=fmSVnuT69dY:rACK6h3yHpo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=fmSVnuT69dY:rACK6h3yHpo:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=fmSVnuT69dY:rACK6h3yHpo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=fmSVnuT69dY:rACK6h3yHpo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=fmSVnuT69dY:rACK6h3yHpo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=fmSVnuT69dY:rACK6h3yHpo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=fmSVnuT69dY:rACK6h3yHpo:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/fmSVnuT69dY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/4643078507506158768/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2010/01/dotnetopenauths-call-home-reporting.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/4643078507506158768?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/4643078507506158768?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/fmSVnuT69dY/dotnetopenauths-call-home-reporting.html" title="DotNetOpenAuth’s “call home” reporting" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.nerdbank.net/2010/01/dotnetopenauths-call-home-reporting.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEGSXo7cSp7ImA9WxBQFks.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-8360348461670980249</id><published>2010-01-15T15:20:00.001-08:00</published><updated>2010-01-16T08:50:28.409-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-16T08:50:28.409-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OAuth" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="InfoCard" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>DotNetOpenAuth v3.4 now available</title><content type="html">&lt;p&gt;You can go download &lt;a href="https://www.ohloh.net/p/dotnetopenauth/download"&gt;DotNetOpenAuth v3.4&lt;/a&gt; today.&amp;#160; Highlights of the new version include:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Support for Google Apps for Domains issued OpenIDs.&amp;#160; This required special work since Google has their own flavor of &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; discovery that had to be supported until something like Google’s scenario get’s standardized. &lt;/li&gt;    &lt;li&gt;Identifier discovery extensibility (this is how Google Apps support was enabled, but the extensibility is exposed for others as well – but use with caution!) &lt;/li&gt;    &lt;li&gt;A new ASP.NET MVC OpenID web project template. &lt;/li&gt;    &lt;li&gt;Twitter image POST via &lt;a href="http://oauth.net"&gt;OAuth&lt;/a&gt; fixed. &lt;/li&gt;    &lt;li&gt;New SSO web-ring samples added, so organizations looking to use OpenID for their SSO solution can see how it might be done. &lt;/li&gt;    &lt;li&gt;Minor bug fixes. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Please note that this is the first version to have &lt;strong&gt;statistical reporting&lt;/strong&gt; enabled by default, which &lt;strong&gt;reports feature usage statistics and the URL of the site hosting the library &lt;/strong&gt;to the library authors.&amp;#160; To opt-out of this feature, you should add this to your web.config file:&lt;/p&gt;  &lt;pre class="xml:nogutter" name="code"&gt;&amp;lt;dotNetOpenAuth&amp;gt;
  &amp;lt;reporting enabled=&amp;quot;false&amp;quot; /&amp;gt;
&amp;lt;/dotNetOpenAuth&amp;gt;&lt;/pre&gt;

&lt;p&gt;The details included in the reports may be selectively turned on or off as well, if you are willing to contribute statistics but don't want the URL to your web site exposed, for example.&amp;#160; More information can be found in my follow-up post: &lt;a href="http://blog.nerdbank.net/2010/01/dotnetopenauths-call-home-reporting.html"&gt;DotNetOpenAuth’s “call home” reporting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don’t forget to &lt;a href="http://www.pledgie.com/campaigns/2678?canvas=false"&gt;donate to the cause&lt;/a&gt; if you like the library.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ihyTDHYwo8A:HZAD1zWK7zo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=ihyTDHYwo8A:HZAD1zWK7zo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ihyTDHYwo8A:HZAD1zWK7zo:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ihyTDHYwo8A:HZAD1zWK7zo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=ihyTDHYwo8A:HZAD1zWK7zo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ihyTDHYwo8A:HZAD1zWK7zo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=ihyTDHYwo8A:HZAD1zWK7zo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ihyTDHYwo8A:HZAD1zWK7zo:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/ihyTDHYwo8A" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/8360348461670980249/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2010/01/dotnetopenauth-v34-now-available.html#comment-form" title="11 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8360348461670980249?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/8360348461670980249?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/ihyTDHYwo8A/dotnetopenauth-v34-now-available.html" title="DotNetOpenAuth v3.4 now available" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>11</thr:total><feedburner:origLink>http://blog.nerdbank.net/2010/01/dotnetopenauth-v34-now-available.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYAQH4-fSp7ImA9WxBTE00.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-3258801272732475606</id><published>2009-12-08T12:12:00.001-08:00</published><updated>2009-12-08T12:12:21.055-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-08T12:12:21.055-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>Rest in peace, ExtremeSwank OpenID and OAuth</title><content type="html">&lt;p&gt;&lt;a href="http://code.google.com/p/extremeswankopenid/"&gt;ExtremeSwankOpenID&lt;/a&gt; and &lt;a href="http://code.google.com/p/extremeswankoauth/"&gt;ExtremeSwankOAuth&lt;/a&gt;, both libraries authored by John Ehn, have been discontinued according to the project sites respective home pages which have a new note that reads: “Note: This … Consumer is no longer in development.”&lt;/p&gt;  &lt;p&gt;ExtremeSwankOpenID was stagnant in development lately, and when &lt;a href="http://wiki.openid.net/Reported_Security_Issues?SearchFor=content-location&amp;amp;sp=1"&gt;a recent OpenID vulnerability&lt;/a&gt; was identified as impacting the ExtremeSwankOpenID library due to a hidden “feature” in the .NET Framework’s handling of HTTP responses, it appears the library was retired rather than fixed.&amp;#160; This library was one of only two &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; implementations written in .NET that were recognized in many OpenID circles.&amp;#160; It also touted a unique feature (which I never investigated personally) of allowing desktop applications to use OpenID to authenticate their users.&lt;/p&gt;  &lt;p&gt;ExtremeSwankOAuth is one of many .NET &lt;a href="http://oauth.net"&gt;OAuth&lt;/a&gt; implementations, and the reasoning for its retirement is less clear.&lt;/p&gt;  &lt;p&gt;Notwithstanding ExtremeSwankOpenID’s recent lack of development, it was ironically John’s library that was under active development and supported OpenID 2.0 while a very early version of &lt;a href="http://dotnetopenid.googlecode.com"&gt;DotNetOpenId&lt;/a&gt; wasn’t being developed and only supported OpenID 1.1.&amp;#160; It was seeing DotNetOpenId’s own users switch to John’s library that motivated me to re-engage development of DotNetOpenId, now rechristened DotNetOpenAuth, which is now the only OpenID implementation for .NET that I know of – and a dang good one too if I may say so.&lt;/p&gt;  &lt;p&gt;Although I did not know John personally, I’ve shared a few emails with him and he seemed a courteous and motivated programmer.&amp;#160; I wish him well on his future pursuits.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=HAE3TTevwks:p2rh91j9dPs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=HAE3TTevwks:p2rh91j9dPs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=HAE3TTevwks:p2rh91j9dPs:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=HAE3TTevwks:p2rh91j9dPs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=HAE3TTevwks:p2rh91j9dPs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=HAE3TTevwks:p2rh91j9dPs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=HAE3TTevwks:p2rh91j9dPs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=HAE3TTevwks:p2rh91j9dPs:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/HAE3TTevwks" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/3258801272732475606/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/12/rest-in-peace-extremeswank-openid-and.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/3258801272732475606?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/3258801272732475606?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/HAE3TTevwks/rest-in-peace-extremeswank-openid-and.html" title="Rest in peace, ExtremeSwank OpenID and OAuth" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/12/rest-in-peace-extremeswank-openid-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQHSHc8eyp7ImA9WxNaGE4.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5860511818364616908</id><published>2009-12-03T01:23:00.001-08:00</published><updated>2009-12-03T01:25:39.973-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-03T01:25:39.973-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OAuth" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="InfoCard" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>DotNetOpenAuth v3.3 is released</title><content type="html">&lt;p&gt;It’s been nearly six months since v3.2 was released.&amp;#160; So what’s in v3.3 that took so long to bake?&amp;#160; Well, a lot of it was waiting for and getting used to &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/codecontracts/threads/"&gt;Code Contracts&lt;/a&gt; to mature enough to bet on the technology.&amp;#160; &lt;/p&gt;  &lt;p&gt;The most exciting changes though are the new OpenIdSelector control, and the new project template that helps you get going fast and strong with a new web site that accepts &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; and/or InfoCard to log users in.&amp;#160; Seriously, you gotta get this version and try it out.&amp;#160; You can see a &lt;a href="http://openidux.dotnetopenauth.net"&gt;live demo of the new login UX now&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://www.ohloh.net/p/dotnetopenauth/download?package=DotNetOpenAuth"&gt;Go download DotNetOpenAuth now&lt;/a&gt;.&amp;#160; And get the &lt;a href="https://www.ohloh.net/p/dotnetopenauth/download?package=DotNetOpenAuth+project+templates"&gt;project template&lt;/a&gt; too.&lt;/p&gt;  &lt;p&gt;As usual, you can get more of the details of the changes on the &lt;a href="http://dotnetopenauth.net:8000/wiki/VersionChanges"&gt;VersionChanges wiki page&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Do you like what you see?&amp;#160; Don’t forget to contribute so that future versions can keep rocking!&lt;/p&gt; &lt;a href="http://www.pledgie.com/campaigns/2678"&gt;&lt;img border="0" alt="Click here to lend your support to: dotnetopenid and make a donation at www.pledgie.com !" src="http://www.pledgie.com/campaigns/2678.png?skin_name=chrome" /&gt;&lt;/a&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=m8OLQRFSZRk:qLx-hHnv-uQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=m8OLQRFSZRk:qLx-hHnv-uQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=m8OLQRFSZRk:qLx-hHnv-uQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=m8OLQRFSZRk:qLx-hHnv-uQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=m8OLQRFSZRk:qLx-hHnv-uQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=m8OLQRFSZRk:qLx-hHnv-uQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=m8OLQRFSZRk:qLx-hHnv-uQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=m8OLQRFSZRk:qLx-hHnv-uQ:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/m8OLQRFSZRk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5860511818364616908/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/12/dotnetopenauth-v33-is-released.html#comment-form" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5860511818364616908?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5860511818364616908?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/m8OLQRFSZRk/dotnetopenauth-v33-is-released.html" title="DotNetOpenAuth v3.3 is released" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/12/dotnetopenauth-v33-is-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUCRXw6fip7ImA9WxNVEkg.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-5787916446147412572</id><published>2009-10-22T15:57:00.001-07:00</published><updated>2009-10-22T15:57:44.216-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-22T15:57:44.216-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="InfoCard" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>Feedback requested: New OpenID RP login UX prototype</title><content type="html">&lt;h4&gt;OpenID RP login UX&lt;/h4&gt;  &lt;p&gt;Live demo location: &lt;a href="http://openidux.dotnetopenauth.net/"&gt;http://openidux.dotnetopenauth.net/&lt;/a&gt;&lt;/p&gt;  &lt;h5&gt;&lt;/h5&gt;  &lt;h4&gt;Design considerations&lt;/h4&gt;  &lt;p&gt;The &lt;a href="http://docs.google.com/Doc?docid=0AXB25E7fZcQCZGY1bm40ampfMTkxaHJ2emZya3M&amp;amp;hl=en"&gt;DNOA&lt;/a&gt;&lt;a href="http://docs.google.com/Doc?docid=0AXB25E7fZcQCZGY1bm40ampfMTkxaHJ2emZya3M&amp;amp;hl=en"&gt; login UX design document&lt;/a&gt; contains the design spec, and some of the reasoning that went into that design.&lt;/p&gt;  &lt;p&gt;One high-level goal of all this work is to produce a set of HTML, CSS, and JS files that can work on any web platform, so that ruby, python, php, coldfusion, and (of course) &lt;a href="http://asp.net/"&gt;ASP.NET&lt;/a&gt; RP web sites can benefit from a better UI for logging users in.&lt;/p&gt;  &lt;h4&gt;Interesting scenarios to experiment with and/or test&lt;/h4&gt;  &lt;ul&gt;   &lt;li&gt;Login by clicking on Members Only. This invokes the full page redirect login UI. &lt;/li&gt;    &lt;li&gt;Login by clicking Login in the upper-right corner of the page. This invokes the popup dialog UI. &lt;/li&gt;    &lt;li&gt;Visit the account management page and add additional OpenIDs or InfoCards to your account so you can log in with multiple identities yet be recognized as holding just one account. &lt;/li&gt;    &lt;li&gt;Login multiple times, using various OPs. Notice first that we highlight the button you chose the prior time. This helps the user not splinter his identity on a return visit in the event he has accounts with more than one displayed OP. &lt;/li&gt;    &lt;li&gt;Notice that in the login UI some OPs support checkid_immediate, and on a return visit, a green checkmark appears in the lower-right corner of an OP button when an immediate login is available. If a green checkmark is not visible on an OP button, a popup window will be used to guide the user through the initial login process. Some OPs (such as Verisign and Yahoo) do not support checkid_immediate, and will never display green checkmarks. &lt;/li&gt;    &lt;li&gt;When logging in, try using the OpenID button. Notice that as soon as you finish typing that discovery on that identifier begins and a login button appears within the text box. Next time you visit, the UX will remember what identifier you typed in and help you log in again. &lt;/li&gt;    &lt;li&gt;Try using the OpenID button with an identifier that delegates to multiple OPs. Notice how the Login button that appears to help you go through checkid_setup (if no checkid_immediate requests come back positive) is a split button, allowing you to actually pick which OP to log in with, and these OPs are in priority order (adjusted for OPs that are down or misbehaving, which are moved to the bottom).&lt;/li&gt;    &lt;li&gt;Use Internet Explorer, and log in with your InfoCard.&lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Special release notes&lt;/h4&gt;  &lt;p&gt;In this iteration, I've elected to go with the popup dialog approach to displaying the login UI rather than a popup browser window. This is still alterable, and your feedback and/or preferences on this decision is most welcome.&lt;/p&gt;  &lt;p&gt;The current set of OP buttons displayed include 4 OPs: Google, Yahoo, Verisign and MyOpenID. The last two of these do not fit the qualifications given in the design document, but they are included here to assist in the feedback process, and because I don't know how to make four buttons (Google, Yahoo, OpenID and InfoCard) look good, so I jumped up from three to six.&lt;/p&gt;  &lt;p&gt;In the OpenID text box area, after authentication completes a green checkmark is displayed, but sometimes no login button appears to complete login. This is a UX issue I haven't figured out how to solve yet. But the way to proceed with login is to click the original, large OpenID button again.&lt;/p&gt;  &lt;p&gt;The browsers I've tested with are IE8, Chrome 3, FireFox 3.5 and Safari 4. If you test with other/older browsers, please leave feedback about how your experience was. But currently I'm not targeting older browsers, so any bug reports regarding backward compatibility may not be fixed.&lt;/p&gt;  &lt;h4&gt;How to leave feedback&lt;/h4&gt;  &lt;p&gt;Leave a comment.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-23YGt-4310:9F9XtGz4-1I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=-23YGt-4310:9F9XtGz4-1I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-23YGt-4310:9F9XtGz4-1I:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-23YGt-4310:9F9XtGz4-1I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=-23YGt-4310:9F9XtGz4-1I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-23YGt-4310:9F9XtGz4-1I:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=-23YGt-4310:9F9XtGz4-1I:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=-23YGt-4310:9F9XtGz4-1I:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/-23YGt-4310" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/5787916446147412572/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/10/feedback-requested-new-openid-rp-login.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5787916446147412572?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/5787916446147412572?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/-23YGt-4310/feedback-requested-new-openid-rp-login.html" title="Feedback requested: New OpenID RP login UX prototype" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>5</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/10/feedback-requested-new-openid-rp-login.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4GSHY5eCp7ImA9WxNWFEo.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-2677541554901398847</id><published>2009-10-10T15:57:00.002-07:00</published><updated>2009-10-13T15:28:49.820-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-13T15:28:49.820-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="MSBuild" /><title>Minify your EmbeddedResource .js and .css files in your MSBuild project</title><content type="html">&lt;p&gt;If you write a C# or VB.NET class library that contains ASP.NET controls that also have .js or .css files embedded in your assembly, you probably want to minify those files for optimal download size in production, but keep the files readable for coding and debugging.  What if you could add a single &amp;lt;Import&amp;gt; to your class library’s project file that would automatically minify these files in Release builds, while leaving them untouched in debug builds?&lt;/p&gt;  &lt;p&gt;Well, I wrote a .targets file and associated MSBuild task that uses Dean Edwards’ excellent &lt;a href="http://dean.edwards.name/packer/"&gt;Packer&lt;/a&gt; algorithm to make .js files really small.  Just import the .targets file right after your last &amp;lt;Import&amp;gt; and you’re done.&lt;/p&gt;  &lt;p&gt;You can get it here:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://teamcity.dotnetopenauth.net:82/project.html?projectId=project3"&gt;http://teamcity.dotnetopenauth.net:82/project.html?projectId=project3&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Just click "Artifacts" then "Download all (.zip)" in the upper-right corner.&lt;/p&gt;  &lt;p&gt;Or the source for it if you're interested:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://github.com/AArnott/JavascriptCssPackerTargets"&gt;http://github.com/AArnott/JavascriptCssPackerTargets&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Just click the "download" button to get it as a zip file.&lt;/p&gt;  &lt;p&gt;Please take this as a tip and not an endorsement.  &lt;strong&gt;This is not a Microsoft product—&lt;/strong&gt;it’s just an open source project that I wanted to point out to you for you to evaluate whether it’s appropriate for your project.  As far as the license goes, this MSBuild task uses code from Dean Edwards that is under the LGPL license, so the whole MSBuild task .dll ships under the LGPL license.  While I don’t interpret that to mean that your shipping project must be under any particular license, you should consult your own attorneys and not take my word for it.&lt;/p&gt;  &lt;p&gt;(cross-posted from &lt;a href="http://blogs.msdn.com/vsproject/"&gt;http://blogs.msdn.com/vsproject/&lt;/a&gt;)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ftINBIm0z1Y:40CCPlAS9Gg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=ftINBIm0z1Y:40CCPlAS9Gg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ftINBIm0z1Y:40CCPlAS9Gg:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ftINBIm0z1Y:40CCPlAS9Gg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=ftINBIm0z1Y:40CCPlAS9Gg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ftINBIm0z1Y:40CCPlAS9Gg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=ftINBIm0z1Y:40CCPlAS9Gg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=ftINBIm0z1Y:40CCPlAS9Gg:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/ftINBIm0z1Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/2677541554901398847/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/10/minify-your-embeddedresource-js-and-css.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2677541554901398847?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2677541554901398847?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/ftINBIm0z1Y/minify-your-embeddedresource-js-and-css.html" title="Minify your EmbeddedResource .js and .css files in your MSBuild project" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/10/minify-your-embeddedresource-js-and-css.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEAERnkycSp7ImA9WhRTEkQ.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-559763819821896016</id><published>2009-10-09T11:22:00.001-07:00</published><updated>2011-11-02T20:58:27.799-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-02T20:58:27.799-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OAuth" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>VS2008 project template for OpenID and InfoCard relying parties</title><content type="html">&lt;p&gt;I finally built a project template to make it easier to write an &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; relying party web site using C# and ASP.NET.&amp;#160; Up to this point all we had were the sample RPs that ship with &lt;a href="http://dotnetopenauth.net/"&gt;DotNetOpenAuth&lt;/a&gt;, which were deliberately kept simple.&amp;#160; They didn’t use a real database, didn’t follow some best practices, and weren’t very real.&amp;#160; &lt;/p&gt;&lt;p&gt;Now you can start your next web site with OpenID and InfoCard logins already working!&amp;#160; Complete with role authorization, account management that allow for multiple OpenID/InfoCards per account, login and account creation.&lt;/p&gt;&lt;p&gt;And did I mention it’s free? (&lt;a href="http://pledgie.com/campaigns/2678"&gt;donations gratefully accepted&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;a href="http://sourceforge.net/projects/dnoa/files/releases/v3.4/v3.4.7/"&gt;Download it&lt;/a&gt; and copy the file "Project Templates\*.vsi" file into your &lt;strong&gt;%USERPROFILE%\Documents\Visual Studio 2008\Templates\ProjectTemplates&lt;/strong&gt; folder and it will appear in your New Project wizard in Visual Studio 2008.&lt;/p&gt;&lt;p&gt;Yes, the site is still unbeautified, but that’s so you can brand it to look like yours.&lt;/p&gt;&lt;p&gt;Have fun.&amp;#160; And let me know what you think of it or can &lt;a href="http://github.com/AArnott/webformsopenidrelyingparty"&gt;contribute&lt;/a&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=Rm26dfekG7c:IysmceoA8Qc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=Rm26dfekG7c:IysmceoA8Qc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=Rm26dfekG7c:IysmceoA8Qc:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=Rm26dfekG7c:IysmceoA8Qc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=Rm26dfekG7c:IysmceoA8Qc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=Rm26dfekG7c:IysmceoA8Qc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=Rm26dfekG7c:IysmceoA8Qc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=Rm26dfekG7c:IysmceoA8Qc:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/Rm26dfekG7c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/559763819821896016/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/10/vs2008-project-template-for-openid-and.html#comment-form" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/559763819821896016?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/559763819821896016?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/Rm26dfekG7c/vs2008-project-template-for-openid-and.html" title="VS2008 project template for OpenID and InfoCard relying parties" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>8</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/10/vs2008-project-template-for-openid-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ACQXg_eSp7ImA9WxFRFUk.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-463330210496348733</id><published>2009-09-25T21:47:00.002-07:00</published><updated>2010-04-29T05:56:00.641-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-04-29T05:56:00.641-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>Optimal OpenID UX finally underway</title><content type="html">&lt;p&gt;I’m finally making progress on building a set of HTML and javascript files that can be used on any &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; relying party web site to allow visitors to &lt;em&gt;easily&lt;/em&gt; log in with OpenID, without even knowing what OpenID is.&amp;#160; I mentioned &lt;a href="http://blog.nerdbank.net/2009/02/fixing-openid-login-user-experience.html"&gt;my goal to do this some time ago&lt;/a&gt;, and now I have a small partially functional prototype.&amp;#160; Please try it out, and keep coming back and letting me know what you think of it and where you’d like to see it go.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Try out the &lt;/strong&gt;&lt;a href="http://openidux.dotnetopenauth.net/"&gt;&lt;strong&gt;OpenID login experience&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt;&amp;#160; Remember to comment on what you like and dislike, and what aspects you’d like to see added or changed.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;At the moment&lt;/em&gt;, I’m struggling to decide whether to go with a fully bona fide popup window or a Javascript in page dialog.&amp;#160; So I provide two links at the top of the page so you can try out each one.&amp;#160; If we don’t go with the full popup window, we’ll have to either redirect the whole page to the Provider, which is sub-optimal for the user and for the RP, or we can use a popup window once the user has selected their OP.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=EJ-ph-wW6ss:kUDdOy14KYU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=EJ-ph-wW6ss:kUDdOy14KYU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=EJ-ph-wW6ss:kUDdOy14KYU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=EJ-ph-wW6ss:kUDdOy14KYU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=EJ-ph-wW6ss:kUDdOy14KYU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=EJ-ph-wW6ss:kUDdOy14KYU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=EJ-ph-wW6ss:kUDdOy14KYU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=EJ-ph-wW6ss:kUDdOy14KYU:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/EJ-ph-wW6ss" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/463330210496348733/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/09/optimal-openid-ux-finally-underway.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/463330210496348733?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/463330210496348733?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/EJ-ph-wW6ss/optimal-openid-ux-finally-underway.html" title="Optimal OpenID UX finally underway" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>4</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/09/optimal-openid-ux-finally-underway.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EFRnc-cSp7ImA9WxNRE0s.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-1752187103953460465</id><published>2009-09-07T16:20:00.001-07:00</published><updated>2009-09-07T16:20:17.959-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-07T16:20:17.959-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>How to easily fetch OpenID attributes, regardless of the Provider</title><content type="html">&lt;p&gt;In a previous &lt;a href="http://blog.nerdbank.net/2009/03/how-to-pretty-much-guarantee-that-you.html"&gt;article&lt;/a&gt;, I bemoan the pain of writing an &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; Relying Party that wants to fetch user attributes from their OpenID Provider, because of the at least 4 ways in which those attributes must be requested.&amp;#160; And then &lt;a href="http://blog.nerdbank.net/2009/06/help-is-coming-for-sregax-interop.html"&gt;later I promised&lt;/a&gt; that DotNetOpenAuth would offer help to alleviate that pain.&amp;#160; That help has come.&amp;#160; It actually came way back on June 26, 2009.&amp;#160; But only now did I officially document that help.&lt;/p&gt;  &lt;p&gt;Introducing the &lt;a href="http://dotnetopenauth.net:8000/wiki/CodeSnippets/OpenIDRP/AXFetchAsSregTransform"&gt;AXFetchAsSregTransform&lt;/a&gt; “behavior”, which is now &lt;a href="http://dotnetopenauth.net:8000/wiki/CodeSnippets/OpenIDRP/AXFetchAsSregTransform"&gt;fully documented on the project wiki site&lt;/a&gt;.&amp;#160; I’ve spent some time recently (and will spend more in the near future) documenting the common scenarios that people have questions about, and since it is on the wiki instead of only on this blog, it will be more likely to be updated as new versions of the library come out.&lt;/p&gt;  &lt;p&gt;The AXFetchAsSregTransform behavior makes it so that all you have to do is work with ClaimsRequest and ClaimsResponse – no matter what Provider you’re talking to.&amp;#160; If the Provider only supports AX, it Just Works because the special behavior will automatically translate your sreg request into an AX request, and then translate the response back from AX to sreg.&amp;#160; Woot.&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=XR1ybdKL2JA:jAD80MlkTJA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=XR1ybdKL2JA:jAD80MlkTJA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=XR1ybdKL2JA:jAD80MlkTJA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=XR1ybdKL2JA:jAD80MlkTJA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=XR1ybdKL2JA:jAD80MlkTJA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=XR1ybdKL2JA:jAD80MlkTJA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=XR1ybdKL2JA:jAD80MlkTJA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=XR1ybdKL2JA:jAD80MlkTJA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/XR1ybdKL2JA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/1752187103953460465/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/09/how-to-easily-fetch-openid-attributes.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/1752187103953460465?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/1752187103953460465?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/XR1ybdKL2JA/how-to-easily-fetch-openid-attributes.html" title="How to easily fetch OpenID attributes, regardless of the Provider" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/09/how-to-easily-fetch-openid-attributes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cCQH0_fSp7ImA9WxJVEUw.&quot;"><id>tag:blogger.com,1999:blog-6894552.post-2253850765828953916</id><published>2009-06-27T08:04:00.001-07:00</published><updated>2009-06-27T08:04:21.345-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-27T08:04:21.345-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OAuth" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="InfoCard" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenID" /><title>DotNetOpenAuth v3.2 is done</title><content type="html">&lt;p&gt;DotNetOpenAuth v3.2 just came off the presses.&amp;#160; &lt;i&gt;Lots&lt;/i&gt; of feature work and a few interop fixes in this release.&amp;#160; The biggest highlights being: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Very simple story for both RPs and OPs interested in interoperating with others whether they use sreg or one of the several AX formats (finally!) &lt;/li&gt;    &lt;li&gt;OAuth 1.0a support &lt;/li&gt;    &lt;li&gt;PPID generation for OPs to protect customers' privacy.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="https://www.ohloh.net/p/dotnetopenauth/download"&gt;Go download it&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;As usual, see our &lt;a href="http://dotnetopenauth.net:8000/wiki/VersionChanges#Version3.2"&gt;VersionChanges&lt;/a&gt; wiki page for a more complete list of the work done for v3.2.&amp;#160; (There are lots more noteworthy changes that I don't describe above).&lt;/p&gt;  &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h_IHh0wyms0:JRYCw-SE6xA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=h_IHh0wyms0:JRYCw-SE6xA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h_IHh0wyms0:JRYCw-SE6xA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h_IHh0wyms0:JRYCw-SE6xA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=h_IHh0wyms0:JRYCw-SE6xA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h_IHh0wyms0:JRYCw-SE6xA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?i=h_IHh0wyms0:JRYCw-SE6xA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/Jmpinline?a=h_IHh0wyms0:JRYCw-SE6xA:cGdyc7Q-1BI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/Jmpinline?d=cGdyc7Q-1BI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/Jmpinline/~4/h_IHh0wyms0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.nerdbank.net/feeds/2253850765828953916/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.nerdbank.net/2009/06/dotnetopenauth-v32-is-done.html#comment-form" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2253850765828953916?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6894552/posts/default/2253850765828953916?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/Jmpinline/~3/h_IHh0wyms0/dotnetopenauth-v32-is-done.html" title="DotNetOpenAuth v3.2 is done" /><author><name>Andrew Arnott</name><uri>https://plus.google.com/114635397638720587251</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-dETLr6cO5U0/AAAAAAAAAAI/AAAAAAABb40/1zTlXWcOsFk/s512-c/photo.jpg" /></author><thr:total>9</thr:total><feedburner:origLink>http://blog.nerdbank.net/2009/06/dotnetopenauth-v32-is-done.html</feedburner:origLink></entry></feed>
