tag:blogger.com,1999:blog-9037620065025712792024-03-07T04:33:50.671+01:00A blog about .net programming and web development.Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.comBlogger64125tag:blogger.com,1999:blog-903762006502571279.post-69617895048130926592013-10-03T09:31:00.001+02:002013-10-03T09:31:34.434+02:00Visual Studio setting of the day!<a href="http://stackoverflow.com/questions/7883966/disabling-highlighting-of-current-line-in-the-visual-studio-2012-editor">Disabling highlighting of current line in the Visual Studio 2012 editor - Stack Overflow</a>Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com1tag:blogger.com,1999:blog-903762006502571279.post-73162143508411805812013-07-07T11:31:00.001+02:002013-07-07T11:31:33.284+02:00Interesting internet findings (weekly)<ul class="diigo-linkroll"> <li> <p class="diigo-link"> <a href="http://geekswithblogs.net/sdorman/archive/2007/08/20/Difference-between-quotthrowquot-and-quotthrow-exquot-in-.NET.aspx">Difference between "throw" and "throw ex" in .NET</a> </p> <p class="diigo-description">Useful info on throw; vs throw ex;</p> <p class="diigo-tags"> <span>tags:</span> <a href="https://www.diigo.com/user/deap82/programming">programming</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a> <a href="https://www.diigo.com/user/deap82/.net">.net</a> <a href="https://www.diigo.com/user/deap82/exception">exception</a> <a href="https://www.diigo.com/user/deap82/trycatch">trycatch</a> <a href="https://www.diigo.com/user/deap82/c#">c#</a></p> </li> </ul><p class="diigo-ps">Posted from <a href='https://www.diigo.com'>Diigo</a>. The rest of my favorite links are <a href='https://www.diigo.com/user/deap82'>here</a>.</p>Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com4tag:blogger.com,1999:blog-903762006502571279.post-21317274408017732802013-05-26T12:31:00.001+02:002013-05-26T12:31:38.789+02:00Blogit (weekly)<ul class="diigo-linkroll"> <li> <p class="diigo-link"> <a href="http://www.hitreach.co.uk/perfect-web-page/">The Anatomy of a Perfect Web Page - Hit Reach</a> </p> <p class="diigo-description">Rejäl genomgång av en perfekt webbplats anatomi från Hit Reach (via @papperstiger)</p> <p class="diigo-tags"> <span>tags:</span> <a href="https://www.diigo.com/user/deap82/Webdesign">Webdesign</a> <a href="https://www.diigo.com/user/deap82/webstrategy">webstrategy</a> <a href="https://www.diigo.com/user/deap82/bestpractice">bestpractice</a> <a href="https://www.diigo.com/user/deap82/guidelines">guidelines</a> <a href="https://www.diigo.com/user/deap82/markup">markup</a> <a href="https://www.diigo.com/user/deap82/video">video</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a></p> </li> <li> <p class="diigo-link"> <a href="http://www.unheap.com/other/social-rss/chatjs/">6Unheap3 - 23A tidy repository of jQuery plugins6e</a> </p> <p class="diigo-description">ChatJs - Facebook style Instant messaging for your web app.</p> <p class="diigo-tags"> <span>tags:</span> <a href="https://www.diigo.com/user/deap82/jquery">jquery</a> <a href="https://www.diigo.com/user/deap82/chat">chat</a> <a href="https://www.diigo.com/user/deap82/signalr">signalr</a> <a href="https://www.diigo.com/user/deap82/programming">programming</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a></p> </li> </ul><p class="diigo-ps">Posted from <a href='https://www.diigo.com'>Diigo</a>. The rest of my favorite links are <a href='https://www.diigo.com/user/deap82'>here</a>.</p>Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-22531577871716859462013-05-05T12:31:00.001+02:002013-05-05T12:31:34.578+02:00Blogit (weekly)<ul class="diigo-linkroll"> <li> <p class="diigo-link"> <a href="http://blog.bufferapp.com/the-science-of-colors-in-marketing-why-is-facebook-blue?utm_source=buffer&utm_medium=twitter&utm_campaign=Buffer:%2BLeoWid%2Bon%2Btwitter&buffer_share=401d6">Why Facebook is blue: The science of colors in marketing - The Buffer Blog</a> </p> <p class="diigo-description">Why Facebook is blue: The science of colors in marketing http://t.co/H7NnoPdVKQ</p> <p class="diigo-tags"> <span>tags:</span> <a href="https://www.diigo.com/user/deap82/Webdesign">Webdesign</a> <a href="https://www.diigo.com/user/deap82/usability">usability</a> <a href="https://www.diigo.com/user/deap82/Colors">Colors</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a></p> </li> </ul><p class="diigo-ps">Posted from <a href='https://www.diigo.com'>Diigo</a>. The rest of my favorite links are <a href='https://www.diigo.com/user/deap82'>here</a>.</p>Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-16802276505365231042013-04-28T12:31:00.001+02:002013-04-28T12:31:34.542+02:00Blogit (weekly)<ul class="diigo-linkroll"> <li> <p class="diigo-link"> <a href="http://www.codeproject.com/Articles/140911/log4net-Tutorial">log4net Tutorial - CodeProject</a> </p> <p class="diigo-description">A nice tutorial on logging in .Net with log4net.</p> <p class="diigo-tags"> <span>tags:</span> <a href="https://www.diigo.com/user/deap82/programming">programming</a> <a href="https://www.diigo.com/user/deap82/log4net">log4net</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a></p> </li> </ul><p class="diigo-ps">Posted from <a href='https://www.diigo.com'>Diigo</a>. The rest of my favorite links are <a href='https://www.diigo.com/user/deap82'>here</a>.</p>Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-83696839429109989292013-04-21T12:31:00.001+02:002013-06-07T06:44:25.791+02:00Blogit (weekly)<ul class="diigo-linkroll">
<li> <div class="diigo-link">
<a href="http://misko.hevery.com/code-reviewers-guide/">Guide: Writing Testable Code</a> </div>
<div class="diigo-description">
Interesting guide about writing testable code.</div>
<div class="diigo-tags">
tags: <a href="https://www.diigo.com/user/deap82/programming">programming</a> <a href="https://www.diigo.com/user/deap82/testing">testing</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a></div>
</li>
<li> <div class="diigo-link">
<a href="http://minifesto.org/">Manifesto for Minimalist Software Engineers | Minifesto.org</a> </div>
<div class="diigo-description">
Nice manifesto for team of developers.</div>
<div class="diigo-tags">
tags: <a href="https://www.diigo.com/user/deap82/programming">programming</a> <a href="https://www.diigo.com/user/deap82/manifesto">manifesto</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a></div>
</li>
<li> <div class="diigo-link">
<a href="http://www.joelonsoftware.com/articles/fog0000000069.html">Things You Should Never Do, Part I - Joel on Software</a> </div>
<div class="diigo-description">
Some good points on legacy code and why we are so eager to throw it away but shouldn't.</div>
<div class="diigo-tags">
tags: <a href="https://www.diigo.com/user/deap82/oldcode">oldcode</a> <a href="https://www.diigo.com/user/deap82/refactoring">refactoring</a> <a href="https://www.diigo.com/user/deap82/programming">programming</a> <a href="https://www.diigo.com/user/deap82/blogit">blogit</a> <a href="https://www.diigo.com/user/deap82/apnpost">apnpost</a></div>
<ul class="diigo-annotations">
<li> <div class="diigoContent">
<div class="diigoContentInner">
It’s harder to read code than to write it. This is why code reuse is so hard. This is why everybody on your team has a different function they like to use for splitting strings into arrays of strings.</div>
</div>
</li>
<li> <div class="diigoContent">
<div class="diigoContentInner">
The idea that new code is better than old is patently absurd. Old code has been <i>used</i>. It has been <i>tested</i>. <i>Lots</i> of bugs have been found, and they've been <i>fixed</i>.</div>
</div>
</li>
<li> <div class="diigoContent">
<div class="diigoContentInner">
Each of these bugs took weeks of real-world usage before they were found. The programmer might have spent a couple of days reproducing the bug in the lab and fixing it. If it's like a lot of bugs, the fix might be one line of code, or it might even be a couple of characters, but a lot of work and time went into those two characters.</div>
</div>
</li>
<li> <div class="diigoContent">
<div class="diigoContentInner">
These problems can be solved, one at a time, by carefully moving code, refactoring, changing interfaces.</div>
</div>
</li>
<li> <div class="diigoContent">
<div class="diigoContentInner">
Even fairly major architectural changes can be done without <i>throwing away the code</i>.</div>
</div>
</li>
<li> <div class="diigoContent">
<div class="diigoContentInner">
So half the functions started with "_" and half with "m_", which looked ugly. Frankly, this is the kind of thing you solve in five minutes with a macro in Emacs, not by starting from scratch.</div>
</div>
</li>
<li> <div class="diigoContent">
<div class="diigoContentInner">
You're just going to make most of the old mistakes again, and introduce some new problems that weren't in the original version.</div>
</div>
</li>
</ul>
</li>
</ul>
<div class="diigo-ps">
Posted from <a href="https://www.diigo.com/">Diigo</a>. The rest of my favorite links are <a href="https://www.diigo.com/user/deap82">here</a>.</div>
Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-52103333480808211202012-07-23T16:21:00.001+02:002012-07-23T16:21:19.916+02:00Compare better in TFS with WinMerge<p>At my new job I’ve moved from Subversion to TFS for source control managing. Today I reacted over the fact that the compare algorithm in the built in compare tool is really bad. I had pretty much only removed some unnecessary try/catch blocks and that made the whole block of code look replaced/edited in the TFS compare view.</p> <p>I was pleased to <a href="http://www.google.com" target="_blank">google</a> out that the wonderful <a href="http://winmerge.org/" target="_blank">WinMerge</a> application can be used as a compare tool and decided instantly <a href="http://jonfuller.codingtomusic.com/2008/08/26/tfs-using-winmerge-as-your-mergediff-tool/" target="_blank">to do the necessary setting</a>. Now I got a much better compare view where I could see what actually changed.</p> <p>For best change comparison in WinMerge I prefer to make sure the following options are checked:</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/TFS-can-use-WinMerge-as-compare-tool_E2CF/winmergecomparesettings.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="winmergecomparesettings" border="0" alt="winmergecomparesettings" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/TFS-can-use-WinMerge-as-compare-tool_E2CF/winmergecomparesettings_thumb.png" width="549" height="459" /></a></p> <p>And if you’re using the merge features of WinMerge and are certain about what you do I would deactivate the creation of backup files by unchecking “Folder compare” and “File compare” on the “Backup files” page of the WinMerge options dialogue. That way you wont end up with a lot of ugly .bak files all over the place.</p> <p>What Compare/Merge tool do you like?</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com1tag:blogger.com,1999:blog-903762006502571279.post-27892351006512715952012-06-21T15:40:00.001+02:002012-06-21T15:53:18.552+02:00EPiServer backend interface only partially loaded in Internet Explorer<p>Long time no see! Since last time I’ve switched employer and I’m currently in over my head learning about all the wonders that is the <a href="http://www.episerver.com" target="_blank">EPiServer</a> CMS system as an employee at <a href="http://www.knowit.se" target="_blank">Knowit</a>.</p> <p>Today I was setting up the <a href="http://demo.episerver.com" target="_blank">Tech Alloy sample site</a> using the <a href="http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-6-R2/EPiServer-Deployment-Center/" target="_blank">EPiServer Deployment Center</a> and once I got it running, <a href="http://sdk.episerver.com/library/cms6/Developers%20Guide/Setting%20Up%20a%20New%20EPiServer%20Site%20with%20Visual%20Studio.htm#create_roles" target="_blank">created a user and logged in</a> I could not access the <em>right click EPiServer context menu</em> and when browsing to the backend I got this weird look:</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/EPiServer-backend-interface-only-partial_D620/01epweird.png"><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="" border="0" alt="EpiServer not fully loaded." src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/EPiServer-backend-interface-only-partial_D620/01epweird_thumb.png" width="644" height="399" /></a></p> <p>It was as if some client side errors caused the interface not to load correctly… After some clicking around I asked my colleague Kim and it turns out that in Windows Server environments there is something called Internet Explorer Enhanced Security (IE ESC) enabled by default which disables a lot of javascript stuff in IE (I’m running in a <a href="http://www.vmware.com/" target="_blank">VM</a> with Windows Server 2008 R2 x64). So he pointed me to Server Manager –> Configure IE ESC where I could turn this off:</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/EPiServer-backend-interface-only-partial_D620/02epiweird_ieescoff.png"><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="02epiweird_ieescoff" border="0" alt="Turning IE Enhanced Security off" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/EPiServer-backend-interface-only-partial_D620/02epiweird_ieescoff_thumb.png" width="669" height="449" /></a></p> <p>Et voila, now the backend user interface works:</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/EPiServer-backend-interface-only-partial_D620/03epiweird_working.png"><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="" border="0" alt="EPiServer backend working" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/EPiServer-backend-interface-only-partial_D620/03epiweird_working_thumb.png" width="682" height="774" /></a></p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com12tag:blogger.com,1999:blog-903762006502571279.post-73916893302355032032011-06-05T17:08:00.001+02:002011-06-05T17:08:20.272+02:00Finally replaced my w3 schools bookmarks<p>Some while ago I found <a href="http://www.w3fools.com" target="_blank">w3fools.com</a> and today I’ve finally replaced my css/html/javascript reference bookmarks to that site with other alternatives; these are the ones I chose from the w3fools recommendations and my own quick inspections:</p> <p><a href="http://www.w3.org/wiki/HTML/Elements" target="_blank">HTML/Elements</a></p> <p><a href="http://reference.sitepoint.com/css" target="_blank">CSS Reference</a></p> <p><a href="https://developer.mozilla.org/en/DOM" target="_blank">DOM Reference</a></p> <p><a href="https://developer.mozilla.org/en/JavaScript/Reference" target="_blank">JavaScript Reference</a></p> <p><a href="http://htmlhelp.com/reference/html40/entities/" target="_blank">HTML 4 Entities</a></p> <p><a href="http://jsfiddle.net/" target="_blank">jsFiddle</a></p> <p>Please read more on why you should not use w3schools at <a href="http://www.w3fools.com" target="_blank">w3fools.com</a>.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-37972301012667769322011-03-09T19:59:00.000+01:002011-03-09T20:00:32.120+01:00Facebook documentation requires login, stopper for generating code? :-/<p>Tonight I’ve ran into a real obstacle with generating code from the Facebook online documentation. Please see my post on the <a href="http://forum.developers.facebook.net/" target="_blank">Facebook Developer Forum</a> here:</p> <p><a title="http://forum.developers.facebook.net/viewtopic.php?pid=323044#p323044" href="http://forum.developers.facebook.net/viewtopic.php?pid=323044#p323044">http://forum.developers.facebook.net/viewtopic.php?pid=323044#p323044</a></p> <p>If this isn’t resolved, it’ll be a real stopper for generating code from the documentation… :-/</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com12tag:blogger.com,1999:blog-903762006502571279.post-39394561526279850662011-03-06T16:21:00.001+01:002011-03-06T16:21:04.180+01:00Taking a stab at generating strongly typed Facebook Graph C# classes for .Net/Asp.Net<p>During the last few weeks I’ve finally continued working on a Facebook application project I started probably over a year ago. </p> <p>First of all I upgraded the application to use the new open source <a href="http://facebooksdk.codeplex.com/" target="_blank">Facebook C# SDK</a>, this seems to be the one used and I really like it even though Facebook has another <a href="http://developers.facebook.com/blog/post/395/" target="_blank">“Official” one</a> that seems pretty... Small.</p> <p>The Facebook C# SDK utilises the .Net 4.0 dynamic type to create a very light-weight and flexible frame work, which I actually think is very good. You can read more about the thoughs on this approach <a href="http://ntotten.com/2010/08/dynamic-csharp-with-frequently-changing-web-services/" target="_blank">here</a> and <a href="http://ntotten.com/2010/09/dynamic-objects-and-the-facebook-c-sdk/" target="_blank">here</a>. The SDK has methods for sending Get, Post, Delete and FQL Query request to the Facebook APIs, as well as authenticating to get the access tokens needed. the Get method also comes in a generic version allowing you to choose whether you want to create strongly typed classes or not and directly deserealize the API results to these types (using <a href="http://json.codeplex.com/" target="_blank">Json.Net</a>).</p> <p>However, working with strongly typed objects are kinda nice ;-) and with my recent learnings about code generation in Visual Studio using <a href="http://msdn.microsoft.com/en-us/library/bb126445.aspx" target="_blank">T4 text templates</a> I started playing with the thought of generating these classes directly from <a href="http://developers.facebook.com/docs/reference/api/" target="_blank">Facebooks online documentation of the Graph API objects</a>. I found that this was <a href="http://facebooksdk.codeplex.com/discussions/233753" target="_blank">not a new idea</a> but I decided to give it a go, in part cause what I would learn from it, but also because, as already stated in above linked blog posts, the Facebook APIs are really big and extensive, and managing classes and methods for all this manually would be a nightmare indeed – and boring. While writing T4 templates is quite fun :-).</p> <p>Before reading further you should probably be acquainted with the following: <br /><a title="http://developers.facebook.com/docs/reference/api/" href="http://developers.facebook.com/docs/reference/api/" target="_blank">http://developers.facebook.com/docs/reference/api/</a> <br /><a title="http://developers.facebook.com/docs/authentication/" href="http://developers.facebook.com/docs/authentication/" target="_blank">http://developers.facebook.com/docs/authentication/</a> <br /><a title="http://json.codeplex.com/" href="http://json.codeplex.com/" target="_blank">http://json.codeplex.com/</a></p> <p><strong>Have a look at the source</strong> <br />I have checked in the workings described in this blog post as a fork to the <a href="http://facebooksdkcontrib.codeplex.com" target="_blank">Facebook C# SDK Contrib</a> project, you can have a look at the described check-in <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/e9d8a04d42c4#" target="_blank">here</a> while reading this post (my stuff is located in the Facebook.Entities folder, which is a new and separate assembly). Please note that the classes that are generated from the <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/e9d8a04d42c4#Source%2fFacebook.Entities%2fGraph%2fGraphEntities.tt" target="_blank">GraphEntities.tt</a> file are not included in the checked in code.</p> <strong>Finding the patterns</strong> <br />After inspecting <a href="http://developers.facebook.com/docs/reference/api/" target="_blank">the documentation pages</a> I found usable patterns in the markup and with the help of the <a href="http://htmlagilitypack.codeplex.com/" target="_blank">HtmlAgilityPack</a> I started to write my text template where I parse the documentation pages to produce one class for each object that is listed in the left side menu. I call these classes “First level classes”. Inside these classes I generate properties for all of the Properties and Connections. <p><strong>Determining the types of properties and generating helper classes</strong> <br />This is what the generated ID and From properties looks like in the <a href="http://developers.facebook.com/docs/reference/api/message/" target="_blank">Message</a> class:</p> <pre class="code"><span style="color: gray">///<summary>
///</span><span style="color: green">The unique ID for this message. Permissions: read_mailbox.
</span><span style="color: gray">///</span><span style="color: green">Returns JSON string.
</span><span style="color: gray">///</summary>
</span>[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"id"</span>)]
<span style="color: blue">public string </span>ID { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
<span style="color: gray">///<summary>
///</span><span style="color: green">The sender of this message. Permissions: read_mailbox.
</span><span style="color: gray">///</span><span style="color: green">Returns a JSON object that contains the name, email and Facebook id (if available) of the sender.
</span><span style="color: gray">///</summary>
</span>[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"from"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">From </span>From { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</pre>
<p>The first row in each summary XML comment is the text contents from the Description and Permissions columns from the documentation page. The second row is the text content from the Returns column and this is what I’ve used to determine what type the property should have. “JSON string” is simple, it results in a string property. When it comes to the From property you can see that it is of type “From”. This is also a generated class that is created from the returns information, I call these classes “Helper classes”:</p>
<pre class="code"><span style="color: gray">///<summary>
///</span><span style="color: green">A JSON object that contains the name, email and Facebook id (if available) of the sender
</span><span style="color: gray">///</summary>
</span>[<span style="color: #2b91af">JsonObject</span>(<span style="color: #2b91af">MemberSerialization</span>.OptIn)]
<span style="color: blue">public partial class </span><span style="color: #2b91af">From
</span>{
[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"name"</span>)]
<span style="color: blue">public string </span>Name { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"email"</span>)]
<span style="color: blue">public string </span>Email { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"id"</span>)]
<span style="color: blue">public string </span>ID { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
}</pre>
<p>This is possible thanks to the fact that the words “name”, “email” and “id” are marked up as <code> html elements in Facebooks documentation. The types for these properties are a bit harder to determine in a certain way. For now I’m associating different names to specific types and if the property has a “non listed” name I’m falling back on string. It is a concern that this is a bit fragile.</p>
<p>A very common combination of properties in these HelperClasses turned out to be two string properties named “id” and “name”. So I decided to <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/e9d8a04d42c4#Source%2fFacebook.Entities%2fIdName.cs" target="_blank">handcode a class</a> for that and use that whenever that combination was found instead of generating yet another helper class. Thats why the from property in the <a href="http://developers.facebook.com/docs/reference/api/album/" target="_blank">Album</a> class is generated like this:</p>
<pre class="code"><span style="color: gray">///<summary>
///</span><span style="color: green">The profile that created this album. Permissions: Publicly available.
</span><span style="color: gray">///</span><span style="color: green">Returns a JSON object containing the id and name fields.
</span><span style="color: gray">///</summary>
</span>[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"from"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">IdName </span>From { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</pre>
<p><strong>Connection properties</strong>
<br />The connection properties are properties that requires another data fetch from the Facebook API and the Json is always formatted as an object with a “data” property containing an array of objects and a “paging” property containing url strings for “previous” and “next”. For this I created the <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/e9d8a04d42c4#Source%2fFacebook.Entities%2fDataContainer.cs" target="_blank">generic DataContainer class</a> and this is what the generated Friends property looks like in the <a href="http://developers.facebook.com/docs/reference/api/user/" target="_blank">User</a> class:</p>
<pre class="code"><span style="color: blue">private </span><span style="color: #2b91af">DataContainer</span><<span style="color: #2b91af">IdName</span>> _friends;
<span style="color: gray">///<summary>
///</span><span style="color: green">The user's friends. Permissions: Available to everyone on Facebook.
</span><span style="color: gray">///</span><span style="color: green">An array of JSON objects containing friend id and name fields.
</span><span style="color: gray">///</span><span style="color: green">This Connection Property requires UserAccessToken to be set on instance before it is accessed.
</span><span style="color: gray">///</span><span style="color: green">To force refresh from Facebook servers after first access (by instance), set RefreshFriends to true before accessing again.
</span><span style="color: gray">///</summary>
</span>[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"friends"</span>)]
<span style="color: blue">public </span><span style="color: #2b91af">DataContainer</span><<span style="color: #2b91af">IdName</span>> Friends
{
<span style="color: blue">get
</span>{
<span style="color: blue">this</span>.EnsureUserAccessToken();
<span style="color: blue">if </span>(_friends == <span style="color: blue">null </span>|| <span style="color: blue">this</span>.RefreshFriends)
{
_friends = <span style="color: blue">new </span><span style="color: #2b91af">FacebookClient</span>().Get<<span style="color: #2b91af">DataContainer</span><<span style="color: #2b91af">IdName</span>>>(<span style="color: blue">this</span>.ID + <span style="color: #a31515">"/friends/?access_token=" </span>+ <span style="color: blue">this</span>.UserAccessToken + <span style="color: #a31515">""</span>) ?? <span style="color: blue">new </span><span style="color: #2b91af">DataContainer</span><<span style="color: #2b91af">IdName</span>>().InitEmpty();
<span style="color: blue">this</span>.RefreshFriends = <span style="color: blue">false</span>;
}
<span style="color: blue">return </span>_friends;
}
}
<span style="color: blue">public bool </span>RefreshFriends { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</pre>
<p>This introduces some new requirements. First of all, the Facebook.Entities dll has a dependency towards the Facebook.dll from the Facebook C# SDK, so that data for the connection properties can be fetched using the FacebookClient class. To fetch data you need to include an access_token in the request, so all first level classes will be generated to inherit from the <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/e9d8a04d42c4#Source%2fFacebook.Entities%2fGraph%2fGraphEntityBase.cs" target="_blank">GraphEntityBase</a> class. This class defines a property called UserAccessToken that needs to be set before you access a Connection Property that requires the access_token to make the call. The method EnsureUserAccessToken is called from each property before making requests and will throw an exception if the UserAccessToken is not set, to avoid unnecessary calls to the Facebook API. </p>
<p>This is how you would get the current users friends in your application:</p>
<pre class="code"><span style="color: #2b91af">User </span>currentUser = <span style="color: blue">new </span><span style="color: #2b91af">FacebookClient</span>().Get<<span style="color: #2b91af">User</span>>(<span style="color: #a31515">"me/?access_token=ACCESSTOKEN"</span>);
currentUser.UserAccessToken = <span style="color: #a31515">"ACCESSTOKEN"</span>;
<span style="color: #2b91af">DataContainer</span><<span style="color: #2b91af">IdName</span>> friends = currentUser.Friends;</pre>
<p>As you can see in the code for the property it uses lazy initalization and caches the friends list in a private member and returns that if you access the Friends property repeatedly on the same instance. This is also to avoid unnecessary calls to the Facebok API. If you want to force fresh data from the Facebook API on a subsequent access to the property you must set the generated RefreshFriends property to true before accessing the Friends property again.</p>
<p><em>When it comes to caching and getting fresh data Facebook advices you to make use of the <a href="http://developers.facebook.com/docs/api/realtime/" target="_blank">Real-time updates API</a> and that is something I’ve been working on including support for in this framework, and I will cover the progress on that in a later blog post. (really, you’ll wanna check this out, I’m working on a solution where you’ll be able to configure what real time updates you want to subscribe to in web.config and then the generated classes and some other code will take care of the rest ;-)</em></p>
<p><strong>Picture connection properties</strong>
<br />There is one exception when it comes to the Connection properties and that is the connection properties named “picture”. Due to that, this is what is generated for a Picture property when it is publicly available. Just assign any of these string properties to the ImageUrl of an Image control and the picture will be displayed:</p>
<pre class="code"><span style="color: gray">///<summary>
///</span><span style="color: green">The user's profile picture. Permissions: Publicly available.
</span><span style="color: gray">///</span><span style="color: green">Returns a HTTP 302 with the URL of the user's profile picture (use ?type=small | normal | large to request a different photo).
</span><span style="color: gray">///</summary>
</span><span style="color: blue">public string </span>Picture { <span style="color: blue">get </span>{ <span style="color: blue">return </span><span style="color: #2b91af">Utils</span>.GetGraphBaseUrl() + <span style="color: blue">this</span>.ID + <span style="color: #a31515">"/picture?"</span>; } }
<span style="color: gray">///<summary>
///</span><span style="color: green">The user's profile picture. Size small. Permissions: Publicly available.
</span><span style="color: gray">///</span><span style="color: green">Returns a HTTP 302 with the URL of the user's profile picture (use ?type=small | normal | large to request a different photo).
</span><span style="color: gray">///</summary>
</span><span style="color: blue">public string </span>PictureSmall { <span style="color: blue">get </span>{ <span style="color: blue">return </span><span style="color: #2b91af">Utils</span>.GetGraphBaseUrl() + <span style="color: blue">this</span>.ID + <span style="color: #a31515">"/picture?&type=small"</span>; } }
<span style="color: gray">///<summary>
///</span><span style="color: green">The user's profile picture. Size normal. Permissions: Publicly available.
</span><span style="color: gray">///</span><span style="color: green">Returns a HTTP 302 with the URL of the user's profile picture (use ?type=small | normal | large to request a different photo).
</span><span style="color: gray">///</summary>
</span><span style="color: blue">public string </span>PictureNormal { <span style="color: blue">get </span>{ <span style="color: blue">return </span><span style="color: #2b91af">Utils</span>.GetGraphBaseUrl() + <span style="color: blue">this</span>.ID + <span style="color: #a31515">"/picture?&type=normal"</span>; } }
<span style="color: gray">///<summary>
///</span><span style="color: green">The user's profile picture. Size large. Permissions: Publicly available.
</span><span style="color: gray">///</span><span style="color: green">Returns a HTTP 302 with the URL of the user's profile picture (use ?type=small | normal | large to request a different photo).
</span><span style="color: gray">///</summary>
</span><span style="color: blue">public string </span>PictureLarge { <span style="color: blue">get </span>{ <span style="color: blue">return </span><span style="color: #2b91af">Utils</span>.GetGraphBaseUrl() + <span style="color: blue">this</span>.ID + <span style="color: #a31515">"/picture?&type=large"</span>; } }</pre>
<p><strong>When the type can’t be determined
<br /></strong>If the type for a property in a “first level class” can not be determined from the Returns information I’m falling back on dynamic. This is what the generated Actions property looks like in the <a href="http://developers.facebook.com/docs/reference/api/post/" target="_blank">Post</a> class:</p>
<pre class="code"><span style="color: gray">///<summary>
///</span><span style="color: green">A list of available actions on the post (including commenting, liking, and an optional app-specified action). Permissions: read_stream.
</span><span style="color: gray">///</span><span style="color: green">Returns a list of JSON objects containing the 'name' and 'link'.
</span><span style="color: gray">///</span><span style="color: green">Type for property actions could not be auto-generated from Facebook online documentation. Use this dynamic implementation or check for, or hand-code, property named Actions in partial class definition.
</span><span style="color: gray">///</summary>
</span>[<span style="color: #2b91af">JsonProperty</span>(<span style="color: #a31515">"actions"</span>)]
<span style="color: blue">public <strong>dynamic</strong> </span>ActionsDynamic { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }</pre>
<p>This allows me to work with the Actions data in my strongly typed class, but for this particular property I will have to check out the Facebook documentation to see what type it is and what properties it has. The reason that the type for this specific property can’t be determined is an irregularity in the facebook documentation where the words “name” and “link” in the returns column are NOT marked up with <code> html elements. I have found a few of these irregularities and documented them in <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/e9d8a04d42c4#Source%2fFacebook.Entities%2fnotes.txt" target="_blank">notes.txt</a>. I will probably post these documentation corrections/change suggestions in the <a href="http://forum.developers.facebook.net/" target="_blank">Facebook Developer Forum</a>.</p>
<p>Before commenting the “Dynamic” added to the property name, let’s discuss the Facebook.Entities assembly; I think the approach must be that the Facebook.Entities assembly actually should be released as a downloadable C# Class Library project and not as a compiled dll. It could be part of the Facebook C# SDK or it could be stand alone. Either way you can use it only in projects where you determine that strongly typed classes are of certain interest. If so, you should include it as a project in your Facebook application solution and be able to extend the generated classes. This would allow you to hand code the properties that can’t be strongly typed generated, and that’s why I leave the name “Actions” available to implement. (The hand coded implementation could also be included in the project, in that scenario I would probably introduce three partial class definitions; one generated, one project maintained and one that by default is empty but meant for you to use to include any type of custom stuff you might want there. The last set of files would never be updated in the project and should not be replaced when you download a new version of the library ).</p>
<p>However, JSON.net introduces a problem in this case, because you can’t reference the same property name in two different JsonProperty attributes within the same class. And since I must be able to de/serialize the generated classes I must use the facebook api names in these attributes. Because of this I’ve made <a href="http://json.codeplex.com/discussions/248604" target="_blank">this suggestion</a> in the JSON.net project.</p>
<p><strong>Going forward
<br /></strong>Although there certainly are some problems with generating these classes I think these numbers looks pretty good:</p>
<pre class="code"><span style="color: green">/*
The GraphEntities.tt of Facebook.Entities can currently generate
- 19 first level classes
with a total of 156 properties, 3 were generated as dynamic.
with a total of 88 connection properties, 9 were generated as dynamic.
- 38 helper classes.
- 2 helper enums.
*/
</span></pre>
<p>The code I’ve produced so far certainly hasn’t been very tested but I will use this in the Facebook application I’ll be releasing within a couple of weeks. I’ll keep you posted on how it goes. If you’re interested in contributing to this work I’d be happy to get in contact with anyone that has some experience in unit testing that could help me out on how to make this code testable and write tests for it.</p>
<p>As I mentioned I’ve been working on including support for the Real-time Updates API, and a first version of this is already checked in <a href="http://facebooksdkcontrib.codeplex.com/SourceControl/network/Forks/deap82/StronglyTypedFacebookEntities/changeset/view/8d404045e6e8" target="_blank">here</a>. I will cover this in a later blog post.</p>
<p>Please let me know your reactions, thoughts and ideas on this.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com8tag:blogger.com,1999:blog-903762006502571279.post-62877214586433995032010-11-28T10:45:00.001+01:002010-11-28T10:45:38.104+01:00The C# Todoist API on CodePlex<p>Today I’ve created a CodePlex project for a Todoist C# Class Library I’ve built.</p> <p>Please check it out at <a href="http://todoistapi.codeplex.com" target="_blank">http://todoistapi.codeplex.com</a></p> <p>The reason for building this has primarily been to enable to convert my Todoist items to iCal and have them displayed in my google calendar. You can also use this service through my new labs site. Have a look at <a title="http://labs.deap.nu/Labs/TodoistIcal/TodoistIcal.aspx" href="http://labs.deap.nu/Labs/TodoistIcal/TodoistIcal.aspx" target="_blank">http://labs.deap.nu/Labs/TodoistIcal/TodoistIcal.aspx</a></p> <p>Anyway, thats probably why the API currently only contains functionality for reading data. But the <a href="http://todoist.com/API/help" target="_blank">Todoist API at todoist.com</a> certainly exposes methods to make it possible to add items, projects etc. If you are planning to do any kind of Todoist integration from a .net application, please contribute to this class library to make it mirror the Todoist API completely. You can request to join the project at codeplex and check out the source code with Tortoise SVN.</p> <p>If you’ve never heard of Todoist, check out <a href="http://todoist.com/" target="_blank">todoist.com</a>, it’s a really great tool for keeping track of stuff to do :-).</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com6tag:blogger.com,1999:blog-903762006502571279.post-91540519468039904082010-07-24T18:25:00.001+02:002010-07-24T18:25:08.376+02:00A little gift for my Stockholm Pride fellas<p>The upcoming week Stockholm Pride will take over my home city with lots of colorful people and events. The official site, <a href="http://www.stockholmpride.org" target="_blank">www.stockholmpride.org</a>, has a great program feature where you can put together your own program for the week. However, it lacked the possibility to export the events in a format accepted by calendar applications such as Apple iCal, Google Calendar and Outlook.</p> <p>So, deap comes to the rescue; I spent last eventing and a good part of this morning putting together a little service that parses your personalized program and exports the events as an <a href="http://en.wikipedia.org/wiki/ICalendar" target="_blank">.ics</a>-file.</p> <p>The original idea was to load the program page url with the help of the .net <a href="http://msdn.microsoft.com/en-us/library/system.net.webclient%28VS.80%29.aspx" target="_blank">WebClient</a> class, but for some reason the program event elements wasn’t included in the response stream I got. I’m guessing that they probably are being loaded through ajax but didn’t investigate it further. Instead I made some instructions on how to download the file as html and then upload that to my application where the parsing will take place.</p> <p>To parse the HTML I made a quick google and decided to make use of the <a href="http://htmlagilitypack.codeplex.com/" target="_blank">HTML Agility Pack</a>, and some nifty XPath (<a href="http://www.tizag.com/xmlTutorial/xpathtutorial.php" target="_blank">see this tutorial</a>) and Regular Expressions. I’ve never used this library before and it’s been a couple of years since I wrote some XPath, but it was really easy to get started. When it came to generating the .ics-file in a proper format, which caused some trouble, I got great help from this <a href="http://severinghaus.org/projects/icv/" target="_blank">.ics validator</a>.</p> <p>I also decided to give a go at adding the internet invading <a href="http://developers.facebook.com/docs/reference/plugins/like" target="_blank">Facebook Like button</a> AND a <a href="http://www.facebook.com/share/" target="_blank">share</a> ;-).</p> <p>You can check the result out at <a href="http://pride.deap.nu" target="_blank">http://pride.deap.nu</a>, but be aware, it’s all in swedish ;-).</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-34930860127845812010-05-18T19:34:00.001+02:002010-05-18T19:34:54.579+02:00A great tool for capturing a part of your screen<p>Continuing my <a href="http://ondotnet.deap.nu/2010/05/my-developer-toolbox.html">previous post on great tools</a> I use for developing I also thought I’d share this one that might be a bit off topic.</p> <p><a href="http://cropper.codeplex.com/" target="_blank">Cropper</a> is a great and simple program to use for capturing a part of your screen. Mostly I set it to capture to the clipboard and then I can easily paste the picture to <a href="http://windowslivewriter.spaces.live.com/" target="_blank">Windows Live Writer</a> (that I use when blogging here) or an email or directly in to Live Messenger whenever I want to share some ideas or get feedback on a design (or why not some code) from a colleague. Just double click to capture.</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Agreattoolforcapturingapartofyourscreen_1135E/image.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Agreattoolforcapturingapartofyourscreen_1135E/image_thumb.png" width="537" height="406" /></a> </p> <p>Get it <a href="http://cropper.codeplex.com/" target="_blank">here</a>.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-60579754424704792432010-05-08T08:06:00.001+02:002010-05-08T09:26:42.998+02:00Failing to create a Visual Studio add-in<p>This morning I’ve been trying to create a Visual Studio add-in with VS 2010. But I ran into problems as described here: <a title="http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/06a32084-301c-47e5-be46-0c93ddd249ec" href="http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/06a32084-301c-47e5-be46-0c93ddd249ec" target="_blank">http://social.msdn.microsoft.com/Forums/en-US/vsx/thread/06a32084-301c-47e5-be46-0c93ddd249ec</a></p> <p>So, I’ll be waiting for an answer before I give another go at it…</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com2tag:blogger.com,1999:blog-903762006502571279.post-36699505989982233072010-05-06T19:03:00.001+02:002010-05-06T19:03:15.207+02:00My developer toolbox<p>Here is a list of software tools (and one online service) that has become invaluable to me when developing, besides Visual Studio of course. ;-) </p> <p><strong>MGLine</strong> <br />This simple, but yet so great, program is a desktop ruler that easily lets you measure pixels on the screen. Great when working with css and webdesigns. I got this from a colleague when doing my gymnasium internship like ten years ago. Never found it on the web, so I decided to share it with you here: <a title="https://secure1.storegate.com/Shares/Home.aspx?ShareID=36905e2d-e6a7-461e-96f5-ee6a56aa25fc" href="https://secure1.storegate.com/Shares/Home.aspx?ShareID=36905e2d-e6a7-461e-96f5-ee6a56aa25fc" target="_blank">Download MGLine</a> and unzip the file where you want the program on your computer and run the executable.</p> <p><a href="http://getfirebug.com/" target="_blank">FireBug</a> <br />I hope no one working with css and html has missed this extension for FireFox. If you have, get it now!</p> <p><strong>Tortoise-SVN and xp-dev.com</strong> <br /><a href="http://tortoisesvn.tigris.org/" target="_blank">Tortoise-SVN</a> is a windows client for the popular open source source control software Subversion. I use it to manage my subversion repositories hosted for free at <a href="http://www.xp-dev.com" target="_blank">xp-dev.com</a>. They also have a good enough task handling system that I use in some projects (based on <a href="http://www.extremeprogramming.org/" target="_blank">XP programming</a> principles). Tortoise integrates with Windows Explorer.</p> <p><a href="http://ankhsvn.open.collab.net/" target="_blank">AnkhSvn</a> <br />Another open source client for Subversion, with the big difference that this one integrates into Visual Studio. Great stuff.</p> <p><a href="http://www.devexpress.com/Products/Visual_Studio_Add-in/CodeRushX/" target="_blank">CodeRush Xpress</a> <br />Totally invaluable extension to Visual Studio. Have not yet tried the 2010 edition but the features for 2008 certainly made my life easier and has saved me a ton of time. Make sure you check out the introductory video.</p> <p><a href="http://www.red-gate.com/products/reflector/" target="_blank">Reflector</a> <br />Have a look at the code in any .net assembly, such as the .net framework itself. A bit tricky to navigate but good when you need to know whats actually going on inside controls and other framework classes.</p> <p><a href="http://www.red-gate.com/products/SQL_Search/index.htm" target="_blank">SQL Search</a> <br />Quite a new free tool from RedGate that extends SQL Server Management Studio with the ability to search on columnnames, tablenames etc within your database. It even searches within the text of your stored procedures and functions which can be quite handy when refactoring becomes inevitable.</p> <p><a href="http://winmerge.org/" target="_blank">WinMerge</a> <br />Another great open source tool for comparing and merging files. This can also be used as the compare tool opened from Tortoise-SVN menu options.</p> <p><a href="http://filezilla-project.org/" target="_blank">FileZilla</a> <br />A free ftp client where my favourite feature is “synchronized browsing”.</p> <p>I think that’s about it, for now anyways. What tools do you use? Please share!</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-26153595464253468792010-05-05T19:54:00.001+02:002010-05-05T19:54:43.442+02:00A few things you might not now about the asp:Panel-control<p>The DefaultButton property let’s you specify the ID of a button control. Doing this will hook this button to the Enter key whenever any type of input control within the panel is focused.</p> <p>Setting the GroupingText property results in the following accessible friendly markup using fieldset and legend-elements;</p> <pre class="code"><span style="color: blue"><</span><span style="color: maroon">div </span><span style="color: red">id</span><span style="color: blue">="pnl">
<</span><span style="color: maroon">fieldset</span><span style="color: blue">>
<</span><span style="color: maroon">legend</span><span style="color: blue">></span>GroupingText value goes here<span style="color: blue"></</span><span style="color: maroon">legend</span><span style="color: blue">>
</span>Panel content is rendered here
<span style="color: blue"></</span><span style="color: maroon">fieldset</span><span style="color: blue">>
</</span><span style="color: maroon">div</span><span style="color: blue">>
</span></pre> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com1tag:blogger.com,1999:blog-903762006502571279.post-76221474945251340932010-05-04T19:32:00.001+02:002010-05-04T19:32:34.968+02:00I love Xmarks and Delicious<p>I just have to say, syncing your bookmarks between browsers and computers using xmarks is absolutely super duper perfect! It’s totally indispensible when reinstalling an old or installing a new computer. And as a bonus, all your bookmarks are backed up. Automatically. I also use the profile feature which lets me choose what bookmarks I want available at home, at work and both. Check it out at <a href="http://www.xmarks.com" target="_blank">xmarks.com</a>!</p> <p>I use Xmarks primarily for the links bar in the browser, other bookmars I save online on <a href="http://www.delicious.com" target="_blank">Delicious</a>. Of course my links bar contains a shortcut to my delicious as well as a shortcut to save the current page to delicious. You can check out my programming related bookmarks to the left here on the blog or at <a href="http://www.delicious.com/deap82/programming" target="_blank">http://www.delicious.com/deap82/programming</a></p> <p>My blogging has been a bit so and so lately, I’ll try to att least share some links and quick tips from now on. So, stay tuned.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-37555221463761817452009-09-05T08:20:00.001+02:002009-09-05T08:22:48.726+02:00The asp.net RegularExpressionValidator email regex does not validate all valid e-mailaddresses<p>In a project I’ve been working on I discovered that the Visual Studo built in regex for email that you get when you work with the <u>RegularExpressionValidator</u> doesn’t work for some email addresses that actually are valid. This goes for email addresses that has for example a hyphen (-) or a dot (.) directly in front of the @, i.e. emailme-@hotmail.com.</p> <p>The built in regular expression looks like this:</p> <pre class="code">\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*</pre>
<p>There are a lot of resources on RegEx on the web so I wont walk it through, let’s just take a look at the problem described above and modify it instead of googling up a working one.</p>
<p>The second instance of \w+ means word boundary, 1 or more times. Change this + to a * to say 0 or more times instead. So now the complete regular expression looks like this:</p>
<pre class="code">\w+([-+.']\w<strong>*</strong>)*@\w+([-.]\w+)*\.\w+([-.]\w+)*</pre>
<a href="http://11011.net/software/vspaste"></a>
<p>Now all I want is a way to save this change in Visual Studio.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com5tag:blogger.com,1999:blog-903762006502571279.post-19489577597138496642009-05-01T12:37:00.001+02:002009-05-02T09:09:59.448+02:00A pattern for sharing code between LINQ data objects<p><strong><font color="#ff0000">(2009-05-02 Important update below!)</font></strong></p> <p><strong>Scenario:</strong> <br />You have a lot of tables in your database with columns such as <u>EditDate</u> and <u>UpdateByUserId</u> and you're using <u>Linq</u> as your data access method. </p> <p><strong>Problem: <br /></strong>Instead of updating these columns all over the place in your code, you want a centralized solution to make sure that these columns are updated whenever an entity is changed. </p> <p><strong>Discussion and Solution:</strong> <br /><em>Disclaimer: This is what I've come up with, please comment on it should you see any problems with it. This article will assume experience with working with Linq and object oriented programming.</em> </p> <p>To keep this example lean and simple we will have only one common column between our entities. I will use the <u>Northwind</u> database, however I have edited the <u>Customers</u> and <u>Products</u> table, adding an <u>EditDate</u> column of type <u>datetime</u>. </p> <p>This of course means that when the Linq to SQL classes are generated (the <u>.dbml </u>file) both the <u>Product </u>and the <u>Customer </u>class will have an <u>EditDate </u>property. My first take on this was to create a superclass and force the <u>Product </u>and <u>Customer </u>classes to inherit from it through a custom <em>partial </em>class definition, like so:</p> <pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">Entity
</span>{
<span style="color: green">//Property definition copied from Product
//class in Northwind.designer.cs, “abstract” added:
</span><span style="color: blue">public abstract </span>System.<span style="color: #2b91af">Nullable</span><System.<span style="color: #2b91af">DateTime</span>> EditDate { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
}
<span style="color: blue">public partial class </span><span style="color: #2b91af">Product </span>: <span style="color: #2b91af">Entity
</span>{
}
<span style="color: blue">public partial class </span><span style="color: #2b91af">Customer </span>: <span style="color: #2b91af">Entity
</span>{
}</pre>
<p><a href="http://11011.net/software/vspaste"></a>However, this gives some errors and warnings:</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image.png"><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="194" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_thumb.png" width="547" border="0" /></a> </p>
<p>As you can see in the warnings, a solution to this would be to go in to the dbml-file and change the <u>EditDate</u> property in each class to be an <u>override</u>;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_3.png"><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="386" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_thumb_3.png" width="597" border="0" /></a></p>
<p>But I don’t really like this solution since this would require me to do this whenever I’ve changed something in the <u>Customer</u> table and regenerates this class… It seems to me that leaving the <u>.dbml </u>file (and it’s designer.cs code behind) <em>as is </em>is more maintainable. This is also the reason why I inherit from my <u>Entity </u>superclass in partial class definitions (of <u>Product </u>and <u>Customer</u>) instead of editing the <u>Northwind.designer.cs </u>file directly. This is possible thanks to the fact that the Linq generated classes are declared as partial.</p>
<p>So, my next approach was to create an <u>interface </u>with the shared property definition and then implement that <u>interface </u>through my partial class definitions;</p>
<pre class="code"><span style="color: blue"><strong>interface </strong></span><strong><span style="color: #2b91af">IEntity
</span>{</strong>
<span style="color: green">//Property definition copied from Product
//class in Northwind.designer.cs:
<strong> </strong></span><strong>System.<span style="color: #2b91af">Nullable</span><System.<span style="color: #2b91af">DateTime</span>> EditDate { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
}</strong>
<span style="color: blue">public partial class </span><span style="color: #2b91af">Product </span>: <span style="color: #2b91af"><strong>IEntity</strong>
</span>{
}
<span style="color: blue">public partial class </span><span style="color: #2b91af">Customer </span>: <span style="color: #2b91af"><strong>IEntity</strong>
</span>{
}</pre>
<a href="http://11011.net/software/vspaste"></a>
<p><a href="http://11011.net/software/vspaste"></a>And this actually compiles just fine. As you can see, my partial class definitions <em>does not</em> implement the <u>EditDate</u> property, but the partial classes in the designer.cs file <em>does</em>.</p>
<p>But hey now, I wanted to share <em>code</em> between my entities. There is no way to share code via an interface… So, we actually have to combine this with a superclass that requires it’s inheritors to implement <u>IEntity</u>. That way we can work with the common column in code inside of that class. Let’s first have a look at the new Entity class;</p>
<pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">Entity
</span>{
<span style="color: blue">public </span>Entity()
{
<span style="color: blue">if </span>(!(<span style="color: blue">this is </span><span style="color: #2b91af">IEntity</span>))
{
<span style="color: blue">throw new </span><span style="color: #2b91af">Exception</span>(<span style="color: #a31515">"Class that inherits from Entity must also implement IEntity."</span>);
}
}
}</pre>
<p>I don’t know any programmatic way of enforcing the combination of class inheritance with a specific interface, so as you can see above I use the default constructor to check if the current object (<u>this</u>) <em>is </em>an <u>IEntity</u>. If not the exception message will hopefully give the developer running this code some hint on what to do. With this validation in place, the <u>Entity </u>will now be able to access members through the <u>IEntity </u>interface.</p>
<p>The Linq entity classes (<u>Product </u>and <u>Customer </u>in the designer.cs file) exposes an event of particular interest, the <u>PropertyChanged </u>event. This event is raised whenever a property value of such an object is changed. Thankfully, the event has the exact same name in all (both) classes, so let’s add this to our <u>IEntity </u>interface so that we can access it in the <u>Entity </u>superclass;</p>
<pre class="code"><span style="color: blue">interface </span><span style="color: #2b91af">IEntity
</span>{
<strong><span style="color: green"> </span><span style="color: blue">event </span><span style="color: #2b91af">PropertyChangedEventHandler </span>PropertyChanged;</strong>
System.<span style="color: #2b91af">Nullable</span><System.<span style="color: #2b91af">DateTime</span>> EditDate { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a>Now, we can add some code to the Entity class;</p>
<pre class="code"><span style="color: blue">public abstract class </span><span style="color: #2b91af">Entity
</span>{
<strong> <span style="color: blue">private </span><span style="color: #2b91af">IEntity </span>_entity;</strong>
<span style="color: blue">public </span>Entity()
{
<span style="color: blue">if </span>(!(<span style="color: blue">this is </span><span style="color: #2b91af">IEntity</span>)) { /.../ }
<strong> _entity = (<span style="color: #2b91af">IEntity</span>)<span style="color: blue">this</span>;
_entity.PropertyChanged +=
<span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedEventHandler</span>(_entity_PropertyChanged);</strong>
}
<strong> <span style="color: blue">void </span>_entity_PropertyChanged(<span style="color: blue">object </span>sender, <span style="color: #2b91af">PropertyChangedEventArgs </span>e)
{
_entity.EditDate = <span style="color: #2b91af">DateTime</span>.Now;
}</strong>
}</pre>
<a href="http://11011.net/software/vspaste"></a>
<p>First of all I have added a private class member of type <u>IEntity</u>, this is assigned in the constructor and now I can easily access all the members of the <u>IEntity </u>interface (which actually will run code in the generated designer.cs-file!).</p>
<p>To achieve my goal I hook up a method to the PropertyChanged event and in that method i update the EditDate property.</p>
<div style="border-right: red 1px solid; padding-right: 5px; border-top: red 1px solid; padding-left: 5px; padding-bottom: 5px; border-left: red 1px solid; padding-top: 5px; border-bottom: red 1px solid">
<p style="margin: 0px"><strong>UPDATE 090502:</strong> When debugging the code today I found that the above eventhandler method causes an infinite loop. This is not strange since the change of <u>EditDate</u> also will trigger the <u>PropertyChanged</u> event. To handle this, the following <u>if</u> statement is added to the method;</p>
<pre class="code"><span style="color: blue">void </span>_entity_PropertyChanged(<span style="color: blue">object </span>sender, <span style="color: #2b91af">PropertyChangedEventArgs </span>e)
{
<strong> <span style="color: blue">if </span>(e.PropertyName != <span style="color: #a31515">"EditDate"</span>)
{</strong>
_entity.EditDate = <span style="color: #2b91af">DateTime</span>.Now;
<strong> }</strong>
}</pre>
<p>The <u>PropertyName</u> property and the <u>PropertyChangedEventArgs</u> gives me the name of the property that got changed causing the <u>PropertyChanged</u> event to trigger. By checking that this isn’t equal to “EditDate” I can update the value of <u>EditDate</u>. This will cause the event to trigger again, but this time <u>e.PropertyName</u> <em>will have</em> the value of “EditDate” so the <u>if</u> statement will be skipped. Should you add code that also updates an UpdatedByUserId field, this too has to be checked in the <u>if</u> statement.</p>
</div>
<p>Before we can test this, we must update the partial class definitions so that they inherit from the Entity class;</p>
<pre class="code"><span style="color: blue">public partial class </span><span style="color: #2b91af">Product </span>: <strong><span style="color: #2b91af">Entity</span>,</strong> <span style="color: #2b91af">IEntity
</span>{
}
<span style="color: blue">public partial class </span><span style="color: #2b91af">Customer </span>: <strong><span style="color: #2b91af">Entity</span>,</strong> <span style="color: #2b91af">IEntity
</span>{
}</pre>
<a href="http://11011.net/software/vspaste"></a>
<p>With this in place we can run some simple code to see that it works;</p>
<pre class="code"><span style="color: #2b91af">NorthwindDataContext </span>dc = <span style="color: blue">new </span><span style="color: #2b91af">NorthwindDataContext</span>();
dc.Products.First().ProductName = <span style="color: #a31515">"Altered Product Name"</span>;
dc.Customers.First().ContactName = <span style="color: #a31515">"Altered Contact Name"</span>;
dc.SubmitChanges();</pre>
<p><a href="http://11011.net/software/vspaste"></a>After this code is run, we can have a look in the database and find that the EditDate column of both tables also has been updated on these posts;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_4.png"><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="192" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_thumb_4.png" width="369" border="0" /></a> </p>
<p><strong>Conclusion:
<br /></strong>Using this approach I have achieved a solution that allows me to share code between classes generated from the <u>.dbml</u>-file without creating any work when a regeneration of the file is needed. The only thing I have to remember to do is when I add a new entity (table) to the <u>.dbml </u>file that also has these common columns, then I have to make sure I create a partial class definition that makes the class inherit from the <u>Entity </u>class and implement <u>IEntity</u>, and that’s it;</p>
<pre class="code"><span style="color: blue">public partial class </span><span style="color: #2b91af">Order </span>: <span style="color: #2b91af">Entity</span>, <span style="color: #2b91af">IEntity </span>{ <span style="color: green">/* An empty class */ </span>}</pre>
<p>No code is needed in this class defintion, the requirements of the <u>IEntity</u> interface should be fulfilled in the generated part of the class (that is based on your db design). (However, these class definitions might come in handy for other purposes.)</p>
<p>Here is a class diagram giving you an overview of the pattern;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_5.png"><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="310" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ApatternforsharingcodebetweenLINQdataobj_B18C/image_thumb_5.png" width="565" border="0" /></a> </p>
<p>The three bottom classes are the ones generated from the .<u>dbml </u>file, remember though that the Product and Customer class are complemented with partial class definitions that makes them inherit from <u>Entity </u>and implement <u>IEntity</u>.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-64948029213580725932009-03-31T14:17:00.001+02:002009-03-31T14:19:19.995+02:00A SQL case: The INTERSECT statement<p>I decided to explore another SQL case that also is inspired by <a href="http://www.facebook.com/" target="_blank">Facebook</a>. When you visit a friends profile you can see what friends you and he/she have in common.</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image.png"><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="157" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb.png" width="207" border="0" /></a> </p> <p>I have extended the database from my <a href="http://ondotnet.deap.nu/2009/03/sql-case-relating-groups-based-on.html">previous post</a> to include a <u>FriendRelations</u> table with the following columns and relations to the <u>Persons</u> table;</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_3.png"><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="99" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_3.png" width="497" border="0" /></a> </p> <p>As in the previous post this is a many-to-many relationship, but it’s a bit special since the foreign keys of the relation table points to <em>the same </em>primary key. This means that a person can be friend with a person in two different ways, either via the <u>PersonId1</u> column <em>or </em>the <u>PersonId2</u> column. Let’s have a look at the test data before we continue;</p> <p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_4.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="194" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_4.png" width="350" border="0" /></a> <em> <br />(In my previous post i accidentally named two persons “Spiderman”, one of them is now changed to “Superman”)</em></p> <p>So, for example, the first row to the right means that “Spiderman” and “Superman” are friends with each other. Another example is that “Superman” is friends with “Spiderman”, “Catwoman” and “Tintin”.</p> <p>In this case there will be two given <u>PersonId</u>s, one that represents the currently logged in user (this might come from a session variable) and one that represents the person profile the user is currently visiting (this might come from a querystring variable). In the following SQL commands these IDs will be hardcoded, I will use 4 (“Spiderman”) as the logged in user and 1 (“Superman”) as the ID of the visited profile. If you study the data above you can see that both these persons are friends with “Catwoman”, so this is the final result set we want from our SQL question;</p> <table cellspacing="0" cellpadding="2" width="196" border="1"><tbody> <tr> <th valign="top" width="90">PersonId</th> <th valign="top" width="104">PersonName</th> </tr> <tr> <td valign="top" width="90">5</td> <td valign="top" width="104">Catwoman</td> </tr> </tbody></table> <p>Let’s start with getting all the friends that “Superman” (<u>PersonId</u> = 1) has;</p> <pre class="code"><span style="color: blue">SELECT
</span>PersonId<span style="color: gray">, </span>PersonName
<span style="color: blue">FROM
</span>Persons <span style="color: blue">AS </span>p <span style="color: gray">INNER JOIN </span>FriendRelations <span style="color: blue">AS </span>fr
<span style="color: blue">ON </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId1
<span style="color: blue">WHERE
</span>fr<span style="color: gray">.</span>PersonId2 <span style="color: gray">= </span>1</pre>
<a href="http://11011.net/software/vspaste"></a>
<p></p>
<p>This will give the following result set;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_5.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="90" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_5.png" width="186" border="0" /></a> </p>
<p>But wait a minute, “Superman” is also friends with “Tintin”, where did he go? In the above SQL we only get friends where “Superman” is connected through the <u>PersonId2</u> column of the <u>FriendRelations</u> table. We need to work some more SQL magic to include friends that are connected through <u>PersonId1</u> as well. Let’s give it a shot;</p>
<pre class="code"> <span style="color: blue">SELECT
</span>PersonId<span style="color: gray">, </span>PersonName
<span style="color: blue">FROM
</span>Persons <span style="color: blue">AS </span>p <span style="color: gray">INNER JOIN </span>FriendRelations <span style="color: blue">AS </span>fr
<span style="color: blue">ON </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId1 <strong><span style="color: gray">OR </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId2</strong>
<span style="color: blue">WHERE
</span>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">= </span>1 <strong><span style="color: gray">OR </span>fr<span style="color: gray">.</span>PersonId2 <span style="color: gray">= </span>1</strong></pre>
<a href="http://11011.net/software/vspaste"></a>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_6.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; margin: 0px 5px 0px 0px; border-left: 0px; border-bottom: 0px" height="161" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_6.png" width="177" align="left" border="0" /></a></p>
<p></p>
<p></p>
<p>So we add some <u>OR</u> statements to the <u>JOIN</u> and the <u>WHERE</u>, but this resultset still looks a bit odd. It does include “Tintin” but “Superman” isn’t friends with himself and he certainly isn’t friends with himself three times over! However there’s nothing strange with this result, since the SQL above will give us all rows that has <em>any</em> connection with <u>PersonId</u> 1 in the <u>FriendRelations</u> table. So, let’s just filter “Superman” out!</p>
<p> </p>
<pre class="code"><span style="color: blue">SELECT
</span>PersonId<span style="color: gray">, </span>PersonName
<span style="color: blue">FROM
</span>Persons <span style="color: blue">AS </span>p <span style="color: gray">INNER JOIN </span>FriendRelations <span style="color: blue">AS </span>fr
<span style="color: blue">ON </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">OR </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId2
<span style="color: blue">WHERE
<strong> </strong></span><strong>p<span style="color: gray">.</span>PersonId <span style="color: gray"><> </span>1
<span style="color: gray">AND (</span></strong>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">= </span>1 <span style="color: gray">OR </span>fr<span style="color: gray">.</span>PersonId2 <span style="color: gray">= </span>1<span style="color: gray"><strong>)</strong></span></pre>
<p>And now we get all the persons that are friends with “Superman” and nothing else;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_7.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="109" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_7.png" width="176" border="0" /></a>
<br /><em>Friends with “Superman”</em></p>
<p>And if we run the very same SQL statement but exchange the 1 for a 4, we get all persons that are friends with “Spiderman”;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_8.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="109" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_8.png" width="176" border="0" /></a>
<br /><em>Friends with “Spiderman”</em></p>
<p>As you can see if you compare these result sets, the only friend they have in common is “Catwoman”. To get only that row in the result set we can separate both our <u>SELECT</u> statements (the one with a 1 and the one with a 4) with <u>INTERSECT</u> and only get those rows that <em>both</em> of the <u>SELECT</u> statements have <em>in common</em>;</p>
<pre class="code"><span style="color: blue">SELECT
</span>PersonId<span style="color: gray">, </span>PersonName
<span style="color: blue">FROM
</span>Persons <span style="color: blue">AS </span>p <span style="color: gray">INNER JOIN </span>FriendRelations <span style="color: blue">AS </span>fr
<span style="color: blue">ON </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">OR </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId2
<span style="color: blue">WHERE
</span>p<span style="color: gray">.</span>PersonId <span style="color: gray"><> </span><strong>1</strong>
<span style="color: gray">AND (</span>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">= </span><strong>1</strong> <span style="color: gray">OR </span>fr<span style="color: gray">.</span>PersonId2 <span style="color: gray">= </span><strong>1</strong><span style="color: gray">)
</span><span style="color: blue"><strong>INTERSECT</strong>
SELECT
</span>PersonId<span style="color: gray">, </span>PersonName
<span style="color: blue">FROM
</span>Persons <span style="color: blue">AS </span>p <span style="color: gray">INNER JOIN </span>FriendRelations <span style="color: blue">AS </span>fr
<span style="color: blue">ON </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">OR </span>p<span style="color: gray">.</span>PersonId <span style="color: gray">= </span>fr<span style="color: gray">.</span>PersonId2
<span style="color: blue">WHERE
</span>p<span style="color: gray">.</span>PersonId <span style="color: gray"><> </span><strong>4</strong>
<span style="color: gray">AND (</span>fr<span style="color: gray">.</span>PersonId1 <span style="color: gray">= </span><strong>4</strong> <span style="color: gray">OR </span>fr<span style="color: gray">.</span>PersonId2 <span style="color: gray">= </span><strong>4</strong><span style="color: gray">)</span></pre>
<a href="http://11011.net/software/vspaste"></a>
<p></p>
<p>And finally we get the expected resultset;</p>
<p><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_9.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="67" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseTheINTERSECTstatement_C8E9/image_thumb_9.png" width="170" border="0" /></a> </p>
<p>Download the database <a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/groupDb.zip">here</a>, this database also includes the final SQL command as a stored procedure.</p>
<p>Note, for an <u>INTERSECT</u> to work, the two <u>SELECT</u> statements has to have identical column lists, at least when it comes to type. In this case it is <u>PersonId</u> (<u>int</u>) and <u>PersonName</u> (<u>varchar</u>).</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com2tag:blogger.com,1999:blog-903762006502571279.post-56317756829872509562009-03-28T12:02:00.001+01:002009-03-28T12:02:10.540+01:00A SQL case: Relating groups based on membership relations<p>The other day when I visited a group page on <a href="http://www.facebook.com" target="_blank">Facebook</a> and looked at the "Related groups" section I started to think about how that SQL question might be implemented.</p> <p><img height="234" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseRelatinggroupsbasedonmembershipr_A77B/image.png" width="210" border="0" />  <br /><em>Screen capture from the MSDN Sweden Facebook group.</em></p> <p>This is not a list that the group owner can control, instead the list automatically shows groups that has a lot of members in common with the group you're currently visiting.</p> <p>Without any knowledge of Facebooks design for this, let's assume that the database structure is like this, a very ordinary many-to-many relationship:</p> <p><img height="113" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseRelatinggroupsbasedonmembershipr_A77B/image_3.png" width="740" border="0" /> </p> <p>To have some test data I filled these tables with the following data.</p> <p><img height="301" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseRelatinggroupsbasedonmembershipr_A77B/image_4.png" width="561" border="0" /> </p> <p>As you can see the "Comic Book Characters" and the "Superheroes" groups have a lot of members in common while the "Celebrities" group is an island.</p> <p>So, based on a given <u>GroupId</u>, how can we get a resultset that lists all of the other groups with a column that specifies the amount of shared members? Let's build this step by step, in fact I do this as I'm writing so the final solution is not totally clear to me yet, even though I have some idea. If you want to follow along and run these SQL commands you can download the database file <a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/GroupDb.zip" target="_blank">here</a> (this database also includes the final SQL command as a stored procedure). </p> <p>Let's say that the given <u>GroupId</u> is 2 (so this might come from a querystring or some other input, in these commands the number 2 will be hard coded). This means that the final result we want is this:</p> <table cellspacing="0" cellpadding="3" width="396" border="1"><tbody> <tr> <th valign="top" width="92">GroupId</th> <th valign="top" width="161">GroupName</th> <th valign="top" width="141">SharedMemberCount</th> </tr> <tr> <td valign="top" width="94">1</td> <td valign="top" width="155">Comic Book Characters</td> <td valign="top" width="147">4</td> </tr> <tr> <td valign="top" width="94">3</td> <td valign="top" width="152">Celebrities</td> <td valign="top" width="152">0</td> </tr> </tbody></table> <p>Let's start with selecting all groups except the given one;</p> <pre class="code"><span style="color: blue">SELECT
</span>GroupId<span style="color: gray">, </span>GroupName
<span style="color: blue">FROM
</span>Groups
<strong><span style="color: blue">WHERE
</span>GroupId <span style="color: gray"><> 2</span></strong></pre>
<p><a href="http://11011.net/software/vspaste"></a>Now, we will need a nested select statement to add the third column, I usually put the outer structure in place, and then I start writing the <u>SELECT</u> statement within the parenthesis:</p>
<pre class="code"><span style="color: blue">SELECT
</span>GroupId<span style="color: gray">, </span>GroupName<span style="color: gray">,
<strong>(</strong></span><strong><span style="color: blue">SELECT </span><em>something</em><span style="color: gray">) </span><span style="color: blue">AS </span>SharedMemberCount</strong>
<span style="color: blue">FROM
</span>Groups
<span style="color: blue">WHERE
</span>GroupId <span style="color: gray"><> 2</span></pre>
<p>Let's start with <strong>just counting the total numbers</strong> of members in each group, to do this the <u>Groups</u> table needs an alias so that we can distinguish the two <u>GroupId</u> columns;</p>
<pre class="code"><span style="color: blue">SELECT
</span>GroupId<span style="color: gray">, </span>GroupName<span style="color: gray">,
(</span><strong><span style="color: blue">SELECT
</span><span style="color: magenta">COUNT</span></strong><span style="color: gray"><strong>(*)
</strong></span><strong><span style="color: blue">FROM
</span>PersonGroupMemberships <span style="color: blue">AS </span>pgm
</strong><strong><span style="color: blue">WHERE
</span>pgm<span style="color: gray">.</span>GroupId <span style="color: gray">= </span>g<span style="color: gray">.</span>GroupId</strong>
<span style="color: gray">) </span><span style="color: blue">AS </span>SharedMemberCount
<span style="color: blue">FROM
</span>Groups <strong><span style="color: blue">AS </span>g</strong>
<span style="color: blue">WHERE
</span>GroupId <span style="color: gray"><> 2</span></pre>
<p>This is the current resultset;</p>
<p> <img height="74" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseRelatinggroupsbasedonmembershipr_A77B/image_5.png" width="349" border="0" /> </p>
<p>Now we need to filter the inner select so that it only counts the members that are also members in the given group (<u>GroupId</u>=2).</p>
<pre class="code"><span style="color: blue">SELECT
</span>GroupId<span style="color: gray">, </span>GroupName<span style="color: gray">,
(</span><span style="color: blue">SELECT
</span><span style="color: magenta">COUNT</span><span style="color: gray">(*)
</span><span style="color: blue">FROM
</span>PersonGroupMemberships <span style="color: blue">AS </span>pgm
<span style="color: blue">WHERE
</span>pgm<span style="color: gray">.</span>GroupId <span style="color: gray">= </span>g<span style="color: gray">.</span>GroupId
<strong><span style="color: gray">AND </span>pgm<span style="color: gray">.</span>PersonId </strong><strong><span style="color: gray">IN
(</span><span style="color: blue">SELECT </span>PersonId
<span style="color: blue">FROM </span>PersonGroupMemberships
<span style="color: blue">WHERE </span>GroupId<span style="color: gray">=2</span></strong><span style="color: gray"><strong>)</strong>
) </span><span style="color: blue">AS </span>SharedMemberCount
<span style="color: blue">FROM
</span>Groups <span style="color: blue">AS </span>g
<span style="color: blue">WHERE
</span>GroupId <span style="color: gray"><> 2</span></pre>
<a href="http://11011.net/software/vspaste"></a>
<p>And really, this was no brain surgery. We simply say that the <u>PersonId</u> of the rows we count has to have a value that corresponds to <em>any </em><u>PersonId</u> that is a member of group 2 by using the <u>IN</u> statement and yet another nested <u>SELECT</u> statement.</p>
<p>Next we should add sorting so that the groups with the most shared members comes on top, I also add a <u>TOP</u> statement since we probably just want the most related groups, not all groups. These changes wont make any difference with this testdata, but they would if we had more groups:</p>
<pre class="code"><span style="color: blue">SELECT <strong>TOP </strong></span><strong>4</strong>
GroupId<span style="color: gray">, </span>GroupName<span style="color: gray">,
(</span><span style="color: blue">SELECT
</span><span style="color: magenta">COUNT</span><span style="color: gray">(*)
</span><span style="color: blue">FROM
</span>PersonGroupMemberships <span style="color: blue">AS </span>pgm
<span style="color: blue">WHERE
</span>pgm<span style="color: gray">.</span>GroupId <span style="color: gray">= </span>g<span style="color: gray">.</span>GroupId
<span style="color: gray">AND </span>pgm<span style="color: gray">.</span>PersonId <span style="color: gray">IN
(</span><span style="color: blue">SELECT </span>PersonId
<span style="color: blue">FROM </span>PersonGroupMemberships
<span style="color: blue">WHERE </span>GroupId<span style="color: gray">=2</span><span style="color: gray">)
) </span><span style="color: blue">AS </span>SharedMemberCount
<span style="color: blue">FROM
</span>Groups <span style="color: blue">AS </span>g
<span style="color: blue">WHERE
</span>GroupId <span style="color: gray"><> </span>2
<strong><span style="color: blue">ORDER BY
</span>SharedMemberCount <span style="color: blue">DESC</span></strong></pre>
<p>And now we get the resultset we wanted;</p>
<p> <img height="74" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/ASQLcaseRelatinggroupsbasedonmembershipr_A77B/image_6.png" width="349" border="0" /> </p>
<p><strong>To think about</strong>
<br />Of course you wouldn't want to display the "Celebrities" group in this case, since it has<em> no</em> members in common with the "Superheroes" group. How could you filter the resultset so that it only includes groups where <u>SharedMemberCount</u> is<em> more than</em> zero? You might wanna use <a href="http://ondotnet.deap.nu/2009/03/sql-select-from-your-select-filtering.html">this</a> technique.</p>
<p>(By the way, I have installed <a href="http://www.microsoft.com/express/sql/default.aspx" target="_blank">SQL Server 2008 Express</a>, and it gives neat intellisense when working with SQL queries! :-)</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com0tag:blogger.com,1999:blog-903762006502571279.post-34965786747671882422009-03-26T15:39:00.001+01:002009-03-26T15:39:37.673+01:00How to get javascript intellisense for Asp.NET AJAX in a usercontrol (ascx) file<p>To get javascript intellisense for <u>jQuery</u> and your own scripts inside a <u>usercontrol</u> file you can use the following hack at the top of the <u>ascx</u>-file (after the <u>@Control</u> directive).</p> <pre class="code"><span style="background: #ffee62"><%</span> <span style="color: blue">if </span>(<span style="color: blue">false</span>) { <span style="background: #ffee62">%>
</span> <span style="color: blue"><</span><span style="color: #a31515">script </span><span style="color: red">src</span><span style="color: blue">="scripts/jquery-1.3.2.js" </span><span style="color: red">type</span><span style="color: blue">="text/javascript"></</span><span style="color: #a31515">script</span><span style="color: blue">>
<</span><span style="color: #a31515">script </span><span style="color: red">src</span><span style="color: blue">="scripts/myScripts.js" </span><span style="color: red">type</span><span style="color: blue">="text/javascript"></</span><span style="color: #a31515">script</span><span style="color: blue">>
</span><span style="background: #ffee62"><%</span> } <span style="background: #ffee62">%></span></pre>
<p><a href="http://11011.net/software/vspaste"></a>This simply means that when you work with the file in Visual Studio, it will give you <u>intellisense</u> for these javascript libraries. But in runtime the <u>if</u> statement will be false so the scripts will not be included again (they shouldn't because they should already be included by the page that hosts the usercontrol. Remember, this hack is for Visual Studio javascript intellisense only).</p>
<p>But what about the Asp.NET AJAX framework (whit the <u>$get</u>, <u>$addHandler</u> methods etc...)? One workaround I figured out is to follow these steps:</p>
<ol>
<li>Load an <u>.aspx</u> page that contains a <u>ScriptManager</u> in your browser.
<br /></li>
<li>View the source and copy out the <u>src</u> for a script tag that contains <u>"ScriptResource.axd"</u> (marked text in this image):
<br /><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Howtogetja.NETAJAXinausercontrolascxfile_DBF2/image.png"><img height="194" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Howtogetja.NETAJAXinausercontrolascxfile_DBF2/image_thumb.png" width="571" border="0" /></a>
<br /> </li>
<li>Paste this after<u> localhost:<em>port</em></u> in the address field of the browser so that the script file loads (I only got this to work in Firefox):
<br /><a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Howtogetja.NETAJAXinausercontrolascxfile_DBF2/image_3.png"><img height="201" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Howtogetja.NETAJAXinausercontrolascxfile_DBF2/image_thumb_3.png" width="572" border="0" /></a>
<br /></li>
<li>If it starts with the comment in the image above, go on to the next step, if not return to step number two and get the next reference that includes <u>"ScriptResource.axd"</u>.
<br /></li>
<li>Once you've found the <u>MicrosoftAjax.debug.js</u> file, copy the entire contents, paste it into a <u>.js</u>-file and put it in your project.
<br /></li>
<li>Now you can reference that file from your <u>ascx</u> file and get intellisense for Asp.NET AJAX even in a <u>usercontrol</u> file: <a href="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Howtogetja.NETAJAXinausercontrolascxfile_DBF2/image_4.png"><img height="130" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/Howtogetja.NETAJAXinausercontrolascxfile_DBF2/image_thumb_4.png" width="737" border="0" /></a> </li>
</ol>
<p>Finally, an appropriate quote: "<a href="http://tiredblogger.wordpress.com/2007/07/11/table-joins-in-linq-good-bad-and-complexly-ugly/" target="_blank">Oh the troubles we put ourselves through for pretty IntelliSense.</a>".</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com2tag:blogger.com,1999:blog-903762006502571279.post-49791918767762339612009-03-20T14:46:00.001+01:002009-03-20T14:46:23.593+01:00Introducing the Ajax ColumnListBoxExtender<p><img src="http://ajaxcolumnlistbox.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=62076" /></p> <p>Today I'm proud to present the first release of my first open source project; The Ajax ColumnListBoxExtender. The idea of the control is to give the possibility to layout an asp:ListBox with a lot of options in multiple columns instead of one single column.</p> <p>Check out the project homepage at <a href="http://ajaxcolumnlistbox.codeplex.com">http://ajaxcolumnlistbox.codeplex.com</a> and the live samples and documentation at <a href="http://ajaxcolumnlistbox.deap.nu">http://ajaxcolumnlistbox.deap.nu</a>.</p> <p>I wont go in to the details of how this is developed, but it is open source so feel free to download the code from the project home page and have a look at it. I can say I've learned a lot both about javascript and Asp.NET AJAX developing this.</p> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com1tag:blogger.com,1999:blog-903762006502571279.post-39340031300070056362009-03-03T20:59:00.001+01:002009-03-03T21:18:07.179+01:00Lesson blog: Creating a plugin accepting application<p>Last week we had a lesson describing a simple sample of how you could create an application that accepts plugins, using an <u>interface </u>approach. This is my take on it;</p> <p>First of all you need to decide quite exactly <em>what</em> the plugin developer should be possible to do. For this example I have created a simple Win Forms application that shows a list of contacts and allows the user to edit the contacts.</p> <p>The Main Window of the application:</p> <p><img height="263" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/LessonblogCreatingapluginacceptingapplic_116FF/image.png" width="600" border="0" /></p> <p>When the user double clicks a contact a simple editing form is opened:</p> <p><img style="margin-right: 4px" height="203" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/LessonblogCreatingapluginacceptingapplic_116FF/image_3.png" width="271" align="left" border="0" /> </p> <p>When the user clicks Save this form is closed and any changes are reflected in the main window. But this form is quite dull and simple. Wouldn't it be cool if you could let some other developer attach a plugin to the application that will change the layout and possibly the behavior of this form? That's what we're going to do.</p> <p>I wont go into the details of how the above application is built, if you want to follow along download this starting point <a href="http://files.deap.nu/deap/blogger/remoteinc/deapondotnet/PluginSolution_StartingPoint.zip">here</a>. </p> <p>Some considerations has already been made when it comes to the plugin part, so lets have a look at the solution as it looks now;</p> <p><img height="263" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/LessonblogCreatingapluginacceptingapplic_116FF/image_4.png" width="258" align="right" border="0" /> </p> <p><em>PluginHost</em> is the <u>Windows Application </u>and <em>PluginLib</em> is a <u>Class Library </u>that is referenced by PluginHost. PluginLib contains the <u>Contact</u> business class that has one string property for each peace of data on each contact (i.e. Firstname, Lastname etc). This is a separate project because the resulting <u>dll</u> is what will be shared both by the Host application and any Plugin "applications".</p> <p>The host application is made up of two <u>Form</u> classes, <em>MainWindow</em> and <em>DefaultContactEditor</em>. Since the editor window might be replaced by a plugin some efforts has been made to keep as much logic as possible in the MainWindow class. Let's have a look att <em>some </em>of the code in the DefaultContactEditor class;</p> <pre class="code"><span style="color: blue">public </span><span style="color: #2b91af">Contact </span>ContactToEdit { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
<span style="color: blue">public event </span><span style="color: #2b91af">EventHandler </span>ContactSaved;
<span style="color: blue">public void </span>LoadContact(<span style="color: #2b91af">Contact </span>c)
{
tbFirstname.Text = c.FirstName;
tbLastname.Text = c.LastName;
tbEmail.Text = c.Email;
tbMSN.Text = c.MSN;
tbHomepage.Text = c.Homepage;
ContactToEdit = c;
}
<span style="color: blue">private void </span>SaveEditedContact()
{
ContactToEdit.FirstName = tbFirstname.Text;
ContactToEdit.LastName = tbLastname.Text;
ContactToEdit.Email = tbEmail.Text;
ContactToEdit.MSN = tbMSN.Text;
ContactToEdit.Homepage = tbHomepage.Text;
<span style="color: blue">if </span>(ContactSaved != <span style="color: blue">null</span>)
{
ContactSaved(<span style="color: blue">this</span>, <span style="color: #2b91af">EventArgs</span>.Empty);
}
}</pre>
<p><a href="http://11011.net/software/vspaste"></a>The <em>LoadContact</em> method is called from the MainWindow when the edit window is opened, and it fills up the windows textboxes with values from the given Contact object and assigns this object to the class member <em>ContactToEdit</em>. It is placed in a separate method instead of in the constructor, because later on an interface will require this method (ideally the interface should require a constructor receiving a contact object but as far as I know that is not possible).</p>
<p>The <em>SaveEditedContact</em> is called when the user clicks the save button in the edit window. This method ends by triggering the ContactSaved event that the MainWindow is listening to.</p>
<p>Now, let's have a look at <em>some</em> of the code in the MainWindow class;</p>
<pre class="code"><span style="color: blue">private void </span>lvContacts_MouseDoubleClick(<span style="color: blue">object </span>sender, <span style="color: #2b91af">MouseEventArgs </span>e)
{
<span style="color: blue">if </span>(lvContacts.SelectedItems.Count > 0)
{
<span style="color: #2b91af">Contact </span>selectedContact = (<span style="color: #2b91af">Contact</span>)lvContacts.SelectedItems[0].Tag;
<span style="color: #2b91af">DefaultContactEditor </span>editor = <span style="color: blue">new </span><span style="color: #2b91af">DefaultContactEditor</span>();
editor.LoadContact(selectedContact);
editor.ContactSaved += <span style="color: blue">new </span><span style="color: #2b91af">EventHandler</span>(editor_ContactSaved);
editor.Show();
}
}
<span style="color: blue">private void </span>editor_ContactSaved(<span style="color: blue">object </span>sender, <span style="color: #2b91af">EventArgs </span>e)
{
((<span style="color: #2b91af">Form</span>)sender).Close();
DisplayContacts();
}</pre>
<p><a href="http://11011.net/software/vspaste"></a>The first method here is an event handler for the double click event for the ListView control that lists the contacts in the main window. After assuring that one item is selected I get a reference to the selected <u>Contact</u> object and creates a new instance of the edit window. Here you can see the call to <u>LoadContact</u>. Also, you can see that the <u>ContactSaved </u>event is attached to the editor_ContactSaved method. This method will ensure that the edit window is closed when the contact is saved and it calls a method - DisplayContacts - that will redraw the ListView control reflecting any changes that might has been made.</p>
<p>Now to the plugin fixing. First, let's create an interface from some of the members in the DefaultContactEditor class. I call this interface IContactEditor and put it in the PluginLib project;</p>
<pre class="code"><span style="color: blue">public interface </span><span style="color: #2b91af">IContactEditor
</span>{
<span style="color: #2b91af">Contact </span>ContactToEdit { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
<span style="color: blue">event </span><span style="color: #2b91af">EventHandler </span>ContactSaved;
<span style="color: blue">void </span>LoadContact(<span style="color: #2b91af">Contact </span>c);
}</pre>
<a href="http://11011.net/software/vspaste"></a>
<p><a href="http://11011.net/software/vspaste"></a>After that I make sure that the DefaultContactEditor implements this interface, by adding it to the inheritance list;</p>
<pre class="code"><span style="color: blue">public partial class </span><span style="color: #2b91af">DefaultContactEditor </span>: <span style="color: #2b91af">Form</span><strong>, <span style="color: #2b91af">IContactEditor</span></strong></pre>
<p><a href="http://11011.net/software/vspaste"></a>Nothing more is needed here since the interface members already are implemented in DefaultContactEditor.</p>
<p>The idea now is to change the code that opens the editor window so that it uses a plugin if available and if not it will use the DefaultContactEditor. Let's start with creating a helper class in the PluginHost application;</p>
<pre class="code"><span style="color: blue">public static class </span><span style="color: #2b91af">PluginUtility
</span>{
<span style="color: blue">private const string </span>PLUGIN_PATH = <span style="color: #a31515">@"Plugins\"</span>;
<span style="color: blue">public static </span><span style="color: #2b91af">IContactEditor </span>GetEditorWindow()
{
<span style="color: #2b91af">IContactEditor </span>result = <span style="color: blue">null</span>;
<span style="color: blue">try
</span>{
<span style="color: blue">foreach </span>(<span style="color: blue">string </span>file <span style="color: blue">in </span><span style="color: #2b91af">Directory</span>.GetFileSystemEntries(PLUGIN_PATH, <span style="color: #a31515">"*.dll"</span>))
{
<span style="color: #2b91af">Assembly </span>dllAssembly = <span style="color: #2b91af">Assembly</span>.LoadFrom(file);
<span style="color: blue">foreach </span>(<span style="color: #2b91af">Type </span>t <span style="color: blue">in </span>dllAssembly.GetTypes())
{
<span style="color: green">//Find class that inherits from Form and implements IContactEditor
</span><span style="color: blue">if </span>(t.IsPublic && !t.IsAbstract &&
t.IsSubclassOf(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Form</span>)) &&
t.GetInterface(<span style="color: #a31515">"IContactEditor"</span>) != <span style="color: blue">null</span>)
{
result = (<span style="color: #2b91af">IContactEditor</span>)dllAssembly.CreateInstance(t.FullName);
<span style="color: blue">break</span>; <span style="color: green">//Exit foreach when plugin is found
</span>}
}
<span style="color: blue">if </span>(result != <span style="color: blue">null</span>)
<span style="color: blue">break</span>; <span style="color: green">//Exit foreach when plugin is found
</span>}
}
<span style="color: blue">catch </span>{ }
<span style="color: green">//If result still is null, return default contact editor
</span><span style="color: blue">if </span>(result == <span style="color: blue">null</span>)
{
result = <span style="color: blue">new </span><span style="color: #2b91af">DefaultContactEditor</span>();
}
<span style="color: blue">return </span>result;
}
}</pre>
<a href="http://11011.net/software/vspaste"></a>
<p><a href="http://11011.net/software/vspaste"></a><img height="144" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/LessonblogCreatingapluginacceptingapplic_116FF/image_5.png" width="243" align="right" border="0" /> First we declare a constant containing the relative path to the folder where the plugin has to be placed. This folder has to be created in the output directory of the application, i.e. bin/Debug.</p>
<p>To keep the example simple this application will only accept one plugin. That one plugin, if existing, will be found in the GetEditorWindow method that returns an IContactEditor. In the first foreach we loop all dll-files within the Plugins directory. Foreach dll we loop the types that exists in the dll and using an if statement we look for classes that are public, not abstract, that inherits from Form and implements IContactEditor. If such a type is found we call the CreateInstance method of the Assembly object, which will create an instance of the found type. This instance is cast to an IContactEditor and assigned to the result variable. After that we make sure we exit both foreach loops. If no plugin is found, the last if will be true and the result variable will be assigned an instance of the DefaultContactEditor class.</p>
<p>Now, the double click event of the Main Windows ListView could be updated as follows;</p>
<pre class="code"><span style="color: blue">private void </span>lvContacts_MouseDoubleClick(<span style="color: blue">object </span>sender, <span style="color: #2b91af">MouseEventArgs </span>e)
{
<span style="color: blue">if </span>(lvContacts.SelectedItems.Count > 0)
{
<span style="color: #2b91af">Contact </span>selectedContact = (<span style="color: #2b91af">Contact</span>)lvContacts.SelectedItems[0].Tag;
<span style="color: green">//OLD: DefaultContactEditor editor = new DefaultContactEditor();
</span><strong><span style="color: #2b91af">IContactEditor </span>editor = <span style="color: #2b91af">PluginUtility</span>.GetEditorWindow();</strong>
editor.LoadContact(selectedContact);
editor.ContactSaved += <span style="color: blue">new </span><span style="color: #2b91af">EventHandler</span>(editor_ContactSaved);
<span style="color: green">//OLD: editor.Show();
</span><strong>((<span style="color: #2b91af">Form</span>)editor).Show();</strong>
}
}</pre>
<a href="http://11011.net/software/vspaste"></a>
<p>Now lets build a plugin by adding another class library to the solution, I call it <u>EditorPlugin</u>. To speed things up I add a copy of the <u>DefaultContactEditor</u> class to this class library (make sure you change the namespace and the class name to <u>EditorPlugin</u> in the code view and in the designer.cs file!). Since this class inherits from <u>Form</u> I also need to reference<u> System.Drawing</u> and <u>System.Windows.Forms</u> which isn't included from the beginning in a Class Library (the compiler will inform you about this). We also need access to the <u>Contact</u> class and the <u>IContactEditor</u> interface; a reference to the <u>PluginLib</u> will solve this. After that I changed the design of the form as follows;</p>
<p><img height="193" alt="image" src="http://files.deap.nu/deap/blogger/remoteinc/deapOnDotNet/LessonblogCreatingapluginacceptingapplic_116FF/image_6.png" width="347" border="0" /> </p>
<p>All that is altered here is a minor layout change, putting together the first and lastname textboxes on one single row. Now, lets build this class library and put the resulting <u>EditorPlugin.dll</u> in the Plugins directory of the PluginHost application.</p>
<p>Now when you run the application this restyled window will be used for editing. <a href="http://files.deap.nu/deap/blogger/remoteinc/deapondotnet/PluginSolution_Finished.zip">Download the complete solution here</a>.</p>
<p><strong>Try for yourself;</strong></p>
<ul>
<li>Add a checkbox by the MSN field with the caption "Same as email", setting the MSN textbox to the same value of the email textbox when the checkbox is checked.</li>
<li>What would you have to inform plugin developers about so that they will be able to develop a plugin for this application?</li>
<li>Add a dialog in the application that let's the user <em>add</em> new contacts to the list. Make it possible for plugin developers to replace this dialog.</li>
</ul> Dan Petterssonhttp://www.blogger.com/profile/02958960710110225708noreply@blogger.com1