<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://stevennagy.spaces.live.com/mmm2008-07-24_12.50/rsspretty.aspx?rssquery=en-US;http%3a%2f%2fstevennagy.spaces.live.com%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Developmental</title><description>Flinging crap at other monkeys in the development forest</description><link>http://stevennagy.spaces.live.com/</link><language>en-US</language><pubDate>Fri, 29 Aug 2008 04:52:51 GMT</pubDate><lastBuildDate>Fri, 29 Aug 2008 04:52:51 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><live:identity><live:id>-5552977989164759373</live:id><live:alias>stevennagy</live:alias></live:identity><image><title>Developmental</title><url>http://blufiles.storage.live.com/y1pmLS1NVYqmipJtJ7Mo1QiR13HgCCIvq2Irdywi9e62ymFU6fWVwl251403fP8U2zU</url><link>http://stevennagy.spaces.live.com/</link></image><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>DEVSTA - The programming competition for star developers!</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!249.entry</link><description>&lt;p&gt;Although it hasn't been officially announced by Microsoft yet, the information was revealed on the OzSilverLight mailing list today that there will be a programming competition for Australian developers starting in September.  &lt;p&gt;Here is the URL: &lt;a title="http://devsta.microsoft.com.au/" href="http://devsta.microsoft.com.au/"&gt;http://devsta.microsoft.com.au/&lt;/a&gt; &lt;p&gt;What's really interesting about this particular competition is that it is offering some seriously cool prizes! For instance, first place is an all expenses paid trip to &lt;a href="http://visitmix.com/2009/default.aspx"&gt;Mix09&lt;/a&gt; in Vegas next year, an XBOX Elite plus games, and a MSDN subscription.  &lt;p&gt;The &amp;quot;theme&amp;quot; of the competition will be announced on 29th September, and then it will be open slather. Developers will have exactly 200 hours and 8 minutes to complete their submission for the competition.  &lt;p&gt;So start stocking that jolt cola and be ready on 29th Sept to compete to become the next DEVSTA! &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Competition" rel=tag&gt;Competition&lt;/a&gt;,&lt;a href="http://technorati.com/tags/DEVSTA" rel=tag&gt;DEVSTA&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Programming" rel=tag&gt;Programming&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.Net" rel=tag&gt;.Net&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+DEVSTA+-+The+programming+competition+for+star+developers!&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><category>None</category><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!249.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!249.entry</guid><pubDate>Fri, 29 Aug 2008 04:52:51 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!249/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!249.entry#comment</wfw:comment><dcterms:modified>2008-08-29T04:52:51Z</dcterms:modified></item><item><title>System.IConvertible - Its not a Ferrari</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!248.entry</link><description>&lt;p&gt;You might be familiar with the System.Convert class, which has a number of methods for converting from/to different types. For example:  &lt;blockquote&gt; &lt;p&gt;short s = Convert.ToInt16(int.MaxValue); &lt;/blockquote&gt; &lt;p&gt;We live in a world of casting and you might find this code somewhat pointless. After all, it will still raise StackOverflowException and lose precision with floating poing conversions, so what's the point?  &lt;p&gt;The convert class is capable of converting an instance of ANY type into one of the common base types (sting, int, ulong, char, etc). If a type implements the System.IConvertible interface, it can define how conversions of that type will occur.  &lt;p&gt;Lets consider a (not so practical) example. Say we have a product class with the following properties:  &lt;blockquote&gt; &lt;p&gt;public int ProductId { get; set; }&lt;br&gt;public DateTime DateAvailable { get; set; }&lt;br&gt;public string Name { get; set; } &lt;/blockquote&gt; &lt;p&gt;Our Product class also has a parameterless constructor. In this example, we also make the Product class implement the IConvertible interface. This forces us to implement 16 methods and 1 property. Those methods all relate directly to conversion. For example, here's the implementation of one of those methods:  &lt;blockquote&gt; &lt;p&gt;public ulong ToUInt64(IFormatProvider provider) {&lt;br&gt;      return (UInt64)ProductId;&lt;br&gt;} &lt;/blockquote&gt; &lt;p&gt;What we are saying here is that if someone tries to convert our Product instance to a ulong then it will simply assign the ProductId. Our test code looks like this:  &lt;blockquote&gt; &lt;p&gt;Product p = new Product { Name=&amp;quot;Car&amp;quot;, DateAvailable=DateTime.Now, ProductId=7 };&lt;br&gt;UInt64 i = Convert.ToUInt64(p);&lt;br&gt;Console.WriteLine(i); &lt;/blockquote&gt; &lt;p&gt;The output is the number &amp;quot;7&amp;quot; because that is how our implementation of IConvertible tells the Convert class to handle conversions to UInt64.  &lt;p&gt;Simple eh? &lt;p&gt;  &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/System.IConvertible" rel=tag&gt;System.IConvertible&lt;/a&gt;,&lt;a href="http://technorati.com/tags/IConvertible" rel=tag&gt;IConvertible&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Convert" rel=tag&gt;Convert&lt;/a&gt;,&lt;a href="http://technorati.com/tags/System.Convert" rel=tag&gt;System.Convert&lt;/a&gt;,&lt;a href="http://technorati.com/tags/cast" rel=tag&gt;cast&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+System.IConvertible+-+Its+not+a+Ferrari&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!248.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!248.entry</guid><pubDate>Wed, 20 Aug 2008 02:08:14 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!248/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!248.entry#comment</wfw:comment><dcterms:modified>2008-08-20T02:08:14Z</dcterms:modified></item><item><title>Rolling back a changeset in TFS</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!242.entry</link><description>&lt;p&gt;In TFS 2005 and 2008 there is no easy way of rolling back a changeset. Sure, you can do a &amp;quot;get specific version&amp;quot; of each file from before the &amp;quot;bad&amp;quot; checkin occurred, and then check the older version back in. But this really sucks if you have a lot of files in your changeset. &lt;p&gt;Luckily the Team Foundation Power Tools can help you here. One of the command line options is as follows: &lt;blockquote&gt; &lt;p&gt;tfpt rollback /changeset:xxxx&lt;/blockquote&gt; &lt;p&gt;Here, you simply replace xxxx with your changeset number, and the power tools will take care of the rest.  &lt;p&gt;First, it will &amp;quot;get latest&amp;quot; of the workspace. Next it will perform an operation for each file that is required to roll it back. For example, if you added a file, it performs a delete. If you deleted a file, it performs an undelete. If you simply edited a file, it will get the code from the changeset previous for that file. The result on the command line indicates which changeset was used for each file it rolled back. &lt;p&gt;It then pops up a window requesting confirmation for all the files. After this, it checks out all those files it will roll back and you can then check them in (or only check some in if you so wish). &lt;p&gt;One caveat with this process is that when you are executing the command line, you might get an error: &amp;quot;Unable to determine workspace&amp;quot;. This simply means you are not currently in a folder that is part of a workspace. Change directory into a folder that is stored in the workspace you want to use (for those that use multiple workspaces with different folders). &lt;p&gt;Good news is that Rosario will have rollback features incorporated. Check out the help for rollback for more information: &lt;blockquote&gt; &lt;p&gt;tfpt rollback /?&lt;/blockquote&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/TFS" rel=tag&gt;TFS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/VSTS" rel=tag&gt;VSTS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/TFPT" rel=tag&gt;TFPT&lt;/a&gt;,&lt;a href="http://technorati.com/tags/rollback" rel=tag&gt;rollback&lt;/a&gt;,&lt;a href="http://technorati.com/tags/changeset" rel=tag&gt;changeset&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Rolling+back+a+changeset+in+TFS&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!242.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!242.entry</guid><pubDate>Tue, 01 Jul 2008 12:14:09 GMT</pubDate><slash:comments>2</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!242/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!242.entry#comment</wfw:comment><dcterms:modified>2008-07-01T12:14:09Z</dcterms:modified></item><item><title>Destroy Work Item : Is it really gone?</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!238.entry</link><description>&lt;p&gt;This week we had a situation where we needed to remove a work item from the TFS database completely. You can delete a work item in Team Explorer however this just marks the row in the database as deleted and as such your database will always grow, never shrink. &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/tfs2008/bb980963.aspx"&gt;Visual Studio Team System 2008 Team Foundation Power Tools&lt;/a&gt; give us the ability to destroy a work item with the 'destroyWI' call. Here's the command line syntax: &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;tfpt destroywi /server:&amp;lt;SERVER&amp;gt; /workitemid:&amp;lt;ID&amp;gt;&lt;/em&gt;&lt;/blockquote&gt; &lt;p&gt;The 'intention' is to delete all instances of the ID from the database, and all related data, and in truth it comes pretty close. However there is one table it misses: '&lt;em&gt;WorkItemsWere&lt;/em&gt;' &lt;p&gt;If you look at your TFS database instance you will notice there are actually a few databases. One of them is &lt;em&gt;'WorkItemTracking'&lt;/em&gt; and this database contains all the tables related to work items. The astute might also notice that each of the databases in their instance seems to match each of the web services provided by TFS. Coincidence? &lt;p&gt;In the &lt;em&gt;'WorkItemTracking'&lt;/em&gt; database you will see a number of tables that all contain work item related data. In particular, notice the two tables: &lt;em&gt;'WorkItemsAre'&lt;/em&gt; and &lt;em&gt;'WorkItemsWere'&lt;/em&gt;. The 'Are' table contains the current state of a work item while the 'Were' table contains its history.  &lt;p&gt;For example, work item 1234 is modified several times. First it is opened as a bug and assigned to 'triage'. Then triage moves it to the developer who fixes the bug and resolves it with comments, where it is assigned back to the user who opened it. The bug isn't fixed, some additional comments are inserted, its assigned back to the developer, and so on. If you are familiar with work items, you will be able to identify the 'History' section where you can view the audit history. This essentially is what is stored in the 'WorkItemsWere' table. Makes sense now right? &lt;p&gt;Yesterday I did a destroy of a work item and discovered that all the various tables had all instances cleaned up, &lt;strong&gt;except&lt;/strong&gt; the 'WorkItemsWere' table. I contacted the VSTS team who indicated that this is indeed a bug and it is now logged in their own work item system (oh the irony!). &lt;p&gt;What to do in the mean time? Well they assure me it is safe to delete the orphaned database rows, despite the general consensus on the net not to mess with the database directly. I &lt;strong&gt;can &lt;/strong&gt;confirm however that this is the only table with orphaned data. And I'm sure this will be fixed up in a future release of the power tools. All round I quite like the TFPT and haven't even bothered with the multitude of 3rd party components that put a UI in front of it: real men use command line! &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/TFS" rel=tag&gt;TFS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/VSTS" rel=tag&gt;VSTS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/TFPT" rel=tag&gt;TFPT&lt;/a&gt;,&lt;a href="http://technorati.com/tags/2008" rel=tag&gt;2008&lt;/a&gt;,&lt;a href="http://technorati.com/tags/power tools" rel=tag&gt;power tools&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Work item" rel=tag&gt;Work item&lt;/a&gt;,&lt;a href="http://technorati.com/tags/delete" rel=tag&gt;delete&lt;/a&gt;,&lt;a href="http://technorati.com/tags/destroy" rel=tag&gt;destroy&lt;/a&gt;,&lt;a href="http://technorati.com/tags/WorkItemsWere" rel=tag&gt;WorkItemsWere&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Destroy+Work+Item+%3a+Is+it+really+gone%3f&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!238.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!238.entry</guid><pubDate>Fri, 13 Jun 2008 10:41:10 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!238/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!238.entry#comment</wfw:comment><dcterms:modified>2008-06-13T10:41:10Z</dcterms:modified></item><item><title>Advanced Generics</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!232.entry</link><description>&lt;p&gt;I've recently been reading &lt;a href="http://www.csharpindepth.com/"&gt;this book by Jon Skeet&lt;/a&gt; about C# 2 and 3, and it got me all inspired to write about generics. Jon's great; he's extremely active in the C# and Java community, and recently responded to an email question I had in less than 10 minutes! I'm finding the book insightful and useful and greatly enjoying my bus rides to work when I get to read it. &lt;p&gt;This post is going to assume you are familiar with using generic classes like List&amp;lt;T&amp;gt; and Nullable&amp;lt;T&amp;gt;. So lets start with the syntax for declaring our own generic class: &lt;blockquote&gt; &lt;p&gt;public class Monkey { }&lt;br&gt;public class Animator&amp;lt;T&amp;gt; {&lt;br&gt;    private T instance;&lt;br&gt;    public Animator(T t)&lt;br&gt;    {&lt;br&gt;        instance = t;&lt;br&gt;    }&lt;br&gt;    public void MoveOnce() { }&lt;br&gt;}&lt;br&gt;Animator&amp;lt;Monkey&amp;gt; animator = new Animator&amp;lt;Monkey&amp;gt;(new Monkey());&lt;br&gt;animator.Move();&lt;/blockquote&gt; &lt;p&gt;This is pretty simple: the Animator class accepts a generic type T and requires you pass a T in its constructor. The MoveOnce() method is empty at the moment, we'll get to that later. &lt;blockquote&gt; &lt;p&gt;Currently our generic Animator class is somewhat type-safe: we can only pass instances of T to its constructor, but we don't really know much about T. We'd like to be able to move our instances (such as a monkey) so we need to define some things about what kinds of T we are willing to accept. Lets go back to our Monkey class for a moment and define an interface for it:&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;public interface IMoveable {&lt;br&gt;    void Move();&lt;br&gt;    void Stop();&lt;br&gt;}&lt;br&gt;public class Monkey : IMoveable {&lt;br&gt;    public void Move() { }&lt;br&gt;    public void Stop() { }&lt;br&gt;}&lt;/blockquote&gt; &lt;p&gt;Great! We've decided that the fact a Monkey can move and stop is pretty general, and is probably something other animals can do, so we've declared an interface to indicate our monkey has those capabilities. We might also define IEater, or IDungFlinger. Now we can revisit our generic type in our Animator class definition as follows: &lt;blockquote&gt; &lt;p&gt;public class Animator&amp;lt;T&amp;gt; where T : IMoveable&lt;br&gt;{&lt;br&gt;    private T instance;&lt;br&gt;    public Animator(T t)&lt;br&gt;    {&lt;br&gt;        instance = t;&lt;br&gt;    }&lt;br&gt;    public void MoveOnce() {&lt;br&gt;        instance.Move();&lt;br&gt;        instance.Stop();&lt;br&gt;    }&lt;br&gt;}&lt;/blockquote&gt; &lt;p&gt;This is where the magic begins. We've placed a constraint on our generic type, stating that it will only ever accept a type that implements our IMoveable interface. If we try to use the Animator class with something else, we will get a compile-time exception. Even better yet is that our development environment knows that since our instance will always implement IMoveable, it therefore &lt;strong&gt;must&lt;/strong&gt; have a Move() and Stop() method, therefore we can call it anywhere in our class; in this case the MoveOnce() method. &lt;p&gt;You can declare more than one generic type in your class definitions. Imaging a class that facilitates a race for monkeys, whether they be chimps, gorillas, or marmosets. Consider this generic class declaration: &lt;blockquote&gt; &lt;p&gt;public class Race&amp;lt;T, U&amp;gt; where T : Monkey where U : Monkey {&lt;br&gt;    public Race(T monkey1, U monkey2) { }&lt;br&gt;    public void RunRace() { }&lt;br&gt;}&lt;br&gt;public class Marmoset : Monkey { }&lt;br&gt;public class Chimp : Monkey { }&lt;/blockquote&gt; &lt;p&gt;Here we have defined that our class accepts 2 generic types: T and U. We have further restricted them that they both have to inherit from the Monkey class. Here's some example calls using this new class: &lt;blockquote&gt; &lt;p&gt;Race&amp;lt;Chimp, Marmoset&amp;gt; race1 = &lt;br&gt;      new Race&amp;lt;Chimp, Marmoset&amp;gt;(new Chimp(), new Marmoset());&lt;br&gt;Race&amp;lt;Monkey, Chimp&amp;gt; race2 = &lt;br&gt;      new Race&amp;lt;Monkey, Chimp&amp;gt;(new Monkey(), new Chimp());&lt;br&gt;Race&amp;lt;Marmoset, Marmoset&amp;gt; race3 = &lt;br&gt;      new Race&amp;lt;Marmoset, Marmoset&amp;gt;(new Marmoset(), new Marmoset());&lt;/blockquote&gt; &lt;p&gt;As you can see that anything that inherits Monkey is valid. Of interest, the second example shows that even an instance of Monkey is valid. This shows that the &lt;strong&gt;where&lt;/strong&gt; clause in our type restriction means anything that inherits from X or &lt;strong&gt;is&lt;/strong&gt; X. &lt;p&gt;Finally here are a couple of extra cool things you can do with generic type restrictions as general non-monkey related examples: &lt;blockquote&gt; &lt;p&gt;public class TestCase1&amp;lt;T&amp;gt; where T : class { }&lt;br&gt;public class TestCase2&amp;lt;T&amp;gt; where T : struct { }&lt;br&gt;public class TestCase3&amp;lt;T&amp;gt; where T : IDisposable, IMoveable, IComparable { }&lt;br&gt;public class TestCase4&amp;lt;T, U&amp;gt; where T : U { }&lt;br&gt;public class TestCase5&amp;lt;T, U&amp;gt; where T : U, IMoveable { }&lt;br&gt;public class TestCase6&amp;lt;T, U&amp;gt; where T : class where U : struct{ }&lt;br&gt;public class TestCase7&amp;lt;T, U&amp;gt; where T : class where U : struct, T { }&lt;/blockquote&gt; &lt;p&gt;TestCase1 demonstrates that we can force the type to be a &lt;strong&gt;reference type&lt;/strong&gt;. &lt;br&gt;Likewise TestCase2 ensures that the type must be a value type. How is this useful? Well consider a generic class that performs expensive operations such as copying from one list to another. Reference types are just pointers and therefore inexpensive to copy around, thus ensuring only reference types are allowed in our class could be quite useful. &lt;p&gt;TestCase3 shows that we can ensure T implements multiple interfaces. &lt;br&gt;TestCase4 shows that one generic type can be forced to inherit from another. An example of an implementation might be: &lt;blockquote&gt; &lt;p&gt;TestCase4&amp;lt;Chimp, Monkey&amp;gt; test = new TestCase4&amp;lt;Chimp, Monkey&amp;gt;();&lt;/blockquote&gt; &lt;p&gt;This is valid because Chimp inherits from Monkey.&lt;br&gt;TestCase5 shows that a type can be restricted to inherit as well as implement interfaces.&lt;br&gt;TestCase6 demonstrates that one type must be a reference type while the other can be a value type. &lt;p&gt;The last TestCase7 is somewhat interesting. Its declaration indicates that T is a reference type, and U is a value type that must inherit from T. How can this be? It essentially states that you must pass a struct that inherits from a class. But C# won't let you declare this.  &lt;p&gt;To be honest at first I didn't know the answer to this. Thus the email to Jon, and his explanation was simple and it made sense: interfaces are reference types. Hopefully you are aware that structs can implement interfaces also (but can't do inheritance), so we might define a new animal as follows: &lt;blockquote&gt; &lt;p&gt;public struct Mouse : IMoveable {&lt;br&gt;    public void Move() { }&lt;br&gt;    public void Stop() { }&lt;br&gt;}&lt;/blockquote&gt; &lt;p&gt;Then we can legitimately use the TestCase7 syntax: &lt;blockquote&gt; &lt;p&gt;TestCase7&amp;lt;IMoveable, Mouse&amp;gt; test = new TestCase7&amp;lt;IMoveable, Mouse&amp;gt;();&lt;/blockquote&gt; &lt;p&gt;Then of course, valid values for an IMoveable are a Chimp, Marmoset, or even another Mouse, while of course you can only use a Mouse for the second type. &lt;p&gt;Hopefully this has given you a better idea of what you can do with generics. &lt;br&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/C#" rel=tag&gt;C#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Generics" rel=tag&gt;Generics&lt;/a&gt;,&lt;a href="http://technorati.com/tags/interfaces" rel=tag&gt;interfaces&lt;/a&gt;,&lt;a href="http://technorati.com/tags/inheritance" rel=tag&gt;inheritance&lt;/a&gt;,&lt;a href="http://technorati.com/tags/constraints" rel=tag&gt;constraints&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Advanced+Generics&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!232.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!232.entry</guid><pubDate>Sun, 01 Jun 2008 05:38:11 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!232/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!232.entry#comment</wfw:comment><dcterms:modified>2008-06-01T05:38:11Z</dcterms:modified></item><item><title>Contravariance, Covariance, and Generics</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!230.entry</link><description>&lt;p&gt;The common question is: what the hell is contravariance and covariance? &lt;p&gt;Ok so you are familiar with casting right? In C# we can do this: &lt;blockquote&gt; &lt;p&gt;public class Animal { }&lt;br&gt;public class Monkey : Animal { }&lt;br&gt;...&lt;br&gt;Animal a = new Monkey();&lt;br&gt;((Monkey)a).FlingCrap();&lt;/blockquote&gt; &lt;p&gt;We can also do this: &lt;blockquote&gt; &lt;p&gt;public void MoveWest(Animal a) { }&lt;br&gt;...&lt;br&gt;MoveWest(new Monkey());&lt;/blockquote&gt; &lt;p&gt;Because the 'MoveWest' method accepts the narrowing type 'Animal' it is said to support 'Contravariance'. If the C# compiler forced us to only pass exact types, then it would be considered 'invariant'. Likewise C# methods support covariance, in that we can return a narrower type and cast the resulting instance to its correct form. &lt;p&gt;There are parts of the .Net framework however that aren't so flexible. In this case, I'm talking about generics. &lt;blockquote&gt; &lt;p&gt;Consider this for example:&lt;br&gt;List&amp;lt;Monkey&amp;gt; monkeys = new List&amp;lt;Monkey&amp;gt;();&lt;br&gt;monkeys .Add(new Monkey());&lt;br&gt;List&amp;lt;Animal&amp;gt; animals = monkeys;&lt;/blockquote&gt; &lt;p&gt;Unfortunately this does not compile. We get the following warning: &lt;blockquote&gt; &lt;p&gt;Cannot implicitly convert type 'System.Collections.Generic.List&amp;lt;FeaturesCsharp2.Monkey&amp;gt;' to 'System.Collections.Generic.List&amp;lt;FeaturesCsharp2.Animal&amp;gt;'&lt;/blockquote&gt; &lt;p&gt;Why is this? Monkey inherits Animal, so the list conversion is perfectly safe. Well this is one case of invariance. But here's the kicker: word on the street is that the CLR actually supports contravariance of generic lists; its just the C# compiler that doesn't!  &lt;p&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/C#" rel=tag&gt;C#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Covariance" rel=tag&gt;Covariance&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Contravariance" rel=tag&gt;Contravariance&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Generics" rel=tag&gt;Generics&lt;/a&gt;,&lt;a href="http://technorati.com/tags/CLR" rel=tag&gt;CLR&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Compiler" rel=tag&gt;Compiler&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Contravariance%2c+Covariance%2c+and+Generics&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!230.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!230.entry</guid><pubDate>Thu, 29 May 2008 11:48:06 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!230/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!230.entry#comment</wfw:comment><dcterms:modified>2008-05-29T11:48:06Z</dcterms:modified></item><item><title>Circle Of Interest</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!228.entry</link><description>&lt;p&gt;My mate and fellow Readifarian &lt;a href="http://www.paulstovell.com/blog/whats-your-circle-of-interest"&gt;Paul Stovell&lt;/a&gt; recently posted his 'Circle Of Interest' and started a meme by nominating 5 others to do the same. I was one of the lucky ones, so here's my circle. &lt;p&gt;&lt;a href="http://blufiles.storage.msn.com/y1pi-7WJDf-Vlm3zQJufhnkg6ENjZfiSCcwXxtkcZPTX5y0KU5Nnjhrb31-7VntlNOyDXArTbW3uvE?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=449 alt=Corethings src="http://blufiles.storage.msn.com/y1pi-7WJDf-VlnSg27JCqGWmTlX5yV4df02D5c0GJQ0fvOdx4VN0PBCFsKnRbACDwj5Dwn4DlgI_lc?PARTNER=WRITER" width=449 border=0&gt;&lt;/a&gt;  &lt;p&gt;I don't doubt this circle will change completely in 6 months. I expect the TFS parts to fade into the middle circle, with more focus on WPF and SilverLight perhaps. Who can tell? &lt;p&gt;The big red circle indicates things I don't care about, the baby-vomit yellow indicates stuff I am interest in but have little time or dedication to fully pursue. The dog-vomit green is the stuff that I am loving working or am most eager to develop as soon as possible. &lt;p&gt;Oh, WCF shouldn't be in the middle circle, but I couldn't be bothered changing it. &lt;p&gt;Now, to continue the meme, I nominate these people: &lt;p&gt;&lt;a href="http://matthewrowan.spaces.live.com/"&gt;Matthew Rowan&lt;/a&gt; , &lt;a href="http://johnmcfadyen.spaces.live.com"&gt;John McFadyen&lt;/a&gt; , &lt;a href="http://jcooney.net/"&gt;Joseph Cooney&lt;/a&gt; , &lt;a href="http://www.secretgeek.net/"&gt;Leon Bambrick&lt;/a&gt; &lt;p&gt;Get to it chumps! &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Circle" rel=tag&gt;Circle&lt;/a&gt;,&lt;a href="http://technorati.com/tags/interest" rel=tag&gt;interest&lt;/a&gt;,&lt;a href="http://technorati.com/tags/meme" rel=tag&gt;meme&lt;/a&gt;,&lt;a href="http://technorati.com/tags/monkeys dressed like penguins" rel=tag&gt;monkeys dressed like penguins&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Circle+Of+Interest&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!228.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!228.entry</guid><pubDate>Thu, 29 May 2008 11:10:39 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!228/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!228.entry#comment</wfw:comment><dcterms:modified>2008-05-29T11:10:39Z</dcterms:modified></item><item><title>Personal Development Plan</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!219.entry</link><description>&lt;p&gt;At Readify we are encouraged to do a plan that we can use for guidance in our personal development. I was pretty generic with mine and have decided to give it more focus today (given that its labour day and all). I figure I'd post it here so that I can hold myself accountable to it next year. Lets say, end of financial year 09? Gives me 14 months to see what I can achieve off of this list. Naturally having a baby will affect this in yet to be discovered ways. &lt;p&gt;The list is priorities by importance for high level headings only. Its mostly just a bullet point list, which is interesting because I am unsure how to measure success for some of these things (for example, when will I 'know' WCF? I've done a bit already but still am not across all the security aspects). &lt;p&gt;Anyway, here's the list. Feel free to critique or post your own list in response. &lt;p&gt;&lt;strong&gt;Certifications&lt;/strong&gt; (importance: HIGH)&lt;br&gt;· MCTS: Web Applications&lt;br&gt;· MCTS: Windows Applications&lt;br&gt;· MCTS: WCF &lt;br&gt;· MCT: Certified Trainer&lt;br&gt;· MCTS: Business Intelligence &lt;p&gt;&lt;strong&gt;Improve blog quality&lt;/strong&gt; (importance: HIGH)&lt;br&gt;· Attract more readers&lt;br&gt;· More diverse topics (as my knowledge increases)&lt;br&gt;· More frequent postings&lt;br&gt;&lt;br&gt;&lt;strong&gt;Specific Technologies&lt;/strong&gt; (importance: HIGH)&lt;br&gt;· LINQ, dLINQ, xLINQ, etc&lt;br&gt;· SilverLight&lt;br&gt;· Expression tools&lt;br&gt;· Windows Presentation Foundation&lt;br&gt;· MVC Framework&lt;br&gt;· ADO.NET Data services&lt;br&gt;· ADO.NET Entity Framework&lt;br&gt;· Windows Workflow Foundation&lt;br&gt;· Windows Communication Foundation&lt;br&gt;· Active Directory, DNS, and networks&lt;br&gt;· Sharepoint&lt;br&gt;· Intermediary Language&lt;br&gt;· Team Foundation Server / Team Build&lt;br&gt;· Visual Studio Team System&lt;br&gt;· ASP.NET Ajax&lt;br&gt;· Business Intelligence&lt;br&gt;· Reporting Services&lt;br&gt;· BizTalk&lt;br&gt;· Integration Services &lt;p&gt;&lt;strong&gt;Attend Special Interest Conferences&lt;/strong&gt; (importance: HIGH)&lt;br&gt;· Tech Ed - Australia&lt;br&gt;· ReMix - Australia&lt;br&gt;· Mix - United States&lt;br&gt;· Tech Ed – Europe &lt;p&gt;&lt;strong&gt;Presenter&lt;/strong&gt; (importance: MEDIUM)&lt;br&gt;· User groups / SIGs&lt;br&gt;· Code Camps&lt;br&gt;· Tech conferences like TechEd&lt;br&gt;&lt;br&gt;&lt;strong&gt;Further Study&lt;/strong&gt; (importance: LOW)&lt;br&gt;· Physics/Chemistry/Astro-physics&lt;br&gt;· MBA &lt;p&gt;&lt;strong&gt;Author&lt;/strong&gt; (importance: LOW)&lt;br&gt;· A technical book, unsure of topic at this stage&lt;br&gt;· Articles to MSDN, code magazines, etc &lt;p&gt;Wow, looking at this list, I feel like I know absolutely nothing! But to be honest, I have groundings in a lot of the technical stuff (like SilverLight, WCF, Reporting Services, BI, LINQ, etc), but I really want to gain expertise in these areas.  &lt;p&gt;Why do I rank certifications so highly? Well I'm keen on the MCT, which requires an MCTS or two. Also they are useful to an employer for points towards partner status. Finally, its a personal milestone, ie the certification is for me, not you. I want to pass all those tests based on my knowledge (not cheating, examining practice tests, etc).  &lt;p&gt;I don't expect I'll get to Tech Ed Europe or Mix US anytime soon, but ReMix is a possibility for me this year (I've never been) and Tech Ed is a definite (see you there!). &lt;p&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/PD Plan" rel=tag&gt;PD Plan&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Personal Development Plan" rel=tag&gt;Personal Development Plan&lt;/a&gt;,&lt;a href="http://technorati.com/tags/certifications" rel=tag&gt;certifications&lt;/a&gt;,&lt;a href="http://technorati.com/tags/blog" rel=tag&gt;blog&lt;/a&gt;,&lt;a href="http://technorati.com/tags/technology" rel=tag&gt;technology&lt;/a&gt;,&lt;a href="http://technorati.com/tags/conferences" rel=tag&gt;conferences&lt;/a&gt;,&lt;a href="http://technorati.com/tags/author" rel=tag&gt;author&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Personal+Development+Plan&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!219.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!219.entry</guid><pubDate>Mon, 05 May 2008 10:41:24 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!219/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!219.entry#comment</wfw:comment><dcterms:modified>2008-05-05T10:41:24Z</dcterms:modified></item><item><title>So You've Ruined Your Life...</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!213.entry</link><description>&lt;div&gt;You might recognise this quote from the Simpsons as the title of the book that doctor Hibbard gives Homer and Marge after they realise they are 'up the duff'. &lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Since I just got the news that my wife Sonia and I are now also 'up the duff' I figured it would make for a good article title. I don't actually believe it of course... I'm as excited as a little kid with a lollipop! It will however mean that my lifestyle will change somewhat, since I now have new priorities.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;So that's all this article is about. Its been just the two of us (married for over 6 years) and a sausage dog up until now. I'm excited, curious, and nervous, all rolled into one. I have no idea how it is affecting my work, but no doubt this will change me in ways I have yet to understand.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Anyway, I just want to apologise for the lack of blogging in the last few weeks, and hopefully I'll be back at it again soon.&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+So+You've+Ruined+Your+Life...&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!213.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!213.entry</guid><pubDate>Fri, 02 May 2008 03:04:25 GMT</pubDate><slash:comments>7</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!213/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!213.entry#comment</wfw:comment><dcterms:modified>2008-05-02T03:04:25Z</dcterms:modified></item><item><title>TeamBuild, PowerShell, and Exit Codes</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!209.entry</link><description>&lt;p&gt;At my work I am starting to integrate PowerShell scripts into the TeamBuild projects for our nightly build. Including PowerShell is very easy: you just need to ensure that PowerShell is installed on the build server. Installing PowerShell will adjust the PATH environment variable, but you may need to restart the build service in order for the build server to pick up this new path. &lt;p&gt;Including a PowerShell script in your TeamBuild (or MSBuild) targets is very easy. You might have a target that looks something like this: &lt;blockquote&gt; &lt;p&gt;&amp;lt;Target Name=&amp;quot;UnrestrictedExecutionPolicy&amp;quot;&amp;gt;&lt;br&gt;    &amp;lt;Exec Command=&amp;quot;powershell set-executionPolicy unrestricted&amp;amp;quot;&amp;quot; /&amp;gt;&lt;br&gt;&amp;lt;/Target&amp;gt;&lt;br&gt;&amp;lt;Target name=&amp;quot;TestScript&amp;quot; DependsOnTargets=&amp;quot;UnrestrictedExecutionPolicy&amp;quot;&amp;gt;&lt;br&gt;    &amp;lt;Exec Command=&amp;quot;PowerShell ./Scripts/testscript.ps1&amp;quot; /&amp;gt;&lt;br&gt;&amp;lt;/Target&lt;/blockquote&gt; &lt;p&gt;As with most environments, we need to change the execution policy so that it will allow scripts to be run. We only need to do this once for our whole build, so best to create it in its own target and place a dependency to it from other targets that will be calling PS scripts. &lt;p&gt;In the above example, we are calling a script in the Scripts folder called testscript.ps1. Pretty simple really. If an error occurs in that script, then the exit code will indicate an error, and the build will fail. However, we may not want the build to fail. Perhaps only a warning is required. Or perhaps we want the script to do things that might break the build AND raise warnings. How can we handle this? &lt;p&gt;An easy way is to use exit codes. Most EXEC calls will return an exit code. 0 usually means success, and 1 or higher means failure. In MSBuild (ie. TeamBuild) that means 1 or higher will break the build. So what if we want our PowerShell script to return all sorts of exit codes, and only have certain exit codes break the build, and others raise warnings? This is easy too, but requires some jigging. &lt;p&gt;First, we call the EXEC task with an attribute that tells it to ignore the exit code that results from the call. This means that even failed calls will not break the build. Second, we capture the exit code of the EXEC task with the Output attribute and assign it to a Property. The target might then look like this: &lt;blockquote&gt; &lt;p&gt;&amp;lt;Exec Command=&amp;quot;PowerShell ./Scripts/testscript.ps1&amp;quot; IgnoreExitCode=&amp;quot;true&amp;quot;&amp;gt;&lt;br&gt;     &amp;lt;Output TaskParameter=&amp;quot;ExitCode&amp;quot; PropertyName=&amp;quot;ScriptExitCode&amp;quot; /&amp;gt;&lt;br&gt;&amp;lt;/Exec&amp;gt;&lt;/blockquote&gt; &lt;p&gt;Cool... we now have the exit code in the property 'ScriptExitCode' and can manually do what we like with it. Using the Warning and Error tasks that already exist, we can react in a more custom way: &lt;blockquote&gt; &lt;p&gt;&amp;lt;Warning Condition=&amp;quot;$(ScriptExitCode)==2&amp;quot; &lt;br&gt;               Text=&amp;quot;Warning: The script raised a warning&amp;quot; /&amp;gt;&lt;br&gt;&amp;lt;Error Condition=&amp;quot;$(ScriptExitCode)==1&amp;quot; &lt;br&gt;           Text=&amp;quot;Error: The script raised an error: Build stopping.&amp;quot; /&amp;gt;&lt;/blockquote&gt; &lt;p&gt;In this example, if the script returns exit code 1, the build still fails. However if it returns 2, then only a warning is raised, and the build continues on. &lt;p&gt;So only one thing remains: how do we tell PowerShell scripts to return a specific exit code? Well that's just as easy. In our PS script, we can use this line:  &lt;blockquote&gt; &lt;p&gt;$host.SetShouldExit(2)&lt;/blockquote&gt; &lt;p&gt;$host is a reserved variable in PowerShell. In the above code, we are telling the script to return exit code 2 when it exits. Note that this line does not tell the script to exit straight away. To do that, call the command 'exit'.  &lt;p&gt;So using this knowledge, we can sprinkle the relative exit codes throughout our scripts and let MSBuild handle it on the outside. &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/TeamBuild" rel=tag&gt;TeamBuild&lt;/a&gt;,&lt;a href="http://technorati.com/tags/MSBuild" rel=tag&gt;MSBuild&lt;/a&gt;,&lt;a href="http://technorati.com/tags/PowerShell" rel=tag&gt;PowerShell&lt;/a&gt;,&lt;a href="http://technorati.com/tags/exit code" rel=tag&gt;exit code&lt;/a&gt;,&lt;a href="http://technorati.com/tags/TFS" rel=tag&gt;TFS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/warning" rel=tag&gt;warning&lt;/a&gt;,&lt;a href="http://technorati.com/tags/error" rel=tag&gt;error&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+TeamBuild%2c+PowerShell%2c+and+Exit+Codes&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!209.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!209.entry</guid><pubDate>Sun, 06 Apr 2008 03:26:05 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!209/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!209.entry#comment</wfw:comment><dcterms:modified>2008-04-06T03:26:05Z</dcterms:modified></item><item><title>How to lose an entire week in conferences and presentations</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!208.entry</link><description>&lt;p&gt;Brisbane: A rich ecosystem of technology, enthusiasm, and deliverance. I often wonder how I manage to stay married when there is so much going on in this town that keeps me distracted. I'm sure its just as rich in other cities, but hell, I don't care about those infestations. Brisbane is great for the developer/enthusiast and here's why: my week since last Wednesday. &lt;p&gt;&lt;strong&gt;Weds 26th March - Heroes Happen&lt;/strong&gt;&lt;br&gt;I was sitting in one of the Server 2008 sessions and I realised &amp;quot;I've seen all this before&amp;quot;. It was at that point in time I remembered last year playing around with server 2008 beta 3 and TFS 2008. I had had so many problems, I'd reinstalled the server like 5 times, so I was very familiar with the interface. I was most interested in the Server Core and Hyper-V products and particularly interested in the Server 2008 license now sitting on my desk waiting to be installed. To be honest, I didn't learn much from the developer sessions. I've been using VS2008 for quite a while: both in production over the last 3 months, and beta last year with 'toy' projects. Still, &lt;a href="http://blogs.msdn.com/dglover/"&gt;Dave Glover&lt;/a&gt; showed a few cool things I hadn't seen before, such as the native debugger support for WCF apps, including the WCF test window. &lt;p&gt;&lt;strong&gt;Thurs 27th March - Sql Server User Group&lt;/strong&gt;&lt;br&gt;The guys from &lt;a href="http://www.soulsolutions.com.au/"&gt;Soul Solutions&lt;/a&gt; showed up to deliver some useful information on Sql Spatial. Unfortunately I couldn't stay from the whole event, but I hung around long enough to find out that John and Bronwen were in fact the 2 people dressed up as Batman and Batgirl at Heroes! Those 2 are crazy... &lt;p&gt;&lt;strong&gt;Mon 1st April - QUT Alumi Presentation&lt;/strong&gt;&lt;br&gt;There was a few hours of work left when &lt;a href="http://callvirt.net/blog/"&gt;Joel Pobar&lt;/a&gt; came roaming through the pods trying to drum up interest in a presentation at QUT by &lt;a href="http://en.wikipedia.org/wiki/Gordon_Bell"&gt;Gordon Bell&lt;/a&gt;. The topic was around data and its management: how do we derive quality information? He covered briefly his history around the starting of the &lt;a title="Microsoft Research" href="http://research.microsoft.com"&gt;Microsoft Research&lt;/a&gt; Centre and the work done there in recent years around data management, in particular a case study into celestial data and the resulting Worldwide Telescope. &lt;p&gt;&lt;strong&gt;Tues 2nd April - Security Interest Group&lt;/strong&gt;&lt;br&gt;A new user group that I only stumbled on as I was walking out the door at the end of the day, this group had a great presentation on Microsoft's product offerings and where security fits into the 'now' and 'future'. While MS product based, it was quite well generalised. I felt quite odd though being the only developer in a room full of system admin-type people! I'm very keen to see where this group goes from here (no link because they don't have a web site yet: hit me up if you want the administrators email, sorry I don't have it handy at the time of this post!). &lt;p&gt;&lt;strong&gt;Weds 3rd April - Briztalk User Group&lt;br&gt;&lt;/strong&gt;This is the second time I have come to this group's meetings and have enjoyed them both greatly. The first was about RFID, and last night's was about the new 2008 offerings in Server and Visual Studio. The second talk was old news (again) but once again I felt fascinated by the infrastructure aspects of 2008 Server, and it was my questions (single handedly) that caused the group to finish 1 hour later than it should have! (sorry everyone) &lt;p&gt;So as you can see, Brisbane is a rich fertile ground of development. I've learnt &lt;strong&gt;so much&lt;/strong&gt; over the last week, its ridiculous. Luckily the VSTS user group (was suppose to be Friday morning) was postponed, help give meaning to the weeks ahead! Next week looks rather quiet, which should be good because I have some interesting ideas around F# that I would like to explore. &lt;p&gt;See you at the next Brisbane community event. &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Heroes" rel=tag&gt;Heroes&lt;/a&gt;,&lt;a href="http://technorati.com/tags/2008" rel=tag&gt;2008&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Launch" rel=tag&gt;Launch&lt;/a&gt;,&lt;a href="http://technorati.com/tags/community" rel=tag&gt;community&lt;/a&gt;,&lt;a href="http://technorati.com/tags/user group" rel=tag&gt;user group&lt;/a&gt;,&lt;a href="http://technorati.com/tags/sql" rel=tag&gt;sql&lt;/a&gt;,&lt;a href="http://technorati.com/tags/visual studio" rel=tag&gt;visual studio&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Microsoft Research" rel=tag&gt;Microsoft Research&lt;/a&gt;,&lt;a href="http://technorati.com/tags/QUT" rel=tag&gt;QUT&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+How+to+lose+an+entire+week+in+conferences+and+presentations&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!208.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!208.entry</guid><pubDate>Thu, 03 Apr 2008 10:44:24 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!208/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!208.entry#comment</wfw:comment><dcterms:modified>2008-04-03T10:44:24Z</dcterms:modified></item><item><title>Introduction to PowerShell XML</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!207.entry</link><description>&lt;p&gt;Hopefully by now you have heard of &lt;a href="http://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx"&gt;PowerShell&lt;/a&gt; (PS) and know that it is a scripting shell much like BASH or any other Unix shell. However unlike those other languages, PS uses an object pipeline, rather than strings, and those objects work directly with the .Net Framework. What this gives us is a powerful, flexible, scripting platform where developers don't have to learn a whole lot before they can start leveraging some real scripting power.  &lt;p&gt;There's lots of examples around how to get started with PowerShell so I'd like to skip that part but first I just want to cover off a few key commands. First, everything in PS is an object of some sort. Unless otherwise specified, most commands will deal with objects or arrays of objects. Since all .Net types inherit from System.Object, this is how PS assumes type safety for all command calls.  &lt;p&gt;Creating an instance of a class is relatively easy. This is how you would create an XmlDocument: &lt;blockquote&gt; &lt;p&gt;$xml = New-Object &amp;quot;System.Xml.XmlDocument&amp;quot;&lt;/blockquote&gt; &lt;p&gt;The dollar $ sign indicates a variable in PS. The New-Object is a command that accepts a string input for the type. We could then continue to load some XML as we would in .Net: &lt;blockquote&gt; &lt;p&gt;$xml.Load(&amp;quot;c:\somefile.xml&amp;quot;)&lt;br&gt;$xml.LoadXml(&amp;quot;&amp;lt;a&amp;gt;&amp;lt;b&amp;gt;test&amp;lt;/b&amp;gt;&amp;lt;/a&amp;gt;&amp;quot;)&lt;/blockquote&gt; &lt;p&gt;However, PS has a nice XML shortcut that you should know about, and that's the [xml] cast: &lt;blockquote&gt; &lt;p&gt;$xml = [xml] Get-Content &amp;quot;c:\somefile.xml&amp;quot;&lt;br&gt;$xml = [xml] &amp;quot;&amp;lt;a&amp;gt;&amp;lt;b&amp;gt;test&amp;lt;/b&amp;gt;&amp;lt;/a&amp;gt;&amp;quot;&lt;/blockquote&gt; &lt;p&gt;Now lets use something more interesting for our XML: &lt;blockquote&gt; &lt;p&gt;$xml = [xml] '&lt;br&gt;    &amp;lt;world&amp;gt;&lt;br&gt;        &amp;lt;continent name=&amp;quot;Africa&amp;quot;&amp;gt;&lt;br&gt;            &amp;lt;country name=&amp;quot;Zimbabwe&amp;quot; /&amp;gt;&lt;br&gt;            &amp;lt;country name=&amp;quot;South Africa&amp;quot; /&amp;gt;&lt;br&gt;            &amp;lt;country name=&amp;quot;Ethiopia&amp;quot; /&amp;gt;&lt;br&gt;        &amp;lt;/continent&amp;gt;&lt;br&gt;        &amp;lt;continent name=&amp;quot;Asia&amp;quot;&amp;gt;&lt;br&gt;            &amp;lt;country name=&amp;quot;China&amp;quot; /&amp;gt;&lt;br&gt;            &amp;lt;country name=&amp;quot;Japan&amp;quot; /&amp;gt;&lt;br&gt;        &amp;lt;/continent&amp;gt;&lt;br&gt;    &amp;lt;/world&amp;gt;'&lt;/blockquote&gt; &lt;p&gt;Another cool operation with XML is referring to Xml Nodes specifically rather than searching. The .Net way would be this: &lt;blockquote&gt; &lt;p&gt;$continents = $xml.SelectNodes(&amp;quot;/world/continent&amp;quot;)&lt;/blockquote&gt; &lt;p&gt;This would return an array of Xml Nodes that represent all continents. In PS we can shortcut to: &lt;blockquote&gt; &lt;p&gt;$continents = $xml.world.continent&lt;/blockquote&gt; &lt;p&gt;You can look at the type of any variable with the standard GetType method: &lt;blockquote&gt; &lt;p&gt;$continents.GetType()&lt;/blockquote&gt; &lt;p&gt;Interestingly you will see that rather than an XmlNodeList or array of XmlElements, this in fact is an array of Objects! However if we look at the contents of that array we will see each item is something more reasonable: &lt;blockquote&gt; &lt;p&gt;$continents | % { $_.GetType() }&lt;/blockquote&gt; &lt;p&gt;This command tells us that we have 2 objects of type System.Xml.XmlLinkedNode in our array. The syntax is specific to PS. The | symbol is a pipe, and means to take everything from the left, and shove it into the right. The % symbol is a shortcut for &amp;quot;foreach&amp;quot;, which also works just as well. Because we have piped in some content, we don't need to specify any condition logic for our loop, and can go straight to the inner contents. When you don't specify what the name of the variable in the range will be, you can use the $_ variable instead. So overall, the above statement is the same as: &lt;blockquote&gt; &lt;p&gt;foreach ($_ in $continents) { $_.GetType() }&lt;/blockquote&gt; &lt;p&gt;Let's do something a little different. We will attempt to now take our array of Xml nodes representing continents, and put just the continent name into a generic collection of strings. The syntax around creating an instance of a generic class is as follows: &lt;blockquote&gt; &lt;p&gt;$list = New-Object &amp;quot;System.Collections.ObjectModel.Collection``1[System.String]&amp;quot;&lt;br&gt;$list.GetType()&lt;/blockquote&gt; &lt;p&gt;The type shows as Collection''1 without the generic part (string) but it is still there, under the covers. Now lets put the name of all continents into that collection with out % syntax: &lt;blockquote&gt; &lt;p&gt;$continents | % { $list.Add($_.Name) }&lt;br&gt;$list | % { $_.GetType() }&lt;/blockquote&gt; &lt;p&gt;The second command shows the type of each item in the collection, and we can see they are all strings.  &lt;p&gt;So that wraps up my first PowerShell post. I've been doing a lot of it this past week, and was very green to begin with. All my work has been around Xml, and I'll be doing some more this week. My specific usage is relating to build and release management in TFS, and am enjoying it greatly. &lt;p&gt;When it comes to using PowerShell you can create your scripts in any text editor. Currently I am using &lt;a href="http://notepad-plus.sourceforge.net/uk/download.php"&gt;Notepad++&lt;/a&gt; with &lt;a href="http://weblogs.asp.net/jgalloway/archive/2006/11/25/powershell-language-definitions-for-notepad.aspx"&gt;PowerShell language definitions&lt;/a&gt;, and also &lt;a href="http://powergui.org/downloads.jspa"&gt;PowerGui&lt;/a&gt;. PowerGui in particular is an excellent free tool. &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/PowerShell" rel=tag&gt;PowerShell&lt;/a&gt;,&lt;a href="http://technorati.com/tags/.Net" rel=tag&gt;.Net&lt;/a&gt;,&lt;a href="http://technorati.com/tags/PowerGui" rel=tag&gt;PowerGui&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Notepad++" rel=tag&gt;Notepad++&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XML" rel=tag&gt;XML&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Introduction+to+PowerShell+XML&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!207.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!207.entry</guid><pubDate>Sat, 29 Mar 2008 22:21:44 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!207/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!207.entry#comment</wfw:comment><dcterms:modified>2008-03-29T22:21:44Z</dcterms:modified></item><item><title>My Introduction To F#</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!206.entry</link><description>&lt;p&gt;During the week the &lt;a title="QLD MSDN User Group Website" href="http://www.qmsdnug.org/"&gt;QLD MSDN User Group&lt;/a&gt; was treated to a presentation by &lt;a title="Leon Bambrick (SecretGeek.Net)" href="http://www.secretgeek.net/"&gt;Leon Bambrick&lt;/a&gt; who demonstrated &lt;a title="F# (Microsoft Research)" href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;F#&lt;/a&gt; in all its glory. The very next day I had the opportunity to meet with &lt;a title="Don Syme's WebLog on F# and Other Research Projects" href="http://blogs.msdn.com/dsyme/"&gt;Don Syme&lt;/a&gt;, inventor of &lt;a title="F# (Microsoft Research)" href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;F#&lt;/a&gt; (you never know who you meet sitting at the hot desks in Microsoft SDC!). &lt;p&gt;To me, this was a sign from the powers that be: play with F# or else! First step to get started, is download the &lt;a href="http://research.microsoft.com/fsharp/release.aspx"&gt;latest version MSI&lt;/a&gt; from the &lt;a title="Microsoft Research" href="http://research.microsoft.com"&gt;Microsoft Research&lt;/a&gt; site. After you install it, you can open Visual Studio and you will find that you have a new project template: &lt;p&gt;&lt;a href="http://csvj6a.tuk.livefilestore.com/y1pgLkij6idljsrtirdXT1BOI3Bq81NF6BwPsS2ctuiWBxwCXbiX4xhaBeLhDGgj38MQWxo4IaQs-w?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=318 alt=image src="http://tk3.storage.msn.com/y1pn-Ptgo1rXQnGw6J-ba27X6nFGPVSUoNQ-sltRxUu41_ZcjFNOON2r3xx_tMY2k3ag_rOR05m2qHT1jhyAXCGoQ?PARTNER=WRITER" width=416 border=0&gt;&lt;/a&gt;  &lt;p&gt;Not a lot of options for project types I'm afraid. But its a start at least, and Leon indicated there will be full commitment from Microsoft in the future (don't make me a liar Leon). When you create a new project, its very empty. So we add a new item, and notice a few options: &lt;p&gt;&lt;a href="http://csvj6a.tuk.livefilestore.com/y1pgLkij6idljvJZvBgVe2Kf3dubnPWinlKGvx2LV4leTVtXUnuhNW85tdEErtG3Vp1HaNcJfcTO9Y?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=249 alt=image src="http://tk3.storage.msn.com/y1pn-Ptgo1rXQl19hGPtpN4wZzBzS8E9X9QUChCILBPa4o0moR2Giitq3ZOm4o-ZUND86vBk3ZY9dTlLT-wA51gAg?PARTNER=WRITER" width=429 border=0&gt;&lt;/a&gt;  &lt;p&gt;To be honest, I have no idea what they all do. I'm as new to this as you! The script file has a FSX extension and this makes me wonder what kind of cool script stuff you can do with it. Undecided, Leon's voice came to me as if in a dream... &amp;quot;Use the Source, Luke, use the source&amp;quot;. &lt;p&gt;Sure enough, the F# Source File option has a FS extension which is what I was looking for. It comes with a heap of template code for you see how the language syntax works. I was pretty comfortable with the magic keyword 'let' already from Leon's presentation. I set off instead to get the 'interactive' mode to work, since I found this quite a neat feature.  &lt;p&gt;So it seems that there is a 'FSI.exe' which stands for F# Interactive. It is a command line tool that allows you to pass snippets of F# code followed by two semi-colons ;; to terminate the parameter. It seems to remember your 'state' such that functions are remembered in between calls. This is further implemented as a command window in Visual Studio, which is a nice feature. You have to activate it after you have installed F# MSI, by turning it on in the 'Add In' section: &lt;p&gt;&lt;a href="http://csvj6a.tuk.livefilestore.com/y1pUetM_rdoneO6ke8eLzx0V2Mz-zbiIVgB0RjPCxGGO4hUxSp9Cz1S0DCqZr-aSl_gcB0-fpWUOiFcCMLfrNMyIIaGPhuA4YG_?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=346 alt=image src="http://tk3.storage.msn.com/y1pn-Ptgo1rXQkTyXGRvNnBGee2_uavOGso0p4LVpv8WYqCjzrwKeOlBMkCsCKZH7bj7SRO3bD6FFbLMBNTs4o09g?PARTNER=WRITER" width=537 border=0&gt;&lt;/a&gt;  &lt;p&gt;Tick all the boxes, and the F# Interactive window opens. Now you can start typing inline F# code to your heart's content! You can even execute sections of existing code in your .FS files by highlighting a section of code, and pressing ALT-ENTER. This is very similar behaviour to SQL Management Studio - Query window, where you can highlight some T-SQL and press F5 to run just that code. The F# Interactive window will show any errors inline.  &lt;p&gt;For example, when you add a new source file, it comes with a bunch of syntactical examples, and one of them is the &amp;quot;highest common factor&amp;quot; code, as follows: &lt;blockquote&gt; &lt;p&gt;let rec hcf a b =           // notice: 2 arguments seperated by spaces&lt;br&gt;    if a=0 then b&lt;br&gt;    elif a&amp;lt;b then hcf a (b-a)           // notice: 2 arguments seperated by spaces&lt;br&gt;    else hcf (a-b) b&lt;/blockquote&gt; &lt;p&gt;So 'let' is kind of like 'dim' in VB, or 'var' in C# / Javascript, but, er, not really. 'rec' means that the call is recursive. You can't have a function that calls itself without the 'rec' identifier. Can't say that I am a fan of 'elif' instead of 'elseif'.  &lt;p&gt;I wanted to test to see if this function really works as indicated. Some tests I thought up in my head: &lt;blockquote&gt; &lt;p&gt;hcf 15 5 // Should return 5&lt;br&gt;hcf 48 52 // should return 4&lt;br&gt;hcf 1 1 // should return 1&lt;/blockquote&gt; &lt;p&gt;I could have deleted all the other redundant code, and entered my 3 tests above, then compiled and run it, but I suppose I would also have to print out the results or some such... too much hassle! So I highlighted the function definition and pressed ALT-RETURN to run it in interactive mode. Then in the interactive window, I typed each example, placing ;; at the end. Each time it returned the correct result: &lt;blockquote&gt; &lt;p&gt;val it : int = 5&lt;/blockquote&gt; &lt;p&gt;Finally I wanted to see the DirectX demo again that Leon showed in his presentation. The MSI also installs these examples, and I ran the DirectX demo in script mode, just to prove to myself Leon isn't a trickster or a witch (burn him!). Very impressive stuff. &lt;p&gt;Great! I now feel that I can put F# on my resume. I am interested in exploring it some more. I have some thoughts around graphing and other mathematical applications. I am particularly interested in finding examples of complex algorythms made extremely simple through the F# syntax. Finally, since FSI can effectively be called script-like (and there are those mysterious FSX files), what advantages might we be able to see in using it with other scripting tools/languages like PowerShell? &lt;p&gt;Oh, see you all at the &lt;a href="http://www.microsoft.com/australia/heroes"&gt;launch&lt;/a&gt; on Wednesday. &lt;p&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/F#" rel=tag&gt;F#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Fsharp" rel=tag&gt;Fsharp&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Don Syme" rel=tag&gt;Don Syme&lt;/a&gt;,&lt;a href="http://technorati.com/tags/script" rel=tag&gt;script&lt;/a&gt;,&lt;a href="http://technorati.com/tags/install" rel=tag&gt;install&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F# Interactive" rel=tag&gt;F# Interactive&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Microsoft Research" rel=tag&gt;Microsoft Research&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+My+Introduction+To+F%23&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!206.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!206.entry</guid><pubDate>Mon, 24 Mar 2008 12:24:44 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!206/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!206.entry#comment</wfw:comment><dcterms:modified>2008-03-24T12:24:44Z</dcterms:modified></item><item><title>Recent Announcements</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!199.entry</link><description>&lt;p&gt;Some interesting things announced today. First, the official dates for ReMIX Australia: &lt;blockquote&gt; &lt;p&gt;Sydney: Tuesday 20th May&lt;br&gt;Melbourne: Thursday 22nd May&lt;/blockquote&gt; &lt;p&gt;To be honest I've never been, but I think I'll see if it's doable this year.  &lt;p&gt;Secondly, the speakers for &lt;a href="http://www.codecampoz.com/"&gt;CodeCampOz&lt;/a&gt; are announced! Check out the sessions &lt;a href="http://www.codecampoz.com/2008/tabid/108/Default.aspx"&gt;here&lt;/a&gt;. &lt;p&gt;Of particular interest to me are the following sessions: &lt;ul&gt; &lt;li&gt;Interactive video using Silverlight and WCF - Jonas Folleso &lt;li&gt;ORM Smackdown - Adam Cogan&lt;/ul&gt; &lt;p&gt;Oh and don't forget the Readify presenters! &lt;ul&gt; &lt;li&gt;&lt;a href="http://notgartner.com/"&gt;Mitch Denny&lt;/a&gt; &lt;li&gt;&lt;a href="http://www.philipbeadle.net/"&gt;Phillip Beadle&lt;/a&gt; &lt;li&gt;&lt;a href="http://blogesh.wordpress.com/"&gt;Mahesh Krishnan&lt;/a&gt; &lt;li&gt;&lt;a href="http://lzcd.com/"&gt;Luke Drumm&lt;/a&gt;&lt;/ul&gt; &lt;p&gt;Finally, my new Microsoft SDC friend: &lt;a href="http://jcooney.net/"&gt;Joseph Cooney&lt;/a&gt; on Silverlight 2.0 and WPF (even though it doesn't say WPF on the CodeCampOz site, trust me, he's doing a WPF / SL comparison). &lt;p&gt;All in all its going to be a great weekend! Look forward to seeing you all there. &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/CodeCampOz" rel=tag&gt;CodeCampOz&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ReMIX" rel=tag&gt;ReMIX&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Australia" rel=tag&gt;Australia&lt;/a&gt;,&lt;a href="http://technorati.com/tags/WPF" rel=tag&gt;WPF&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SilverLight 2.0" rel=tag&gt;SilverLight 2.0&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Readify" rel=tag&gt;Readify&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Recent+Announcements&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!199.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!199.entry</guid><pubDate>Thu, 20 Mar 2008 11:49:32 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!199/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!199.entry#comment</wfw:comment><dcterms:modified>2008-03-20T11:49:32Z</dcterms:modified></item><item><title>Visual Studio Built-in Web Server</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!198.entry</link><description>&lt;p&gt; No doubt you've hit F5 to debug your web application from time to time, and you noticed the little web server that sits in your system tray. &lt;p&gt;&lt;a href="http://tkfiles.storage.msn.com/y1pi-7WJDf-VlntoqkliBmmisGgpObIPaBHA8qs6qsI_YH1j0B1A2CP1GWY32UyRJD0_hr3DT-xeqo?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;margin:0px 15px 0px 0px;border-left:0px;border-bottom:0px" height=82 alt="aspnet_devserver1" src="http://tkfiles.storage.msn.com/y1pi-7WJDf-VlmYiqbVKj-xHHcto73-4N5KsxPCOgYWrUqrqURwWaArUMRcEZRc67wRi7b2eWWAUbw?PARTNER=WRITER" width=243 align=left border=0&gt;&lt;/a&gt;In the old days you needed to have your web site setup as a virtual directory in IIS in order to be able to debug it. Now days it's a lot easier: the first time you debug Visual Studio starts up its own mini-IIS that hosts your web application and lets you debug. This works for web sites, ASMX web services, and WCF services.  &lt;p&gt;By default, it assigns a random port on the local machine. If you already have IIS then no doubt it is configured to use port 80, which is why the VS web server uses another random one. When your application loads up in browser, it will usually have a URL similar to this: &lt;blockquote&gt; &lt;p&gt;http://localhost:53669/default.aspx&lt;/blockquote&gt; &lt;p&gt;Even when you stop debugging, the web server continues to run! Which means you can manually open a browser and still hit that same location. This is perfect if you don't have a version of XP or Vista that comes with IIS.  &lt;p&gt;However, by default the port number &lt;strong&gt;is&lt;/strong&gt; random. This means tomorrow when you go to open and debug your application, it will run up with a different port number. Sometimes this is no big deal, but with web services and (in my case) WCF services, this hurts. Your WCF endpoints will be configured for debugging and the endpoints will specify the port number, so that you can debug them in VS. Every time the VS web server starts up, it gets a new random port number, which you then have to update in your WCF client endpoint. &lt;p&gt;Luckily the internal web server is configurable. With your web projects there is a property under the project properties - Web section: &lt;p&gt;&lt;a href="http://csvj6a.tuk.livefilestore.com/y1pgLkij6idljvYWwzk88yHmXZdSToqaCdyn8hGbiqCTHkClsCefovJBNhgZCoS7YG-Fza4olXA8Lk?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=433 alt="webproject_properties" src="http://csvj6a.tuk.livefilestore.com/y1pUetM_rdoneMGpBPFEL-2H-VEi8faKk3iJJqZmBOaWcyXyopNJzyqzVwmItF88AqK6fNqQG4m8SEJyJGgKBmJIUyJTNAN7b1a?PARTNER=WRITER" width=601 border=0&gt;&lt;/a&gt; &lt;p&gt;By default, the &amp;quot;Use Visual Studio Development Server&amp;quot; option is checked, and &amp;quot;Auto-assign Port&amp;quot; is selected. However you can change this to &amp;quot;Specific Port&amp;quot; as I have in the above example. You can also configure the web server further to pretend to use a virtual directory. This is great because it allows you to simulate production environments by specifying the same combination of ports and virtual directories as would exist on the production server. &lt;p&gt;Of course, you can save yourself the hassle of having multiple web servers running at once by just selecting &amp;quot;Use IIS Web Server&amp;quot; instead, however this isn't ideal in environments where multiple people work on a project and could potentially have different workstation setups.  &lt;p&gt;&lt;strong&gt;Further Resources&lt;/strong&gt;&lt;br&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms178477.aspx"&gt;ASP.NET and IIS Configuration&lt;/a&gt;&lt;br&gt;&lt;a href="http://msdn2.microsoft.com/en-us/magazine/cc164241.aspx"&gt;Build Web Server Solutions with End-To-End Extensibility&lt;/a&gt;&lt;br&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/58wxa9w5(VS.80).aspx"&gt;Web Servers in Visual Web Developer&lt;/a&gt;&lt;br&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/w566a94d.aspx"&gt;Troubleshooting the ASP.NET Development Server&lt;/a&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Visual Studio" rel=tag&gt;Visual Studio&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Visual Studio 2005" rel=tag&gt;Visual Studio 2005&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Visual Studio 2008" rel=tag&gt;Visual Studio 2008&lt;/a&gt;,&lt;a href="http://technorati.com/tags/IIS" rel=tag&gt;IIS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ASP.NET" rel=tag&gt;ASP.NET&lt;/a&gt;,&lt;a href="http://technorati.com/tags/development server" rel=tag&gt;development server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/web server" rel=tag&gt;web server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/port" rel=tag&gt;port&lt;/a&gt;,&lt;a href="http://technorati.com/tags/virtual directory" rel=tag&gt;virtual directory&lt;/a&gt;,&lt;a href="http://technorati.com/tags/system tray" rel=tag&gt;system tray&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Visual+Studio+Built-in+Web+Server&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!198.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!198.entry</guid><pubDate>Sun, 16 Mar 2008 01:30:17 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!198/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!198.entry#comment</wfw:comment><dcterms:modified>2008-03-16T01:30:17Z</dcterms:modified></item><item><title>Notification Services : Debug Tips and Tricks</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!190.entry</link><description>&lt;p&gt;Sql Server Notification Services can be tricky to debug. You have no code that you can put a breakpoint in (except for your managed api calls of course) and there's a lot of working parts inside. Here's a couple of tips that have helped me today dealing with a local and alpha problem. &lt;p&gt;&lt;strong&gt;Rule Testing&lt;/strong&gt;&lt;br&gt;After you upload your instance and the application is created, a &lt;u&gt;view&lt;/u&gt; is created for your event, subscription, and notification schemas. This means that the Sql you define in your subscription rule can be run against the table. I tend to remove the &amp;quot;INSERT&amp;quot; part of the rule, and just execute the select to make sure that my event is getting picked up and associated with a subscriber. &lt;p&gt;Even one step lower, you can just view the contents of your events schema (view) to make sure the event was posted there correctly, and view your subscriptions schema (view) to ensure that the correct subscription information is in there.  &lt;p&gt;&lt;strong&gt;Enable Distributor Logging&lt;/strong&gt;&lt;br&gt;In your Application XML there is a node for settings called &lt;em&gt;&amp;lt;ApplicationExecutionSettings&amp;gt;&lt;/em&gt;. You can use this to turn on 3 layers of debugging in your Notification Services application as follows: &lt;blockquote&gt; &lt;p&gt;&amp;lt;DistributorLogging&amp;gt;&lt;br&gt;    &amp;lt;LogBeforeDeliveryAttempts&amp;gt;true&amp;lt;/LogBeforeDeliveryAttempts&amp;gt;&lt;br&gt;    &amp;lt;LogStatusInfo&amp;gt;true&amp;lt;/LogStatusInfo&amp;gt;&lt;br&gt;    &amp;lt;LogNotificationText&amp;gt;true&amp;lt;/LogNotificationText&amp;gt;&lt;br&gt;&amp;lt;/DistributorLogging&amp;gt;&lt;/blockquote&gt; &lt;p&gt;Obviously this will add some overhead to your processing, but if you don't have high through-put then you could leave this on all the time. But for initial setups (such as on your local machine, or on production databases) it is invaluable.  &lt;p&gt;As the name suggests, the logging occurs around distributions of notifications. Your event should get stored in the relevant table after it is submitted, and your rule should process the events and post them to the notifications table. At this point, the distributor logging kicks in. When the service 'ticks' and processes your notifications for delivery, information is logged in a view matching your notifications view. For example, if your notifications class name is &amp;quot;BlogUpdates&amp;quot; then there will be a view automatically created called 'NSBlogUpdatesNotificationDistribution'. You can monitor this view for changes while you post an event that &lt;strong&gt;should&lt;/strong&gt; trigger a distribution. Keep refreshing the view and you will see a new entry appear for a desired notification delivery. It details what delivery channel to use, the user, the content being delivered, and a status of the delivery. Eventually this will change to &amp;quot;Delivery Succeeded&amp;quot;. If not, you can find information inline to assist in debugging. &lt;p&gt;&lt;strong&gt;Windows Event Log&lt;br&gt;&lt;/strong&gt;Some problems are not specific to Notification Services. For example, your distributor account might not have read access to the XSLT needed to format the content for delivery. In these cases, information is posted to the event log. &lt;p&gt;&lt;strong&gt;Email Notifications&lt;/strong&gt;&lt;br&gt;A final tip relates specifically to email notifications. I have noticed that if the SMTP server rejects the service sending the distributions (for whatever reason) you will not receive any information to the affect. Nothing appears in the event log, and nothing in the distributor log view. If you suspect this is your issue, then I can only suggest installing an SMTP relay locally and pointing your delivery channel to that server instead. At least you can get more information in your SMTP logs this way. &lt;p&gt;&lt;strong&gt;More Information On Notification Services&lt;br&gt;&lt;/strong&gt;My 4 part series for beginners:&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!165.entry"&gt;Notification Services - Part 1 - Technology Overview&lt;/a&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!172.entry"&gt;Notification Services - Part 2 - Example Overview and Instance XML&lt;/a&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!180.entry"&gt;Notification Services - Part 3 - Application XML&lt;/a&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!181.entry"&gt;Notification Services - Part 4 - Managed API&lt;/a&gt; &lt;p&gt;Notification Services tutorial: &lt;a href="http://msdn2.microsoft.com/en-au/library/ms170337.aspx"&gt;http://msdn2.microsoft.com/en-au/library/ms170337.aspx&lt;/a&gt;&lt;br&gt;MSDN help: &lt;a href="http://msdn2.microsoft.com/en-au/library/ms172483.aspx"&gt;http://msdn2.microsoft.com/en-au/library/ms172483.aspx&lt;/a&gt;&lt;br&gt;API reference: &lt;a href="http://msdn2.microsoft.com/en-au/library/microsoft.sqlserver.notificationservices.aspx"&gt;http://msdn2.microsoft.com/en-au/library/microsoft.sqlserver.notificationservices.aspx&lt;/a&gt; &lt;p&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Sql Server Notification Services" rel=tag&gt;Sql Server Notification Services&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Notification Services" rel=tag&gt;Notification Services&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SSNS" rel=tag&gt;SSNS&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Sql Server 2005" rel=tag&gt;Sql Server 2005&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Sql Server" rel=tag&gt;Sql Server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XML" rel=tag&gt;XML&lt;/a&gt;,&lt;a href="http://technorati.com/tags/debug" rel=tag&gt;debug&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Event log" rel=tag&gt;Event log&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SMTP" rel=tag&gt;SMTP&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Notification+Services+%3a+Debug+Tips+and+Tricks&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!190.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!190.entry</guid><pubDate>Fri, 07 Mar 2008 07:32:15 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!190/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!190.entry#comment</wfw:comment><dcterms:modified>2008-03-07T07:32:15Z</dcterms:modified></item><item><title>Particls</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!189.entry</link><description>&lt;p&gt;Presumably you subscribe to blogs. You might even subscribe to &lt;strong&gt;this&lt;/strong&gt; blog. How many do you subscribe to? What about other feeds, like Engadget? Podcasts? What about sites you read manually, like your local newspaper site?  &lt;p&gt;Let's be honest, there's a lot of information on the web that we would like to be able to digest. 3 years ago, I would simply load up my browser, go to a url of a site, and read the articles. This is how I kept up with the technology industry and the goings-on. Unfortunately it was hard to sort through and get to the quality pieces of information that I really wanted to know about. &lt;p&gt;Then I started subscribing to blogs. A few at first. People who were at the top of their game and were driving the technologies I was interested in. I tried some other tools (including Outlook) for periods at a time, and eventually came across Google Reader. By now my list of feeds had grown.  &lt;p&gt;&lt;strong&gt;Content Is King&lt;/strong&gt; &lt;p&gt;I was following the big corporate bloggers as well as the little guy down the street. I was more interested in the content of the post than the poster themselves. In a move that would shock the world, some of the big guys on campus were scratched from my feed list. I spent a fair amount of time customising my Reader with the information I really wanted to receive. I still had a dilemna though: what about those posters who provide quality sometimes, boring crap other times? Well I guess I just had to skip those entries, 'mark as read', although sometimes I didn't know the post was crap and not related until I had spent time reading the first few lines or summary. &lt;p&gt;&lt;strong&gt;Enter Particls&lt;/strong&gt; &lt;p&gt;I can't remember how I first came across Particls. But for me it was a smash hit instantly. The essence of &lt;a title=Particls href="http://www.particls.com/"&gt;Particls&lt;/a&gt; is about attention management. From their &lt;a href="http://www.particls.com/about/"&gt;About&lt;/a&gt; page: &lt;blockquote&gt; &lt;p&gt;The web is just too big. No one has time to keep track of all the sites and topics that interest them.&lt;/blockquote&gt; &lt;p&gt;You see, every person, site, feed has something interesting to say at some point. Why not have a system that can rate and prioritise the information for you so that you only get presented with information you are specifically interested in? &lt;p&gt;&lt;a href="http://tkfiles.storage.msn.com/y1pi-7WJDf-VllZVzcMpuG5P1GqH0wdZPZpyc5-RELGoeLxFWW-whMvkhq4-YSFnYxAnQJT-R8sDmI?PARTNER=WRITER"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px" height=353 alt=Particls1 src="http://tkfiles.storage.msn.com/y1pi-7WJDf-VlnvSVSFweH59qy0Ljb6qQLCGDb3ZMCcSzDWyDRBCLPNoQnBLOplH2MK7tQVCw278Ok?PARTNER=WRITER" width=428 border=0&gt;&lt;/a&gt; &lt;br&gt;For example, with Particls I can specify all those blog feeds I follow in Reader (imported as OPML of course) and all those feeds I previously removed. Then I can prioritise them individually: which ones are more important to me on the whole? Further, I can specify key words that I am interested in, and keywords that I am &lt;strong&gt;not&lt;/strong&gt; interested in. &lt;p&gt;&lt;a href="http://tkfiles.storage.msn.com/y1pi-7WJDf-Vll1anbyMQZgDK7n7nCdUJE8zWwXOhhZjPi-r46nIESv-sn-plKe3Yjs8yq19UP1w1w?PARTNER=WRITER"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px" height=244 alt=Particls2 src="http://tkfiles.storage.msn.com/y1pi-7WJDf-Vlk8oUN6pXxWXBASgfJZB6z2FjoxC-BtHDlyuWm-hN34JI58UAKRQM55uUk3jKkXxIY?PARTNER=WRITER" width=180 align=left border=0&gt;&lt;/a&gt;Particls will present the inf ormation to me based on relevancy. By spending a certain amount of time up front defining the kinds of information I want to hear about, Particls can continue to deliver information that I specifically want to read.  &lt;p&gt;Furthermore, you can tell Particls to search for information. This means even if you don't have any blogs you subscribe to, you can still specify keywords of interest, and let Particls do the rest.  &lt;p&gt;The information can be delivered to you in a number of ways. If you must, you can get the annoying popups around the system tray area. You can get a news ticker across the top, or a nice sidebar (my personal choice). You can use multiple options if you like: tell your news ticker to display only the most relevant and important information, tell your sidebar to disappear when not in use and show less relevant information. Particls can even provide an RSS feed for you to consume in another reader if you so desire.  &lt;p&gt;&lt;a href="http://csvj6a.tuk.livefilestore.com/y1pgLkij6idljur8nbS0nWTHRiACqnRaFtSNzhJu0aCQY1mwYDbFPix5vTIvu6SeE4BSss9LnIgJaQ?PARTNER=WRITER"&gt;&lt;img style="border-top-width:0px;border-left-width:0px;border-bottom-width:0px;border-right-width:0px" height=367 alt=desktop src="http://tk3.storage.msn.com/y1pn-Ptgo1rXQnv-dCLdwtfq23OsAGDSPZi56T-gdqHhqCJCyXM_BXcdDgBbz2Lj35U-7TopsiGdOdnp6LpCuWFbg?PARTNER=WRITER" width=591 border=0&gt;&lt;/a&gt;  &lt;p&gt;On my wide screen it works great with Vista sidebar. If you get a notification that is inaccurate, you can simply right click and tell it to give less information about this topic. In this way, &lt;a title=Particls href="http://www.particls.com/"&gt;Particls&lt;/a&gt; quickly learns what your priorities are in order to deliver you more relevant information. &lt;p&gt;Oh, did I mention &lt;a title=Particls href="http://www.particls.com/"&gt;Particls&lt;/a&gt; is free? Enough reason to go and give it a shot. &lt;br&gt;Even better, it is produced by a local Brisbane (Australia) company called &lt;a title="Faraday Media" href="Faraday Media"&gt;Faraday Media&lt;/a&gt;.  &lt;p&gt;Currently the download link on the site is disabled. I believe this is because they might be moving from beta to production (can anyone shed light on this?). I'll let you know as soon as I hear something. &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I've tried to contact Chris Saad from &lt;a title="Faraday Media" href="http://www.faradaymedia.com/"&gt;Faraday Media&lt;/a&gt; about this a few times this week but didn't want to delay the article any longer waiting for a reply. &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Particls" rel=tag&gt;Particls&lt;/a&gt;,&lt;a href="http://technorati.com/tags/RSS" rel=tag&gt;RSS&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Particls&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!189.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!189.entry</guid><pubDate>Thu, 06 Mar 2008 08:45:28 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!189/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!189.entry#comment</wfw:comment><dcterms:modified>2008-03-06T08:45:28Z</dcterms:modified></item><item><title>Notification Services - Part 4 - Managed API</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!181.entry</link><description>&lt;p&gt;In the first 3 parts of this series we discovered how to define a Notification Services application via the instance and application XML. In part 2 we defined an example scenario where users are automatically subscribed to receive notifications in their email whenever someone posts a comment against their blog post. In this part we will discover how to write code to access the event schemas we defined in part 3, and how to insert subscribers. For the sake of brevity, this post will define sections of code, not entire classes. Assume a class library project in C# that will be called by our main blog ASP.NET application. The methods defined in this post would be found in such a library. &lt;p&gt;This post assumes that the Notification Services instance is installed on the same machine that will be running the code. This is important because to access a NS instance, you don't use connection strings as is typical in ADO.NET. Instead, it refers to registry entries which are automatically placed by NS when the instances is 'Registered' and 'Started'. For more information, see the MSDN link. &lt;p&gt;&lt;strong&gt;Preperation&lt;/strong&gt;&lt;br&gt;Our class library project will need access to the Notification Services libraries in order to communicate with Notification Services. You can add this through references. The assembly file name is &lt;em&gt;Microsoft.SqlServer.NotificationServices.dll&lt;/em&gt;. This assembly is installed in the GAC when Notification Services is installed (with SQL Server).  &lt;p&gt;At some stage we will also need to define what our Instance name and Application name is. We could put this in a constant but ideally it would be in web.config and accessible through a property somewhere. This code will assume a class called 'Settings' which has properties called 'InstanceName' and 'ApplicationName'. Eg. &lt;em&gt;string application = Settings.ApplicationName;&lt;/em&gt;  &lt;p&gt;A lot of the time we will need access to an instance of a class called &lt;em&gt;NSInstance&lt;/em&gt;. Through this class we can get access to our NS application, by getting an instance of &lt;em&gt;NSApplication&lt;/em&gt;. The rest of this post will refer to instances of both of these classes, so we will define some code for them now: &lt;blockquote&gt; &lt;p&gt;NSInstance BlogInstance = new NSInstance(Settings.InstanceName); &lt;br&gt;NSApplication BlogApplication = &lt;br&gt;             new NSApplication(BlogInstance, Settings.ApplicationName);&lt;/blockquote&gt; &lt;p&gt;In Notification Services an instance can have multiple applications, even though previously we have defined only 1. &lt;p&gt;&lt;strong&gt;Subscribers&lt;br&gt;&lt;/strong&gt;First we'll define some methods for subscribing and unsubscribing users. Before we do this, we need to think about how authentication is tracked. For simplicity sake, we will assume that users are authenticated by active directory. This means the current windows principal will provide us with a username as a string: &lt;blockquote&gt; &lt;p&gt;string userId = WindowsIdentity.GetCurrent().Name;&lt;/blockquote&gt; &lt;p&gt;You may remember from our application schemas that we needed to store a UserId. This was a simple string that represents the user a subscription belongs to. Before we can add subscriptions, we need to first check that the instance has the user registered as a subscriber. We can do this as follows: &lt;blockquote&gt; &lt;p&gt;public bool Exists(string userId)   {&lt;br&gt;         SubscriberEnumeration mySubscriberEnumeration =&lt;br&gt;                new SubscriberEnumeration(BlogInstance);&lt;br&gt;         Subscriber mySubscriber = mySubscriberEnumeration[userId];&lt;br&gt;         return (mySubscriber != null);&lt;br&gt;}&lt;/blockquote&gt; &lt;p&gt;As you can see we use our &lt;em&gt;BlogInstance&lt;/em&gt; to access an enumeration of all users, which can be indexed by the user's name. We could easily modify this into a Delete method for a subscriber as follows: &lt;blockquote&gt; &lt;p&gt;if (mySubscriber != null)  mySubscriber.Delete();&lt;/blockquote&gt; &lt;p&gt;Now we know how to check for a subscriber, we can write code to add one: &lt;blockquote&gt; &lt;p&gt;if (Exists(userId)==false) {&lt;br&gt;      Subscriber subscriber = new Subscriber(BlogInstance);&lt;br&gt;      subscriber.Enabled = true;&lt;br&gt;      subscriber.SubscriberId = userId; &lt;br&gt;      subscriber.Add();&lt;br&gt;}&lt;/blockquote&gt; &lt;p&gt;Simple! If we don't check for a subscriber first, an exception will occur if a name is added twice.  &lt;p&gt;&lt;strong&gt;Devices&lt;br&gt;&lt;/strong&gt;In my last post I discussed Devices very quickly. Devices allow you to specify different delivery locations for different subscriptions. For example, I might want to receive notifications by email &lt;strong&gt;and&lt;/strong&gt; instant message. We need to define a device for our subscriptions to be allocated against: &lt;p&gt;            SubscriberDevice device = new SubscriberDevice(BlogInstance);&lt;br&gt;            device.DeviceName = &amp;quot;WorkEmail&amp;quot;;&lt;br&gt;            device.SubscriberId = userId;&lt;br&gt;            device.DeviceTypeName = &amp;quot;Email&amp;quot;;&lt;br&gt;            device.DeviceAddress = &amp;quot;myrealemailaddress@hotmail.com&amp;quot;;&lt;br&gt;            device.DeliveryChannelName = &amp;quot;SMTP&amp;quot;;&lt;br&gt;            device.Add();  &lt;p&gt;DeviceName is often referenced in your application XML rule for subscriptions so it is usually important to have a naming standard for your devices. However we have not been using devices up to this point so the values you put here aren't important for now.  &lt;p&gt;DeliveryChannelName however is extremely important. In part 2 we defined the instance XML and part of that was the &amp;lt;DeliveryChannels&amp;gt;. In that XML we defined a protocol of type SMTPDelivery with a name of SMTP. When defining the device delivery channel name, it must match one of the channels specified in your instance XML otherwise no deliveries will be sent (no exception will occur, however when the service runs your notifications, it is at this point that it will fail, and details will be inserted into the event log). &lt;p&gt;As with subscribers you can check if the device has already been added as follows: &lt;blockquote&gt; &lt;p&gt;SubscriberDeviceEnumeration deviceEnumeration =&lt;br&gt;                new SubscriberDeviceEnumeration(BlogInstance, userId);&lt;br&gt;SubscriberDevice mySubscriberDevice = deviceEnumeration [&amp;quot;WorkEmail&amp;quot;];&lt;br&gt;return (mySubscriberDevice != null);&lt;/blockquote&gt; &lt;p&gt;As with subscribers, we should check the device has not already been added before commencing the insert process. And as with subscribers, deleting a device is as easy as calling the Delete method of the SubscriberDevice instance.&lt;br&gt;&lt;br&gt;&lt;strong&gt;Subscriptions&lt;br&gt;&lt;/strong&gt;Since we are only concerned with adding a subscription, the code for this is reasonably simple. Remember our requirements originally stated that a user will be automatically subscribed to a post after the post is created. This means we don't even need to check if the user is already subscribed since they couldn't possibly be. This makes our code even easier. Here is what the add method might look like:  &lt;blockquote&gt; &lt;p&gt;public void Add(string userId, string deviceName, int PostId) {  &lt;br&gt;            Subscription subscription = &lt;br&gt;                         new Subscription(BlogApplication, &amp;quot;CommentSubscription&amp;quot;);          &lt;br&gt;            subscription.SetFieldValue(&amp;quot;DeviceName&amp;quot;, &amp;quot;WorkEmail&amp;quot;);&lt;br&gt;            subscription.SetFieldValue(&amp;quot;SubscriberLocale&amp;quot;, &amp;quot;en-au&amp;quot;);&lt;br&gt;            subscription.SubscriberId = userId;&lt;br&gt;            subscription.SetFieldValue(&amp;quot;PostId&amp;quot;, PostId);&lt;br&gt;            subscription.Add();&lt;br&gt;}&lt;/blockquote&gt; &lt;p&gt;Because the .Net type subscription has no way of knowing at design-time what fields your subscription schema might have, it uses a common method for setting your subscription fields. This means you won't get compile errors if you don't really have a &amp;quot;PostId&amp;quot; in your subscription schema in Notification Services, but you will get a runtime exception on the &lt;em&gt;subscription.Add();&lt;/em&gt;  method call. &lt;p&gt;Important to note is that in the constructor for a &lt;em&gt;Subscription&lt;/em&gt; takes an &lt;em&gt;NSApplication&lt;/em&gt; instance now. This is because even though subscribers and devices are specific to an instance, an actual subscription is specific to an application only. Also note the second parameter of the constructor. This is the name of the subscription class we are subscribing to. Note that the name we supplied 'CommentSubscription' is the name we specified for our subscription class in the application XML. Once again, this will cause a runtime exception at the &lt;em&gt;subscription.Add(); &lt;/em&gt;method call if the subscription class name is invalid. &lt;p&gt;Well done! The user is now subscribed to receive notifications when comments are posted. However we still have to define how comments are posted to Notification Services so that those subscriptions can be acted upon. &lt;p&gt;&lt;strong&gt;Events&lt;br&gt;&lt;/strong&gt;Going back to our Events schema defined in our application XML, there is a number of fields we need to supply information for. The &lt;em&gt;Event&lt;/em&gt; class helps us set values for those fields very easily, just like it does for subscriptions. To add an event to Notification Services is as easy as this: &lt;blockquote&gt; &lt;p&gt;Event event = new Event(BlogApplication, &amp;quot;NewCommentEvent&amp;quot;);&lt;br&gt;event[&amp;quot;PostId&amp;quot;] = postId;&lt;br&gt;event[&amp;quot;Name&amp;quot;] = CommentPosterUserName;&lt;br&gt;event[&amp;quot;Details&amp;quot;] = CommentText;EventCollector eventCollector = &lt;br&gt;                new EventCollector(BlogApplication, &amp;quot;BlogEventsProvider&amp;quot;);&lt;br&gt;eventCollector.Write(event);&lt;/blockquote&gt; &lt;p&gt;In this code, we assume that we already have the values of the comment text, the user who posted the comment, and the original blog postId that the comment was posted against. The &lt;em&gt;Event &lt;/em&gt;class lets us define the details to post to Notification Services through an indexer, and the &lt;em&gt;EventCollector&lt;/em&gt; class will write the events to Notification Services for us. As usual incorrect fields specified will result in a runtime exception. &lt;p&gt;Some items to note here. First, the constructor for an event needs the name of the event class we are posting to. We only defined 1 in our events schema; this was defined in the last post in our application XML. Secondly, in our last post we also defined the &amp;lt;Providers&amp;gt; node and the &amp;lt;NonHostedProvider&amp;gt; sub node (right at the end). When defining an &lt;em&gt;EventCollector&lt;/em&gt; we must pass our provider name to the contstructor. You can not post an event to Notification Services without using one of the providers specified in your application XML. Because we are specifying events in code outside of Notification Services, our provider is a 'NonHostedProvider': not hosted by Notification Services. &lt;p&gt;&lt;strong&gt;Summary&lt;br&gt;&lt;/strong&gt;Well that's it. We call the events to post a subscription in the very next line of code after we post our blog entry. And we call our event method whenever someone posts a comment against a blog entry. And Notification Services will take care of the rest.  &lt;p&gt;This brings us to the end of my series on Notification Services. If there is anything else you would like to know about, please don't hesitate to contact me and I'll do my best to provide useful information.  &lt;p&gt;&lt;strong&gt;Notification Services Series&lt;/strong&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!165.entry"&gt;Notification Services - Part 1 - Technology Overview&lt;/a&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!172.entry"&gt;Notification Services - Part 2 - Example Overview and Instance XML&lt;/a&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!180.entry"&gt;Notification Services - Part 3 - Application XML&lt;/a&gt;&lt;br&gt;&lt;a href="http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!181.entry"&gt;Notification Services - Part 4 - Managed API&lt;/a&gt; &lt;p&gt;&lt;strong&gt;Further Resources &lt;br&gt;&lt;/strong&gt;Notification Services tutorial: &lt;a href="http://msdn2.microsoft.com/en-au/library/ms170337.aspx"&gt;http://msdn2.microsoft.com/en-au/library/ms170337.aspx&lt;/a&gt;&lt;br&gt;MSDN help: &lt;a href="http://msdn2.microsoft.com/en-au/library/ms172483.aspx"&gt;http://msdn2.microsoft.com/en-au/library/ms172483.aspx&lt;/a&gt;&lt;br&gt;API reference: &lt;a href="http://msdn2.microsoft.com/en-au/library/microsoft.sqlserver.notificationservices.aspx"&gt;http://msdn2.microsoft.com/en-au/library/microsoft.sqlserver.notificationservices.aspx&lt;/a&gt;&lt;br&gt; &lt;div style="padding-right:0px;display:inline;padding-left:0px;padding-bottom:0px;margin:0px;padding-top:0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/Notification Services" rel=tag&gt;Notification Services&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Sql Server" rel=tag&gt;Sql Server&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Sql Server 2005" rel=tag&gt;Sql Server 2005&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XML" rel=tag&gt;XML&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Events" rel=tag&gt;Events&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Notifications" rel=tag&gt;Notifications&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Subscriptions" rel=tag&gt;Subscriptions&lt;/a&gt;,&lt;a href="http://technorati.com/tags/C#" rel=tag&gt;C#&lt;/a&gt;,&lt;a href="http://technorati.com/tags/API" rel=tag&gt;API&lt;/a&gt;&lt;/div&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=-5552977989164759373&amp;page=RSS%3a+Notification+Services+-+Part+4+-+Managed+API&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=stevennagy.spaces.live.com&amp;amp;GT1=stevennagy"&gt;</description><comments>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!181.entry#comment</comments><guid isPermaLink="true">http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!181.entry</guid><pubDate>Sun, 24 Feb 2008 02:42:09 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://stevennagy.spaces.live.com/blog/cns!B2EFDBF0964586B3!181/comments/feed.rss</wfw:commentRss><wfw:comment>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!181.entry#comment</wfw:comment><dcterms:modified>2008-02-24T02:43:14Z</dcterms:modified></item><item><title>Notification Services - Part 3 - Application XML</title><link>http://stevennagy.spaces.live.com/Blog/cns!B2EFDBF0964586B3!180.entry</link><description>&lt;p&gt;The application XML defines the key information about your Notification Services (NS) application. This includes the schemas for event data being received, schemas for what users can subscribe to, and schemas for the information that will be sent in a notification. At the bare minimum you need 1 schema for each section. The application XML is defined with the following elements: &lt;blockquote&gt; &lt;p&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; ?&amp;gt;&lt;br&gt;&amp;lt;Application xmlns:xsd=&amp;quot;...&lt;a href="http://www.w3.org/2001/XMLSchema&amp;quot;"&gt;&amp;quot;&lt;/a&gt;  xmlns:xsi=&amp;quot;&lt;a href="http://www.w3.org/2001/XMLSchema-instance&amp;quot;"&gt;...&amp;quot;&lt;/a&gt;  xmlns=&amp;quot;&lt;a href="http://www.microsoft.com/MicrosoftNotificationServices/ApplicationDefinitionFileSchema&amp;quot;"&gt;...&amp;quot;&lt;/a&gt;&amp;gt; &lt;br&gt;    &amp;lt;EventClasses&amp;gt;&amp;lt;/EventClasses&amp;gt;&lt;br&gt;    &amp;lt;SubscriptionClasses&amp;gt;&amp;lt;/SubscriptionClasses&amp;gt;&lt;br&gt;    &amp;lt;NotificationClasses&amp;gt;&amp;lt;/NotificationClasses&amp;gt;  &lt;p&gt;    &amp;lt;Providers&amp;gt;&amp;lt;/Providers&amp;gt;&lt;br&gt;    &amp;lt;Generator&amp;gt;&amp;lt;/Generator&amp;gt;&lt;br&gt;    &amp;lt;Distributors&amp;gt;&amp;lt;/Distributors&amp;gt;&lt;br&gt;    &amp;lt;ApplicationExecutionSettings&amp;gt;&amp;lt;/ApplicationExecutionSettings&amp;gt;  &lt;p&gt;&amp;lt;/Application&amp;gt;&lt;/blockquote&gt; &lt;p&gt;Here you can see the sections where we define our 3 different schemas: EventClasses, SubscriptionClasses, and NotificationClasses.  &lt;p&gt;&lt;strong&gt;Events&lt;br&gt;&lt;/strong&gt;Continuing on from the example we mentioned previously, users will subscribe to comments for a particular blog. This means that the comment itself is an event: when a comment is sent to notification services, the system checks for any subscribers who should be notified, and notifies them. This means that the comment is in fact our event.  &lt;p&gt;It is important to decide early on what information you want to track about the comment. In our case, users will be subscribing to receive comments for a particular blog post. The best way to track a blog post is by its Id. Referring to the schema defined in part 2 each blog post has a 'PostId' and this is referenced as a foreign key to the Comment table. This is the first item of information we will need in our schema. No doubt we'll also need to send notifications with the comment title and contents, so we'll add those two fields to our schema as well. Our final entry for the application XML looks like this: &lt;blockquote&gt; &lt;p&gt;&amp;lt;EventClasses&amp;gt;&lt;br&gt;    &amp;lt;EventClass&amp;gt;&lt;br&gt;        &amp;lt;EventClassName&amp;gt;NewCommentEvent&amp;lt;/EventClassName&amp;gt;&lt;br&gt;        &amp;lt;Schema&amp;gt;&lt;br&gt;            &amp;lt;Field&amp;gt;&lt;br&gt;                &amp;lt;FieldName&amp;gt;PostId&amp;lt;/FieldName&amp;gt;&lt;br&gt;                &amp;lt;FieldType&amp;gt;int&amp;lt;/FieldType&amp;gt;&lt;br&gt;                &amp;lt;FieldTypeMods&amp;gt;not null&amp;lt;/FieldTypeMods&amp;gt;&lt;br&gt;            &amp;lt;/Field&amp;gt;&lt;br&gt;            &amp;lt;Field&amp;gt;&lt;br&gt;                &amp;lt;FieldName&amp;gt;Name&amp;lt;/FieldName&amp;gt;&lt;br&gt;                &amp;lt;FieldType&amp;gt;varchar(255)&amp;lt;/FieldType&amp;gt;&lt;br&gt;                &amp;lt;FieldTypeMods&amp;gt;not null&amp;lt;/FieldTypeMods&amp;gt;&lt;br&gt;            &amp;lt;/Field&amp;gt;&lt;br&gt;            &amp;lt;Field&amp;gt;&lt;br&gt;                &amp;lt;FieldName&amp;gt;Details&amp;lt;/FieldName&amp;gt;&lt;br&gt;                &amp;lt;FieldType&amp;gt;nvarchar(4000)&amp;lt;/FieldType&amp;gt;&lt;br&gt;                &amp;lt;FieldTypeMods&amp;gt;not null&amp;lt;/FieldTypeMods&amp;gt;&lt;br&gt;            &amp;lt;/Field&amp;gt;                &lt;br&gt;        &amp;lt;/Schema&amp;gt;&lt;br&gt;        &amp;lt;IndexSqlSchema&amp;gt;&lt;br&gt;            &amp;lt;SqlStatement&amp;gt;&lt;br&gt;                CREATE INDEX KnowledgeEventIndex&lt;br&gt;                ON KnowledgeEvent ( PostId );&lt;br&gt;            &amp;lt;/SqlStatement&amp;gt;&lt;br&gt;        &amp;lt;/IndexSqlSchema&amp;gt;&lt;br&gt;    &amp;lt;/EventClass&amp;gt;&lt;br&gt;&amp;lt;EventClasses&amp;gt;&lt;/blockquote&gt; &lt;p&gt;When your instance XML is imported into NS, and the application XML is processed, these fields will actually be created in a new table. You can also see we have defined an index that will be created in the same table. &lt;p&gt;&lt;strong&gt;Notifications&lt;/strong&gt;&lt;br&gt;This is quite simple to define. What information will our users receive in their email? Well we already had to consider this when defining our event schema. The user will receive the comment name and contents in their email. So this is the only information we need to define in our schema for notifications: &lt;blockquote&gt; &lt;p&gt;&amp;lt;NotificationClasses&amp;gt;&lt;br&gt;    &amp;lt;NotificationClass&amp;gt;&lt;br&gt;        &amp;lt;NotificationClassName&amp;gt;BlogCommentNotification&amp;lt;/NotificationClassName&amp;gt;&lt;br&gt;        &amp;lt;Schema&amp;gt;&lt;br&gt;            &amp;lt;Fields&amp;gt;                    &lt;br&gt;                &amp;lt;Field&amp;gt;&lt;br&gt;                    &amp;lt;FieldName&amp;gt;Name&amp;lt;/FieldName&amp;gt;&lt;br&gt;                    &amp;lt;FieldType&amp;gt;nvarchar(255)&amp;lt;/FieldType&amp;gt;&lt;br&gt;                &amp;lt;/Field&amp;gt;&lt;br&gt;                &amp;lt;Field&amp;gt;&lt;br&gt;                    &amp;lt;FieldName&amp;gt;Details&amp;lt;/FieldName&amp;gt;&lt;br&gt;                    &amp;lt;FieldType&amp;gt;nvarchar(4000)&amp;lt;/FieldType&amp;gt;&lt;br&gt;                &amp;lt;/Field&amp;gt;                    &lt;br&gt;            &amp;lt;/Fields&amp;gt;&lt;br&gt;        &amp;lt;/Schema&amp;gt;&lt;br&gt;        &amp;lt;ContentFormatter&amp;gt;&lt;br&gt;            &amp;lt;ClassName&amp;gt;XsltFormatter&amp;lt;/ClassName&amp;gt;&lt;br&gt;            &amp;lt;Arguments&amp;gt;&lt;br&gt;                &amp;lt;Argument&amp;gt;&lt;br&gt;                    &amp;lt;Name&amp;gt;XsltBaseDirectoryPath&amp;lt;/Name&amp;gt;&lt;br&gt;                    &amp;lt;Value&amp;gt;....&amp;lt;/Value&amp;gt;&lt;br&gt;                &amp;lt;/Argument&amp;gt;&lt;br&gt;                &amp;lt;Argument&amp;gt;&lt;br&gt;                    &amp;lt;Name&amp;gt;XsltFileName&amp;lt;/Name&amp;gt;&lt;br&gt;                    &amp;lt;Value&amp;gt;NotificationFormatter.xslt&amp;lt;/Value&amp;gt;&lt;br&gt;                &amp;lt;/Argument&amp;gt;&lt;br&gt;            &amp;lt;/Arguments&amp;gt;&lt;br&gt;        &amp;lt;/ContentFormatter&amp;gt;&lt;br&gt;        &amp;lt;Protocols&amp;gt;&lt;br&gt;            &amp;lt;Protocol&amp;gt;&lt;br&gt;                &amp;lt;ProtocolName&amp;gt;SMTP&amp;lt;/ProtocolName&amp;gt;&lt;br&gt;                &amp;lt;Fields&amp;gt;&lt;br&gt;                    &amp;lt;Field&amp;gt;&lt;br&gt;                        &amp;lt;FieldName&amp;gt;Subject&amp;lt;/FieldName&amp;gt;&lt;br&gt;                        &amp;lt;SqlExpression&amp;gt;'[BLOG_COMMENT] ' + Name&amp;lt;/SqlExpression&amp;gt;&lt;br&gt;                    &amp;lt;/Field&amp;gt;&lt;br&gt;                    &amp;lt;Field&amp;gt;&lt;br&gt;                        &amp;lt;FieldName&amp;gt;From&amp;lt;/FieldName&amp;gt;&lt;br&gt;                        &amp;lt;SqlExpression&amp;gt;N'blogbot@snagy.name'&amp;lt;/SqlExpression&amp;gt;&lt;br&gt;                    &amp;lt;/Field&amp;gt;&lt;br&gt;                    &amp;lt;Field&amp;gt;&lt;br&gt;                        &amp;lt;FieldName&amp;gt;To&amp;lt;/FieldName&amp;gt;&lt;br&gt;                        &amp;lt;SqlExpression&amp;gt;DeviceAddress&amp;lt;/SqlExpression&amp;gt;&lt;br&gt;                    &amp;lt;/Field&amp;gt;&lt;br&gt;                    &amp;lt;Field&amp;gt;&lt;br&gt;                        &amp;lt;FieldName&amp;gt;Priority&amp;lt;/FieldName&amp;gt;&lt;br&gt;                        &amp;lt;SqlExpression&amp;gt;N'Normal'&amp;lt;/SqlExpression&amp;gt;&lt;br&gt;                    &amp;lt;/Field&amp;gt;&lt;br&gt;                    &amp;lt;Field&amp;gt;&lt;br&gt;                        &amp;lt;FieldName&amp;gt;BodyFormat&amp;lt;/FieldName&amp;gt;&lt;br&gt;                        &amp;lt;SqlExpression&amp;gt;N'html'&amp;lt;/SqlExpression&amp;gt;&lt;br&gt;                    &amp;lt;/Field&amp;gt;&lt;br&gt;                &amp;lt;/Fields&amp;gt;&lt;br&gt;                &amp;lt;ProtocolExecutionSettings&amp;gt;&amp;lt;/ProtocolExecutionSettings&amp;gt;&lt;br&gt;            &amp;lt;/Protocol&amp;gt;&lt;br&gt;        &amp;lt;/Protocols&amp;gt;&lt;br&gt;    &amp;lt;/NotificationClass&amp;gt;&lt;br&gt;&amp;lt;/NotificationClasses&amp;gt;&lt;/blockquote&gt; &lt;p&gt;The first part of the &amp;lt;NotificationClass&amp;gt; node is very simple to create. First we give our schema a name via the &amp;lt;NotificationClassName&amp;gt; node. Then we define our 2 fields in the &amp;lt;schema&amp;gt; node.  &lt;p&gt;Next we go on to define our content formatter. In our case, we want to use a stock standard XSLT to define our markup. So we specify its base path and file name. Finally, we want to define what protocol to use for this notification class. In the last post we defined our &amp;lt;DeliveryChannels&amp;gt; in the instance XML. Here, we must match a valid protocol from that list. We only defined one: of type SMTPDelivery, and called it 'SMTP'. We use that name here and go on to define all the important fields required for sending an email. Note that the &amp;lt;SqlExpression&amp;gt; field specifies the value to use. This actually is a valid SQL expression; the value you supply here is translated into an SQL statement to retrieve the values required for the notification. For example, the 'To' section specifies &lt;strong&gt;DeviceAddress&lt;/strong&gt; as the value to use for this field. We'll learn about the DeviceAddress and where it comes from a little later, but suffice to say it is pulled from the database. For absolte literal values, we follow normal SQL conventions and put them in 'single quotes'. In the case you want to combine a literal value with a database field, combine them with normal SQL syntax, such as in the case of the 'Subject' field where we defined the literal '[BLOG_COMMENT] ' and the database value &lt;strong&gt;Name&lt;/strong&gt; (which is the comment name).  &lt;p&gt;&lt;strong&gt;Subscriptions&lt;br&gt;&lt;/strong&gt;Next we have to define how to turn event data into notifications, and we do this through the &amp;lt;SubscriptionClasses&amp;gt; node:  &lt;blockquote&gt; &lt;p&gt;&amp;lt;SubscriptionClasses&amp;gt;&lt;br&gt;    &amp;lt;SubscriptionClass&amp;gt;&lt;br&gt;        &amp;lt;SubscriptionClassName&amp;gt;CommentSubscription&amp;lt;/SubscriptionClassName&amp;gt;&lt;br&gt;        &amp;lt;Schema&amp;gt;&amp;lt;/Schema&amp;gt;&lt;br&gt;        &amp;lt;EventRules&amp;gt;&lt;br&gt;            &amp;lt;EventRule&amp;gt;&amp;lt;/EventRule&amp;gt;&lt;br&gt;        &amp;lt;/EventRules&amp;gt;&lt;br&gt;    &amp;lt;/SubscriptionClass&amp;gt;        &lt;br&gt;&amp;lt;/SubscriptionClasses&amp;gt;&lt;/blockquote&gt; &lt;p&gt;As usual, we give our subscription class a name through the &amp;lt;SubscriptionClassName&amp;gt; node. Then, we define 2 parts to our subscription: the schema defining what fields can be subscribed to, and the rule that will process an event and turn it into a notification.  &lt;p&gt;The schema follows the same format as the &amp;lt;EventClasses&amp;gt; schema. For our application, we only want the user to be able to subscribe to a particular blog post, so we specify the PostId. However, we also want to track subscriptions on a 'per device' basis, so we also need to track what device the user is subscribing with. This manifests in our schema as follows:  &lt;blockquote&gt; &lt;p&gt;&amp;lt;Schema&amp;gt;&lt;br&gt;    &amp;lt;Field&amp;gt;&lt;br&gt;        &amp;lt;FieldName&amp;gt;DeviceName&amp;lt;/FieldName&amp;gt;&lt;br&gt;        &amp;lt;FieldType&amp;gt;nvarchar(255)&amp;lt;/FieldType&amp;gt;&lt;br&gt;        &amp;lt;FieldTypeMods&amp;gt;not null&amp;lt;/FieldTypeMods&amp;gt;&lt;br&gt;    &amp;lt;/Field&amp;gt;&lt;br&gt;    &amp;lt;Field&amp;gt;&lt;br&gt;        &amp;lt;FieldName&amp;gt;PostId&amp;lt;/FieldName&amp;gt;&lt;br&gt;        &amp;lt;FieldType&amp;gt;int&amp;lt;FieldType&amp;gt;&lt;br&gt;        &amp;lt;FieldTypeMods&amp;gt;not null&amp;lt;/FieldTypeMods&amp;gt;&lt;br&gt;    &amp;lt;/Field&amp;gt;&lt;br&gt;&amp;lt;/Schema&amp;gt;&lt;/blockquote&gt; &lt;p&gt;Essentially, any subscription being made to the application will &lt;strong&gt;have&lt;/strong&gt; to supply a device name and a PostId. However, when this schema is created as a table, Notification Services adds some other fields, such as a SubscriberId. In fact, all the schemas we've seen so far will be slightly modified by NS to keep things running smoothly.  &lt;p&gt;Next we must specify the rule to bring it all together. This rule takes the form of an SQL statement which joins potential subscriptions on to events. Each resulting row is a notification to be sent, and is parsed through the NotificationClass schema and formatters. Here is the &amp;lt;EventRule&amp;gt; we need to create notifications:  &lt;blockquote&gt; &lt;p&gt;&amp;lt;EventRule&amp;gt;&lt;br&gt;    &amp;lt;RuleName&amp;gt;CommentSubscriptionRule&amp;lt;/RuleName&amp;gt;&lt;br&gt;    &amp;lt;EventClassName&amp;gt;NewCommentEvent&amp;lt;/EventClassName&amp;gt;&lt;br&gt;    &amp;lt;Action&amp;gt;&lt;br&gt;        INSERT INTO BlogCommentNotification (SubscriberId, DeviceName, Name, Details)&lt;br&gt;        SELECT s.SubscriberId, s.DeviceName, e.Name, e.Details&lt;br&gt;        FROM NewCommentEvent e, CommentSubscription s&lt;br&gt;        WHERE e.PostId = s.PostId ;&lt;br&gt;    &amp;lt;/Action&amp;gt;&lt;br&gt;&amp;lt;/EventRule&amp;gt;&lt;/blockquote&gt; &lt;p&gt;So first up we give our rule a name. Next, we define which event class we are comparing against for subscriptions. We only have one: NewCommentEvent. Finally the &amp;lt;Action&amp;gt; node defines our SQL statement that discovers potential notifications. Later on we define a time interval for how often NS should check for new notifications. When this interval fires, NS goes through all Event Rules and runs them.  &lt;p&gt;So lets delve into that a little further. Lets pretend NS is configured to fire off notification checks every 4 hours. Over a 4 hour period, our blog site gets 15 comments spread over 3 different blog posts: PostId 17, 18, and 19. NS already has received subscriptions for PostId 17 only, however 3 people are subscribed to that single post. In total 7 comments were made. The 4 hours expires, and the above SQL statement is processed. The result of the select statement will return 21 rows, which are inserted into the 'BlogCommentNotification' table. Another process fires and passes each row in this table to our XSLT formatter, and sends the notification via the defined channel (SMTP).  &lt;p&gt;&lt;strong&gt;Other Settings&lt;/strong&gt;&lt;br&gt;Besides the Events, Subscriptions, and Notifications classes, we originally mentioned some other nodes in our application XML. These provide settings for how often the service should check for notifications, trace detail levels, and vacuuming (the process of cleaning out data from events table once sent, etc). For example, with the &amp;lt;Distributors&amp;gt; node you can specify a &lt;strong&gt;different machine&lt;/strong&gt; as being responsible for sending the notifications (useful for high-load scenarios). The only other node worth specifically mentioning is the &amp;lt;Providers&amp;gt; node: &lt;blockquote&gt; &lt;p&gt;&amp;lt;Providers&amp;gt;&lt;br&gt;    &amp;lt;NonHostedProvider&amp;gt;&lt;br&gt;        &amp;lt;ProviderName&amp;gt;BlogEventsProvider&amp;lt;/ProviderName&amp;gt;&lt;br&gt;    &amp;lt;/NonHostedProvider&amp;gt;&lt;br&gt;&amp;lt;/Providers&amp;gt;&lt;/blockquote&gt; &lt;p&gt;This node is used to define how events get submitted to the application. If you intend to provide events through the managed API (as we are) then this must be set to a &amp;lt;NonHostedProvider&amp;gt;. The name you specify here will be used in your code. More on this in the next post.  &lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;Well that wraps it up. Sorry for such a long post: I just didn't want to separate the application XML out into different posts. Note that all 3 major classes allow you to supply multiple schemas. This way you can have different kinds of notifications, different delivery methods, etc all depending on how users subscribe. The additional setting nodes that we didn't cover in detail can be found in the MSDN reference mentioned at the bottom. Next post will cover the managed API, specifically how 