<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:blogChannel="http://backend.userland.com/blogChannelModule" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" version="2.0">
  <channel>
    <title>Jeff Garoutte</title>
    <description>c# .net and anything else that happens across my desk</description>
    <link>http://www.jeffgaroutte.net/</link>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>BlogEngine.NET 1.5.0.7</generator>
    <language>en-US</language>
    <blogChannel:blogRoll>http://www.jeffgaroutte.net/opml.axd</blogChannel:blogRoll>
    <blogChannel:blink>http://www.dotnetblogengine.net/syndication.axd</blogChannel:blink>
    <dc:creator>Jeff Garoutte</dc:creator>
    <dc:title>Jeff Garoutte</dc:title>
    <geo:lat>0.000000</geo:lat>
    <geo:long>0.000000</geo:long>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/JeffGaroutte" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Older posts are broken for the moment</title>
      <description>&lt;p&gt;Recently, we did an upgrade to a new version of the .net blog engine.&amp;nbsp; This update changed how the URLs work and relate back to posts, images, and attachments.&amp;nbsp; While I am kicking myself for not testing the upgrade before deploying it; I am also a bit surprised that the new code was released without maintaining backwards compatibility of posts that were already published. &lt;/p&gt; &lt;p&gt;This brings me to a cross roads of choice.&amp;nbsp; Do I...&lt;/p&gt; &lt;ol&gt; &lt;li&gt;dig in the code, find the issue and and the backwards compatibility and have to do this each time a new release is issued.&lt;/li&gt; &lt;li&gt;leave the old posts as is and ignore the problem/issue (which, honestly, is irking me)&lt;/li&gt; &lt;li&gt;Fix each post individually.&lt;/li&gt; &lt;li&gt;Write my own blog engine and use it instead.&lt;/li&gt; &lt;li&gt;hope the development team fixes the problem and releases an update.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Given the options, 1 is too much repeated work, 2 will slowly drive me nuts over time, 3 is a bit of work but doable, 4 has a host of issues... and 5.... well...that might happen before 3 or 4 was finished anyway.&amp;nbsp; Who knows.&lt;/p&gt; &lt;p&gt;#4 Write my own blog engine and use it instead...&amp;nbsp; while the idea is entertaining, the reality is I like the .net blog engine.&amp;nbsp; I am not a fan of reinventing the wheel.&lt;/p&gt; &lt;p&gt;Now I don't believe I could write a better blog engine nor do I want to spend the time trying.&amp;nbsp; But everyone should have a personal project to work on to push their skills and try new things.&amp;nbsp;&amp;nbsp; A project like a blog engine is an excellent system to do exactly that.&amp;nbsp;&amp;nbsp; But it is not really what I want to do for a project.&amp;nbsp; So I am going to look at my options and see what I can do.&amp;nbsp; The real problem here however is the external links, from places like dotnetkicks.com are now broken to the old posts and writing a new engine, or updating the old articles wont address that issue.&amp;nbsp; So it looks like I have no choice but to sit down and add in the backwards compatibility for the old URL rewriting system.&amp;nbsp; The kick here is finding the time to do it.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Ill look into it and see what I can do.&amp;nbsp; In the mean time, my apologies to anyone looking for old posts, they are still here, just hiding.&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2009/10/04/Older-posts-are-broken-for-the-moment.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2009/10/04/Older-posts-are-broken-for-the-moment.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=a1608734-e071-4d04-98b7-5c17fe8e23e8</guid>
      <pubDate>Sun, 04 Oct 2009 21:37:05 -0400</pubDate>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=a1608734-e071-4d04-98b7-5c17fe8e23e8</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=a1608734-e071-4d04-98b7-5c17fe8e23e8</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2009/10/04/Older-posts-are-broken-for-the-moment.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=a1608734-e071-4d04-98b7-5c17fe8e23e8</wfw:commentRss>
    </item>
    <item>
      <title>The Hidden Requirement</title>
      <description>&lt;p&gt;Every developer runs into a hidden requirement leaving them feeling like a bird who discovered a closed window.&amp;#160; Hidden requirements are not new, nor are they exclusive to software development.&amp;#160; The first time I recall learning about hidden requirements was many years ago when I was in high school.&lt;/p&gt;  &lt;p&gt;My Father owned a couple duplexes which he took good care of.&amp;#160; My brother and I spent what seemed like an eternity doing yard work, small repairs, and shoveling the deep Minnesota snow from the sidewalks there.&amp;#160; In reality it was was not that much time and when I was old enough to use the snow blower it was even faster; but I digress.&amp;#160; Dad did not like paying someone else to do something that he could do himself.&amp;#160; So it comes as no surprise that when the branch of a tree in the backyard of one of the duplexes had grown over the power line that he scoffed at what NSP (Northern States Power Company) wanted to charge to remove the offending limb.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;- The tree was old, the branch was heavy and when winter came it was possible the weight of the snow and ice on the branch could break branch off and take down the power line.&amp;#160; Dad tried to be proactive and fix a problem before it was a problem.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;He looked at the branch, the line and the yard before hatching a simple plan.&amp;#160; What he needed to do was get the branch off the tree, to the ground, without taking out the power line or wounding himself in the process.&amp;#160; Higher up in the tree there was a &amp;quot;Y&amp;quot; formed by the trunk and a heavy branch.&amp;#160; &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;The Plan&lt;/strong&gt;- Tie a rope around the branch and run it through the &amp;quot;Y&amp;quot; higher up in the tree and down to the his Ford Ranger pickup truck.&amp;#160; He could cut the branch off the tree and it would swing around away from the power line.&amp;#160; After that, he could simply backup his truck to lower the branch safely to the ground.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;So, that is exactly what he did.&amp;#160; Now, before I go on allow me to say, no one was in the truck and no one was injured in the process.&amp;#160; &lt;/p&gt;  &lt;p&gt;He attached and ran the rope securely, got in the tree and cut the branch free.&amp;#160; For those of you thinking at this point, &amp;quot;He was standing on the branch and fell.... No, but plenty of people miss that safety tip as shown on youtube. &lt;/p&gt;  &lt;p&gt;The branch, as planned, swung safely away from the power line... Now enter the hidden requirement&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;The Hidden Requirement&lt;/strong&gt;- The nature of the the plan caused an additional requirement that was hidden.&amp;#160; The Ford Ranger was a &amp;quot;half ton&amp;quot; pickup truck.&amp;#160; The branch was more than a &amp;quot;half ton&amp;quot; branch.&amp;#160; Gravity, which had been accounted for by planning to back the truck up to lower the branch had an equation of it's own to introduce.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The branch, out weighing the truck, begin a slow but steady decent to the ground.&amp;#160; This means the unmanned truck was sliding back along the ground and began it's ascent up the tree.&amp;#160; The truck came to rest with the front bumper balancing on the ground and the branch sitting not far from it.&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;- How to safely get a truck out of a tree?*&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;A hidden requirement and a missing requirement are not the same thing.&amp;#160; Hidden requirements are specific to the solution that may have been over looked, for example: the weight of the truck must be greater than the weight of the branch.&amp;#160; Had Dad used a crane (or NSP) the weight of his truck would not have been an issue.&amp;#160; A missing requirement is something that is part of the problem in the first place that was overlooked or missed like &amp;quot;Don't break the power line&amp;quot;.&lt;/p&gt;  &lt;p&gt;A hidden requirement is only a problem if it becomes a &amp;quot;missed requirement&amp;quot;.&amp;#160; Avoiding the feeling of being the bird hitting the glass with hidden requirements is, in theory, fairly straight forward.&amp;#160; When you find a solution step through the use case(s) with the solution and reconsider each step of the solution.&amp;#160; If you change the solution slightly, repeat the process.&lt;/p&gt;  &lt;p&gt;Hidden requirements will always pop up unexpectedly.&amp;#160; Everyone will overlook something at some point.&amp;#160; When it happens I cant help but laugh and say,&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Well, that looks like a truck in a tree.&lt;/p&gt; &lt;/blockquote&gt;  &lt;h6&gt;*No trucks were harmed in the making of this post.&amp;#160; In fact, aside from having a really clean cab, the truck was in the same condition as it was before it went up the tree.&lt;/h6&gt;  &lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2009/10/04/The-Hidden-Requirement.aspx&amp;amp;title=The Hidden Requirement"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2009/10/04/The-Hidden-Requirement.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2009/10/04/The-Hidden-Requirement.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2009/10/04/The-Hidden-Requirement.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=d7ae63cd-0ef9-4b12-bfb7-9ca9fef56189</guid>
      <pubDate>Sun, 04 Oct 2009 21:15:29 -0400</pubDate>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=d7ae63cd-0ef9-4b12-bfb7-9ca9fef56189</pingback:target>
      <slash:comments>3</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=d7ae63cd-0ef9-4b12-bfb7-9ca9fef56189</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2009/10/04/The-Hidden-Requirement.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=d7ae63cd-0ef9-4b12-bfb7-9ca9fef56189</wfw:commentRss>
    </item>
    <item>
      <title>Using an Object for an Id</title>
      <description>&lt;p&gt;It's not that uncommon to use an ID for a data object.&amp;#160; However, sometimes more information is needed to uniquely identify an object than a number.&amp;#160; In these cases is useful to use another object.&amp;#160; It can contain an integer, guid, date created, created by, or even the date and time and object was modified.&lt;/p&gt;  &lt;p&gt;A good example of this would be a content management system.&amp;#160; A given piece of content could have a content object ID, which would contain an ID, the day and time of the modification, who modified the content and a revision number.&amp;#160; This would allow content to be retrieved not only by an ID but by revision allowing the content management system to save a history of the edits made to the content as well as draft's of pending revisions.&lt;/p&gt;  &lt;p&gt;Another example would be in a customer records management system.&amp;#160;&amp;#160; An address, an e-mail, a phone number, or instant messenger ID are all types of a contact information.&amp;#160; An abstract contact information base class could use an integer as an identifier for the object; however, if we used a contact information identifier object we would be able to inherit the identifier object to determine the type of relationship or parent object with contact information belong to.&amp;#160; For example, a phone number can belong to a person or a company.&amp;#160; We could use a person contact information identifier object or a company contact information identifier object inherited from an abstract contact information identifier object to determine what the type of parent object is in code.&amp;#160; &lt;/p&gt;  &lt;p&gt;The abstract contact information identifier object (that's a mouthful isn't it? ) could contain an int32 or int64 as an ID field.&amp;#160; It would also have a parent ID field.&amp;#160; &lt;/p&gt;  &lt;p&gt;The hard part of using an object for an id is giving up the easy &amp;quot;Id=5;&amp;quot; syntax.&amp;#160; But who says that needs to be given up?&lt;/p&gt;  &lt;p&gt;We all have overloaded a method or two at some point.&amp;#160; But what about overloading an operator?&amp;#160; &lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationId
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationId(Int32 id)
        {
            Id = id;
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Int32 Id { get; set; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; ContactInformationId(Int32 id)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationId(id);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; Int32(ContactInformationId id)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; id.Id;
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Ah ha! So if we took the following code not only would it compile but at the end id.Id would equal 12.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ContactInformationId id = 5;
id = 10;
&lt;span class="kwrd"&gt;if&lt;/span&gt; (id &amp;lt; 7) id = 13;
&lt;span class="kwrd"&gt;if&lt;/span&gt; (id &amp;gt; 7) id = 2;
&lt;span class="kwrd"&gt;if&lt;/span&gt; (id == 5) id = 6;
&lt;span class="kwrd"&gt;if&lt;/span&gt; (6 != id) id = 12;&lt;/pre&gt;
&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;But it is not all roses.&amp;#160; If you add another property...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationId
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationId(Int32 id)
        {
            Id = id;
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Int32 Id { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Int32 version { get; set; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; ContactInformationId(Int32 id)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationId(id);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; Int32(ContactInformationId id)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; id.Id;
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;and you run the following code&lt;/p&gt;

&lt;pre class="csharpcode"&gt;            ContactInformationId id = 5;
            id.version = 2;
            id = 10;

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (id &amp;lt; 7) id = 13;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (id &amp;gt; 7) id = 2;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (id == 5) id = 6;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (6 != id) id = 12;&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;id.Id will still be 12; but id.Version will be 0. &lt;/p&gt;

&lt;p&gt;Every time the ContactInformationId object uses the operator overload it return a new object &amp;quot;crushing&amp;quot; any other properties.&amp;#160; In the case of an id this might not be so bad.&amp;#160; In a Content Management System (CMS) a version number of 0 could be used to call the &amp;quot;Head&amp;quot; version.&amp;#160; But in cases where, &amp;quot;I don't need that, I only need an Int32,&amp;quot; there is a greater &amp;quot;hidden&amp;quot; value. &lt;/p&gt;

&lt;p&gt;Lets say I have a Person object with a PersonId object in it for an Id property.&amp;#160; I use lazy loading to get back a list of contact information.&amp;#160; I call ContactInformationDataService.GetByParentId(somePerson.Id); &lt;/p&gt;

&lt;p&gt;Now lets say I have a Company object with a CompanyId in it for an Id property. Again I call ContactInformationDataService.GetByParentId(someCompany.Id);&lt;/p&gt;

&lt;p&gt;if the Id properties were just Int32 there would be no way to know what return; after all company id 5 and person id 5 look the same as an Int32.&amp;#160; &lt;em&gt;But&lt;/em&gt; when they are a PersonId and CompanyId object we can use standard method overloading to know what we are returning.&lt;/p&gt;

&lt;p&gt;Take this another step and inherit the id objects from a common base class like...BaseId.&amp;#160; Now you can have a method in your data layer like GetByParentId(BaseId id) and, in the case of SQL server, set the stored procedure name based on the type of id object.&amp;#160; &lt;/p&gt;

&lt;p&gt;if(id is PersonId) sprocName=&amp;quot;usp_ContactInformation_GetByPersonId&amp;quot;; 
  &lt;br /&gt;else if(id is CompanyId) sprocName=&amp;quot;usp_ContactInformation_GetByCompanyId&amp;quot;;&lt;/p&gt;

&lt;p&gt;If you are a big xml fan, you can set the file name or top node based on the id type.&lt;/p&gt;

&lt;p&gt;More importantly you can use overloads on the methods to take action based on the type*. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ContactInformationList GetContactInformationByParentId(SomeBaseId id)
{
     &lt;span class="kwrd"&gt;if&lt;/span&gt;(id &lt;span class="kwrd"&gt;is&lt;/span&gt; PersonId) GetContactInformationByParentId((PeronsId)id);
     &lt;span class="kwrd"&gt;if&lt;/span&gt;(id &lt;span class="kwrd"&gt;is&lt;/span&gt; CompanyId) GetContactInformationByParentId((CompanyId)id);
}

&lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList GetContactInformationByParentId(PersonId id)
{
     ...
}

&lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList GetContactInformationByParentId(CompanyId id)
{
     ...
}&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;*Note: the Microsoft .Net Framework maps methods at compile time not run time.&amp;#160; So if a variable is boxed into a base type it will go to the method that uses the &amp;quot;boxed&amp;quot; type in the signature, not the type of object stored in the box at run time.&amp;#160; Always pay attention to how your variables are boxed when you pass them.&amp;#160; This is why logic like if(id is PersonId) in the GetContactInformationByParentId(BaseId id) method is needed.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I normally just declare my overloads in the abstract provider and avoid the type checking.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; ContactInformationList GetContactInformationByParentId(PersonId id);
&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; ContactInformationList GetContactInformationByParentId(CompanyId id);&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;In the end, it makes for somewhat cleaner code (it would be even cleaner if .net supported runtime type checking).&amp;#160; While the Id object does have an issue with crushing itself when assigned to...that is the expected behavior of an object that it is overwritten when we assign to it instead of a property.&lt;/p&gt;

&lt;p&gt;Below is an example of an abstract base class and subclass.&amp;#160; Something like GetByParentId(GenericId&amp;lt;Int32&amp;gt; id) would be extremely useful.&amp;#160; Notice the operator overloads are on the ContactInformation and not the abstract class.&amp;#160; This has to do with operator overloads needing to be &amp;quot;contained&amp;quot; within the type they are converting to or from.&amp;#160; In other words, they have to be there to prevent errors at compile time. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; GenericId&amp;lt;BaseIdType&amp;gt; 
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; GenericId(BaseIdType id)
        {
            Id = id;
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; BaseIdType Id { get; set; }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationId : GenericId&amp;lt;Int32&amp;gt;
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationId(Int32 id) : &lt;span class="kwrd"&gt;base&lt;/span&gt;(id)
        {
            
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; ContactInformationId(Int32 id)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationId(id);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; Int32(ContactInformationId id)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; id.Id;
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This solves a few issues for me when I am going back and forth between an object model and a relational data source like SQL Server.&lt;/p&gt;

&lt;p&gt;While the operator overloads make things a bit easier, they are not really required.&lt;/p&gt;

&lt;p&gt;You could get fancy and create an IIdentifier interface that defines an Id property &lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IIdentifier
{
    &lt;span class="kwrd"&gt;object&lt;/span&gt; Id { get; set; }
}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Now if you explicitly implement the IIdentifier interface or your base GenericId&amp;lt;BaseIdType&amp;gt; class like...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; IIdentifier.Id
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Id;
            }
            set
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;value&lt;/span&gt; &lt;span class="kwrd"&gt;is&lt;/span&gt; BaseIdType)
                    &lt;span class="kwrd"&gt;this&lt;/span&gt;.Id = (BaseIdType)&lt;span class="kwrd"&gt;value&lt;/span&gt;;
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                    &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidCastException(&lt;span class="kwrd"&gt;value&lt;/span&gt;.GetType().ToString() + &lt;span class="str"&gt;&amp;quot; can not be cast as a &amp;quot;&lt;/span&gt; + &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(BaseIdType).ToString());
            }
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;You can use the IIdentifier in your method signatures and not worry about the type of the internal Id....That means PersonId could be a Guid and CompanyId remains an Int32 and nothing explodes.&amp;#160; &lt;/p&gt;

&lt;p&gt;There is one little trick, you will want to implement the IEquatable&amp;lt;IIdentifier&amp;gt; on the GenericId&amp;lt;BaseIdType&amp;gt; class.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Equals(IIdentifier other)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; result = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.GetType()==other.GetType())            {
                result = Id.Equals(other.Id);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;We start off saying they are not equal.&amp;#160; We check the types to see if they are the same type and we call the equals method of the Id property and pass in the other identifiers Id property.&amp;#160; Because other is boxed as an IIdentifier this.Id==other.Id will &lt;strong&gt;always&lt;/strong&gt; be false.&amp;#160; &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Well not &amp;quot;always&amp;quot;, the Id property is boxed as an object and the default Equals method on an object checks to see if the two objects are both references to the same instance of an object (and while it is possible that they might be; they very rarely will be because of the nature of Int32, Guid, decimals and structs in general). See my blog about &lt;a href="http://www.jeffgaroutte.com/post/2009/06/Variable-boxing-and-3d3d-vs-Equals.aspx" target="_blank"&gt;variable boxing and == vs. Equals&lt;/a&gt; for more information.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Calling the equals method instead of using the == operator invokes the correct Equals method on the GenericId&amp;lt;BaseIdType&amp;gt; instead of the default object equals method...it has to do with compile time mapping of methods.&lt;/p&gt;

&lt;p&gt;If you add the ICloneable interface to the object as well you have a very nice little object that you can clone, pass around and do anything you need to do with it.&lt;/p&gt;

&lt;p&gt;I have seen people put methods in their identity object to get or delete an object with that id or return a list of child/parent objects.&amp;#160; &lt;/p&gt;

&lt;p&gt;What does all of this do?&amp;#160; It gives us a non generic type to use in our method signatures, a strongly typed generic base class and strongly typed sub classes to use in our methods.&amp;#160;&amp;#160; &lt;/p&gt;

&lt;p&gt;Finally, it does one more thing.&amp;#160; When someone changes the requirement from the Id being an Int32 to a Guid the the logic of the Id is separated from your code making it a little easier to change.&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2009/06/Using-an-Object-for-an-Id.aspx&amp;amp;title=Using an Object for an Id"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2009/06/Using-an-Object-for-an-Id.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2009/06/19/Using-an-Object-for-an-Id.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2009/06/19/Using-an-Object-for-an-Id.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=6548f3c4-05e2-4636-b936-c4a425456f4f</guid>
      <pubDate>Fri, 19 Jun 2009 18:00:07 -0400</pubDate>
      <category>General</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=6548f3c4-05e2-4636-b936-c4a425456f4f</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=6548f3c4-05e2-4636-b936-c4a425456f4f</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2009/06/19/Using-an-Object-for-an-Id.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=6548f3c4-05e2-4636-b936-c4a425456f4f</wfw:commentRss>
    </item>
    <item>
      <title>Variable boxing and == vs. Equals</title>
      <description>&lt;p&gt;Let's take a moment and think about exactly how boxed variables work when checking to see if they are equal.&lt;/p&gt;  &lt;p&gt;Here is a little Console application to do a quick comparison of how the Equals function and == operator work.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; VariableBoxEqualityTest
{
    &lt;span class="kwrd"&gt;class&lt;/span&gt; Program
    {
        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)
        {
            &lt;span class="kwrd"&gt;int&lt;/span&gt; x = 1;
            &lt;span class="kwrd"&gt;int&lt;/span&gt; y = 1;

            test(x, y);
           
            x = 2;
            y = 3;
            test(x, y);

            x = 5;
            test(x);
            Console.ReadKey();
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test(&lt;span class="kwrd"&gt;int&lt;/span&gt; x)
        {
            Console.WriteLine();
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Testing with x=y={0}&amp;quot;&lt;/span&gt;, x);
            DoTests(x, x);
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ox = x;
            ObjectRefIsEquals(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; ox);
            ObjectRefIsEqual(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; ox);

            Console.WriteLine();
            ObjectIsEqual(ox, ox);
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
        {
            Console.WriteLine();
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Testing with x={0} and y={1}&amp;quot;&lt;/span&gt;, x, y);
            DoTests(x, y);
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ox = x;
            &lt;span class="kwrd"&gt;object&lt;/span&gt; oy = y;
            ObjectRefIsEquals(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; oy);
            ObjectRefIsEqual(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; oy);
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DoTests(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
        {
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ox = x;
            &lt;span class="kwrd"&gt;object&lt;/span&gt; oy = y;
            ObjectIsEqual(ox, oy);
            ObjectIsEquals(ox, oy);
            intIsEqual(x, y);
            intIsEquals(x, y);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; intIsEqual(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;(int)x==(int)y : {0}&amp;quot;&lt;/span&gt;, x == y);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; intIsEquals(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;((int)x).Equals((int)y) : {0}&amp;quot;&lt;/span&gt;, x.Equals(y));
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectIsEqual(&lt;span class="kwrd"&gt;object&lt;/span&gt; x, &lt;span class="kwrd"&gt;object&lt;/span&gt; y)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;(object)x==(object)y : {0}&amp;quot;&lt;/span&gt;, x == y);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectIsEquals(&lt;span class="kwrd"&gt;object&lt;/span&gt; x, &lt;span class="kwrd"&gt;object&lt;/span&gt; y)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;((object)x).Equals((object)y) : {0}&amp;quot;&lt;/span&gt;, x.Equals(y));
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectRefIsEquals(&lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; x, &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; y)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;((ref object)x).Equals((ref object)y) : {0}&amp;quot;&lt;/span&gt;, x.Equals(y));
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectRefIsEqual(&lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; x, &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; y)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;((ref object)x)==((ref object)y) : {0}&amp;quot;&lt;/span&gt;, x==y);
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Now here are the results....&lt;/p&gt;

&lt;p&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="376" alt="Console application result." src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/Variableboxingandvs.Equals_A7E4/image_3.png" width="674" border="0" /&gt; &lt;/p&gt;

&lt;p&gt;There are four groups of results above, let us about the first result in each set (and the only one in the last set).&lt;/p&gt;

&lt;p&gt;(object)x==(object)y : False.&amp;#160; With the exception of the last result this test was always False.&amp;#160; Why?&amp;#160; Because == was checking to see if the object was the same object, not if the values were the same.&amp;#160; In the first 3 sets x and y were boxed into the ox and oy objects before the call to ObjectIsEqual.&amp;#160; The forth set passed ox in twice ObjectIsEqual(ox, ox); .&lt;/p&gt;

&lt;p&gt;Even when the values of x and y are the same the act of boxing them makes the objects different, and therefore not equal using the == operator.&lt;/p&gt;

&lt;p&gt;If you box the same variable a second time the two objects will not be equal even though they are the same variable.&amp;#160; &lt;/p&gt;

&lt;p&gt;Here's a code change you can use to easily test that if you like...&lt;/p&gt;

&lt;pre class="csharpcode"&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test(&lt;span class="kwrd"&gt;int&lt;/span&gt; x)
        {
            Console.WriteLine();
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Testing with x=y={0}&amp;quot;&lt;/span&gt;, x);
            DoTests(x, x);
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ox = x;
            ObjectRefIsEquals(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; ox);
            ObjectRefIsEqual(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; ox);

            Console.WriteLine();
            ObjectIsEqual(ox, ox);

            Console.WriteLine();
            &lt;span class="kwrd"&gt;object&lt;/span&gt; oy = x;
            ObjectIsEqual(ox, oy);
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;the 2nd test in in set is the ((object)x).Equals((object)y) test.&amp;#160; It passed in the 1st and 3rd set while failing in the 2nd.&amp;#160; Which is what we would expect since 1=1, 2!=3 and 5=5.&amp;#160; So the Equals function on a boxed (or unboxed) int works.&lt;/p&gt;

&lt;p&gt;The 3rd and 4thtests in each set&amp;#160; are the same functions from the first two tests except on unboxed ints.&amp;#160; Both the == operator and the Equals method were correct in little tests. (If they were Id be worried).&lt;/p&gt;

&lt;p&gt;the 5th and 6th test in each set are the same as the first two expect we are passing the objects in by reference.&amp;#160; We would expect the same results...but no, the in the 3rd set (object)x==(object y) was false and ref object x==ref object y was true.... what happened?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/Variableboxingandvs.Equals_A7E4/image_7.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="114" alt="What happened?" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/Variableboxingandvs.Equals_A7E4/image_thumb_2.png" width="370" align="left" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The 1st test boxes x twice and passes it into the test. So the objects are not the same and it fails.&lt;/p&gt;

&lt;p&gt;The 6th test boxes x once and pass in the same object twice so they match.&amp;#160; It has nothing to do with them being passed as a ref.&amp;#160;&amp;#160; Here's another code snip you can use to test it.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test(&lt;span class="kwrd"&gt;int&lt;/span&gt; x)
        {
            Console.WriteLine();
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Testing with x=y={0}&amp;quot;&lt;/span&gt;, x);
            DoTests(x, x);
            &lt;span class="kwrd"&gt;object&lt;/span&gt; ox = x;
            ObjectRefIsEquals(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; ox);
            ObjectRefIsEqual(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; ox);

            Console.WriteLine();
            ObjectIsEqual(ox, ox);

            Console.WriteLine();
            &lt;span class="kwrd"&gt;object&lt;/span&gt; oy = x;
            ObjectIsEqual(ox, oy);

            Console.WriteLine();
            ObjectRefIsEqual(&lt;span class="kwrd"&gt;ref&lt;/span&gt; ox, &lt;span class="kwrd"&gt;ref&lt;/span&gt; oy);
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;My point is, when you box a variable you have to pay attention to how you work with it while it is boxed.&amp;#160; I have seen code where it was assumed that x==y is true when x and y both equal 1 and they are boxed as an object.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2009/06/Variable-boxing-and-3d3d-vs-Equals.aspx&amp;amp;title=Variable boxing and the equal operator vs. the Equals method" target="_blank"&gt;&lt;img height="18" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2009/06/Variable-boxing-and-3d3d-vs-Equals.aspx" width="82" border="0" /&gt; &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2009/06/18/Variable-boxing-and-3d3d-vs-Equals.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2009/06/18/Variable-boxing-and-3d3d-vs-Equals.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=5be32498-1084-4152-83de-b54b6cf85605</guid>
      <pubDate>Thu, 18 Jun 2009 10:04:08 -0400</pubDate>
      <category>General</category>
      <category>Research</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=5be32498-1084-4152-83de-b54b6cf85605</pingback:target>
      <slash:comments>1</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=5be32498-1084-4152-83de-b54b6cf85605</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2009/06/18/Variable-boxing-and-3d3d-vs-Equals.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=5be32498-1084-4152-83de-b54b6cf85605</wfw:commentRss>
    </item>
    <item>
      <title>Extending the ASP.Net Security model to use rights: Cassini</title>
      <description>&lt;p&gt;I get a few messages about how the rights system fires many times per request and it is a lot of SQL traffic.&amp;#160; Allow me to address this issue and introduce to your silent partner Cassini.&lt;/p&gt;  &lt;p&gt;Most developers, myself included, love being able to click the &amp;quot;play&amp;quot; icon (press F5 or select start debugging from the menu) and be able to debug their WebForms or MVC application on their local box.&amp;#160; &lt;/p&gt;  &lt;p&gt;The catch here is this- the site you are debugging is not running on/being served by IIS.&amp;#160; It's Cassini.&amp;#160; &lt;/p&gt;  &lt;p&gt;Ok now do not jump up and say yes served by IIS...&amp;#160; I am talking about the default configuration that unless you have changed, it is running on Cassini.&amp;#160; That little web page down in the icon tray that says ASP.NET Development Server - Port #### when you mouse over it...that is Cassini.&amp;#160; &lt;/p&gt;  &lt;p&gt;I know, &amp;quot;big deal it just serves the application.&amp;quot;&amp;#160; What is often over looked is Cassini is not IIS and it behaves very differently.&amp;#160; I am going to talk in some generalities here and gloss over certain details but my good friend Google is more than happy to help fill in the gaps.&amp;#160; IIS handles all web requests through ISAPI filters, one of these filters is the asp.net filter.&amp;#160; The filters sort out who gets to handle each file request.&amp;#160; So by default on IIS; only apsx, .config, ascx etc etc files are handled by the asp.net framework.&lt;/p&gt;  &lt;p&gt;Cassini is IIS's dog who ate a cracker with a mound of peanut butter on top of it.&amp;#160; Every request that Cassini gets is handled by the asp.net framework and Cassini just keeps chomping away at it.&lt;/p&gt;  &lt;p&gt;Here is where this difference comes into play.&amp;#160; Lets say your site's home page has a 3 js files, 2 style sheets (one of general media and one for print), a logo image, a background image, an image used as li bullets, 4 images that are part of the navigation and another 4 images that are part of the sites design/layout.&amp;#160; Not an unreasonable page makeup right?&amp;#160; &lt;/p&gt;  &lt;p&gt;IIS and Cassini both get the request for the aspx page, sends it to asp.net to get the html and sends it back to the client. The client browser see's all of the images, scripts and css files and issues requests to get each file.&lt;/p&gt;  &lt;p&gt;IIS gets each request and sends the requests to filters based on the file type requested, in the example we talked about none of them are the asp.net filter.&amp;#160; So you get 1 request to asp.net for the page itself (you may get more because of webresources.axd but we will ignore those....glossing over)&lt;/p&gt;  &lt;p&gt;Cassini, still trying to get the peanut butter off the roof of it's mouth, gets every request and, not having filters, passes all of them to asp.net for processing...all of them.&amp;#160; 3 js + 2 css + logo + background +li image + 4 navigation + other 4 images....16 additional files for a total of 17 requests that generate an IPrincipal and rights.&amp;#160; Oh, and yes, you still get those other webresource.axd requests.&amp;#160; &lt;/p&gt;  &lt;p&gt;If you really want a shock open SQL Profiler and watch the asp.net membership and roles system at work in Cassini.&amp;#160; &lt;/p&gt;  &lt;p&gt;How do you fix this?&amp;#160; Well, strictly speaking you can not &amp;quot;fix&amp;quot; it.&amp;#160; By design an HttpModule gets called for every request so it will always get called.&amp;#160; But, you can try to cut down on the sql overhead by modifying your HttpModule to look at the file extension and not do anything for certain file types.&amp;#160; The downside to this is if someone changes the IIS configuration to pass jpg files to asp.net and tries to secure a directory of images in the web.config the Principle may not be correct for it work until you edit the code (you could but the file extensions in an appsetting so it would require modifying the web.config instead of a code change.)&lt;/p&gt;  &lt;p&gt;You can suffer with (or ignore) it in Cassini and test performance on a real IIS server...(which we all do anyway's right?)&lt;/p&gt;  &lt;p&gt;Or you can use a SqlDependency object or caching in the provider layer or serve back recently cached objects.&amp;#160; Even if you do this, the default asp.net membership and roles is going to kick your SQL Servers butt (Really try SQL Profiler on your database and watch it...)&lt;/p&gt;  &lt;p&gt;This is a spot where you need to figure out where you want to eat the cycles of doing it.&amp;#160; If SQL is local to the the web server the memory hit with caching may out weigh the SQL processing costs.&amp;#160; If the SQL Server is over a WAN cache it!&amp;#160;&amp;#160; If the SQL Server is on the same switch/network there are lots of factors you will want to look at....bandwidth, throughput, cost of development...etc etc.&lt;/p&gt;  &lt;p&gt;However this difference between IIS and Cassini raises it's ugly head in other areas of development as well.&amp;#160; For example, I wrote a HttpModule to stop bandwidth leeching once.&amp;#160; It worked fine on my local PC but failed to work when deployed in the production environment.&amp;#160; Because Cassini passed image requests to ASP.net it worked fine in development; but IIS does not pass them to asp.net so the module never had any requests come in to process.&amp;#160; After altering the IIS configuration to pass images files to the asp.net dll it worked wonderfully.&lt;/p&gt;  &lt;p&gt;One other place I have seen Cassini/IIS differences break things was with a large/bulk file uploader that provided a status bar in the browser.&amp;#160; It hooked into a &amp;quot;worker process&amp;quot; class for the web server to pull/write some information.&amp;#160; The problem was Cassini and IIS used different worker process classes and the method being used did not work with Cassini.&amp;#160; For the same reason it did not work on a newer version IIS.&amp;#160; Which means, not all version of IIS behave exactly the same under the hood and if you &amp;quot;hack&amp;quot; something in to get things to work, well....yeah.&amp;#160; It might not work after some random update/SP.&lt;/p&gt;  &lt;p&gt;I do development/testing with Cassini, I deploy to my local IIS where I test again; and finally I publish to the production server. When I need to debug HttpModules I set a conditional break that checks the file information so I am not stopping when I do not need to be.&lt;/p&gt;  &lt;p&gt;The short of it is, Cassini is not as smart as IIS and it processes files as asp.net request causing extra traffic in your code when you are debugging.&amp;#160; It is too busy with peanut butter to learn about filtering what requests are for ASP.net and which are not. &lt;/p&gt;  &lt;p&gt;Cassini on Wikipedia: &lt;a title="http://en.wikipedia.org/wiki/UltiDev_Cassini_Web_Server" href="http://en.wikipedia.org/wiki/UltiDev_Cassini_Web_Server"&gt;http://en.wikipedia.org/wiki/UltiDev_Cassini_Web_Server&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Special thanks to JB for reminding me to post this article that has been on my flash drive for a long time.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2009/06/Extending-the-ASPNet-Security-model-to-use-rights-Cassini.aspx&amp;amp;title=Extending the ASP.Net Security model to use rights: Cassini" target="_blank"&gt;&lt;img height="18" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2009/06/Extending-the-ASPNet-Security-model-to-use-rights-Cassini.aspx" width="82" border="0" /&gt; &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2009/06/18/Extending-the-ASPNet-Security-model-to-use-rights-Cassini.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2009/06/18/Extending-the-ASPNet-Security-model-to-use-rights-Cassini.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=ff9b4bc0-af09-4dcd-9d57-ee7044d73316</guid>
      <pubDate>Thu, 18 Jun 2009 09:49:55 -0400</pubDate>
      <category>General</category>
      <category>Visual Studio</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=ff9b4bc0-af09-4dcd-9d57-ee7044d73316</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=ff9b4bc0-af09-4dcd-9d57-ee7044d73316</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2009/06/18/Extending-the-ASPNet-Security-model-to-use-rights-Cassini.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=ff9b4bc0-af09-4dcd-9d57-ee7044d73316</wfw:commentRss>
    </item>
    <item>
      <title>Ajax Popup Tooltips</title>
      <description>&lt;p&gt;I was sent a link to &lt;a href="http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html" target="_blank"&gt;Caleb's blog about an ajax tooltip popup script.&lt;/a&gt;&amp;#160; It's a great article but the script was a little to specific for my uses.&amp;#160; As I played with the script I found some things I wanted to change a bit.&amp;#160; &lt;/p&gt;  &lt;p&gt;One issue is I needed to add it to a site with jQuery 1.2.6 (and for reasons I cant begin to understand) upgrading to a newer version of jQuery was not an option.&amp;#160; the other issue was I needed several different tooltips on the same page.&amp;#160; So I rewrote parts of the script.&amp;#160; &lt;/p&gt;  &lt;pre class="csharpcode"&gt;; (function($)
{
    $.popup = {
        defaults: {
            hideDelay: 500,
            currentID: &lt;span class="kwrd"&gt;null&lt;/span&gt;,
            hideTimer: &lt;span class="kwrd"&gt;null&lt;/span&gt;,
            popupAjaxRequest: &lt;span class="kwrd"&gt;null&lt;/span&gt;,
            requestUrl: &lt;span class="str"&gt;''&lt;/span&gt;,
            containerHtml: &lt;span class="str"&gt;'&amp;lt;div class=&amp;quot;PopupContainer&amp;quot;&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;table width=&amp;quot;&amp;quot; border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot; class=&amp;quot;PopupPopup&amp;quot;&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;tr&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;corner topLeft&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;corner topRight&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;/tr&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;tr&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;left&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;PopupContent&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;right&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;/tr&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;tr&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;corner bottomLeft&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;bottom&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'   &amp;lt;td class=&amp;quot;corner bottomRight&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;/tr&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;/table&amp;gt;'&lt;/span&gt;
            + &lt;span class="str"&gt;'&amp;lt;/div&amp;gt;'&lt;/span&gt;,
            emptyContent: &lt;span class="str"&gt;'&amp;amp;nbsp;'&lt;/span&gt;,
            errorMessage: {
                idReplacementRegEx: &lt;span class="str"&gt;'\{0\}'&lt;/span&gt;,
                errorText: &lt;span class="str"&gt;'&amp;lt;span style=&amp;quot;color:red&amp;quot; class=&amp;quot;smallText&amp;quot;&amp;gt;We did not return a valid result for Id {0}.  Please have your administrator check the error log.&amp;lt;/span&amp;gt;'&lt;/span&gt;
            },
            cssClasses: {
                PopupContentDiv: &lt;span class="str"&gt;'.PopupContent'&lt;/span&gt;,
                PopupTrigger: &lt;span class="str"&gt;'.PopupTrigger'&lt;/span&gt;,
                RequestDiv: &lt;span class="str"&gt;'.PopupResult'&lt;/span&gt;
            }
        }
    };

    $.fn.extend({
        popup: function(settings)
        {

            settings = $.extend({}, $.popup.defaults, settings);
            &lt;span class="rem"&gt;//var hideDelay = 500;&lt;/span&gt;
            &lt;span class="rem"&gt;//var currentID;&lt;/span&gt;
            &lt;span class="rem"&gt;//var hideTimer = null;&lt;/span&gt;
            &lt;span class="rem"&gt;//var popupAjaxrequest = null;&lt;/span&gt;

            var container = $(settings.containerHtml).mouseout(function()
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (settings.hideTimer)
                    clearTimeout(settings.hideTimer);
                settings.hideTimer = setTimeout(function()
                {
                    container.find(settings.cssClasses.PopupContentDiv).html(settings.emptyContent);
                    container.css(&lt;span class="str"&gt;'display'&lt;/span&gt;, &lt;span class="str"&gt;'none'&lt;/span&gt;);
                    settings.currentID = &lt;span class="str"&gt;''&lt;/span&gt;;
                }, settings.hideDelay);
            }).mouseover(function()
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (settings.hideTimer)
                    clearTimeout(settings.hideTimer);
            });

            $(&lt;span class="str"&gt;'body'&lt;/span&gt;).append(container);

            $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).find(settings.cssClasses.PopupTrigger).mouseover(function()
            {
                &lt;span class="rem"&gt;// format of 'rel' tag: pageid,guid&lt;/span&gt;
                var newId = $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).attr(&lt;span class="str"&gt;'rel'&lt;/span&gt;);


                &lt;span class="rem"&gt;// If no guid in url rel tag, don't popup blank&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (newId == &lt;span class="str"&gt;''&lt;/span&gt;)
                {
                    container.css(&lt;span class="str"&gt;'display'&lt;/span&gt;, &lt;span class="str"&gt;'none'&lt;/span&gt;);
                    settings.currentID = &lt;span class="str"&gt;''&lt;/span&gt;;
                    &lt;span class="kwrd"&gt;return&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (settings.hideTimer)
                    clearTimeout(settings.hideTimer);
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (settings.currentID == newId)
                    &lt;span class="kwrd"&gt;return&lt;/span&gt;;
                settings.currentID = newId;

                var pos = $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).offset();
                var width = $(&lt;span class="kwrd"&gt;this&lt;/span&gt;).width();


                &lt;span class="kwrd"&gt;if&lt;/span&gt; (settings.popupAjaxrequest)
                {
                    settings.popupAjaxrequest.abort();
                    settings.popupAjaxrequest = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                }
                popupAjaxrequest = $.ajax({
                    type: &lt;span class="str"&gt;'GET'&lt;/span&gt;,
                    url: settings.requestUrl,
                    data: &lt;span class="str"&gt;'id='&lt;/span&gt; + settings.currentID,
                    success: function(data)
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; ($(data).find(settings.cssClasses.RequestDiv).length != 0)
                        {
                            var text = $(data).find(settings.cssClasses.RequestDiv).html();
                            &lt;span class="rem"&gt;// Verify that we're pointed to a page that returned the expected results.&lt;/span&gt;
                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (text != &lt;span class="str"&gt;''&lt;/span&gt;)
                            {
                                container.find(settings.cssClasses.PopupContentDiv).html(settings.errorMessage.errorText.replace(settings.errorMessage.idReplacementRegEx, settings.currentID));
                            }
                            &lt;span class="rem"&gt;// Verify requested id is this id since we could have multiple ajax&lt;/span&gt;
                            &lt;span class="rem"&gt;// requests out if the server is taking a while.&lt;/span&gt;
                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (data.indexOf(settings.currentID) &amp;gt; 0)
                            {
                                container.find(settings.cssClasses.PopupContentDiv).html(text);
                            }
                            container.css({
                                left: (pos.left + width) + &lt;span class="str"&gt;'px'&lt;/span&gt;,
                                top: pos.top - 5 + &lt;span class="str"&gt;'px'&lt;/span&gt;
                            });
                            container.css(&lt;span class="str"&gt;'display'&lt;/span&gt;, &lt;span class="str"&gt;'block'&lt;/span&gt;);
                        }
                        &lt;span class="kwrd"&gt;else&lt;/span&gt;
                        {
                            container.find(settings.cssClasses.PopupContentDiv).html(settings.emptyContent);
                            container.css(&lt;span class="str"&gt;'display'&lt;/span&gt;, &lt;span class="str"&gt;'none'&lt;/span&gt;);
                        }
                        settings.popupAjaxrequest = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                    },
                    error: function(data)
                    {
                        container.find(settings.cssClasses.PopupContentDiv).html(settings.errorMessage.errorText.replace(settings.errorMessage.idReplacementRegEx, settings.currentID));
                        container.css({
                            left: (pos.left + width) + &lt;span class="str"&gt;'px'&lt;/span&gt;,
                            top: pos.top - 5 + &lt;span class="str"&gt;'px'&lt;/span&gt;
                        });
                        container.css(&lt;span class="str"&gt;'display'&lt;/span&gt;, &lt;span class="str"&gt;'block'&lt;/span&gt;);
                        settings.popupAjaxrequest = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                    }
                });
            }).mouseout(function()
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (settings.hideTimer)
                    clearTimeout(settings.hideTimer);
                settings.hideTimer = setTimeout(function()
                {
                    container.find(settings.cssClasses.PopupContentDiv).html(settings.emptyContent);
                    container.css(&lt;span class="str"&gt;'display'&lt;/span&gt;, &lt;span class="str"&gt;'none'&lt;/span&gt;);
                    settings.currentID = &lt;span class="str"&gt;''&lt;/span&gt;;
                }, settings.hideDelay);
            });
        }
    }); &lt;span class="rem"&gt;//fnextend end&lt;/span&gt;

})(jQuery);&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Using the script is fairly simple &lt;/p&gt;

&lt;pre class="csharpcode"&gt;$(&lt;span class="str"&gt;&amp;quot;#container&amp;quot;&lt;/span&gt;).popup({requestUrl:&lt;span class="str"&gt;&amp;quot;/someurl.aspx&amp;quot;&lt;/span&gt;});&lt;/pre&gt;

&lt;p&gt;When I have more time, I will try to make it work using the 1.3.x jquery live function. &lt;/p&gt;

&lt;p&gt;If you have not already, check out &lt;a href="http://rndnext.blogspot.com/2009/02/jquery-ajax-tooltip.html" target="_blank"&gt;Caleb's post about it&lt;/a&gt;.&amp;#160; I understand he has posted a newer version that tries to avoid excessive ajax requests. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http://jeffgaroutte.net/post/2009/02/Ajax-Popup-Tooltips.aspx&amp;amp;title=Ajax Popup Tooltips" target="_blank"&gt;&lt;img height="18" alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://jeffgaroutte.net/post/2009/02/Ajax-Popup-Tooltips.aspx" width="82" border="0" /&gt; &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2009/02/23/Ajax-Popup-Tooltips.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2009/02/23/Ajax-Popup-Tooltips.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=7c6f4f34-66cd-4f47-8a54-c78aa4e7953d</guid>
      <pubDate>Mon, 23 Feb 2009 01:13:00 -0400</pubDate>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=7c6f4f34-66cd-4f47-8a54-c78aa4e7953d</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=7c6f4f34-66cd-4f47-8a54-c78aa4e7953d</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2009/02/23/Ajax-Popup-Tooltips.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=7c6f4f34-66cd-4f47-8a54-c78aa4e7953d</wfw:commentRss>
    </item>
    <item>
      <title>The Dummy Provider: Testing membership and roles</title>
      <description>&lt;p&gt;Asp.net has a wonderful system built in for handling user accounts and roles. The administration interface is encapsulated in a separate web site that can be accessed from within Visual Studio but it is difficult to integrate into the site.&amp;#160; This often leads to building a new user administration area in each site.&amp;#160; The problem I have with this is going into the data store and deleting the incomplete test data and not having &amp;quot;known good&amp;quot; data for testing.&lt;/p&gt;  &lt;p&gt;In the past, I have talked about &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-1Getting-Started.aspx" target="_blank"&gt;provider pattern&lt;/a&gt; and the built is membership and roles systems both use providers.&amp;#160; This offers a wonderful framework for unit testing and more importantly for have a data store that reverts to a known good state every time the application is run.&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Enter the &amp;quot;dummy provider&amp;quot;.&amp;#160; A dummy provider contains the data store in the code.&amp;#160; It is nothing more than a list of objects that is modified by the providers methods.&amp;#160; Because of this the data will revert to its initial state when it is run, it can be used without a SQL server (or some other data store) and the user interface can be tested by adding, deleting and modifying the data until your hearts content.&amp;#160;&amp;#160; This makes testing and changing the user interface for membership and roles faster and easier; but the dummy provider is not limited to membership and roles.&amp;#160; &lt;/p&gt;  &lt;p&gt;Lets look at the some code, the dummy role provider&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Security;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CS.Data.Providers.Dummies
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DummyRoleProvider : RoleProvider
    {
        &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; _roles;
        &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;PersonToRole&amp;gt; _userToRole;
        &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PersonToRole : IEqualityComparer&amp;lt;PersonToRole&amp;gt;
        {
            &lt;span class="kwrd"&gt;public&lt;/span&gt; PersonToRole(&lt;span class="kwrd"&gt;string&lt;/span&gt; user, &lt;span class="kwrd"&gt;string&lt;/span&gt; role)
            {
                _userName = user;
                _roleName = role;
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; String _userName;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; String UserName
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _userName; }
                set { _userName = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; String _roleName;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; String RoleName
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _roleName; }
                set { _roleName = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="preproc"&gt;#region&lt;/span&gt; IEqualityComparer&amp;lt;PersonToRole&amp;gt; Members

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Equals(PersonToRole x, PersonToRole y)
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; ((x._userName == y._userName) &amp;amp;&amp;amp; (x._roleName == y._roleName));
            }

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetHashCode(PersonToRole obj)
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.GetHashCode();
            }

            &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
        }
        &lt;span class="kwrd"&gt;static&lt;/span&gt; DummyRoleProvider()
        {
            _roles = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();
            _roles.Add(&lt;span class="str"&gt;&amp;quot;Administrator&amp;quot;&lt;/span&gt;);
            _roles.Add(&lt;span class="str"&gt;&amp;quot;Cat&amp;quot;&lt;/span&gt;);
            _roles.Add(&lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;);
            _roles.Add(&lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;);

            _userToRole = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;PersonToRole&amp;gt;();
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Cat&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Administrator&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;));

            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;SomeCustomer&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;SomeCustomer1&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;SomeCustomer2&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin2&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin3&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Customer&amp;quot;&lt;/span&gt;));

            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;SomeCustomer2&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin3&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;));

            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;SomeCustomer&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;SomeCustomer1&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;));

            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin2&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Administrator&amp;quot;&lt;/span&gt;));
            _userToRole.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(&lt;span class="str"&gt;&amp;quot;Admin3&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Administrator&amp;quot;&lt;/span&gt;));

        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddUsersToRoles(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] usernames, &lt;span class="kwrd"&gt;string&lt;/span&gt;[] roleNames)
        {
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; user &lt;span class="kwrd"&gt;in&lt;/span&gt; usernames)
            {
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; role &lt;span class="kwrd"&gt;in&lt;/span&gt; roleNames)
                {
                    PersonToRole ptr = &lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(user, role);
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!_userToRole.Contains(ptr)) _userToRole.Add(ptr);
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ApplicationName { get; set; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CreateRole(&lt;span class="kwrd"&gt;string&lt;/span&gt; roleName)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!_roles.Contains(roleName)) _roles.Add(roleName);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; DeleteRole(&lt;span class="kwrd"&gt;string&lt;/span&gt; roleName, &lt;span class="kwrd"&gt;bool&lt;/span&gt; throwOnPopulatedRole)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_roles.Contains(roleName))
            {
                _userToRole = _userToRole.Where(p =&amp;gt; p.RoleName != roleName).ToList();
                _roles.Remove(roleName);
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] FindUsersInRole(&lt;span class="kwrd"&gt;string&lt;/span&gt; roleName, &lt;span class="kwrd"&gt;string&lt;/span&gt; usernameToMatch)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _userToRole.Where(p =&amp;gt; p.RoleName == roleName).Select(u =&amp;gt; u.UserName).ToArray();
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] GetAllRoles()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _roles.ToArray();
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] GetRolesForUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; username)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _userToRole.Where(p =&amp;gt; p.UserName == username).Select(r =&amp;gt; r.RoleName).ToArray();
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] GetUsersInRole(&lt;span class="kwrd"&gt;string&lt;/span&gt; roleName)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _userToRole.Where(p =&amp;gt; p.RoleName == roleName).Select(u =&amp;gt; u.UserName).ToArray();
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsUserInRole(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; roleName)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _userToRole.Contains(&lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(username,roleName));
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveUsersFromRoles(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] usernames, &lt;span class="kwrd"&gt;string&lt;/span&gt;[] roleNames)
        {
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; user &lt;span class="kwrd"&gt;in&lt;/span&gt; usernames)
            {
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; role &lt;span class="kwrd"&gt;in&lt;/span&gt; roleNames)
                {
                    PersonToRole p = &lt;span class="kwrd"&gt;new&lt;/span&gt; PersonToRole(user, role);
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_userToRole.Contains(p)) _userToRole.Remove(p);
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; RoleExists(&lt;span class="kwrd"&gt;string&lt;/span&gt; roleName)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _roles.Contains(roleName);
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;br /&gt;

&lt;p&gt;First you may notice there are 2 lists inside the provider.&amp;#160; One is just a list of strings.&amp;#160; because the asp.net role system treats roles as nothing more than a string the dummy provider does not need to hang onto any extra data.&amp;#160; The second list is holds onto a PersonToRole object.&amp;#160; The PersonToRole object just holds the username and role.&amp;#160; &lt;/p&gt;

&lt;p&gt;Using the provider is as easy as configuring the web.config...&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/TheDummyProviderTestingmembershipandrole_899/image_2.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="237" alt="image" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/TheDummyProviderTestingmembershipandrole_899/image_thumb.png" width="522" border="0" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;

&lt;p&gt;The user membership provider has a bit more too it.&amp;#160; Again there is a private class that defines the user that is stored in the list.&amp;#160; The providers constructor creates several users and stores them in an internal list.&lt;/p&gt;

&lt;p&gt;In the constructor there is a list of names that is used to create the user accounts.&amp;#160; To add the account to a specific role simply add the user name and role to the role providers constructor. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Security;
&lt;span class="kwrd"&gt;using&lt;/span&gt; CS.People;
&lt;span class="kwrd"&gt;using&lt;/span&gt; CS.Identifiers;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CS.Data.Providers.Dummies
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DummyMembershipProvider : MembershipProvider
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; myUser
        {
            &lt;span class="preproc"&gt;#region&lt;/span&gt; security fields &lt;span class="kwrd"&gt;for&lt;/span&gt; asp.net member and roles

            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _email = String.Empty;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Email
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _email; }
                set { _email = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; String _comments = String.Empty;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; String Comments
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _comments; }
                set { _comments = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _isApproved=&lt;span class="kwrd"&gt;true&lt;/span&gt;;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsApproved
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _isApproved; }
                set { _isApproved = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _isLocked=&lt;span class="kwrd"&gt;false&lt;/span&gt;;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsLocked
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _isLocked; }
                set { _isLocked = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; DateTime _created = DateTime.Now;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime CreatedDate
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _created; }
                set { _created = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; DateTime _login = DateTime.Now;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime LastLoginDate
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _login; }
                set { _login = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; DateTime _lastActivity = DateTime.Now;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime LastActivityDate
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _lastActivity; }
                set { _lastActivity = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; DateTime _lastPasswordChange = DateTime.Now;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime LastPasswordChangeDate
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _lastPasswordChange; }
                set { _lastPasswordChange = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; DateTime _lastLock=DateTime.Now;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime LastLockDate
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _lastLock; }
                set { _lastLock = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _passwordQuestion = String.Empty;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; PasswordQuestion
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _passwordQuestion; }
                set { _passwordQuestion = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _passwordAnswer=String.Empty;
            &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
            &lt;span class="rem"&gt;/// Used only by the dummy provider for testing&lt;/span&gt;
            &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; PasswordAnswer
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _passwordAnswer; }
                set { _passwordAnswer = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }
            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _password = String.Empty;
            &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
            &lt;span class="rem"&gt;/// Used only by the dummy provider for testing&lt;/span&gt;
            &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Password
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _password; }
                set { _password = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _userName = String.Empty;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UserName
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _userName; }
                set { _userName = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; Guid _id=Guid.Empty;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; Guid Id
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _id; }
                set { _id = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _isOnline;

            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsOnline
            {
                get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _isOnline; }
                set { _isOnline = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
            }

            &lt;span class="preproc"&gt;#endregion&lt;/span&gt;


        }
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, myUser&amp;gt; _users;
        &lt;span class="kwrd"&gt;static&lt;/span&gt; DummyMembershipProvider()
        {
            _users = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, myUser&amp;gt;();

            List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; names = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;{&lt;span class="str"&gt;&amp;quot;Administrator&amp;quot;&lt;/span&gt;,&lt;span class="str"&gt;&amp;quot;User&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Bob&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Ed&amp;quot;&lt;/span&gt;,&lt;span class="str"&gt;&amp;quot;George&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Frank&amp;quot;&lt;/span&gt;,
                &lt;span class="str"&gt;&amp;quot;Admin&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;SomeCustomer1&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;SomeCustomer&amp;quot;&lt;/span&gt;};
            &lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; name &lt;span class="kwrd"&gt;in&lt;/span&gt; names)
            {
                i++;
                CreateUser(name, &lt;span class="str"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;, name + &lt;span class="str"&gt;&amp;quot;@someplace.com&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;What is my name?&amp;quot;&lt;/span&gt;, name, (i % 2) == 0, Guid.NewGuid());
            }
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ApplicationName { get; set; }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; MembershipUser GetMembershipUser(myUser p)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MembershipUser(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Name, p.UserName, p.Id, p.Email, p.PasswordQuestion, p.Comments
                , p.IsApproved, p.IsLocked, p.CreatedDate, p.LastLoginDate, p.LastActivityDate, p.LastPasswordChangeDate
                , p.LastLockDate);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ChangePassword(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; oldPassword, &lt;span class="kwrd"&gt;string&lt;/span&gt; newPassword)
        {
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u.Password == oldPassword)
            {
                u.Password = newPassword;
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ChangePasswordQuestionAndAnswer(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; password, &lt;span class="kwrd"&gt;string&lt;/span&gt; newPasswordQuestion, &lt;span class="kwrd"&gt;string&lt;/span&gt; newPasswordAnswer)
        {
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u.Password != password)
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                u.PasswordAnswer = newPasswordAnswer;
                u.PasswordQuestion = newPasswordQuestion;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; myUser CreateUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; password, &lt;span class="kwrd"&gt;string&lt;/span&gt; email
            , &lt;span class="kwrd"&gt;string&lt;/span&gt; passwordQuestion, &lt;span class="kwrd"&gt;string&lt;/span&gt; passwordAnswer, &lt;span class="kwrd"&gt;bool&lt;/span&gt; isApproved
            , &lt;span class="kwrd"&gt;object&lt;/span&gt; providerUserKey)
        {
            myUser m = &lt;span class="kwrd"&gt;new&lt;/span&gt; myUser();
            m.UserName = username;
            m.Password = password;
            m.Email = email;
            m.PasswordQuestion = passwordQuestion;
            m.PasswordAnswer = passwordAnswer;
            m.IsApproved = isApproved;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (providerUserKey != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; providerUserKey &lt;span class="kwrd"&gt;is&lt;/span&gt; Guid)
                m.Id = (Guid)providerUserKey;
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
                m.Id = Guid.NewGuid();

            _users.Add(m.UserName, m);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; m;

        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUser CreateUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; password, &lt;span class="kwrd"&gt;string&lt;/span&gt; email
            , &lt;span class="kwrd"&gt;string&lt;/span&gt; passwordQuestion, &lt;span class="kwrd"&gt;string&lt;/span&gt; passwordAnswer, &lt;span class="kwrd"&gt;bool&lt;/span&gt; isApproved
            , &lt;span class="kwrd"&gt;object&lt;/span&gt; providerUserKey, &lt;span class="kwrd"&gt;out&lt;/span&gt; MembershipCreateStatus status)
        {
            status = MembershipCreateStatus.Success;
            myUser m = CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_users.Values.FirstOrDefault(u =&amp;gt; u.UserName == m.UserName) != &lt;span class="kwrd"&gt;null&lt;/span&gt;) status = MembershipCreateStatus.DuplicateUserName;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_users.Values.Count(u =&amp;gt; u.Email == email) &amp;gt; 0) status = MembershipCreateStatus.DuplicateEmail;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_users.Values.Count(u =&amp;gt; u.Id == m.Id) &amp;gt; 0) status = MembershipCreateStatus.DuplicateProviderUserKey;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (status == MembershipCreateStatus.Success) _users.Add(m.UserName, m);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetMembershipUser(m);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; DeleteUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;bool&lt;/span&gt; deleteAllRelatedData)
        {
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            u.IsApproved = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            u.Comments += &lt;span class="str"&gt;&amp;quot;/r/nDeleted&amp;quot;&lt;/span&gt;;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; EnablePasswordReset
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; EnablePasswordRetrieval
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUserCollection FindUsersByEmail(&lt;span class="kwrd"&gt;string&lt;/span&gt; emailToMatch, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; totalRecords)
        {
            MembershipUserCollection c = &lt;span class="kwrd"&gt;new&lt;/span&gt; MembershipUserCollection();
            totalRecords = _users.Count;
            List&amp;lt;myUser&amp;gt; usersFound = _users.Values.Where(u =&amp;gt; u.Email.ToLower().Contains(emailToMatch.ToLower())).ToList();
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MembershipUser m &lt;span class="kwrd"&gt;in&lt;/span&gt; usersFound.Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(u =&amp;gt; GetMembershipUser(u)))
            {
                c.Add(m);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; c;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUserCollection FindUsersByName(&lt;span class="kwrd"&gt;string&lt;/span&gt; usernameToMatch, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; totalRecords)
        {
            MembershipUserCollection c = &lt;span class="kwrd"&gt;new&lt;/span&gt; MembershipUserCollection();
            totalRecords = _users.Count;
            List&amp;lt;myUser&amp;gt; usersFound = _users.Values.Where(u =&amp;gt; u.UserName.ToLower().Contains(usernameToMatch.ToLower())).ToList();
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MembershipUser m &lt;span class="kwrd"&gt;in&lt;/span&gt; usersFound.Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(u =&amp;gt; GetMembershipUser(u)))
            {
                c.Add(m);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; c;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUserCollection GetAllUsers(&lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; totalRecords)
        {
            MembershipUserCollection c = &lt;span class="kwrd"&gt;new&lt;/span&gt; MembershipUserCollection();
            totalRecords = _users.Count;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MembershipUser m &lt;span class="kwrd"&gt;in&lt;/span&gt; _users.Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(u =&amp;gt; GetMembershipUser(u.Value)))
            {
                c.Add(m);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; c;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; GetNumberOfUsersOnline()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _users.Values.Where(u =&amp;gt; u.IsOnline).Count();
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetPassword(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; answer)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; result = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (u.PasswordAnswer == answer) result = u.PasswordAnswer;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUser GetUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;bool&lt;/span&gt; userIsOnline)
        {
            MembershipUser result = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                u.IsOnline = userIsOnline;
                result = GetMembershipUser(u);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipUser GetUser(&lt;span class="kwrd"&gt;object&lt;/span&gt; providerUserKey, &lt;span class="kwrd"&gt;bool&lt;/span&gt; userIsOnline)
        {
            MembershipUser result = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            myUser m = _users.Values.FirstOrDefault(u =&amp;gt; u.Id == (Guid)providerUserKey);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (m != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                m.IsOnline = userIsOnline;
                result = GetMembershipUser(m);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetUserNameByEmail(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; result = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.Email == email);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u != &lt;span class="kwrd"&gt;null&lt;/span&gt;) result = u.UserName;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; MaxInvalidPasswordAttempts
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; 3; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; MinRequiredNonAlphanumericCharacters
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; 0; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; MinRequiredPasswordLength
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; 4; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; PasswordAttemptWindow
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; 5; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; MembershipPasswordFormat PasswordFormat
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; MembershipPasswordFormat.Clear; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; PasswordStrengthRegularExpression
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; RequiresQuestionAndAnswer
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; RequiresUniqueEmail
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ResetPassword(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; answer)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; result = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; ((u != &lt;span class="kwrd"&gt;null&lt;/span&gt;) &amp;amp;&amp;amp; (u.PasswordAnswer == answer))
            {
                result = &lt;span class="str"&gt;&amp;quot;password1&amp;quot;&lt;/span&gt;;
                u.Password = result;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; UnlockUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; userName)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; result = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == userName);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (u != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                u.IsLocked = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; UpdateUser(MembershipUser user)
        {
            myUser m = _users.Values.FirstOrDefault(u =&amp;gt; u.UserName == user.UserName);
            m.Comments = user.Comment;
            m.Email = user.Email;
            m.IsApproved = user.IsApproved;
            m.IsLocked = user.IsLockedOut;
            m.LastActivityDate = user.LastActivityDate;
            m.LastLockDate = user.LastLockoutDate;
            m.LastLoginDate = user.LastLoginDate;
            m.LastPasswordChangeDate = user.LastPasswordChangedDate;
            m.PasswordQuestion = user.PasswordQuestion;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ValidateUser(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; password)
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; result = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            myUser u = _users.Values.FirstOrDefault(m =&amp;gt; m.UserName == username);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; ((u != &lt;span class="kwrd"&gt;null&lt;/span&gt;) &amp;amp;&amp;amp; (u.Password == password))
                result = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;

        }
    }
}&lt;/pre&gt;

&lt;p&gt;There is always room for improvement; for example some settings could be taken from the web.config instead of code.&amp;#160; The dummy provider allows direct control of test data at the start of the application which allows unit tests to be created that are not dependant on a database.&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.com/post/2008/11/The-Dummy-Provider-Testing-membership-and-roles.aspx&amp;amp;title=The Dummy Provider: Testing membership and roles"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.com/post/2008/11/The-Dummy-Provider-Testing-membership-and-roles.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/11/04/The-Dummy-Provider-Testing-membership-and-roles.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/11/04/The-Dummy-Provider-Testing-membership-and-roles.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=8a0f0890-e25f-47df-a811-f5468e8fb47a</guid>
      <pubDate>Tue, 04 Nov 2008 23:32:13 -0400</pubDate>
      <category>Providers</category>
      <category>Unit testing</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=8a0f0890-e25f-47df-a811-f5468e8fb47a</pingback:target>
      <slash:comments>2</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=8a0f0890-e25f-47df-a811-f5468e8fb47a</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/11/04/The-Dummy-Provider-Testing-membership-and-roles.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=8a0f0890-e25f-47df-a811-f5468e8fb47a</wfw:commentRss>
    </item>
    <item>
      <title>Windows 2008 and SQL 2000</title>
      <description>&lt;p&gt;Ok we all know SQL2K has lost support from Microsoft.&amp;#160; We all know it is marked with &amp;quot;compatibility&amp;quot; issues with Win2k8.&amp;#160; But will it run?&amp;#160; Microsoft dropped the ball on us here.&amp;#160; They shipped Win2K8 before SQL2000.&amp;#160; leaving those of us with giant budgets in a pickle... The option from Microsoft &amp;quot;upgrade to SQL2k5 and buy software assurance&amp;quot;.&lt;/p&gt;  &lt;p&gt;I assure you, their bottom line will thank you.&amp;#160; &lt;/p&gt;  &lt;p&gt;But if you are a smaller shop with limited resources and getting Win2k8 approved was nearly impossible you may be in a jam about SQL.&amp;#160; &lt;/p&gt;  &lt;p&gt;Or if you, like me, do not want to spend thousands on Sql2k8 just because MS is slow in sending you the &amp;quot;heroes happen here&amp;quot; copy of sql2k8 so you can start playing...err working... with win2k8 and you have limited hardware resources in your home lab... than running sql2000 on win2k8 seems reasonable as a short term solution.&lt;/p&gt;  &lt;p&gt;When you try to install sql2k you get a scary message that it is not compatible.&amp;#160; Nice message, but it does not really say it will not work, nor does it stop you.&amp;#160; Just click continue; now I always setup a domain service account for SQL and set all services to run under that account (there are articles out there about securing SQL in a domain environment that explain the reasons for this so I will leave that to them).&amp;#160; After setting my configuration and letting the files copy I noticed the service did not start.&amp;#160; Taking a page from install Sql2k on win2k3 I choose to install SQL sp4.&amp;#160; After a few errors I tracked down the only issue I really ran into....security.&amp;#160; After giving the service account modify rights to the Microsoft SQL server directory in the program files directory the service started and sp4 installed like a champ.&lt;/p&gt;  &lt;p&gt;So my server rebooted, came back up and SQL was running.&lt;/p&gt;  &lt;p&gt;And that's it.&amp;#160; SQL runs in an unsupported and &amp;quot;not compatible&amp;quot; but working manner.&amp;#160; Would I do this in a production environment?&amp;#160; Not if I could help it.&amp;#160; Do I trust it?&amp;#160; Not really.&amp;#160; Would I recommend it?&amp;#160; No way.&amp;#160; When SQL2k8 arrives Ill be upgrading to that and removing SQL2K.&amp;#160; &lt;/p&gt;  &lt;p&gt;I see lots of people asking if it will work and the responses all seem to be the same &amp;quot;It is not supported, upgrade to SQL2k5 or get SQL2k8&amp;quot;.&amp;#160; No one seems to be willing to answer the question that was asked.&lt;/p&gt;  &lt;p&gt;Yes, it will run.&amp;#160; No it is not supported.&amp;#160; Will every single feature work?&amp;#160; I do not know, I do not use every feature of SQL.&amp;#160; But SQL itself will run.&lt;/p&gt;  &lt;p&gt;Of course one can drive their car off a cliff too... that does not make it a good idea nor recommend. &lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/11/03/Windows-2008-and-SQL-2000.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/11/03/Windows-2008-and-SQL-2000.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=8cc3d21e-2187-469b-a5d6-1b4b33664fd0</guid>
      <pubDate>Mon, 03 Nov 2008 00:37:26 -0400</pubDate>
      <category>SQL</category>
      <category>Win2k8</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=8cc3d21e-2187-469b-a5d6-1b4b33664fd0</pingback:target>
      <slash:comments>7</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=8cc3d21e-2187-469b-a5d6-1b4b33664fd0</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/11/03/Windows-2008-and-SQL-2000.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=8cc3d21e-2187-469b-a5d6-1b4b33664fd0</wfw:commentRss>
    </item>
    <item>
      <title>WebService Documentation: Using a custom Site Map</title>
      <description>&lt;p&gt;Not long ago I started working on changing the look and feel of the default WebService documentation that is generated by asp.net.&amp;#160; While I demonstrated how to replace the default page template with a custom one I &amp;quot;glossed&amp;quot; over the details of what you can do with it.&amp;#160; &lt;/p&gt;  &lt;p&gt;By using a custom Sitemap Provider you can create a dynamic Map of all of your WebServices methods.&amp;#160; &lt;strong&gt;Please note&lt;/strong&gt; I am not out to explain SiteMaps in this article.&amp;#160; They list the pages in a site for use by some asp.net controls, like the menu control.&amp;#160; That over simplified short description of a SiteMap is about as deep as I will be getting into the the general topic of SiteMaps.&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Here is a quick peek at my sample web.config.&amp;#160; The first SiteMap, &amp;quot;Help&amp;quot;, is a simple &amp;quot;out of the box&amp;quot; XmlSiteMapProvider.&amp;#160; We will take a look at the associated Help.sitemap file a little later on.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&amp;lt;siteMap&amp;gt;
      &amp;lt;providers&amp;gt;
        &amp;lt;add name=&lt;span class="str"&gt;&amp;quot;Help&amp;quot;&lt;/span&gt; type=&lt;span class="str"&gt;&amp;quot;System.Web.XmlSiteMapProvider&amp;quot;&lt;/span&gt;
                siteMapFile=&lt;span class="str"&gt;&amp;quot;help.sitemap&amp;quot;&lt;/span&gt;/&amp;gt;
        &amp;lt;add name=&lt;span class="str"&gt;&amp;quot;ObjectHelpDesk.WebServices.help_desk&amp;quot;&lt;/span&gt;
                 type=&lt;span class="str"&gt;&amp;quot;SiteMapProviders.WebServiceSiteMapProvider,SiteMapProviders&amp;quot;&lt;/span&gt;
                 webServiceType=&lt;span class="str"&gt;&amp;quot;ObjectHelpDesk.WebServices.help_desk,ObjectHelpDesk&amp;quot;&lt;/span&gt;
                 path=&lt;span class="str"&gt;&amp;quot;~/help/help-desk.asmx&amp;quot;&lt;/span&gt;/&amp;gt;
      &amp;lt;/providers&amp;gt;
    &amp;lt;/siteMap&amp;gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The second SiteMap is a little more interesting.&amp;#160; The type is our custom SiteMapProvider class.&amp;#160; We give it 2 pieces of information, one is the path to the asmx file; the other is the class type of the WebService.&amp;#160; I am using the same WebService I used in the pervious &lt;a href="http://www.jeffgaroutte.net/post/2008/08/WebService-Documentation-Using-a-custom-template.aspx" target="_blank"&gt;&amp;quot;WebService Documentation: Using a Custom Template&amp;quot;&lt;/a&gt; post.&amp;#160; I moved the WebService code behind into an assembly; this makes locating the class from the web.config easy.&amp;#160; Speaking of the code...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Configuration;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Specialized;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Services;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Services.Description;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Reflection;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; SiteMapProviders
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; WebServiceSiteMapProvider : StaticSiteMapProvider
    {
        Type _webServiceType = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        SiteMapNode _root = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        String[] roles = { &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt; };
        NameValueCollection _attributes = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;string&lt;/span&gt; path = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize(&lt;span class="kwrd"&gt;string&lt;/span&gt; name, NameValueCollection attributes)
        {
            &lt;span class="kwrd"&gt;base&lt;/span&gt;.Initialize(name, attributes);
            &lt;span class="kwrd"&gt;string&lt;/span&gt; typeName = attributes[&lt;span class="str"&gt;&amp;quot;webServiceType&amp;quot;&lt;/span&gt;];
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(typeName))
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ConfigurationErrorsException(&lt;span class="str"&gt;&amp;quot;webServiceType is not configured for &amp;quot;&lt;/span&gt; + name);

            path = attributes[&lt;span class="str"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;];
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(path))
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ConfigurationErrorsException(&lt;span class="str"&gt;&amp;quot;path is not configured for &amp;quot;&lt;/span&gt; + name);
            
            attributes.Remove(&lt;span class="str"&gt;&amp;quot;path&amp;quot;&lt;/span&gt;);
            attributes.Remove(&lt;span class="str"&gt;&amp;quot;webServiceType&amp;quot;&lt;/span&gt;);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (attributes[&lt;span class="str"&gt;&amp;quot;roles&amp;quot;&lt;/span&gt;] != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                roles = attributes[&lt;span class="str"&gt;&amp;quot;roles&amp;quot;&lt;/span&gt;].Split(&lt;span class="str"&gt;','&lt;/span&gt;);
                attributes.Remove(&lt;span class="str"&gt;&amp;quot;roles&amp;quot;&lt;/span&gt;);
            }
            _attributes = attributes;

            _webServiceType = Type.GetType(typeName, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_webServiceType == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ConfigurationErrorsException(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;webServiceType '{0}' was not found for {1}&amp;quot;&lt;/span&gt;, typeName, name));
            }
        }

        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; SiteMapNode GetRootNodeCore()
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_root == &lt;span class="kwrd"&gt;null&lt;/span&gt;) BuildSiteMap();
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _root;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; SiteMapNode BuildSiteMap()
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_root == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="rem"&gt;//verify it is null&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;lock&lt;/span&gt; (&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;())&lt;span class="rem"&gt;//create a lock&lt;/span&gt;
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_root == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;span class="rem"&gt;//make sure no one else has already started it&lt;/span&gt;
                    {
                        &lt;span class="rem"&gt;//build the map here&lt;/span&gt;
                        _root = &lt;span class="kwrd"&gt;new&lt;/span&gt; SiteMapNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;, _webServiceType.ToString(), path, _webServiceType.Name, _webServiceType.Name + &lt;span class="str"&gt;&amp;quot; documentation&amp;quot;&lt;/span&gt;);
                        _root.Roles = roles;

                        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MethodInfo method &lt;span class="kwrd"&gt;in&lt;/span&gt; _webServiceType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance))
                        {
                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (method.DeclaringType!=_webServiceType) &lt;span class="kwrd"&gt;continue&lt;/span&gt;;
                            &lt;span class="kwrd"&gt;string&lt;/span&gt; url = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
                            &lt;span class="kwrd"&gt;string&lt;/span&gt; title = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
                            &lt;span class="kwrd"&gt;string&lt;/span&gt; desc = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
                            
                            &lt;span class="kwrd"&gt;object&lt;/span&gt;[] customAttributes = method.GetCustomAttributes(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(WebMethodAttribute), &lt;span class="kwrd"&gt;true&lt;/span&gt;);
                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (customAttributes.Count() &amp;gt; 0)
                            {
                                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (WebMethodAttribute attribute &lt;span class="kwrd"&gt;in&lt;/span&gt; customAttributes)
                                {
                                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(attribute.Description))
                                        desc = attribute.Description;
                                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(attribute.MessageName))
                                        title = attribute.MessageName;
                                    title = method.Name;
                                }&lt;span class="rem"&gt;//foreach (WebMethodAttribute attribute in customAttributes)&lt;/span&gt;
                                url = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;{0}?op={1}&amp;quot;&lt;/span&gt;, path, title);
                                CreateNode(_root, title, desc, url, roles, _attributes, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);
                            }&lt;span class="rem"&gt;//if (customAttributes.Count() &amp;gt; 0)&lt;/span&gt;
                        }&lt;span class="rem"&gt;//foreach (MethodInfo method &lt;/span&gt;
                    }&lt;span class="rem"&gt;// if (_root == null)&lt;/span&gt;
                }&lt;span class="rem"&gt;//lock (new object())&lt;/span&gt;
            }&lt;span class="rem"&gt;// if (_root == null)&lt;/span&gt;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _root;
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; SiteMapNode CreateNode(SiteMapNode parent, &lt;span class="kwrd"&gt;string&lt;/span&gt; title, &lt;span class="kwrd"&gt;string&lt;/span&gt; desc, &lt;span class="kwrd"&gt;string&lt;/span&gt; url, &lt;span class="kwrd"&gt;string&lt;/span&gt;[] roles, NameValueCollection attributes, NameValueCollection explicitResourceKeys, &lt;span class="kwrd"&gt;string&lt;/span&gt; implicitResourceKey)
        {
            SiteMapNode node = &lt;span class="kwrd"&gt;new&lt;/span&gt; SiteMapNode(&lt;span class="kwrd"&gt;this&lt;/span&gt;, url, url, title, desc, roles, attributes, explicitResourceKeys, implicitResourceKey);
            AddNode(node, parent);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; node;
        }

    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The Initialize method sets up the basics of the SiteMap.&amp;#160; It grabs the path to the asmx and gets the Type of the WebService.&amp;#160; It also grabs a comma separated list of role names and populates a roles variable for use later.&amp;#160; This can be used with security trimming depending on your sites configuration (It is a SiteMap thing and outside of the scope of this post).&lt;/p&gt;

&lt;p&gt;The next method is GetRootNodeCore.&amp;#160; All it does is check to see if the _root variable is set and call BuildSiteMap if it is null.&lt;/p&gt;

&lt;p&gt;I am going to skip BuildSiteMap for a moment; down at the bottom we have a simple private method CreateNode.&amp;#160; CreateNode takes all of the information about a SiteMapNode, creates it and adds it to it's parent node. &lt;/p&gt;

&lt;p&gt;And that brings us back to the BuildSiteMap method.&amp;#160; If we check if the _root node has been created.&amp;#160; If it has we do not need to do anything.&amp;#160; Next we create a lock and check the _root again.&amp;#160; Why 3 checks?&amp;#160; A web application (or site) is multi threaded.&amp;#160; Seven, One hundred, or a thousand people might all hit it at once.&amp;#160; Because providers, including SiteMapProviders, are created once and last the lifetime of the application having several people create the _root node and build the entire site is bad voodoo.&amp;#160; So by checking before we call BuildSiteMap we avoid hoping around code.&amp;#160; By checking before the lock we are basically making sure that we still need to do it and the check after the lock ensures we did not already start building the SiteMap on a different thread while we were trying to lock people out.&lt;/p&gt;

&lt;p&gt;So now that we have locked everyone out and are building the site map we need to create a Root Node (_root).&amp;#160; We create the node setting the path to the asmx file path and the title to the WebService type name.&amp;#160; We also slap out roles collection into the roles property of the node.&lt;/p&gt;

&lt;p&gt;Next we do a little reflection.&amp;#160; Why does everyone cringe when I say reflection?&amp;#160; We loop through all the methods in the class type we got from the web.config.&amp;#160; Next we check to see if it has a WebMethodAttribute set on it.&amp;#160; Keep in mind [WebMethodAttribute()] and [WebMethod()] are the same thing.&amp;#160; We grab the description from the attribute and the title from the method name.&amp;#160;&amp;#160; Notice there is a check setting the title to the &amp;quot;MessageName&amp;quot; of the WebMethodAttribute that is completely unused.&amp;#160; In fact we step on it when we set the title to the method name.&amp;#160; If you set the message name, you might want to put an &amp;quot;else&amp;quot; in between the two title sets.&amp;#160; I have not had to use a message name yet and therefore have not tested if it is needed in the title or not.&amp;#160; Next I create the SiteMapNodes URL from the path of the asmx and the method name (or title).&amp;#160;&amp;#160; Finally, I call CreateNode passing all of the important information.&lt;/p&gt;

&lt;p&gt;Now if you have 15 different WebServices, you could add 15 SiteMap data sources to your page with a bunch of Menus; but there is an easier way.&amp;#160; Let's look at the help.sitemap file from our XmlSiteMapProvider.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&amp;lt;?xml version=&lt;span class="str"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt; encoding=&lt;span class="str"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt; ?&amp;gt;
&amp;lt;siteMap xmlns=&lt;span class="str"&gt;&amp;quot;http://schemas.microsoft.com/AspNet/SiteMap-File-1.0&amp;quot;&lt;/span&gt; &amp;gt;
  &amp;lt;siteMapNode url=&lt;span class="str"&gt;&amp;quot;~/help/default.aspx&amp;quot;&lt;/span&gt; title=&lt;span class="str"&gt;&amp;quot;Help&amp;quot;&lt;/span&gt;  description=&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&amp;gt;
    &amp;lt;siteMapNode url=&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt; title=&lt;span class="str"&gt;&amp;quot;Web Services&amp;quot;&lt;/span&gt;  description=&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&amp;gt;
      &amp;lt;siteMapNode provider=&lt;span class="str"&gt;&amp;quot;ObjectHelpDesk.WebServices.help_desk&amp;quot;&lt;/span&gt;/&amp;gt;
    &amp;lt;/siteMapNode&amp;gt;
  &amp;lt;/siteMapNode&amp;gt;
&amp;lt;/siteMap&amp;gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The only node in this SiteMap that is relevant to us is in the middle; in fact it is missing a URL and title attribute.&amp;#160; The only thing it has is a provider attribute.&amp;#160; The provider attribute is the name of the provider to include at that position in the SiteMap.&amp;#160; Now you can include all 15 different WebService SiteMap's by adding them to the web.config and creating a node in the help.sitemap.&lt;/p&gt;

&lt;p&gt;Create a page with a menu control bound to the &amp;quot;help&amp;quot; SiteMap provider.&amp;#160; Open the page. &lt;/p&gt;

&lt;p&gt;Add 5 new WebMethods to a WebService, recompile and refresh the page.&amp;#160; The new methods are already in the menu without any extra work.&amp;#160;&amp;#160; &lt;/p&gt;

&lt;p&gt;Now you can add a nice menu to a custom template or, even better, a master page that you've set the template to use.&amp;#160; &lt;/p&gt;

&lt;p&gt;Happy coding&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/08/WebService-Documentation-Using-a-custom-Site-Map.aspx&amp;amp;title=WebService Documentation: Using a custom Site Map"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/08/WebService-Documentation-Using-a-custom-Site-Map.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/08/18/WebService-Documentation-Using-a-custom-Site-Map.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/08/18/WebService-Documentation-Using-a-custom-Site-Map.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=eefd75fe-deca-4b6b-b855-c6800bca7002</guid>
      <pubDate>Mon, 18 Aug 2008 00:32:17 -0400</pubDate>
      <category>General</category>
      <category>Providers</category>
      <category>WebService</category>
      <category>SiteMap</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=eefd75fe-deca-4b6b-b855-c6800bca7002</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=eefd75fe-deca-4b6b-b855-c6800bca7002</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/08/18/WebService-Documentation-Using-a-custom-Site-Map.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=eefd75fe-deca-4b6b-b855-c6800bca7002</wfw:commentRss>
    </item>
    <item>
      <title>WebService Documentation: Using a custom template</title>
      <description>&lt;p&gt;Web Services: they are an easy way to make information accessible or use information from some other site.&amp;#160; For example, &lt;a href="http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl" target="_blank"&gt;weather.gov's wsdl&lt;/a&gt;.&amp;#160; The beauty of web services is that not all web services are .net and we don't have to care.&amp;#160; Any web service that adheres to the w3's standards and that provides a wsdl we can easily use in asp.net.&amp;#160; In order to help people understand how to consume the service; asp.net even gives us a nice page of generated documentation when someone opens the asmx in their browser.&lt;/p&gt;  &lt;p&gt;I, for one, hate that page.&amp;#160; If I have gone to all the trouble of building a WebService for someone to submit data or request information, why would I want to send them to a page that looks nothing like the rest of my site to learn how to use it?&amp;#160; At the very least brand it in a way that identifies my company.&amp;#160; But no, the sad state is such that the generate page is fixed and only by adding a theme to the page section in a web.config can you get it to use a custom style sheet or theme.&lt;/p&gt;  &lt;p&gt;So what are we to do?&amp;#160; Replace it!&amp;#160; That's right, we can replace it.&amp;#160; The first thing we need is, a web service of course.&lt;/p&gt;  &lt;p&gt;I've cracked open the ObjectHelpDesk solution and added a new folder, &amp;quot;help&amp;quot;.&amp;#160; I have added a new WebService &amp;quot;help-desk&amp;quot; in the help folder.&amp;#160; I moved the code-behind into a dll and edited the asmx accordingly.&lt;/p&gt;  &lt;p&gt;I left HelloWorld in place and added EchoHelloWorld.&amp;#160; Do not forget to but the WebMethod tag on EchoHelloWorld; otherwise the method will not be available in the web service.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="126" alt="image" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/WebServiceSiteMaps_1EEC/image_7.png" width="240" align="left" border="0" /&gt;Now we can browse out to the site and see how it looks.&amp;#160; If you added comments to the code you might be thinking, &amp;quot;It would be a vast improvement if my comments listed under the methods.&amp;quot;&lt;/p&gt;  &lt;p&gt; I agree, and we can come close; by editing the WebMethod attribute tag, above the methods, we can add a basic description to the default documentation page.&amp;#160; We are going to replace the default page; but we are also going to be using its &amp;quot;guts&amp;quot; as the base of our new page.&amp;#160; Because turning off the custom WebService documentation page is as easy as editing one line in the web.config it is important to make sure everything is in order.&amp;#160;&amp;#160; There is also a description property on the WebService tag that can be set as well. &lt;/p&gt;  &lt;pre class="csharpcode"&gt;[WebMethod(Description=&lt;span class="str"&gt;&amp;quot;Echos back the passed in string&amp;quot;&lt;/span&gt;)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; EchoHelloWorld(&lt;span class="kwrd"&gt;string&lt;/span&gt; echoMessage)
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;Hello World &amp;quot;&lt;/span&gt; + echoMessage;
}&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;em&gt;(don't forget to set a description for the WebService)&lt;/em&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;[WebService(Namespace = &lt;span class="str"&gt;&lt;a href="http://www.JeffGaroutte.net/"&gt;http://www.JeffGaroutte.net/&lt;/a&gt;&lt;/span&gt;, 
    Description=&lt;span class="str"&gt;&amp;quot;This web service is currently used for testing.&amp;quot;&lt;/span&gt;)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(&lt;span class="kwrd"&gt;false&lt;/span&gt;)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; help_desk : System.Web.Services.WebService&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Browse out to C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG and look for DefaultWsdlHelpGenerator.aspx.&amp;#160; Copy the file into your project and rename it.&amp;#160; I renamed mine to WsdlTemplate.aspx and placed it in the &amp;quot;help&amp;quot; folder with the asmx.&amp;#160; &lt;strong&gt;Tip:&lt;/strong&gt; Do not delete, remove, edit or rename the original DefaultWsdlHelpGenerator.aspx file.&amp;#160; Sites that do not have a custom template specified in the web.config will need the file.&amp;#160; If for some reason you need to turn off the custom template will will still need the file. &lt;/p&gt;

&lt;p&gt;Edit the web.config and add a webServices section.&amp;#160; &lt;/p&gt;

&lt;p&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="133" alt="image" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/WebServiceSiteMaps_1EEC/image_11.png" width="494" border="0" /&gt;&lt;/p&gt;

&lt;p&gt;Notice the href; it looks like a relative path.&amp;#160; If the href starts with ~/ or / asp.net will throw a 404 error.&amp;#160; You can also add a protocols section to the webServices to remove the &amp;quot;documentation&amp;quot; feature entirely.&amp;#160; This is an excellent idea if the WebService is not meant to be open to general public use.&amp;#160; For &amp;quot;&lt;a title="That is what Microsoft says"&gt;security reasons&lt;/a&gt;&amp;quot; the HttpPost and HttpGet protocols methods are disabled for any request that is not from the localhost.&amp;#160;&amp;#160; &lt;/p&gt;

&lt;p&gt;Now you can edit your WsdlTemplate.aspx page and change to your hearts content.&amp;#160; However, the page must be dymancily complied.&amp;#160; I tried moving the huge code block out into a code behind and found that asp.net did not like it.&amp;#160; I believe this is due to the way the rendered page is generated from the template inside of the framework.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/08/WebService-Documentation-Using-a-custom-template.aspx&amp;amp;title=WebService Documentation: Using a custom template"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/08/WebService-Documentation-Using-a-custom-template.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/08/10/WebService-Documentation-Using-a-custom-template.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/08/10/WebService-Documentation-Using-a-custom-template.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=141525eb-0c0b-4677-a3f3-ddb4d84dc278</guid>
      <pubDate>Sun, 10 Aug 2008 04:00:29 -0400</pubDate>
      <category>General</category>
      <category>WebService</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=141525eb-0c0b-4677-a3f3-ddb4d84dc278</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=141525eb-0c0b-4677-a3f3-ddb4d84dc278</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/08/10/WebService-Documentation-Using-a-custom-template.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=141525eb-0c0b-4677-a3f3-ddb4d84dc278</wfw:commentRss>
    </item>
    <item>
      <title>The returning event delegate</title>
      <description>&lt;style&gt;
pre {overflow:scroll;}&lt;/style&gt;  &lt;p&gt;Delegates have been a great help to developers everywhere; coupled with Events they form the basis of every asp.net web application.&amp;#160; Check out the page event life cycle, events are firing long before the code written by the sites developer.&amp;#160; But what happens when events and delegates are used with a return value?&lt;/p&gt;  &lt;p&gt;I've heard people say that it depends on the return type, it varies by how many functions have been added to the delegate, etc etc...&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Poppycock&lt;/strong&gt;.&amp;#160; Never thought I would use that word, however I have no idea the age of everyone who visits here.&lt;/p&gt;  &lt;p&gt;It is all about the order.&amp;#160; Users have dealt with this same issue for years; If two users open the same file from the network, edit and save it whose changes are kept or lost?&amp;#160; Last save wins.&amp;#160; So the last delegate to &amp;quot;save&amp;quot; the result wins.&amp;#160; So which Delegate is last?&amp;#160; &lt;/p&gt;  &lt;p&gt;Delegates, like good fast food, follow fifo (&lt;em&gt;First In First Out&lt;/em&gt;).&amp;#160; Before anyone picks on that statement and points out how many times they placed an order only to get it after the guy who order after them, I said &amp;quot;good fast food&amp;quot;.&amp;#160; You'll find that hanging out with Santa and the Easter bunny.&lt;/p&gt;  &lt;p&gt;The order that method are added to the delegate is the order they will fire in.&amp;#160; So the last one added is the last one to run and, therefore, controls the result.&lt;/p&gt;  &lt;p&gt;But do not take my word for it, let the code do the talking.&amp;#160; Here is the contents for a Program.cs file from a C# console application project.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Delegates
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;delegate&lt;/span&gt; ReturnType LessonEventHandler&amp;lt;ReturnType&amp;gt;(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e);

    &lt;span class="kwrd"&gt;class&lt;/span&gt; Program
    {
        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)
        {
            &lt;span class="kwrd"&gt;int&lt;/span&gt; order = 1;
            RunTestByOrder(order);
            order++;
            RunTestByOrder(order);
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Press any key to exit.&amp;quot;&lt;/span&gt;);
            Console.ReadLine();

        }
        
        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RunTestByOrder(&lt;span class="kwrd"&gt;int&lt;/span&gt; order)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Order &amp;quot;&lt;/span&gt; + order.ToString() + &lt;span class="str"&gt;&amp;quot;:Start&amp;quot;&lt;/span&gt;);
            EventMaster master = &lt;span class="kwrd"&gt;new&lt;/span&gt; EventMaster();
            RunBooleanTests(master, order);
            RunInt32Tests(master, order);
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Order &amp;quot;&lt;/span&gt; + order.ToString() + &lt;span class="str"&gt;&amp;quot;:End&amp;quot;&lt;/span&gt;);
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RunBooleanTests(EventMaster master, &lt;span class="kwrd"&gt;int&lt;/span&gt; order)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;BooleanTest:Start&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (order)
            {
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 2:
                    master.BooleanTest += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;(master_BooleanTest2);
                    master.BooleanTest += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;(master_BooleanTest1);
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 1:
                &lt;span class="kwrd"&gt;default&lt;/span&gt;:
                    master.BooleanTest += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;(master_BooleanTest1);
                    master.BooleanTest += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;(master_BooleanTest2);
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
            }
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;BooleanTest result: &amp;quot;&lt;/span&gt; + master.DoBooleanTest().ToString());
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;BooleanTest:End&amp;quot;&lt;/span&gt;);
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RunInt32Tests(EventMaster master, &lt;span class="kwrd"&gt;int&lt;/span&gt; order)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test:Start&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (order)
            {
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 2:
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test4);
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test3);
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test2);
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test1);
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 1:
                &lt;span class="kwrd"&gt;default&lt;/span&gt;:
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test1);
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test2);
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test3);
                    master.Int32Test += &lt;span class="kwrd"&gt;new&lt;/span&gt; LessonEventHandler&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;(master_Int32Test4);
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
            }
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test result: &amp;quot;&lt;/span&gt; + master.DoInt32Test().ToString());
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test:End&amp;quot;&lt;/span&gt;);
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; master_Int32Test1(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            Int32 i = 10;
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test:&amp;quot;&lt;/span&gt; + i.ToString());
            &lt;span class="kwrd"&gt;return&lt;/span&gt; i;
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; master_Int32Test2(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            Int32 i = 20;
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test:&amp;quot;&lt;/span&gt; + i.ToString());
            &lt;span class="kwrd"&gt;return&lt;/span&gt; i;
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; master_Int32Test3(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            Int32 i = 30;
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test:&amp;quot;&lt;/span&gt; + i.ToString());
            &lt;span class="kwrd"&gt;return&lt;/span&gt; i;
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; master_Int32Test4(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            Int32 i = 40;
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Int32Test:&amp;quot;&lt;/span&gt; + i.ToString());
            &lt;span class="kwrd"&gt;return&lt;/span&gt; i;
        }

        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; master_BooleanTest1(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;BooleanTest:True&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }
        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; master_BooleanTest2(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            Console.WriteLine(&lt;span class="str"&gt;&amp;quot;BooleanTest:False&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EventMaster
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; LessonEventHandler&amp;lt;Boolean&amp;gt; BooleanTest;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; LessonEventHandler&amp;lt;Int32&amp;gt; Int32Test;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; Boolean DoBooleanTest()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; BooleanTest(&lt;span class="kwrd"&gt;this&lt;/span&gt;, EventArgs.Empty);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; Int32 DoInt32Test()
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; Int32Test(&lt;span class="kwrd"&gt;this&lt;/span&gt;, EventArgs.Empty);
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;And here is a screen capture of the output...&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="409" alt="image" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/Thereturningeventdelegate_17F8/image_3.png" width="361" border="0" /&gt; &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If you need to do something like a &amp;quot;IsCanceled&amp;quot; for an event do not use the return from the delegate, use a property in a custom EventArgs object.&amp;#160; &lt;/li&gt;

  &lt;li&gt;There is no way to see the result of the method that fired before you in the delegate.&amp;#160; &lt;/li&gt;

  &lt;li&gt;If there could be more than one method wired into a delegate the result is fairly worthless.&amp;#160; If there is only on method wired in, how has it been secured so no one else can hook into it?&amp;#160; Private/protected?&amp;#160; why not just use a virtual method? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When is a delegate with a return useful?&amp;#160; Like everything, it has its place and use; for example: Threading!&amp;#160; They can be used to ensure thread safety.&amp;#160; But that is topic for another day.&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/08/The-returning-event-delegate.aspx&amp;amp;title=The returning event delegate"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/08/The-returning-event-delegate.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/08/04/The-returning-event-delegate.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/08/04/The-returning-event-delegate.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=aaae4fb3-1dc6-4c5f-a70a-6061080406eb</guid>
      <pubDate>Mon, 04 Aug 2008 02:42:28 -0400</pubDate>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=aaae4fb3-1dc6-4c5f-a70a-6061080406eb</pingback:target>
      <slash:comments>4</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=aaae4fb3-1dc6-4c5f-a70a-6061080406eb</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/08/04/The-returning-event-delegate.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=aaae4fb3-1dc6-4c5f-a70a-6061080406eb</wfw:commentRss>
    </item>
    <item>
      <title>The woes of SourceForge.net and SVN</title>
      <description>&lt;p&gt;It's no secret, I use &lt;a href="http://sourceforge.net/" target="_blank"&gt;SourceForge.net&lt;/a&gt; to work on an open source project &lt;a href="https://sourceforge.net/projects/objecthelpdeskn" target="_blank"&gt;ObjectHelpDesk.net&lt;/a&gt; and most of the code, patterns and nick nacks that I write about come from that project.&amp;#160; I also use TortoiseSVN coupled with &lt;a href="http://www.visualsvn.com/" target="_blank"&gt;VisualSVN&lt;/a&gt; to manage my source code.&amp;#160; Recently, as part of the &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-1Getting-Started.aspx"&gt;Generics, Interfaces, Providers and You series&lt;/a&gt; I choose to branch from the trunk and rewrite the projects provider model.&amp;#160; When I was finished I attempted to merge them back together.&lt;/p&gt;  &lt;p&gt;Recently, I updated Tortoise and &lt;a href="http://www.visualsvn.com/" target="_blank"&gt;VisualSVN&lt;/a&gt; so I now have version 1.5.1.&amp;#160; SO I switched my working copy back to the trunk, and attempted to reintegrate a branch into the trunk.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/ThewoesofSourceForge.netandSVN_1516C/image_2.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="107" alt="image" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/ThewoesofSourceForge.netandSVN_1516C/image_thumb.png" width="260" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&amp;quot;Retrieval of mergeinfo unsupported by 'https://objecthelpdeskn.svn.sourceforge.net/...'&amp;quot; errr what?&amp;#160; So I did a little digging with my good friend Google.&amp;#160; What I found was a whole bunch of people having the same basic issue.&amp;#160; Turns out that SVN made a change around version 1.5 and added a mergeinfo command to make it so you do not have to remember what the last version you merged was so you do not double merge files by accident.&amp;#160; Great idea, except...&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sourceforge.net/" target="_blank"&gt;SourceForge.net&lt;/a&gt; is not running the 1.5 SVN server.&amp;#160; No problem, find the option to use an older merge method and away we go... So I searched, I looked, hunted and pondered.&amp;#160; For the life of me I could not find an option to &amp;quot;reintegrate&amp;quot; the branch into the trunk.&amp;#160; Back to Google for an answer.&lt;/p&gt;  &lt;p&gt;I found one common suggestion, or fix, download an older client from before 1.5 and use that to do the merge.&lt;/p&gt;  &lt;p&gt;Ok first, I hate downgrading.&amp;#160; Second, I just got everything installed on a new development machine and I am not about to go mucking about uninstalling tortoise so I can reinstall an older version just to do a merge because &lt;a href="http://sourceforge.net/" target="_blank"&gt;Sourceforge.net&lt;/a&gt; does not have the latest version of a SVN server.&amp;#160; So there had to be another option, one that seemed sane.&lt;/p&gt;  &lt;p&gt;Let me explain, I refused to believe that the folks over at &lt;a href="http://sourceforge.net/" target="_blank"&gt;SourceForge.net&lt;/a&gt; would leave something like source control merges broken for any length of time.&amp;#160; On the other hand It seemed that SVN/TortoiseSVN would not go as far as to break their software with a &amp;quot;hub&amp;quot; of the open source community like &lt;a href="http://sourceforge.net/" target="_blank"&gt;SourceForge.net&lt;/a&gt;.&amp;#160; And there was another option right under my nose...&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/ThewoesofSourceForge.netandSVN_1516C/image_4.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="223" alt="image" src="http://www.jeffgaroutte.net/image.axd?picture=WindowsLiveWriter/ThewoesofSourceForge.netandSVN_1516C/image_thumb_1.png" width="244" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Merge two Different Tress.&amp;#160; Really, that is all we are doing, the trunk and branch are two different tress.&amp;#160; This merge method asks you which tree/revision you want to start with and which tree/revision you want to end up at and it makes in happen in your working copy.&amp;#160; Run the merge, compile the code and commit the changes.&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;What surprised me was not the fix for the issue, but it was the number of posts about this message and people saying &amp;quot;Oh downgrade your client or upgrade the server&amp;quot; and that number of replies that said &amp;quot;thanks downgrading the client fixed it&amp;quot;.&amp;#160; In the case of many open source projects, we depend on free tools and systems, like &lt;a href="http://sourceforge.net/" target="_blank"&gt;SourceForge.net&lt;/a&gt; to host our projects and we have no control over what version of source control repository software they gave installed (However, I do thank them for giving us a choice of source control repositories and being there).&amp;#160; I use &lt;a href="http://www.visualsvn.com/" target="_blank"&gt;VisualSVN&lt;/a&gt; heavily in Visual Studio and I cant just downgrade tortoise without affecting it and my development environment.&amp;#160; So using this &amp;quot;manual&amp;quot; fix seems like the sane method to me.&lt;/p&gt;  &lt;p&gt;So if you run into a problem merging with an unsupported mergeinfo message do not just downgrade your client, try merging the two trees instead of reintegrating the branch into the trunk.&lt;/p&gt;  &lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/07/The-woes-of-SourceForgenet-and-SVN.aspx&amp;amp;title=The woes of SourceForge.net and SVN"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/07/The-woes-of-SourceForgenet-and-SVN.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/07/29/The-woes-of-SourceForgenet-and-SVN.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/07/29/The-woes-of-SourceForgenet-and-SVN.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=fdb3284c-726a-43c6-bc6c-83d19e09bc78</guid>
      <pubDate>Tue, 29 Jul 2008 01:32:30 -0400</pubDate>
      <category>General</category>
      <category>Source Control</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=fdb3284c-726a-43c6-bc6c-83d19e09bc78</pingback:target>
      <slash:comments>6</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=fdb3284c-726a-43c6-bc6c-83d19e09bc78</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/07/29/The-woes-of-SourceForgenet-and-SVN.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=fdb3284c-726a-43c6-bc6c-83d19e09bc78</wfw:commentRss>
    </item>
    <item>
      <title>Beyond Generics, Interfaces, Providers and You : IReadByParentId</title>
      <description>&lt;p&gt;Ok so in the Generics, Interfaces, Providers and You series, &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-1Getting-Started.aspx"&gt;Part 1&lt;/a&gt;, &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-2IDataObject-amp3b-IProvider.aspx"&gt;Part 2&lt;/a&gt;, &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-3IProviderCollection-amp3b-IProviderRepository.aspx"&gt;Part 3&lt;/a&gt; &amp;amp; &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-4-Building-the-Classes.aspx"&gt;Part 4&lt;/a&gt;, we made a flexible system of interfaces to make working with a data access provider model easier.&amp;#160; In &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-4-Building-the-Classes.aspx"&gt;Part 4&lt;/a&gt;, I listed some ideas where there was room for improvement in the interfaces/class that we made.&amp;#160; If you have not read the series yet, go ahead and take a few minutes to read them; this post will not make much sense without it.&amp;#160; So here it is, the IReadByParentId interface(s).&lt;/p&gt;  &lt;p&gt;Of course we need something to return the collection of items back as and this means we have a new interface in this set, IReadByParentIdDataObjectCollection.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadByParentIdDataObjectCollection&amp;lt;DataObject, IdType&amp;gt; : IList&amp;lt;DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IReadByParentIdDataObject&amp;lt;DataObject, IdType&amp;gt;
    {
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The interface requires that the class inherits an IList&amp;lt;DataObject&amp;gt;.&amp;#160; Next we need the IReadByParentIdDataObject interface.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadByParentIdDataObject&amp;lt;DataObject, IdType&amp;gt; &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IReadByParentIdDataObject&amp;lt;DataObject, IdType&amp;gt;
    {
        IdType ParentId { get; }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This does not look that different from the IReadDataObject interface.&amp;#160; At this point I should point out that both interfaces can be put on the same onject and the IdType between IReadDataObject&amp;#160; and IReadByParentIdDataObject do not need to match.&amp;#160; Next we need a provider interface...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadByParentIdProvider&amp;lt;ProviderType, DataObjectTypeCollection, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : IReadByParentIdProvider&amp;lt;ProviderType, DataObjectTypeCollection, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IReadByParentIdDataObject&amp;lt;DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObjectTypeCollection : IReadByParentIdDataObjectCollection&amp;lt;DataObject, IdType&amp;gt;
    {
        DataObjectTypeCollection GetByParentId(IdType id, IPrincipal user);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Aside from one more generic type in the signature for the interface and the method returning a DataObjectTypeCollection this is not that different from the IReadProvider.&amp;#160; Now that we have the provider we need a new collection for them,&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadByParentIdProviderCollection&amp;lt;ProviderType, DataObjectTypeCollection, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : IReadByParentIdProvider&amp;lt;ProviderType,DataObjectTypeCollection, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IReadByParentIdDataObject&amp;lt;DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObjectTypeCollection : IReadByParentIdDataObjectCollection&amp;lt;DataObject, IdType&amp;gt;
    {
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name] { get; }
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index] { get; }
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider);
    }&lt;/pre&gt;

&lt;p&gt;The changes here only involve the new generic collection type.&amp;#160; Finally we have a new repository interface...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadByParentIdProviderRepository&amp;lt;ProviderCollectionType, ProviderType, DataObjectTypeCollection, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderCollectionType : ProviderCollection, IReadByParentIdProviderCollection&amp;lt;ProviderType, DataObjectTypeCollection,DataObject, IdType&amp;gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;()
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ProviderBase, IReadByParentIdProvider&amp;lt;ProviderType,DataObjectTypeCollection, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IReadByParentIdDataObject&amp;lt;DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObjectTypeCollection : IReadByParentIdDataObjectCollection&amp;lt;DataObject, IdType&amp;gt;
    {
        ProvidersRepositoryGeneric&amp;lt;ProviderCollectionType,ProviderType&amp;gt; LoadedProviders{get;}

        DataObjectTypeCollection GetByParentId(IdType id, IPrincipal user);
        DataObjectTypeCollection GetByParentId(IdType id, String providerName, IPrincipal user);
        DataObjectTypeCollection GetByParentId(IdType id, Int32 providerIndex, IPrincipal user);
        DataObjectTypeCollection GetByParentId(IdType id, ProviderType provider, IPrincipal user);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;At this point I will introduce a new object to the example tree... a Person&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;    public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Person
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Int32 Id { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FirstName { get; set; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; String LastName { get; set; }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList _contactInformation = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationList ContactInformation
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _contactInformation;
            }
            set
            {
                _contactInformation = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }
    }&lt;/pre&gt;

&lt;p&gt;We will also need a collection of ContactInformation so we will make one,&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationList : List&amp;lt;ContactInformation&amp;gt;,
        IReadByParentIdDataObjectCollection&amp;lt;ContactInformation, Int32&amp;gt;
    {
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Now lets start editing the ContactInformation objects to use our new interfaces.&lt;/p&gt;

&lt;p&gt;First we will change the ContactInformation Object&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformation : IReadDataObject&amp;lt;ContactInformation, Int32&amp;gt;, 
        IUpdateDataObject&amp;lt;ContactInformationProvider,ContactInformation&amp;gt;,
        IReadByParentIdDataObject&amp;lt;ContactInformation, Int32&amp;gt;
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ContactInformation GetById(Int32 id, IPrincipal user)
        {
           &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProviderRepository().GetById(id, user);
        }
        &lt;span class="rem"&gt;//public event EventHandler onValidate;&lt;/span&gt;
        

        &lt;span class="kwrd"&gt;private&lt;/span&gt; String _name;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; String Name
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _name;
            }
            set
            {
                _name = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadableDataObject&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;private&lt;/span&gt; Int32 _id;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _id; }
            set { _id = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IUpdateDataObject&amp;lt;ContactInformationProvider,ContactInformation&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(IPrincipal user)
        {
            &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProviderRepository().Update(&lt;span class="kwrd"&gt;this&lt;/span&gt;, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(ContactInformationProvider provider, IPrincipal user)
        {
            provider.Update(&lt;span class="kwrd"&gt;this&lt;/span&gt;, user);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadByParentIdDataObject&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ParentId { get; set; }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The only changes here are the class declaration and the addition of the ParentId property; seems simple enough;&amp;#160; Now we will update the Provider...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationProvider : ProviderBase,
        IReadProvider&amp;lt;ContactInformationProvider,ContactInformation, Int32&amp;gt;,
        IUpdateProvider&amp;lt;ContactInformationProvider,ContactInformation&amp;gt;,
        IReadByParentIdProvider&amp;lt;ContactInformationProvider, 
            ContactInformationList, ContactInformation, Int32&amp;gt;
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadProvider&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user);

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IUpdateProvider&amp;lt;ContactInformationProvider,ContactInformation&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotSupportedException(&lt;span class="str"&gt;&amp;quot;The abstract ContactInformation can not be updated.&amp;quot;&lt;/span&gt;);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(EmailAddress item, System.Security.Principal.IPrincipal user);
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(PhoneNumber item, System.Security.Principal.IPrincipal user);

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadByParentIdProvider&amp;lt;ContactInformationProvider,ContactInformationList,ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; ContactInformationList GetByParentId(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user);

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;Again the only changes here are adding the interface and the new abstract method.&amp;#160; &lt;strong&gt;Breaking change&lt;/strong&gt; &lt;em&gt;by adding a new abstract method we break any providers that were built before this new version.&amp;#160; To maintain backwards compatibility you could mark the method virtual and throw a NotSupportedException, NotImplementedException, or even do something like return new ContactInformationList();. &lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next we will modify the provider collection...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationProviderCollection : ProviderCollection, 
        IReadProviderCollection&amp;lt;ContactInformationProvider,ContactInformation, Int32&amp;gt;,
        IUpdateProviderCollection&amp;lt;ContactInformationProvider,ContactInformation&amp;gt;,
        IReadByParentIdProviderCollection&amp;lt;ContactInformationProvider, ContactInformationList, ContactInformation, Int32&amp;gt;
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadProviderCollection&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProvider &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name]
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(name)) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException();
                ContactInformationProvider result = (ContactInformationProvider)&lt;span class="kwrd"&gt;base&lt;/span&gt;[name];
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (result == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException();

                &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationProvider &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index]
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; ((index &amp;lt; 0) || (index &amp;gt;= &lt;span class="kwrd"&gt;this&lt;/span&gt;.Count)) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException();
                &lt;span class="kwrd"&gt;int&lt;/span&gt; currentIndex = 0;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (ContactInformationProvider item &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;)
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (currentIndex == index) &lt;span class="kwrd"&gt;return&lt;/span&gt; item;
                    currentIndex++;
                }
                &lt;span class="rem"&gt;//if we reach this point something really odd happened&lt;/span&gt;
                &lt;span class="rem"&gt;//in theory since we already verdified the index is 0 or greater&lt;/span&gt;
                &lt;span class="rem"&gt;//and is less than the total provider count this should never be hit.&lt;/span&gt;
                &lt;span class="rem"&gt;//it would be possible if a provider was removed during run time...&lt;/span&gt;
                &lt;span class="rem"&gt;//so it should blow up.&lt;/span&gt;
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException();
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider)
        {
            &lt;span class="rem"&gt;//cant add a null so die if we try&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException();

            &lt;span class="rem"&gt;//check the type of the provider&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider &lt;span class="kwrd"&gt;is&lt;/span&gt; ContactInformationProvider)
            {
                &lt;span class="rem"&gt;//all good so add the provider to the collection&lt;/span&gt;
                &lt;span class="kwrd"&gt;base&lt;/span&gt;.Add(provider);
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="rem"&gt;//Invalid type so blow up.&lt;/span&gt;
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException();
            }
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;

&lt;p&gt;In this case the only change was adding the interface to the class.&amp;#160; Seems easy so far, now to edit the Repository...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationProviderRepository : 
        IReadProviderRepository&amp;lt;ContactInformationProviderCollection, 
            ContactInformationProvider, ContactInformation, Int32&amp;gt;,
        IUpdateProviderRepository&amp;lt;ContactInformationProviderCollection, 
            ContactInformationProvider, ContactInformation&amp;gt;,
        IReadByParentIdProviderRepository&amp;lt;ContactInformationProviderCollection,
            ContactInformationProvider, ContactInformationList, 
            ContactInformation, Int32&amp;gt;
    {

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadProviderRepository&amp;lt;ContactInformationProviderCollection,ContactInformationProvider,ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt; _loadedProviders = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt; LoadedProviders
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_loadedProviders == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                {
                    Object processLock = &lt;span class="kwrd"&gt;new&lt;/span&gt; Object();
                    &lt;span class="kwrd"&gt;lock&lt;/span&gt; (processLock)
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (_loadedProviders == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                        {
                            _loadedProviders = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt;();
                        }
                    }

                }
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _loadedProviders;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetById(id, LoadedProviders.Provider, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, &lt;span class="kwrd"&gt;string&lt;/span&gt; providerName, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetById(id, LoadedProviders.Providers[providerName], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, &lt;span class="kwrd"&gt;int&lt;/span&gt; providerIndex, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetById(id, LoadedProviders.Providers[providerIndex], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; provider.GetById(id, user);

        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;


        &lt;span class="preproc"&gt;#region&lt;/span&gt; IUpdateProviderRepository&amp;lt;ContactInformationProviderCollection,ContactInformationProvider,ContactInformation&amp;gt; Members


        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, System.Security.Principal.IPrincipal user)
        {
            Update(item, LoadedProviders.Provider, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, &lt;span class="kwrd"&gt;string&lt;/span&gt; providerName, System.Security.Principal.IPrincipal user)
        {
            Update(item, LoadedProviders.Providers[providerName], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, &lt;span class="kwrd"&gt;int&lt;/span&gt; providerIndex, System.Security.Principal.IPrincipal user)
        {
            Update(item, LoadedProviders.Providers[providerIndex], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;);
            item.Save(provider, user);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
        
        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadByParentIdProviderRepository&amp;lt;ContactInformationProviderCollection,ContactInformationProvider,ContactInformationList,ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members


        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationList GetByParentId(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetByParentId(id, LoadedProviders.Provider, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationList GetByParentId(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, &lt;span class="kwrd"&gt;string&lt;/span&gt; providerName, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetByParentId(id, LoadedProviders.Providers[providerName], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationList GetByParentId(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, &lt;span class="kwrd"&gt;int&lt;/span&gt; providerIndex, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetByParentId(id, LoadedProviders.Providers[providerIndex], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationList GetByParentId(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; provider.GetByParentId(id, user);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Well we added the the new interface to the class and added code for the new methods to the class.&amp;#160; The new code looks a lot like the code for the GetById methods.&amp;#160; Of course now we need to populate the list in the person object.&amp;#160; In this case we will use a little lazy loading to populate the list.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Person
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Int32 Id { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FirstName { get; set; }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; String LastName { get; set; }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList _contactInformation = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationList ContactInformation
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_contactInformation == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                    _contactInformation = &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProviderRepository()
                        .GetByParentId(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Id, Thread.CurrentPrincipal);
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _contactInformation;
            }
            set
            {
                _contactInformation = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;the only thing that remains is to edit the dummyContactInformationProvider to handle the new method.&amp;#160; In a real provider this would be, I think, the hardest part.&amp;#160; You have to deal with the data store here and may, or may not, be easy (betrive anyone?). &lt;/p&gt;

&lt;pre class="csharpcode"&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; dummyContactInformationProvider : ContactInformationProvider
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList _memoryDataStore = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList MemoryDataStore
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_memoryDataStore == &lt;span class="kwrd"&gt;null&lt;/span&gt;) _memoryDataStore=BuildMemoryDataStore();
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _memoryDataStore;
            }
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; ContactInformationList BuildMemoryDataStore()
        {
            ContactInformationList result = &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationList();
            HomePhoneNumber phone = &lt;span class="kwrd"&gt;new&lt;/span&gt; HomePhoneNumber();
            phone.Number = &lt;span class="str"&gt;&amp;quot;555.555.1234&amp;quot;&lt;/span&gt;;
            phone.ParentId = 1;
            result.Add(phone);

            phone = &lt;span class="kwrd"&gt;new&lt;/span&gt; HomePhoneNumber();
            phone.Number = &lt;span class="str"&gt;&amp;quot;555.555.9999&amp;quot;&lt;/span&gt;;
            phone.ParentId = 2;
            result.Add(phone);

            phone = &lt;span class="kwrd"&gt;new&lt;/span&gt; HomePhoneNumber();
            phone.Number = &lt;span class="str"&gt;&amp;quot;555.555.1234&amp;quot;&lt;/span&gt;;
            phone.ParentId = 3;
            result.Add(phone);

            EmailAddress email = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmailAddress();
            email.Address = &lt;span class="str"&gt;&amp;quot;bob@test.com&amp;quot;&lt;/span&gt;;
            email.ParentId = 1;
            result.Add(email);

            email = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmailAddress();
            email.Address = &lt;span class="str"&gt;&amp;quot;dilbert@dilbert.com&amp;quot;&lt;/span&gt;;
            email.ParentId = 2;
            result.Add(email);

            email = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmailAddress();
            email.Address = &lt;span class="str"&gt;&amp;quot;Jones@microsoft.com&amp;quot;&lt;/span&gt;;
            email.ParentId = 3;
            result.Add(email);

            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user)
        {
            ContactInformation result = MemoryDataStore.FirstOrDefault(ci =&amp;gt; ci.Id == id);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(EmailAddress item, System.Security.Principal.IPrincipal user)
        {
            EmailAddress email = (EmailAddress)MemoryDataStore.FirstOrDefault(ci =&amp;gt; ci &lt;span class="kwrd"&gt;is&lt;/span&gt; EmailAddress &amp;amp;&amp;amp; ci.Id == item.Id);
            email.Address = item.Address;
            email.ParentId = item.ParentId;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(PhoneNumber item, System.Security.Principal.IPrincipal user)
        {
            PhoneNumber phone = (PhoneNumber)MemoryDataStore.FirstOrDefault(ci =&amp;gt; ci &lt;span class="kwrd"&gt;is&lt;/span&gt; PhoneNumber &amp;amp;&amp;amp; ci.Id == item.Id);
            
            phone.Number = item.Number;
            phone.ParentId = item.ParentId;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ContactInformationList GetByParentId(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user)
        {
            ContactInformationList result = &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationList();
            result.AddRange(MemoryDataStore.Where(ci =&amp;gt; ci.ParentId == id));
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;And there you have it. There is a reason it is named &amp;quot;dummy&amp;quot; but it does the basics and will mock a real data store fairly nicely.&amp;#160; Why did I rewrite a &amp;quot;dummy&amp;quot; provider... I now have a data store that will reset to known values each time I start the application, I can make changes to the data in my application (or unit tests) pull the modified data and when the application ends my data store is back to it's known state.&lt;/p&gt;

&lt;p&gt;If you're interested in seeing the code itself, check out the &lt;a href="http://objecthelpdeskn.svn.sourceforge.net/viewvc/objecthelpdeskn/trunk/?pathrev=56" target="_blank"&gt;SVN Repository at SourceFroge.net&lt;/a&gt;.&amp;#160; The code samples in my blog(s) come from the project at &lt;a title="http://sourceforge.net/projects/objecthelpdeskn" href="http://sourceforge.net/projects/objecthelpdeskn"&gt;http://sourceforge.net/projects/objecthelpdeskn&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/07/Beyond-Generics2c-Interfaces2c-Providers-and-You--IReadByParentId.aspx&amp;amp;title=Beyond Generics, Interfaces, Providers and You : IReadByParentId"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/07/Beyond-Generics2c-Interfaces2c-Providers-and-You--IReadByParentId.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/07/27/Beyond-Generics2c-Interfaces2c-Providers-and-You-IReadByParentId.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/07/27/Beyond-Generics2c-Interfaces2c-Providers-and-You-IReadByParentId.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=593fb634-ef17-47c1-ae14-9713cbf4d0f5</guid>
      <pubDate>Sun, 27 Jul 2008 23:06:47 -0400</pubDate>
      <category>General</category>
      <category>Providers</category>
      <category>Unit testing</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=593fb634-ef17-47c1-ae14-9713cbf4d0f5</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=593fb634-ef17-47c1-ae14-9713cbf4d0f5</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/07/27/Beyond-Generics2c-Interfaces2c-Providers-and-You-IReadByParentId.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=593fb634-ef17-47c1-ae14-9713cbf4d0f5</wfw:commentRss>
    </item>
    <item>
      <title>Generics, Interfaces, Providers and You - Part 4: Building the Classes</title>
      <description>&lt;p&gt;Now that we have our interfaces we need to make some changes to our existing objects.&amp;#160; Back in &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-1Getting-Started.aspx"&gt;part 1&lt;/a&gt; we defined an object tree for contact information.&amp;#160; For this example, a 3rd parting marketing system is loading new contact information into our data store and management does not want anyone to delete data, but in a &lt;a href="http://www.dilbert.com/animation/" target="_blank"&gt;truely pointy hair boss fashion&lt;/a&gt; they want people to be able to update the data...&amp;#160; &lt;/p&gt;  &lt;p&gt;First we will create the ContactInformationProviderRepository.&amp;#160; We make a static ProvidersRepositoryGeneric to hold the Providers we load based on the web.config.&amp;#160; By looking at GetById and Update you can see they use the same logic to locate the correct provider.&amp;#160; If the overload that takes the provider as a parameter has a null for the provider it simply throws an exception.&lt;/p&gt;  &lt;p&gt;The LoadedProviders accessor is where the real trick happens.&amp;#160; First we look to see if the static&amp;#160; ProvidersRepositoryGeneric is populated.&amp;#160; If it is null we create a lock to stop anyone from accessing it and we check it again to make sure someone else did not set it between our first check and the lock.&amp;#160; &lt;strong&gt;This is important to do&lt;/strong&gt; because we are running in a multi thread environment (multiple web requests at once) we need to be sure we are not stepping on our own feet.&amp;#160; If it is still null we create it.&amp;#160; The constructor goes out and gets the provider information from the web.config and populates the collection.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationProviderRepository : 
        IReadProviderRepository&amp;lt;ContactInformationProviderCollection, 
            ContactInformationProvider, ContactInformation, Int32&amp;gt;,
        IUpdateProviderRepository&amp;lt;ContactInformationProviderCollection, 
            ContactInformationProvider, ContactInformation&amp;gt;
    {

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadProviderRepository&amp;lt;ContactInformationProviderCollection,ContactInformationProvider,ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt; _loadedProviders = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt; LoadedProviders
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_loadedProviders == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                {
                    Object processLock = &lt;span class="kwrd"&gt;new&lt;/span&gt; Object();
                    &lt;span class="kwrd"&gt;lock&lt;/span&gt; (processLock)
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (_loadedProviders == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
                        {
                            _loadedProviders = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt;();
                        }
                    }

                }
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _loadedProviders;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetById(id, LoadedProviders.Provider, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, &lt;span class="kwrd"&gt;string&lt;/span&gt; providerName, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetById(id, LoadedProviders.Providers[providerName], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, &lt;span class="kwrd"&gt;int&lt;/span&gt; providerIndex, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetById(id, LoadedProviders.Providers[providerIndex], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; provider.GetById(id, user);

        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IUpdateProviderRepository&amp;lt;ContactInformationProviderCollection,ContactInformationProvider,ContactInformation&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, System.Security.Principal.IPrincipal user)
        {
            Update(item, LoadedProviders.Provider, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, &lt;span class="kwrd"&gt;string&lt;/span&gt; providerName, System.Security.Principal.IPrincipal user)
        {
            Update(item, LoadedProviders.Providers[providerName], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, &lt;span class="kwrd"&gt;int&lt;/span&gt; providerIndex, System.Security.Principal.IPrincipal user)
        {
            Update(item, LoadedProviders.Providers[providerIndex], user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;provider&amp;quot;&lt;/span&gt;); &lt;br /&gt;            item.Save(provider, user);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Even though ProvidersRepositoryGeneric&amp;lt;ContactInformationProviderCollection, ContactInformationProvider&amp;gt; LoadedProviders&amp;#160; is defined in both the IReadProviderRepository and IUpdateProviderRepository interfaces it only appears once in the class.&amp;#160; That is because the property signature matches between the two and they use the same one.&lt;/p&gt;

&lt;p&gt;Now let us get the provider collection created.&lt;/p&gt;

&lt;pre class="csharpcode"&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationProviderCollection : ProviderCollection, 
        IReadProviderCollection&amp;lt;ContactInformationProvider,ContactInformation, Int32&amp;gt;,
        IUpdateProviderCollection&amp;lt;ContactInformationProvider,ContactInformation&amp;gt;
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadProviderCollection&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProvider &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name]
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(name)) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException();
                ContactInformationProvider result = (ContactInformationProvider)&lt;span class="kwrd"&gt;base&lt;/span&gt;[name];
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (result == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException();

                &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ContactInformationProvider &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index]
        {
            get
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; ((index &amp;lt; 0) || (index &amp;gt;= &lt;span class="kwrd"&gt;this&lt;/span&gt;.Count)) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException();
                &lt;span class="kwrd"&gt;int&lt;/span&gt; currentIndex = 0;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (ContactInformationProvider item &lt;span class="kwrd"&gt;in&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;)
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (currentIndex == index) &lt;span class="kwrd"&gt;return&lt;/span&gt; item;
                    currentIndex++;
                }
                &lt;span class="rem"&gt;//if we reach this point something really odd happened&lt;/span&gt;
                &lt;span class="rem"&gt;//in theory since we already verdified the index is 0 or greater&lt;/span&gt;
                &lt;span class="rem"&gt;//and is less than the total provider count this should never be hit.&lt;/span&gt;
                &lt;span class="rem"&gt;//it would be possible if a provider was removed during run time...&lt;/span&gt;
                &lt;span class="rem"&gt;//so it should blow up.&lt;/span&gt;
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentOutOfRangeException();
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider)
        {
            &lt;span class="rem"&gt;//cant add a null so die if we try&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException();

            &lt;span class="rem"&gt;//check the type of the provider&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (provider &lt;span class="kwrd"&gt;is&lt;/span&gt; ContactInformationProvider)
            {
                &lt;span class="rem"&gt;//all good so add the provider to the collection&lt;/span&gt;
                &lt;span class="kwrd"&gt;base&lt;/span&gt;.Add(provider);
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="rem"&gt;//Invalid type so blow up.&lt;/span&gt;
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException();
            }
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;We are doing 3 things here, we are way to get the provider by the index.&amp;#160;&amp;#160; Next we are hiding the base class implementation of get by name &amp;quot;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProvider &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name] &amp;quot;.&amp;#160; Finally we are hiding the the Add method on the base class.&amp;#160; We hide it so we can check to make sure the provider being added is of the correct type.&lt;/p&gt;

&lt;p&gt;Next we setup an abstract provider...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformationProvider : ProviderBase,
        IReadProvider&amp;lt;ContactInformationProvider,ContactInformation, Int32&amp;gt;,
        IUpdateProvider&amp;lt;ContactInformationProvider,ContactInformation&amp;gt;
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadProvider&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user);

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IUpdateProvider&amp;lt;ContactInformationProvider,ContactInformation&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(ContactInformation item, System.Security.Principal.IPrincipal user)
        {
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotSupportedException(&lt;span class="str"&gt;&amp;quot;The abstract ContactInformation can not be updated.&amp;quot;&lt;/span&gt;);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(EmailAddress item, System.Security.Principal.IPrincipal user);
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(PhoneNumber item, System.Security.Principal.IPrincipal user);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;We will be able to inherit this class to make a working provider for contact information.&amp;#160; We added two overloads to the update method to take the specific types of contact information we have in our model.&amp;#160; Because ContactInforamtion is an abstract class and is the root of the object tree, or the branch we are interested in saving, we do not want to try to update it so we can throw a NotImplementedException or a NotSupportedException; I marked the method as virtual just incase a provider is created that can handle an unboxed ContactInformation; you could do a if else tree checking if (item is EmailAddress){ Update(((EmailAddress)item),user); } else if (item is PhoneNumber).....&lt;/p&gt;

&lt;p&gt;Now we need to modify the ContactInofrmation base class.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ContactInformation : IReadDataObject&amp;lt;ContactInformation, Int32&amp;gt;, 
        IUpdateDataObject&amp;lt;ContactInformationProvider,ContactInformation&amp;gt;
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ContactInformation GetById(Int32 id, IPrincipal user)
        {
           &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProviderRepository().GetById(id, user);
        }        

        &lt;span class="kwrd"&gt;private&lt;/span&gt; String _name;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; String Name
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _name;
            }
            set
            {
                _name = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IReadableDataObject&amp;lt;ContactInformation,&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt; Members

        &lt;span class="kwrd"&gt;private&lt;/span&gt; Int32 _id;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _id; }
            set { _id = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; IUpdateDataObject&amp;lt;ContactInformationProvider,ContactInformation&amp;gt; Members

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(IPrincipal user)
        {
            &lt;span class="kwrd"&gt;new&lt;/span&gt; ContactInformationProviderRepository().Update(&lt;span class="kwrd"&gt;this&lt;/span&gt;, user);
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(ContactInformationProvider provider, IPrincipal user)
        {
            provider.Update(&lt;span class="kwrd"&gt;this&lt;/span&gt;, user);
        }

        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;First we added a static method, GetById that will return a contact information by id.&amp;#160; It simply calls a new ContactInformationProviderRepository and calls the GetById method.&amp;#160; Next we added an Id property.&amp;#160; The set accessor was not required by the interface but we still added one. &lt;/p&gt;

&lt;p&gt;The save method calls out to the repository to get back the provider.&amp;#160; The repository finds the requested provider and calls the items save method passing the provider as a parameter (The delete method would do the same thing).&amp;#160; The Save overload that accepts the provider is marked virtual so it can be overridden in subclasses.&amp;#160; &lt;/p&gt;

&lt;p&gt;Now let's update the PhoneNumber EmailAddress clasesses&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PhoneNumber : ContactInformation
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _number;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Number
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _number;
            }
            set
            {
                _number = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            provider.Update(&lt;span class="kwrd"&gt;this&lt;/span&gt;, user);
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EmailAddress : ContactInformation
    {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; EmailAddress()
        {
            Name = &lt;span class="str"&gt;&amp;quot;Email Address&amp;quot;&lt;/span&gt;;
        }
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _address;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Address
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _address;
            }
            set
            {
                _address = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(ContactInformationProvider provider, System.Security.Principal.IPrincipal user)
        {
            provider.Update(&lt;span class="kwrd"&gt;this&lt;/span&gt;, user);
        }
    }&lt;/pre&gt;

&lt;p&gt;Both classes have the same change; they both override the Save method.&amp;#160; The code seems the same but it is important to be there.&amp;#160; There is a type boxing issue, (I mentioned the boxing issue back in &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-2IDataObject-amp3b-IProvider.aspx"&gt;part 2&lt;/a&gt; as well), that we want to get around.&amp;#160; Let me explain...&lt;/p&gt;

&lt;p&gt;The the method calls are mapped at compile time, not runtime.&amp;#160; For example say you have a variable &amp;quot;contact&amp;quot; defined as ContactInformation contact=new EmailAddress(); and ContactInformationProvider provider=new DummyContactInformationProvider();&lt;/p&gt;

&lt;p&gt;Now what happens if you call provider.Update(contact,Thread.CurrentPrincipal);?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;the provider update method is passed an object of type ContactInformation &lt;/li&gt;

  &lt;li&gt;the NotSupportedException is thrown &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&amp;#160; The fact that contact is holding an object of type EmailAddress is not checked.&amp;#160; This is because of the compile time mapping of method calls.&amp;#160; Now let's look at what happens if you use the same objects and call Contact.Save(Thread.CurrentPrincipal); &lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The item is passed to the repository boxed as a ContactInformation object &lt;/li&gt;

  &lt;li&gt;The repository calls its own overload passing the item, provider, and user &lt;/li&gt;

  &lt;li&gt;The items save method is called with the provider and user as the parameters. &lt;/li&gt;

  &lt;li&gt;Because EmailAddress overrides the save method overload with that signature, it is used. &lt;/li&gt;

  &lt;li&gt;The Save method call provider.Update passing &amp;quot;this&amp;quot; and the user. &lt;/li&gt;

  &lt;li&gt;Because &amp;quot;this&amp;quot; from inside of the EmailAddress is strongly typed as an EmailAddress the provider's Update method that accepts an EmailAddress object is called and there is no exception. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;provider.Update(contact,Thread.CurrentPrincipal); would work if .net used runtime mapping.&amp;#160; However I suspect the overhead in doing that might be a performance killer.&amp;#160; This is the same reason why we can not use a System.Type variable with generics to make runtime generic objects.&amp;#160; &lt;/p&gt;

&lt;p&gt;The only thing remaining is to build a provider...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; ObjectHelpDesk.ContactInformations;
&lt;span class="kwrd"&gt;using&lt;/span&gt; ObjectHelpDesk.ContactInformations.PhoneNumbers;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DummyProviders
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; dummyContactInformationProvider : ContactInformationProvider
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; email = &lt;span class="str"&gt;&amp;quot;bob@test.com&amp;quot;&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; phone = &lt;span class="str"&gt;&amp;quot;555.555.1234&amp;quot;&lt;/span&gt;;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ContactInformation GetById(&lt;span class="kwrd"&gt;int&lt;/span&gt; id, System.Security.Principal.IPrincipal user)
        {
            ContactInformation result = &lt;span class="kwrd"&gt;null&lt;/span&gt;; ;
            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (id)
            {
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 1:
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 2:
                    result = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmailAddress();
                    ((EmailAddress)result).Address = email;
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; 3:
                &lt;span class="kwrd"&gt;default&lt;/span&gt;:
                    result = &lt;span class="kwrd"&gt;new&lt;/span&gt; HomePhoneNumber();
                    ((PhoneNumber)result).Number = phone;
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
            }
            
            result.Id = id;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(EmailAddress item, System.Security.Principal.IPrincipal user)
        {
            email = item.Address;
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(PhoneNumber item, System.Security.Principal.IPrincipal user)
        {
            phone = item.Number;
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&amp;#160;&lt;/pre&gt;

&lt;p&gt;This provider is really simple, and fairly useless, but it gets the point across of how this works.&amp;#160; GetById returns an EmailAddress object for if the id is 1 or 2 and a phone number for anything else.&amp;#160; The update methods update private strings that are used to generate those objects.&amp;#160; &lt;/p&gt;

&lt;p&gt;All of these interfaces make setting up a new provider fairly quick and easy.&amp;#160; More importantly they give you a great deal of flexibility.&amp;#160; There is room for expansion/improvement here; Off the top of my head...&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;you could add another set of interfaces for a function that would be common, &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Beyond-Generics2c-Interfaces2c-Providers-and-You--IReadByParentId.aspx"&gt;IReadByParentId&lt;/a&gt;. &lt;/li&gt;

  &lt;li&gt;Make the update interfaces use an IsDirty property and the INotifiyPropertyChanged interface.&amp;#160; It is part of the .net framework. &lt;/li&gt;

  &lt;li&gt;make the abstract providers have a public concrete implementation of the methods and call a protected version of the method internally... like public void Update(IUpdateDataObject item, IPrincipal user) { DoUpdate(item,user);} protected abstract void DoUpdate( IUpdateDataObject item, IPrincipal user); &lt;/li&gt;

  &lt;li&gt;add pre/post events for each data method (this ties into #3) &lt;/li&gt;

  &lt;li&gt;make the pre event able to cancel the call. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Happy Coding! &lt;/p&gt;

&lt;p&gt;&amp;#160; &lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-4-Building-the-Classes.aspx&amp;amp;title=Generics, Interfaces, Providers and You - Part 4: Building the Classes"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-4-Building-the-Classes.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/07/27/Generics2c-Interfaces2c-Providers-and-You-Part-4-Building-the-Classes.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/07/27/Generics2c-Interfaces2c-Providers-and-You-Part-4-Building-the-Classes.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=5c5769bf-58ee-4f01-a580-bae08d7b2c25</guid>
      <pubDate>Sun, 27 Jul 2008 20:53:03 -0400</pubDate>
      <category>General</category>
      <category>Providers</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=5c5769bf-58ee-4f01-a580-bae08d7b2c25</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=5c5769bf-58ee-4f01-a580-bae08d7b2c25</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/07/27/Generics2c-Interfaces2c-Providers-and-You-Part-4-Building-the-Classes.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=5c5769bf-58ee-4f01-a580-bae08d7b2c25</wfw:commentRss>
    </item>
    <item>
      <title>Generics, Interfaces, Providers and You - Part 3:IProviderCollection &amp;amp; IProviderRepository</title>
      <description>&lt;p&gt;In &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-1Getting-Started.aspx"&gt;part 1&lt;/a&gt; We talked about the web.config and the basic classes to get started with a provider model.&amp;#160; &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-2IDataObject-amp3b-IProvider.aspx"&gt;Part 2&lt;/a&gt; covered the interface for the data object and the Provider.&amp;#160; Now in part 3 we will address the IProviderCollection and the IProviderRepository.&lt;/p&gt;  &lt;p&gt;Back in part one we added a provider collection to the generic provider repository by taking the provider collection as a generic parameter.&amp;#160; Now we are going to define the ProviderCollection interfaces.&amp;#160; They are going to be ICreateProviderCollection, IReadProviderCollection, IUpdateProviderCollection, IDeleteProviderCollection and ICrudProviderCollection.&lt;/p&gt;  &lt;p&gt;First ICreateProviderCollection&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICreateProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ICreateProvider&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : ICreateDataObject&amp;lt;ProviderType,DataObject&amp;gt;
    {
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name] {get;}
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index] { get; }
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;We define to methods of getting back a provider, one by name and the other by it's index in the collection.&amp;#160; We also define a way to add a provider to the collection. &lt;/p&gt;

&lt;p&gt;Next IReadProviderCollection&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadProviderCollection&amp;lt;ProviderType, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : IReadProvider&amp;lt;ProviderType,DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IReadDataObject&amp;lt;DataObject, IdType&amp;gt;
    {
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name] { get; }
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index] { get; }
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Except for the where clause, it is identical to the ICreateProviderCollection;&amp;#160; In fact so are IUpdateProviderCollection and&amp;#160; IDeleteProviderCollections&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUpdateProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : IUpdateProvider&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IUpdateDataObject&amp;lt;ProviderType, DataObject&amp;gt;
    {
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name] { get; }
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index] { get; }
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IDeleteProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : IDeleteProvider&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IDeleteDataObject&amp;lt;ProviderType, DataObject&amp;gt;
    {
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;string&lt;/span&gt; name] { get; }
        ProviderType &lt;span class="kwrd"&gt;this&lt;/span&gt;[&lt;span class="kwrd"&gt;int&lt;/span&gt; index] { get; }
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(ProviderBase provider);
    }&lt;/pre&gt;

&lt;p&gt;The ICrudProviderCollection on the other hand is empty...&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICrudProviderCollection&amp;lt;ProviderType, DataObject, IdType&amp;gt; : 
        ICreateProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;,
        IReadProviderCollection&amp;lt;ProviderType, DataObject, IdType&amp;gt;,
        IUpdateProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;,
        IDeleteProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ICrudProvider&amp;lt;ProviderType, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : ICrudDataObject&amp;lt;ProviderType, DataObject, IdType&amp;gt;
    {
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;This is because the methods and properties are defined on the other interfaces already.&lt;/p&gt;

&lt;p&gt;So, let's move on to the IProviderRepository.&lt;/p&gt;

&lt;p&gt;First we have the ICrudProviderRepository&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICrudProviderRepository&amp;lt;ProviderCollectionType,ProviderType, DataObject, IdType&amp;gt; :
        ICreateProviderRepository&amp;lt;ProviderCollectionType, ProviderType, DataObject&amp;gt;,
        IReadProviderRepository&amp;lt;ProviderCollectionType, ProviderType, DataObject, IdType&amp;gt;,
        IUpdateProviderRepository&amp;lt;ProviderCollectionType, ProviderType, DataObject&amp;gt;,
        IDeleteProviderRepository&amp;lt;ProviderCollectionType, ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderCollectionType : ProviderCollection,
            ICrudProviderCollection&amp;lt;ProviderType, DataObject, IdType&amp;gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;()
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ProviderBase, ICrudProvider&amp;lt;ProviderType, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : ICrudDataObject&amp;lt;ProviderType, DataObject, IdType&amp;gt;
    {
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Again all of the methods and properties are defined on the other interfaces.&amp;#160; &lt;/p&gt;

&lt;p&gt;ICreateProviderRepository&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICreateProviderRepository&amp;lt;ProviderCollectionType,ProviderType,DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderCollectionType : ProviderCollection, ICreateProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;()
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ProviderBase, ICreateProvider&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : ICreateDataObject&amp;lt;ProviderType,DataObject&amp;gt;
    {
        ProvidersRepositoryGeneric&amp;lt;ProviderCollectionType, ProviderType&amp;gt; LoadedProviders { get; }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; Create(DataObject item, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Create(DataObject item, String providerName, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Create(DataObject item, Int32 providerIndex, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Create(DataObject item, ProviderType provider, IPrincipal user);

    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The interface defines 4 overloads of the create method.&amp;#160; The first, in a concret class, would use the default provider.&amp;#160; The second accepts the name of the provider and uses it to find the correct provider to use.&amp;#160; The 3 overload&amp;#160; takes the index of the provider in the collection to try and find the provider.&amp;#160; And last but not least is the 4th overload which accepts the provider itself.&amp;#160; The IReadProviderRepository, IUpdateProviderRepository and IDeleteProviderRepositorys all have these 4 overloads with similar signatures.&amp;#160; In IReadProviderRepository the read methods return a DataObject instead of taking one as a parameter.&amp;#160; Back in part one we defined the ProvidersRepositoryGeneric and this is where we use it. &lt;/p&gt;

&lt;p&gt;IReadProviderRepository&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IReadProviderRepository&amp;lt;ProviderCollectionType, ProviderType,DataObject,IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderCollectionType : ProviderCollection,IReadProviderCollection&amp;lt;ProviderType, DataObject, IdType&amp;gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt;()
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ProviderBase,IReadProvider&amp;lt;ProviderType, DataObject, IdType&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject: IReadDataObject&amp;lt;DataObject,IdType&amp;gt;
    {
        ProvidersRepositoryGeneric&amp;lt;ProviderCollectionType,ProviderType&amp;gt; LoadedProviders{get;}

        DataObject GetById(IdType id, IPrincipal user);
        DataObject GetById(IdType id, String providerName, IPrincipal user);
        DataObject GetById(IdType id, Int32 providerIndex, IPrincipal user);
        DataObject GetById(IdType id, ProviderType provider, IPrincipal user);
    }&lt;/pre&gt;

&lt;p&gt;IUpdateProviderRepository&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IUpdateProviderRepository&amp;lt;ProviderCollectionType,ProviderType,DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderCollectionType : ProviderCollection, IUpdateProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;()
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ProviderBase, IUpdateProvider&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IUpdateDataObject&amp;lt;ProviderType,DataObject&amp;gt;
    {
        ProvidersRepositoryGeneric&amp;lt;ProviderCollectionType, ProviderType&amp;gt; LoadedProviders { get; }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(DataObject item, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(DataObject item, String providerName, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(DataObject item, Int32 providerIndex, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Update(DataObject item, ProviderType provider, IPrincipal user);
    }&lt;/pre&gt;

&lt;p&gt;IDeleteProviderRepository&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IDeleteProviderRepository&amp;lt;ProviderCollectionType, ProviderType,DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; DataObject : IDeleteDataObject&amp;lt;ProviderType, DataObject&amp;gt;
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderCollectionType : ProviderCollection, IDeleteProviderCollection&amp;lt;ProviderType, DataObject&amp;gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;()
        &lt;span class="kwrd"&gt;where&lt;/span&gt; ProviderType : ProviderBase, IDeleteProvider&amp;lt;ProviderType, DataObject&amp;gt;
    {
        ProvidersRepositoryGeneric&amp;lt;ProviderCollectionType, ProviderType&amp;gt; LoadedProviders { get; }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(DataObject item, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(DataObject item, String providerName, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(DataObject item, &lt;span class="kwrd"&gt;int&lt;/span&gt; providerIndex, IPrincipal user);
        &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(DataObject item, ProviderType provider, IPrincipal user);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Our basic interfaces are done, now we need to create classes that use them and build a provider&lt;/p&gt;

&lt;p&gt;Next : &lt;a href="http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-4-Building-the-Classes.aspx"&gt;Generics, Interfaces, Providers and You - Part 4: Building the Classes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a target="_blank" href="http://www.dotnetkicks.com/kick/?url=http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-3IProviderCollection-amp3b-IProviderRepository.aspx&amp;amp;title=Generics, Interfaces, Providers and You - Part 3:IProviderCollection &amp;amp; IProviderRepository"&gt;
                    &lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http://www.jeffgaroutte.net/post/2008/07/Generics2c-Interfaces2c-Providers-and-You---Part-3IProviderCollection-amp3b-IProviderRepository.aspx" border="0" alt="kick it on DotNetKicks.com" /&gt;
                  &lt;/a&gt;&lt;/p&gt;
&lt;style type="text/css"&gt;


.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;</description>
      <link>http://www.jeffgaroutte.net/post/2008/07/27/Generics2c-Interfaces2c-Providers-and-You-Part-3IProviderCollection-amp3b-IProviderRepository.aspx</link>
      <author>jeff</author>
      <comments>http://www.jeffgaroutte.net/post/2008/07/27/Generics2c-Interfaces2c-Providers-and-You-Part-3IProviderCollection-amp3b-IProviderRepository.aspx#comment</comments>
      <guid>http://www.jeffgaroutte.net/post.aspx?id=4abe940b-1cea-4019-8528-b75eac4c84ad</guid>
      <pubDate>Sun, 27 Jul 2008 05:43:57 -0400</pubDate>
      <category>General</category>
      <category>Providers</category>
      <dc:publisher>jeff</dc:publisher>
      <pingback:server>http://www.jeffgaroutte.net/pingback.axd</pingback:server>
      <pingback:target>http://www.jeffgaroutte.net/post.aspx?id=4abe940b-1cea-4019-8528-b75eac4c84ad</pingback:target>
      <slash:comments>0</slash:comments>
      <trackback:ping>http://www.jeffgaroutte.net/trackback.axd?id=4abe940b-1cea-4019-8528-b75eac4c84ad</trackback:ping>
      <wfw:comment>http://www.jeffgaroutte.net/post/2008/07/27/Generics2c-Interfaces2c-Providers-and-You-Part-3IProviderCollection-amp3b-IProviderRepository.aspx#comment</wfw:comment>
      <wfw:commentRss>http://www.jeffgaroutte.net/syndication.axd?post=4abe940b-1cea-4019-8528-b75eac4c84ad</wfw:commentRss>
    </item>
  </channel>
</rss>
