<?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:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-13720715</atom:id><lastBuildDate>Mon, 28 Nov 2011 01:04:09 +0000</lastBuildDate><category>script</category><category>Community Server</category><category>web development</category><category>SEM</category><category>SEO</category><category>Training</category><category>BlogUrls</category><category>ajax</category><title>Pensieve</title><description>A place for my notes and thoughts on development and configuration of Microsoft and Microsoft related products.</description><link>http://gabe19.blogspot.com/</link><managingEditor>noreply@blogger.com (gabe19)</managingEditor><generator>Blogger</generator><openSearch:totalResults>67</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/blogspot/wXhI" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="blogspot/wxhi" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-2797969641517592634</guid><pubDate>Wed, 15 Dec 2010 15:16:00 +0000</pubDate><atom:updated>2010-12-15T10:53:41.892-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">web development</category><category domain="http://www.blogger.com/atom/ns#">ajax</category><category domain="http://www.blogger.com/atom/ns#">script</category><title>Script Block Type and Dynamic Script Loading</title><description>Obviously I haven't written in a while, but after spending a few debugging hours on this simple issue I hope to save somebody some time.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I am re-writing a widget framework for a client so that all widgets are loaded dynamically client side after page load. Widget content may be complex and include all manner of scripting.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was having problems getting javascript blocks in the dynamically loaded content to execute in any other browser than Firefox. I was also seeing some blocks execute in the other browsers, but not all and couldn't figure out what was special about the syntax, methodology, or source of those that would work. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I finally figured out that it was the 'type' attribute on the script blocks themselves. We had some script tags with 'ecmascript' and others with 'javascript'. The 'ecmascript' type is not dynamically executed by webkit browsers, or IE; 'javascript' type blocks are. This includes omitting the type attribute altogether as these browsers assume javascript when not otherwise indicated.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Perhaps this script type exclusion is well documented somewhere, but most discussions surrounding problems loading scripts dynamically center on getting around same source issues. Here it is simply a matter of type.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Take home point: always indicate 'text/javascript' if you include the type attribute.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can test for yourself with the code below. Change the type in the content page to see the background behind 'HI' turn red in browsers other than Firefox.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Simple script loading page...&lt;/div&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="html"&gt;DOCTYPE&lt;/span&gt; &lt;span class="attr"&gt;html&lt;/span&gt; &lt;span class="attr"&gt;PUBLIC&lt;/span&gt; &lt;span class="kwrd"&gt;"-//W3C//DTD XHTML 1.0 Transitional//EN"&lt;/span&gt; &lt;span class="kwrd"&gt;"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://www.w3.org/1999/xhtml"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/javascript"&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;="//ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&amp;lt;script language=&lt;span class="str"&gt;"javascript"&lt;/span&gt; type=&lt;span class="str"&gt;"text/ecmascript"&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;pre&gt;    $(document).ready(&lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;/pre&gt;&lt;pre class="alt"&gt;        $(&lt;span class="str"&gt;"#target"&lt;/span&gt;).load(&lt;span class="str"&gt;"/testcontent.htm"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;    })&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="target"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, serif; white-space: normal; font-size: 16px; "&gt;Simple Content Page:&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/ecmascript"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;    $(&lt;span class="str"&gt;"#test"&lt;/span&gt;).css(&lt;span class="str"&gt;"background-color"&lt;/span&gt;, &lt;span class="str"&gt;"red"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="test"&lt;/span&gt; &lt;span class="attr"&gt;style&lt;/span&gt;&lt;span class="kwrd"&gt;="height:20px;width:20px;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;HI!&lt;/pre&gt;&lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-2797969641517592634?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2010/12/script-block-type-and-dynamic-script.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-2318712461304571387</guid><pubDate>Thu, 17 Sep 2009 02:14:00 +0000</pubDate><atom:updated>2009-09-17T09:30:45.869-04:00</atom:updated><title>Building General Purpose Lambda Expressions</title><description>&lt;p&gt;I was fascinated a while back to find the use of the Expression class to build general purpose lambda expressions while researching the use the Repository pattern and the Entity Framework. I didn’t look into it much at the time, but have recently had the time to dig a little deeper.&lt;/p&gt;By general purpose lambda I mean using classes in the System.Linq.Expressions namespace to build a run-time lambda from parameters that let you manipulate which class, method, and properties are used to build the expression executed as a delegate.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Let’s say you have an entity with several properties by which a user may want to sort a list. For example a Person with FirstName, LastName, DateJoined, and UserRank.&lt;br /&gt;&lt;div style="margin: 0px auto; width: 225px; height: 132px"&gt;&lt;br /&gt;&lt;table style="width: 218px; height: 132px" border="1" cellspacing="0" cellpadding="2" width="218"&gt;&lt;tbody&gt;      &lt;tr&gt;        &lt;td valign="top" width="200" colspan="2" align="center"&gt;&lt;br /&gt;  &lt;p align="center"&gt;&lt;strong&gt;Person&lt;/strong&gt; &lt;/p&gt;&lt;br /&gt;&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="200"&gt;FirstName&lt;/td&gt;        &lt;td valign="top" width="200"&gt;string&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="200"&gt;LastName&lt;/td&gt;        &lt;td valign="top" width="200"&gt;string&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="200"&gt;DateJoined&lt;/td&gt;        &lt;td valign="top" width="200"&gt;DateTime&lt;/td&gt;      &lt;/tr&gt;      &lt;tr&gt;        &lt;td valign="top" width="200"&gt;UserRank&lt;/td&gt;        &lt;td valign="top" width="200"&gt;Int32&lt;/td&gt;      &lt;/tr&gt;    &lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;You have an instance of a generic List&lt;person&gt; and want to sort it according to a user’s selection on a column. Of course you can probably think of some other ways to get this done, but it’s a good opportunity for a general purpose lambda (and actually just  a neat thing to do).&lt;/person&gt;&lt;/p&gt;&lt;p&gt;We can start to understand what we need if we decide that we’re going to use the Sort operation on List&lt;t&gt;, and specifically the overload that takes a Comparison&lt;t&gt; delegate. If we were to hard-code our delegates we would have:&lt;/t&gt;&lt;/t&gt;&lt;/p&gt;&lt;div  style="border-bottom: black 1px solid; border-left: black 1px solid;border-top: black 1px solid; border-right: black 1px solid;background-color:#ebebeb;"&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; SortBy&lt;br /&gt;{&lt;br /&gt;FirstName&lt;br /&gt;,LastName&lt;br /&gt;,DateJoined&lt;br /&gt;,UserRank&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;Comparison&lt;/span&gt;&amp;lt;&lt;span class="kwrd"&gt;Person&lt;/span&gt;&amp;gt; fnameCompare =&lt;br /&gt;(x, y) = x.FirstName.CompareTo(y.FirstName);&lt;br /&gt;&lt;span class="kwrd"&gt;Comparison&lt;/span&gt;&amp;lt;&lt;span class="kwrd"&gt;Person&lt;/span&gt;&amp;gt; lnameCompare =&lt;br /&gt;(x, y) = x.LastName.CompareTo(y.LastName);&lt;br /&gt;&lt;span class="kwrd"&gt;Comparison&lt;/span&gt;&amp;lt;&lt;span class="kwrd"&gt;Person&lt;/span&gt;&amp;gt; dateCompare =&lt;br /&gt;(x, y) = x.DateJoined.CompareTo(y.DateJoined);&lt;br /&gt;&lt;span class="kwrd"&gt;Comparison&lt;/span&gt;&amp;lt;&lt;span class="kwrd"&gt;Person&lt;/span&gt;&amp;gt; rankCompare =&lt;br /&gt;(x, y) = x.UserRank.CompareTo(y.UserRank);&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;We could do a switch statement and sort with the correct delegate. However, with the availability of a "CompareTo" method on every type on which we want to sort, and a common delegate type with basically the same expression syntax, it looks like we can do better.&lt;/p&gt;&lt;p&gt;The goal of our expression building will be to build the expression of the form (x,y) = x.[FieldName].CompareTo(y.[FieldName]) where x and y are Person type input arguments and the CompareTo operation is being executed against the underlying field type.&lt;/p&gt;&lt;p&gt;In order to build such an expression we will need parameters for the delegate, which in this case is an x and y parameter of the type Person since the Comparison delegate signature is&lt;/p&gt;&lt;span class="Apple-style-span"   style="  white-space: pre; font-family:monospace;font-size:13px;"&gt;public delegate int Comparison&amp;lt;T&amp;gt;(&lt;/span&gt;&lt;br /&gt;&lt;pre&gt; T x,&lt;br /&gt;T y&lt;br /&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;div  style="border-bottom: black 1px solid; border-left: black 1px solid; border-top: black 1px solid; border-right: black 1px solid;background-color:#ebebeb;"&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;var xparam = &lt;span class="kwrd"&gt;Expression&lt;/span&gt;.Parameter(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Person), &lt;span class="str"&gt;"x"&lt;/span&gt;);&lt;br /&gt;var yparam = &lt;span class="kwrd"&gt;Expression&lt;/span&gt;.Parameter(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Person), &lt;span class="str"&gt;"y"&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;We are also going to need references to the field on each delegate parameter so we can run the CompareTo operation on fields involved:&lt;/p&gt;&lt;br /&gt;&lt;div  style="border-bottom: black 1px solid; border-left: black 1px solid;border-top: black 1px solid; border-right: black 1px solid;background-color:#ebebeb;"&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;var xprop =&lt;br /&gt;&lt;span class="kwrd"&gt;Expression&lt;/span&gt;.Property(xparam, &lt;span class="kwrd"&gt;this&lt;/span&gt;.SortBy.ToString());&lt;br /&gt;var yprop =&lt;br /&gt;&lt;span class="kwrd"&gt;Expression&lt;/span&gt;.Property(yparam, &lt;span class="kwrd"&gt;this&lt;/span&gt;.SortBy.ToString());&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;All 4 of these statements are creating expressions. In the first case we are creating instances of ParameterExpression, and in the second case MemberExpression. I found it was most helpful to my understanding that each concrete type of Expression is adding a node to the parse tree. As such, picking the right type of Expression to represent what you want is key to building the pieces of your overall lambda expression. &lt;/p&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;&lt;strong&gt;Note&lt;/strong&gt; in the given expression, a local field with the SortBy enum has values equal to the field names on the target type – this is a stand-in for expressing a string field name.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Since we now have our delegate parameters, and the participating fields from those parameters, we can build the call to CompareTo. Since we want to add a method call to the tree, we will build a MethodCallExpression using the static Expression.Call helper method:&lt;/p&gt;&lt;br /&gt;&lt;div  style="border-bottom: black 1px solid; border-left: black 1px solid;border-top: black 1px solid; border-right: black 1px solid;background-color:#ebebeb;"&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;&lt;span class="kwrd"&gt;BindingFlags&lt;/span&gt; flags = &lt;span class="kwrd"&gt;BindingFlags&lt;/span&gt;.FlattenHierarchy |&lt;br /&gt;        &lt;span class="kwrd"&gt;BindingFlags&lt;/span&gt;.ExactBinding |&lt;br /&gt;        &lt;span class="kwrd"&gt;BindingFlags&lt;/span&gt;.NonPublic |&lt;br /&gt;        &lt;span class="kwrd"&gt;BindingFlags&lt;/span&gt;.Public |&lt;br /&gt;        &lt;span class="kwrd"&gt;BindingFlags&lt;/span&gt;.Instance;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;MethodInfo info = xprop.Type.GetMethod(&lt;span class="str"&gt;"CompareTo"&lt;/span&gt;, flags, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; Type[] { xprop.Type }, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;var methodCall = &lt;span class="kwrd"&gt;Expression&lt;/span&gt;.Call(xprop,info,yprop);&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I used an overload that takes a MethodInfo because the underlying FindMethod used in the Expression class does not specify "ExactBinding" and fails because it also finds the CompareTo overload with the object type parameter. Also note that the ParameterExpression instance xprop has a handy Type field that provides the type of the referenced field on the MemberExpression type to which it was bound.&lt;br /&gt;&lt;br /&gt;With these 5 expressions ready to go all we need to do is generate a lambda expression of the appropriate delegate type and compile it:&lt;br /&gt;&lt;br /&gt;&lt;div  style="border-bottom: black 1px solid; border-left: black 1px solid;border-top: black 1px solid; border-right: black 1px solid;background-color:#ebebeb;"&gt;&lt;br /&gt;&lt;pre class="csharpcode"  style="background-color:#ebebeb;"&gt;var sortExpression = &lt;span class="kwrd"&gt;Expression&lt;/span&gt;.Lambda&lt;&lt;span class="kwrd"&gt;Comparison&lt;/span&gt;&lt;&lt;span style="color:#0000ff;"&gt;Person&lt;/span&gt;&gt;&gt;(&lt;br /&gt;        methodCall&lt;br /&gt;        , xparam&lt;br /&gt;        , yparam);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; sortExpression.Compile();&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Place this code in a method with a return type of Comparison&amp;lt;Person&amp;gt; which could be called to retrieve the delegate and sort your list:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;myList.Sort(GetSortExpression());&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some good discussions and samples on the topic:&lt;br /&gt;&lt;br /&gt;&lt;a title="http://rogeralsing.com/2009/03/23/linq-expressions-from-and-to-delegates/" href="http://rogeralsing.com/2009/03/23/linq-expressions-from-and-to-delegates/"&gt;http://rogeralsing.com/2009/03/23/linq-expressions-from-and-to-delegates/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Nate Kohari’s use in Community Server 5’s REST API: &lt;a title="http://kohari.org/2009/03/06/fast-late-bound-invocation-with-expression-trees/" href="http://kohari.org/2009/03/06/fast-late-bound-invocation-with-expression-trees/"&gt;http://kohari.org/2009/03/06/fast-late-bound-invocation-with-expression-trees/&lt;/a&gt; and the related Rick Strahl entry: &lt;a title="http://www.west-wind.com/weblog/posts/653034.aspx" href="http://www.west-wind.com/weblog/posts/653034.aspx"&gt;http://www.west-wind.com/weblog/posts/653034.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a title="http://www.codeproject.com/KB/recipes/Generic_Sorting.aspx" href="http://www.codeproject.com/KB/recipes/Generic_Sorting.aspx"&gt;http://www.codeproject.com/KB/recipes/Generic_Sorting.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a title="http://www.codeproject.com/KB/architecture/linqrepository.aspx" href="http://www.codeproject.com/KB/architecture/linqrepository.aspx"&gt;http://www.codeproject.com/KB/architecture/linqrepository.aspx&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-2318712461304571387?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/09/building-general-purpose-lambda.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-517824819457055771</guid><pubDate>Mon, 17 Aug 2009 21:21:00 +0000</pubDate><atom:updated>2009-08-17T17:21:40.744-04:00</atom:updated><title>VS 2008 SharePoint Workflow Templates on x64</title><description>&lt;p&gt;As acknowledged by MS in the readme file, the SharePoint workflow project templates for sequential and state machine workflows do not work on an x64 machine. &lt;/p&gt;  &lt;p&gt;The error is blunt and unhelpful: “A 32-bit version of SharePoint Server is not installed. Please install a 32-bit version of SharePoint server.”&lt;/p&gt;  &lt;p&gt;The hurdle to developing a SharePoint workflow in no way requires such involved effort. &lt;/p&gt;  &lt;p&gt;Instead:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Create a standard WF workflow from the given .Net 3.0 template of your choice &lt;/li&gt;    &lt;li&gt;Add a file called feature.xml with the following content:      &lt;p style="background-color: #d0d0d0; width: 400px"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; ?&amp;gt;        &lt;br /&gt;&amp;lt;Feature xmlns=&amp;quot;&lt;a href="http://schemas.microsoft.com/sharepoint/&amp;quot;"&gt;http://schemas.microsoft.com/sharepoint/&amp;quot;&lt;/a&gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Id=&amp;quot;My generated unique GUID&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Title=&amp;quot;My Workflow&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Description=&amp;quot;This feature creates my workflow.&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Version=&amp;quot;1.0.0.0&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Scope=&amp;quot;Site&amp;quot;&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;ElementManifests&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;ElementManifest Location=&amp;quot;workflow.xml&amp;quot;/&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160; &amp;lt;/ElementManifests&amp;gt;         &lt;br /&gt;&amp;lt;/Feature&amp;gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Add a file called workflow.xml with the following content:      &lt;p style="background-color: #d0d0d0; width: 400px"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; ?&amp;gt;        &lt;br /&gt;&amp;lt;Elements xmlns=&amp;quot;&lt;a href="http://schemas.microsoft.com/sharepoint/&amp;quot;"&gt;http://schemas.microsoft.com/sharepoint/&amp;quot;&lt;/a&gt;&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;Workflow         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Id=&amp;quot;726DC49B-B3DE-455d-8ACB-A8CA86894F87&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Name=&amp;quot;Expense Report Approval Workflow Template&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Description=&amp;quot;This workflow template enables expense report approvals and payment&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CodeBesideClass=&amp;quot;MyWorkflowNamespace.MyWorkflowClass&amp;quot;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; CodeBesideAssembly=&amp;quot;MyWorkflow,Version=1.0.0.0, Culture=neutral, PublicKeyToken=MySigningKeyToken&amp;quot;&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;Categories&amp;gt;&amp;lt;/Categories&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;lt;MetaData&amp;gt;&amp;lt;/MetaData&amp;gt;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/Workflow&amp;gt;         &lt;br /&gt;&amp;lt;/Elements&amp;gt;&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Create a folder structure in your project for TEMPLATE\FEATURES\MyFeatureFolder &lt;/li&gt;    &lt;li&gt;Add a file called install.bat which automates the tasks of gac registration, feature file copying, feature installation, and IIS resetting. Set this file to be called by a post-build action. The file should contain something like:      &lt;div style="background-color: #d0d0d0; width: 400px"&gt;       &lt;p&gt;@SET TEMPLATEDIR=&amp;quot;C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE&amp;quot;          &lt;br /&gt;@SET GACUTIL=&amp;quot;C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe&amp;quot;           &lt;br /&gt;@SET STSADM=&amp;quot;C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\STSADM&amp;quot; &lt;/p&gt;        &lt;p&gt;Echo Installing in GAC          &lt;br /&gt;%GACUTIL% -if bin\debug\MyWorkflow.dll &lt;/p&gt;        &lt;p&gt;Echo Copying files          &lt;br /&gt;xcopy /e /y TEMPLATE\* %TEMPLATEDIR% &lt;/p&gt;        &lt;p&gt;Echo Installing feature          &lt;br /&gt;%STSADM% -o installfeature -filename&amp;#160; MyFeatureFolder\feature.xml -force &lt;/p&gt;        &lt;p&gt;ECHO Restarting IIS Worker process          &lt;br /&gt;&amp;quot;c:\windows\system32\inetsrv\appcmd&amp;quot; recycle APPPOOL &amp;quot;SharePoint Apps&amp;quot;&lt;/p&gt;     &lt;/div&gt;   &lt;/li&gt;    &lt;li&gt;Add an OnWorkflowActivated activity to your workflow from the SharePoint activities in your toolbox. &lt;/li&gt;    &lt;li&gt;Optionally change the base class on your workflow program class to SharePointSequentialWorkflowActivity &lt;/li&gt;    &lt;li&gt;Add the following field declarations to your workflow class:      &lt;p&gt;public Guid workflowId = default(System.Guid);        &lt;br /&gt;public SPWorkflowActivationProperties workflowProperties = new SPWorkflowActivationProperties();&lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Set the WorkflowProperties property on your OnWorkflowActivated activity equal to your new workflowProperties field.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;a href="http://pointstoshare.spaces.live.com/blog/cns!AEC42F315B4528B0!3018.entry"&gt;There is another workaround posted&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;I won’t hold my breath, but you can also &lt;a href="http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=325668"&gt;go vote on the bug&lt;/a&gt; in hopes that perhaps a patch will be released. I also imagine that packages for VS ‘10 will not have this problem.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-517824819457055771?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/08/vs-2008-sharepoint-workflow-templates.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-700040109337081147</guid><pubDate>Mon, 06 Jul 2009 18:20:00 +0000</pubDate><atom:updated>2009-07-09T10:16:03.355-04:00</atom:updated><title>LINQ, Persistence Ignorance, and Testing with Data Context/Entity Framework</title><description>&lt;p&gt;One thing I really try to avoid when writing tests is testing things that just aren’t going to break; or at least are of no concern to the application code I wrote. Database IO certainly fits this description, and yet I have found myself testing it by consequence of the desire to test Linq-based statements embedded in the data access code. &lt;/p&gt;  &lt;p&gt;Since other people have encountered and attempted to solve the same problem, a few hours of reading showed that in order to remove database IO testing from my tests, and to improve the design of the data access layer, it is necessary to implement some pattern of persistence ignorance like the Repository. &lt;/p&gt;  &lt;p&gt;In short form a repository allows business code to ask questions of the data layer without knowing anything more than the interfaces of data-storage objects. Want all the customers with outstanding invoices? Get a list of ICustomer objects back from the CustomerRepository.CustomersWithOutstandingInvoices method. As a business layer developer I have no idea what you did to return this list of customers, and don’t care. You don’t expose your DataContext (or other DAL implementation) to me, and I don’t write LINQ directly against the Customers table because the management of the DataContext and particulars of locating outstanding invoices may be too wonderful for me to know. Pretty standard separation of concerns, and very simple to implement. There are a few unique issues in a LINQ-centric world: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;How can I take advantage of delayed execution? &lt;/li&gt;    &lt;li&gt;How can LINQ best be supported outside the Repository &lt;/li&gt;    &lt;li&gt;How can I mock-up data-centric tests when I don’t have a database to execute against? &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;If you hide LINQ execution behind a repository you don’t really want to provide access to ObjectQuery objects or hand out Table&amp;lt;T&amp;gt; references, as you are tied immediately back into what you were hiding. This being the case you really need to execute the queries before they leave the repository*. Performance should come from good caching techniques, and by limiting the scope of queries through tight definition of access to the data.&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: 9pt;"&gt;*update* It isn't really necessary to disconnect the query in any way that breaks delayed execution. You can maintain all the benefits and still hand back an IQueryable&amp;lt;T&amp;gt;. However, it would then be up to developer discipline to not do further manipulation that takes advantage of the underlying data provider's specific types.&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;LINQ can work on any IQueryable, so handing back objects that can be used in LINQ syntax queries outside the context is as easy as handing back List&amp;lt;T&amp;gt;, or IQueryable&amp;lt;T&amp;gt; references. Referring back up to issue 1 above, these post-repository queries will be disconnected from the database.&lt;/p&gt;  &lt;p&gt;When it comes to testing, we played around with a number of different mocks and tricks to fool LINQ into executing disconnected; fake data contexts, entities without db connection strings, overrides and events that modify queries, etc. It turns out that the simplest way (in my view) is to use the repository to simply remove the database from the equation – that was after all the goal of this whole exercise. However, rather than go with a repository directly exposed to business logic code, I prefer to put what I will call a Provider in front of the repository. This ‘Provider’ is really just another sort of repository as some envision the concept, except that it contains all the LINQ queries and specific entity related methods and takes an IRepository implementation that simply has CRUD operations exposed with internal knowledge of the DAL implementation contained in this simple repository. Why? &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;It’s easier to create a general purpose IRepository interface for use in any project. &lt;/li&gt;    &lt;li&gt;With a simple IRepository interface you can create a simple general-purpose FakeRepository for use in testing. &lt;/li&gt;    &lt;li&gt;Once you can have LINQ statements dependent upon a single interface, you can inject the dependency and thereby replace the source of data during testing. You can test your LINQ query logic without going to the database. &lt;/li&gt;    &lt;li&gt;The logic used to obtain entity objects from methods like “CustomersWithOutstandingInvoices” is still removed from knowledge of the DAL, moving persistence ignorance as far up as we can. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;How does this all come together?&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;You create a concrete repository that has a concrete ObjectContext or DataContext. &lt;/li&gt;    &lt;li&gt;With EF ObjectContexts (my preference) you implement the Get&amp;lt;T&amp;gt;() functions on your repository by using CreateQuery methods:  &lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; Get&amp;lt;T&amp;gt;() &lt;span class="kwrd"&gt;where&lt;/span&gt; T : &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt; _context.CreateQuery&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(T).Name) &lt;/pre&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;as&lt;/span&gt; IQueryable&amp;lt;T&amp;gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You create a concrete ‘Provider’ that takes an inject-able IRepository object in the constructor.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Write your Provider LINQ queries against Get&amp;lt;T&amp;gt;() statements from the repository&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Write tests against your provider, inject a FakeRepository that has lists as it’s data source. Add objects to your Provider in test setup and confirm proper retrieval/manipulation in tests. &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can download our assembly with an IRepository/FakeRepository implementation from:&lt;/p&gt;&lt;p&gt;&lt;a href="http://atgitesting.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=29772"&gt;http://atgitesting.codeplex.com/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Inspiration and understanding from:&lt;/p&gt;&lt;p&gt;&lt;a href="http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx"&gt;The Repository Pattern Explained&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a title="Andrew Peters’ Blog » Blog Archive » Fixing Leaky Repository Abstractions with LINQ" href="http://andrewpeters.net/2007/04/28/fixing-leaky-repository-abstractions-with-linq/"&gt;Andrew Peters’ Blog » Blog Archive » Fixing Leaky Repository Abstractions with LINQ&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a title="Diego Vega - Unit Testing Your Entity Framework Domain Classes" href="http://blogs.msdn.com/diego/archive/2008/03/03/unit-testing-your-entity-framework-domain-classes.aspx" style="text-decoration: none;"&gt;Diego Vega - Unit Testing Your Entity Framework Domain Classes&lt;/a&gt;&lt;/p&gt;&lt;a title="Dynamic Queries and LINQ Expressions - Rick Strahl's Web Log" href="http://www.west-wind.com/WebLog/posts/314663.aspx"&gt;Dynamic Queries and LINQ Expressions - Rick Strahl's Web Log&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-700040109337081147?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/07/linq-persistence-ignorance-and-testing.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-6669289748564685039</guid><pubDate>Fri, 17 Apr 2009 18:06:00 +0000</pubDate><atom:updated>2009-09-21T13:55:38.544-04:00</atom:updated><title>Working with detached entities and Linq to Sql</title><description>On my current project we are using Linq to Sql, and as it is a web application are working with the DataContext in limited scope only during data operations. This means that objects generally need to be attached to the context in order for all operations to succeed (all related parent objects must be attached when inserting children, changed objects before updates/deletes)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One annoyance I have is that I can't really tell if I should attach the object, insert it, or just update it. If every operation is done in an entirely atomic fashion, or you associate objects by key values only; this can be avoided. Yet that robs me of the features I like such as adding any number of new objects, associate object instances together and let the context figure out the order of operations. With fairly atomic data operations defined in our data class we end up blind to the state of the objects when dealing with a new context.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To help out with this I have created the following extension on DataContext...&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DCExtensions{&lt;/pre&gt;&lt;pre class="csharpcode"&gt; &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; SafeAttach&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; DataContext context&lt;br /&gt;                                             , T entity)&lt;br /&gt;     &lt;span class="kwrd"&gt;where&lt;/span&gt; T : &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;   Table&amp;lt;T&amp;gt; entityTable = context.GetTable&amp;lt;T&amp;gt;();&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; (entityTable == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;   T instance = entityTable.GetOriginalEntityState(entity);&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; (instance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (!entityTable.Contains(entity))&lt;br /&gt;           entityTable.InsertOnSubmit(entity);&lt;br /&gt;       &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;           entityTable.Attach(entity);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;I can then have a method like the following that isn't concerned with entity state:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;internal&lt;/span&gt; ChildObject AddAssociation(ParentObject1 parent1&lt;br /&gt;                                     , ParentObject2 parent2)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;using&lt;/span&gt; (var dc = &lt;span class="kwrd"&gt;new&lt;/span&gt; MyDataContext())&lt;br /&gt;   {&lt;br /&gt;      dc.SafeAttach(parent1);&lt;br /&gt;      dc.SafeAttach(parent2);&lt;br /&gt;      ChildObject child = &lt;span class="kwrd"&gt;new&lt;/span&gt; ChildObject();&lt;br /&gt;      child.Parent1 = parent1;&lt;br /&gt;      child.Parent2 = parent2;&lt;br /&gt;      dc.ChildObjects.InsertOnSubmit(child);&lt;br /&gt;      dc.SubmitChanges();&lt;br /&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; child;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-6669289748564685039?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/04/working-with-detached-entities-and-linq.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-4384745663580212760</guid><pubDate>Tue, 24 Mar 2009 18:11:00 +0000</pubDate><atom:updated>2009-03-24T14:24:16.834-04:00</atom:updated><title>IIS 7 Wildcard mapping issues</title><description>I recently ran into an issue while converting a site to use the managed pipeline in IIS 7 that took a while to fix but turned out to be one single attribute in web.config. This also turned out to be the answer to something we had simply hacked around before.&lt;br /&gt;&lt;br /&gt;I was converting this asp.net website into an application, and configuring it to run under iis 7. The previous developers had setup a url rewriting scheme in global.asax intended to run for extensionless urls such that http:/example.com/placename would properly respond with the information for said place name.&lt;br /&gt;&lt;br /&gt;I moved the rewriter logic into a new IHttpModule implementation and configured it in system.webserver. This helped to get my requests mapped properly but the page came up with an error stating: "Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive.". This was an unfortunate error as I had everything already in place for session to work. After a good bit of digging  I found that the problem is that when you have a custom module in place to handle all requests you lose the functionality of any other configured module which has a pre-condition for managedHandler. Session is one of these, as is FormsAuthentication.&lt;br /&gt;&lt;br /&gt;You can either go through and remove each module and replace with a config that has an empty preCondition attribute, or you can just force all with the following:&lt;br /&gt;&lt;br /&gt;&amp;lt;modules runallmanagedmodulesforallrequests="false"&amp;gt;&lt;br /&gt;&lt;br /&gt;This turned out to be the best option in my case. As I said, this also helped solve an old problem where we would get authentication failures when going to extensionless urls. The behavior is a bit perplexing - logged in when on default.aspx, logged out when at /. It turns out this is the source of that problem too.&lt;br /&gt;&lt;br /&gt;The answers are out &lt;a href="http://ruslany.net/2008/09/wildcard-script-mapping-and-iis-7-integrated-pipeline/"&gt;there&lt;/a&gt;, I just had a hell of time finding them so I thought I would re-share.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-4384745663580212760?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/03/iis-7-wildcard-mapping-issues.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-6703357407393540714</guid><pubDate>Tue, 17 Feb 2009 16:36:00 +0000</pubDate><atom:updated>2009-02-17T11:40:59.882-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Community Server</category><category domain="http://www.blogger.com/atom/ns#">Training</category><title>Community Server Training Class Announced</title><description>I haven't been into writing much content here lately as I have been focusing on class materials and labs for our upcoming Community Server training class.&lt;br /&gt;&lt;br /&gt;I am really excited about this, and even more so today as we finally announce the date and costs and open up registration! The class will be April 27th-29th and will cover everything from basic site configuration to creating custom chameleon controls. At ATGi we're very excited, and a little bit nervous, but I think the content is excellent and can't wait to give the class.&lt;br /&gt;&lt;br /&gt;If you are working with Community Server as a customized community platform, check it out:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.atgi.com/training.aspx"&gt;http://www.atgi.com/training.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-6703357407393540714?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/02/community-server-training-class.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-8462385221355184066</guid><pubDate>Tue, 10 Feb 2009 22:27:00 +0000</pubDate><atom:updated>2009-02-10T17:31:22.888-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Community Server</category><title>Bright Cove Controls for Community Server</title><description>I have published a project on &lt;a href="http://www.codeplex.com/bcforcs"&gt;code plex&lt;/a&gt; with a set of tools and controls for working with &lt;a href="http://help.brightcove.com/publisher/faqs/overall_faq.cfm"&gt;Bright Cove video&lt;/a&gt; inside &lt;a href="http://www.communityserver.com/"&gt;Community Server&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It includes&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A Bright Cove video File Viewer&lt;/li&gt;&lt;li&gt;A Bright Cove video Content Fragment&lt;/li&gt;&lt;li&gt;List, data, and image Chameleon controls that work directly against the &lt;a href="http://help.brightcove.com/developer/docs/mediaapi/media-API.cfm"&gt;BC Media API&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Use it if you need it, join me in updating it if you need more features.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-8462385221355184066?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2009/02/bright-cove-controls-for-community.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-7229696608522330879</guid><pubDate>Tue, 25 Nov 2008 14:25:00 +0000</pubDate><atom:updated>2008-11-25T10:06:07.321-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Community Server</category><category domain="http://www.blogger.com/atom/ns#">SEO</category><title>SEO and Community Server</title><description>I am not an SEO expert but have been working with one to optimize Community Server urls and pages for a client's install. I recently read &lt;a href="http://dev.communityserver.com/forums/t/503839.aspx"&gt;this post &lt;/a&gt;on CS forums and it deals directly with many of the same issues surfaced by the expert we have been working with.&lt;br /&gt;&lt;br /&gt;It seems that one of the major problems for SEO experts is the forum post perma-link urls which come out as duplicated content urls. Which is to say that threads have links, and so do posts:&lt;br /&gt;&lt;br /&gt;http://mycommunitysite.example.com/t/2323.aspx (the thread)&lt;br /&gt;&lt;br /&gt;and any number of post urls like this:&lt;br /&gt;&lt;br /&gt;http://mycommunitysite.example.com/p/2323/83839.aspx&lt;br /&gt;&lt;br /&gt;Where the post ID as the page name is the individual post in the thread.&lt;br /&gt;&lt;br /&gt;The simple solution is to use only thread references, right?. This isn't quite so simple if you have multiple pages to display posts. How do you indicate which page of the thread a post should link to? Posts can also be deleted or moved, which could affect page position for every post in a thread.&lt;br /&gt;&lt;br /&gt;You can solve these problems in dynamic site links by changing post perma-links in a new ForumUrls provider:&lt;br /&gt;&lt;br /&gt;public override string PostPermaLink(int threadID, int postID)&lt;br /&gt;{&lt;br /&gt;int _pageIndex = Posts.GetPageIndex(postID, PageSize, 0,&lt;br /&gt;(int)CSContext.Current.User.PostSortOrder);&lt;br /&gt;return ThreadPaged(threadID, _pageIndex) + "#" + postID.ToString();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This methodology has the mild inconvenience of requiring a set page-size for display of posts in a thread.&lt;br /&gt;&lt;br /&gt;However, this doesn't solve the problem of what may be indexed. Once a link is stored, it may end up being on the incorrect page if posts are moved or deleted. Setting all of your post pages to noindex can help here. You could also set all of your thread display pages to list a very large number of posts at a time and virtually eliminate pages.&lt;br /&gt;&lt;br /&gt;To really deal with posts and threads I think the best way would be to implement a script-based solution. Most crawlers don't implement script, which allows you to hide content from crawlers while still having a user-friendly implementation.&lt;br /&gt;&lt;br /&gt;In a thread-centric implementation you could have only the thread page with all content on it, and implement paging via script. Post references are handled via anchors (as they can be in ootb CS).&lt;br /&gt;&lt;br /&gt;My preference would be for a post-centric implementation where every post is in fact its own page and you implement the threaded view via client script. Links to 'threads' are in fact links to the thread-starter post.&lt;br /&gt;&lt;br /&gt;When a post page is rendered you can dynamically 'locate' the post within the thread based on paging configuration.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-7229696608522330879?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2008/11/seo-and-community-server.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-2969056727589872064</guid><pubDate>Tue, 28 Oct 2008 20:04:00 +0000</pubDate><atom:updated>2008-10-28T16:14:09.938-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Community Server</category><category domain="http://www.blogger.com/atom/ns#">SEO</category><category domain="http://www.blogger.com/atom/ns#">BlogUrls</category><category domain="http://www.blogger.com/atom/ns#">SEM</category><title>CS Blog post dates and links</title><description>I have been working on another &lt;a href="http://communityserver.org"&gt;Community Server&lt;/a&gt; installation for a client concerned with SEO (more on lessons here later). Duplicate urls are one of the major issues we have tried to elimate in his site. CS publishes lots of urls for the same content, and in particular will display blog post urls that are date based where the date is dependent on the publishing user's time zone or the server time. These probably don't cross over too often, but we needed to eliminate different date-based urls.&lt;br /&gt;&lt;br /&gt;Here are the things I learned about CS blog urls while investigating how to change this behavior:&lt;br /&gt;&lt;br /&gt;1.      During post creation two dates are stored – the server date/time  as PostDate and the user’s date/time as UserTime.&lt;br /&gt;&lt;br /&gt;2.      When posts are retrieved as IndexPost through the SearchBarrel (search, tags/topics) the UserTime is set directly from the PostDate field before requesting the url.&lt;br /&gt;&lt;br /&gt;3.      When posts are retrieved as WeblogPost through the WeblogPosts component (weblog archive lists, googlesitemap) the UserTime is populated from the UserTime property.&lt;br /&gt;&lt;br /&gt;4.      The BlogUrls provider uses the UserTime property to createthe url. Based on 2 and 3, this could vary depending on execution path.&lt;br /&gt;&lt;br /&gt;5.      WeblogPost picks up a third property called CurrentUserTime which is a manipulation of the PostDate to the viewing user’s timezone and is dynamic. This property does not appear to be used anywhere in the SDK.&lt;br /&gt;&lt;br /&gt;6.      Any object property that is of the type DateTime will be formatted by the default property formatter to be displayed in the current user’s time zone manipulated date and time. In the case of blog post display, this property is supposed to be "PostDate" but actually comes out to be CurrentUserTime because of this property formatting. While this seems like a failure of consistency to me on the part of Telligent, it is not 'dangerous' in terms of SEO because it is simply the text displayed to the user. Changing this behavior would require new IndexPostData and BlogPostData controls to properly override the FormatProperty method and a global replace of their use in the site’s theme files. Not a prohibitive change if required, but probably not necessary.&lt;br /&gt;&lt;br /&gt;Our fix here was to create our own BlogUrls provider, override the Post(WeblogPost, Weblog) method, and standardize UserTime to PostDate before getting the url from the base provider.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-2969056727589872064?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2008/10/cs-blog-post-dates-and-links.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-7457723346126353391</guid><pubDate>Fri, 15 Aug 2008 15:10:00 +0000</pubDate><atom:updated>2008-08-15T12:16:02.234-04:00</atom:updated><title>Section 8.5.2 of CSS 2.1 and the border-color property</title><description>I realize this is minutea, but I wanted to get this down for later recall.&lt;br /&gt;&lt;br /&gt;First of all, when working with Firefox, I usually find that it is reliably strict, and so developing for FF will allow you to get a result that transfers to other browsers. Of course, sometimes the strictness is annoying but at least it's reliable. In this case I thought I had found something it just wasn't doing right, but giving it the benefit of the doubt on just being a PITA, I looked at the &lt;a href="http://www.w3.org/TR/CSS21/box.html#border-color-properties" target="_blank"&gt;spec&lt;/a&gt; and of course FF was proved right.&lt;br /&gt;&lt;br /&gt;The problem was that I was setting some border colors for various containers on the page like so (heavily simplified):&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;.boxtype1&lt;br /&gt;{&lt;br /&gt;     border-color:blue;&lt;br /&gt;     ...other properties...&lt;br /&gt;}&lt;br /&gt;.boxtype1-alert&lt;br /&gt;{&lt;br /&gt;     border-color:red;&lt;br /&gt;     ...other properties...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What I was seeing was that boxtype1 was getting a black border color (the color of the 'color' property in the body tag), and the -alert type box was getting the proper red border - only in FF; IE (6 &amp;amp; 7) and Safari were 'fine' in that they displayed my chosen color as the border color. After cursing FF for it's lame implementation I decided to check the spec and found the answer as related to the use of some border-side specific styling and the order of styles implemented.&lt;br /&gt;&lt;br /&gt;The fact is that other declarations subsequent to the style I was using to set color were setting other properties on left/right/top/bottom borders without setting the color:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;.boxtype1&lt;br /&gt;{&lt;br /&gt; border-left:solid 2px;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This doesn't leave the color as previously set, but makes it work as "inherit" or default because it was not set specifically.&lt;br /&gt;&lt;br /&gt;The solution is to either make sure the order of execution is correct (a fragile waste of time) or set each border specifically, making sure it will take on the style no matter the order.&lt;br /&gt;&lt;br /&gt;You can see for yourself that if you have the following html:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="boxtype1"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            Some text with a border around container.&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;and apply the following styles:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;body&lt;br /&gt;{&lt;br /&gt;    color:Blue;&lt;br /&gt;}&lt;br /&gt;.boxtype1&lt;br /&gt;{&lt;br /&gt;    border:solid 1px;   &lt;br /&gt;}&lt;br /&gt;.boxtype1&lt;br /&gt;{&lt;br /&gt;    border-color:Red;&lt;br /&gt;}&lt;br /&gt;.boxtype1&lt;br /&gt;{&lt;br /&gt;    border-left:solid 2px;   &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;You will get a red border all the way around in IE, but will have a blue, 2px border on the left in FF.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-7457723346126353391?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2008/08/section-852-of-css-21-and-border-color.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-6013701951053982066</guid><pubDate>Mon, 11 Aug 2008 17:19:00 +0000</pubDate><atom:updated>2008-08-19T16:10:44.110-04:00</atom:updated><title>Asp.Net AJAX Client Side Templated Data Bound Control</title><description>&lt;a href="http://community.hydrussoftware.com/files/folders/ajax/entry672.aspx"&gt;Source Code &lt;/a&gt;Available from Hydrus Software&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I recently read these two articles by Dino Esposito about ajax templates (&lt;a title="Cutting Edge: Asp.Net Ajax and Client Side Templates" href="http://msdn.microsoft.com/en-us/magazine/cc546561.aspx" target="_blank"&gt;part1&lt;/a&gt;, &lt;a title="Cutting Edge: The HTML Message Pattern" href="http://msdn.microsoft.com/en-us/magazine/cc699560.aspx" target="_blank"&gt;part2&lt;/a&gt;) and was intrigued by the possibilities. I spend a lot of time working on customizing Community Server which is one page after another of templated data-bound lists. In a number of situations we have needed to customize lists to respond to client input. This can present performance problems when lists are in tabs, or the page is very heavy.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In any case, I had some time available and worked out a client script control that implements the template builder Mr. Esposito showed in part 1 of his article.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I created a server control that allows you to specify header, item, and footer templates for a basic data list that will be bound on the client based on either a given web service method, or on a data-source provided client side. The templates are rendered server-side before being passed to the client behavior which allows you to use other server-side controls in the development of the templates.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I had not built an asp.net ajax client script control before, but the magic lies in the &lt;a title="System.Web.UI.IScriptControl interface" href="http://msdn.microsoft.com/en-us/library/system.web.ui.iscriptcontrol.aspx" target="_blank"&gt;IScriptControl&lt;/a&gt; interface. There are plenty of articles out there on this, so I won't go into it. At a high level, this interface provides a way for you to instantiate your client-side object (behavior) with properties set on your server side control.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Finally, in order to make the server-side declarative coding a bit cleaner, I implemented the client-template replacement string as a control. Once you have this nifty server-side control, you can setup the client repeater with code like this:&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HydrusClient:ClientRepeater&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerList"&lt;/span&gt; &lt;span class="attr"&gt;ServiceMethod&lt;/span&gt;&lt;span class="kwrd"&gt;="GetCustomers"&lt;/span&gt;&lt;br /&gt;        &lt;span class="attr"&gt;ServicePath&lt;/span&gt;&lt;span class="kwrd"&gt;="Service.svc"&lt;/span&gt; &lt;span class="attr"&gt;DataBindingFunctionName&lt;/span&gt;&lt;span class="kwrd"&gt;="MyFunction"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HeaderTemplate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;thead&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Label&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Full Name&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:Label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:Label&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Role&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:Label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;thead&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tbody&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HeaderTemplate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemTemplate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HydrusClient:ClientBoundDataProperty&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;="FullName"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HydrusClient:ClientBoundDataProperty&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;="Role"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;td&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tr&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemTemplate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;FooterTemplate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;tbody&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;table&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;FooterTemplate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HydrusClient:ClientRepeater&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;A few words about getting the control to work properly... &lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;While we instantiate the templates into containers in CreateChildControls, the templates are rendered into strings in the RenderChildControls method. These strings must have insignificant whitespace removed.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Because the template strings must be properties on the client-side behavior, we cannot call RegisterScriptDescriptors until after the children have been rendered, thus we make the call in the overridden Render method.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The ScriptManager must have the id of a rendered client element with which to register the behavior when creating the ScriptControlDescriptor. In this case my server control renders a placeholder. You could write this control as a rendered control extension and force the user to identify the rendered element.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-6013701951053982066?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2008/08/aspnet-ajax-client-side-templated-data.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-4078952570654750657</guid><pubDate>Wed, 03 Oct 2007 17:07:00 +0000</pubDate><atom:updated>2007-10-03T13:07:31.027-04:00</atom:updated><title>Community Server and Extended Profile Properties</title><description>&lt;p&gt;Anyone who has done much customization for &lt;a href="http://communityserver.org/"&gt;Community Server&lt;/a&gt; will eventually run into the need to add more profile properties for users. These properties are really easy to add. The problem is that you cannot easily search on these fields because they are stored as two text columns in the database. There's an old &lt;a href="http://communityserver.org/blogs/announcements/archive/2005/06/20/FetchExtendendAttributeValue.aspx"&gt;add-on&lt;/a&gt; that offered one way to get at these values. Another would be do your searching in code since the values are easy to get at once the User objects have been loaded.&lt;/p&gt; &lt;p&gt;While it isn't efficient enough for regular site-based use, and it certainly isn't pretty; you can query the database for these values using text manipulation procedures in Sql Server. Adding first-class columns to the profile table requires a major&amp;nbsp;effort in&amp;nbsp;CS, so this approach can work if you want to add ad-hoc usre reports. &lt;/p&gt; &lt;p&gt;&lt;em&gt;&amp;lt;disclaimer&amp;gt;I really can't recommend the following for adding functionality to your CS search page - but if you manage to use it and have some performance measures, please share them.&amp;lt;/disclaimer&amp;gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;I added three functions to my CS database*:&lt;/p&gt; &lt;p&gt;GetUserPropertyValue - takes the UserId, property name, property type (b,s,i), and settingsID and comes back with the named property value. &lt;/p&gt; &lt;p&gt;GetPropertyStartIndex - takes the property name you're searching for, and the list of property names. Used by GetUserPropertyValue.&lt;/p&gt; &lt;p&gt;GetPropertyLength - takes the same params as above, and returns the text&amp;nbsp;length of the property value. &lt;/p&gt; &lt;p&gt;The start index, and length are what is stored in the property names string. You then go to the property values string to get the value only. I broke this operation&amp;nbsp;up to into separate procedures for readability.&lt;/p&gt; &lt;p&gt;Finally, I created a&amp;nbsp;modified version of cs_vw_Users_FullUser to include values for the fields I was interested in by adding this function call into the select query:&lt;/p&gt; &lt;p&gt;dbo.GetUserPropertyValue(cs_UserID, N'MySpecialProperty', N'S', SettingsID)&lt;/p&gt; &lt;p&gt;This way, I could write a report against all users and search, sort, and filter by custom values.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.atgi.com/dist/ExtendedUserPropertySearch.zip"&gt;Download the sql code&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;This hack will work for asp.net based profiles too since the methodology used to store these key/value strings&amp;nbsp;in cs_UserProfile (PropertyNames | PropertyValues) is the same as is used for the base aspnet_Profile table for&amp;nbsp;asp.net&amp;nbsp;membership profiles.&lt;/p&gt; &lt;p&gt;&lt;em&gt;*my sql-guru friend &lt;a href="http://community.hydrussoftware.com/blogs/john/default.aspx"&gt;John&lt;/a&gt; wrote the original manipulation query.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-4078952570654750657?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/10/community-server-and-extended-profile.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-8929472527851727930</guid><pubDate>Mon, 24 Sep 2007 15:05:00 +0000</pubDate><atom:updated>2007-09-24T11:09:48.754-04:00</atom:updated><title>Earned Value Early Results</title><description>&lt;p&gt;We have our first reporting period under our belts, and I am very excited about the EV results.&lt;/p&gt;&lt;p&gt;In this fictionalized representation of our first project, we see the period % complete reporting by the team leader:&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atgi.com/pensieve_images/evpercentcomplete.png" atomicselection="true"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="307" src="http://www.atgi.com/pensieve_images/evpercentcomplete.png" width="251" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;This evaluation of our status leads to the following period values for EV:&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atgi.com/pensieve_images/evhoursreporting.png" atomicselection="true"&gt;&lt;img style="WIDTH: 465px; HEIGHT: 375px" height="417" src="http://www.atgi.com/pensieve_images/evhoursreporting.png" width="517" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;You'll notice that while 145 hours were spent instead of only 120, we also saw 8.2% EV, instead of the planned 6.63%. However, the question we have is, was this enough extra EV to justify the hours spent? In our calculations we have the answer:&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atgi.com/pensieve_images/evperiodstats.png" atomicselection="true"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="232" src="http://www.atgi.com/pensieve_images/evperiodstats.png" width="219" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;We're still all green because the EV was indeed enough to overcome the overspending. Notice that the CPI is roughly $1.02 - this means that the EV just barely covered the cost overrun for the period (we got $1.02 effort out of our team for each project $1 planned). Thus, while we spent over $17K in the period on labor instead of just over $14K, the project is projected to end early, and still come in under budget. What this also shows, is that we'll need to watch this team's hours closely over the coming weeks to make sure this level of efficiency is maintained.&lt;/p&gt;&lt;p&gt;Our second team had a more modest hours overage, but still managed a healthy start on EV:&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atgi.com/pensieve_images/evteam2hours.png" atomicselection="true"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="108" src="http://www.atgi.com/pensieve_images/evteam2hours.png" width="253" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Leading to an even rosier bottom line report:&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.atgi.com/pensieve_images/evteam2stats.png" atomicselection="true"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="215" src="http://www.atgi.com/pensieve_images/evteam2stats.png" width="252" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;So far, this seems like a realistic view of real project progress. Obviously, there's still a ways to go. BTW - it didn't take even close to 15 minutes to enter and analyze the data.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-8929472527851727930?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/09/earned-value-early-results.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-2619836200550932502</guid><pubDate>Fri, 21 Sep 2007 16:35:00 +0000</pubDate><atom:updated>2007-09-21T12:35:12.891-04:00</atom:updated><title>Earned Value Management</title><description>&lt;p&gt;One session&amp;nbsp;of a conference I attended way back in March was a discussion about managing projects presented by &lt;a href="http://idesign.net/idesign/DesktopDefault.aspx?tabindex=3&amp;amp;tabid=5"&gt;Juval Löwy&lt;/a&gt;. One of Juval's excellent claims was that he had used earned value analysis to keep his management time to 15 minutes every Friday afternoon. He explained he used the rest of his time to become a better architect, and when he was finally too bored with the simplistic task of management, he moved on to architecture.&lt;/p&gt; &lt;p&gt;A great story, and certainly a compelling one for someone that needs to manage&amp;nbsp;on less than 40 hours a week.&amp;nbsp;I have been waiting to use this magical method, so as a recent project was ramping up, I pulled out my notes and hit a few websites to try and prepare for the 15 minute management job. Going on scant examples of exactly the type of project analysis I wanted caused this task to take somewhat more than 15 minutes. I found some helpful examples &lt;a href="http://www.earnedvalueanalysis.com/index.cfm?nextpage=example"&gt;here&lt;/a&gt; and &lt;a href="http://www.computerworld.com/action/article.do?command=viewArticleBasic&amp;amp;articleId=110065&amp;amp;intsrc=article_pots_bot"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;If you aren't familiar with EV, the basic idea is that actual&amp;nbsp;work is tracked against the amount of value accrued by the work completed against the plan of value to have been accrued according to the plan milestones. The notion of Earned Value has to do with tracking accomplished activities, rather than just time spent (I think this works well with my management objectives - I don't care how much time you spent, I care that the work gets done). Each activity has some percentage of value to the overall project. A simple way to get at this in software development is to divide the hours for one task against the total hours estimated for the project. Choosing the proper level of task granularity to track is a matter of balancing ease of reporting with meaningful levels of detail for catching problems before they go out of control. Once the earned percentage values are assigned to milestone tasks, you can either work with dollar figures or just work with hours - it doesn't matter. The important thing is to calculate how much earned value should be accrued at various key&amp;nbsp;intervals along the project path. For instance, if I am checking in on my developers every Friday night, then I calculate EV earned to each Friday. When my developers report in, they tell me how many hours they worked this week, and what % complete they are for each milestone task. &lt;/p&gt; &lt;p&gt;Planned EV will be the number of developer hours available in the time period divided by the total number of project hours. When each developer reports a percent done, you multiply that by the percentage EV calculated for each task against which you are reporting. Summing each EV gives you the period EV which you compare against your goal. You can then use the total actual hours reported as a measure of how much real effort it took to get actual EV. This calculation comes into play as you forecast the future effort expenditure of the project. If you thought you could complete 10% EV with 80 hours, and got 8% EV with 80 hours, your SPI will give you a multiplier for estimating future period effort. This is where the 15 minutes&amp;nbsp;comes in. Each Friday you must inspect your planned EV and and planned Costs against your actual's. You then analyze what variances in the charts mean to you:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&amp;nbsp;PEV way ahead of AEV? You underestimated and should add resources  &lt;li&gt;AEV way ahead of PEV? - You overestimated and may be able to divert resources  &lt;li&gt;AEV=PEV but costs overrun? - You can meet the deadline, but your resources are inefficient - you need to figure out what's bogging down your resources.&lt;/li&gt;&lt;/ul&gt;You get the idea. Manage next week's resources based on your 15 minutes of EV and cost analysis. &lt;p&gt;Without a tool to provide EV analysis for me, I turned to Excel. The only gotchas I had in setting up the calculations was discerning the best path for tracking - either project to date sums, or per period values; and getting graphs to show the EV and cost trends. In the end I went with per period values and some extra calculations to show trends and two separate graphs for EV and Cost.&lt;/p&gt; &lt;p&gt;With the plan in place, I simply communicated the project milestone tasks to the team along with target dates and requested weekly reporting of progress. Hopefully this leaves the devs with schedule freedom and a sense of autonomy, while giving me a way to know which adjustments are necessary before we have a big problem.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-2619836200550932502?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/09/earned-value-management.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-5700452266942462483</guid><pubDate>Fri, 21 Sep 2007 15:41:00 +0000</pubDate><atom:updated>2007-09-21T11:41:44.515-04:00</atom:updated><title>Orcas Beta 1 and other new stuff</title><description>&lt;p&gt;It seems to me that the development world&amp;nbsp;is experiencing another period of rapid evolution again, much as it did in '99-'01 around web application servers, XML, and all the XML spinoff technologies. Interestingly, during the last evolution many people left javascript in the dust; but it has had a massive resurgence to the forefront this time around. I think it also interesting to note that the lastest tools and technologies are clearly evolutionary in that most are still new ways of utilizing the XML breakthrough. Well, I am sure someone more knowledgable wrote about this years ago; but it's clear that it is time to dig deep into&amp;nbsp;the recent mountain&amp;nbsp;of information.&lt;/p&gt; &lt;p&gt;As one who is primarily an MS-based developer, a lot of that mountain I am facing is coming out Redmond lately.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;.net&amp;nbsp;3.0  &lt;ul&gt; &lt;li&gt;Windows Communication Foundation  &lt;li&gt;Windows Workflow Foundation  &lt;li&gt;Windows Presentation Foundation&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Silverlight  &lt;li&gt;C# 3/3.5 (lambdas, extensions, implicit types, anonymous types, type initializers, expression trees, and LINQ)  &lt;li&gt;AJAX Framework  &lt;li&gt;PowerShell scripting  &lt;li&gt;Vista/Longhorn Server (IIS7 being the big one here so far)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Along with this has been the birth of Ruby and the resurgence of javascript. &lt;/p&gt; &lt;p&gt;Of course, many of these things have been around or brewing for years, but the pressure has mounted as more of the MS stuff nears release.&lt;/p&gt; &lt;p&gt;I've had the opportunity to play with Orcas the last couple of days, and it has been fun. Silverlight programming isn't really something&amp;nbsp;I think I'll do a lot of, but it provided a good way to mess around with XAML and learn about what's available. It also provided a way to get into VS 9, and the new Blend tool. &lt;/p&gt; &lt;p&gt;First, the XAML stuff is cool, especially the web delivered Silverlight. Updating markup, and then watching visuals automatically update was great. However, my artistic skills approach those of a first grader so the appeal is limited. I can see a potential upside in using Silverlight for rich administrative interfaces. I hate all-flash sites because they are usually more about style than substance (i don't need to hear sounds when I drop down menus or wait for transition effects when I go to a new page), but if used carefully and mixed with AJAX it could be good.&lt;/p&gt; &lt;p&gt;VS 9 has some&amp;nbsp;fairly exciting innovations too. I especially like the javascript editor has improvements (though it could be a lot better - see &lt;a href="http://www.aptana.com/"&gt;Aptana&lt;/a&gt;).&amp;nbsp; &lt;/p&gt; &lt;p&gt;C# 3.5 has some great stuff going on. &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx"&gt;Scott Guthrie's coverage of LINQ features&lt;/a&gt; has been excellent. It does take some time to get used to the LINQ programming model (which utilizes most of the new language features), but it's well worth it. Start investing the time now.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-5700452266942462483?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/09/orcas-beta-1-and-other-new-stuff.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-5430906211540379215</guid><pubDate>Tue, 05 Jun 2007 19:17:00 +0000</pubDate><atom:updated>2007-06-05T15:29:58.982-04:00</atom:updated><title>Private Workspace Config Mgmt w/Team System</title><description>&lt;p&gt;On a recent project our team has been using &lt;a href="http://msdn2.microsoft.com/en-us/teamsystem/default.aspx"&gt;Microsoft's Team System&lt;/a&gt; from within Visual Studio. We are using the built-in capabilities for:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Requirements Definition  &lt;li&gt;Task Assignments  &lt;li&gt;Source Control  &lt;li&gt;Build Server  &lt;li&gt;Bug Tracking  &lt;li&gt;Code Coverage  &lt;li&gt;Unit Testing&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;So, we're involved in it up to our necks. We've been using pieces of the system for quite a while, but this is our first immersion. The SCM is a little funky sometimes, and really annoys my &lt;a href="http://community.hydrussoftware.com/blogs/jeffesp/default.aspx"&gt;SCM-geeked&lt;/a&gt; teammate. &lt;/p&gt; &lt;p&gt;Honestly, I think it has been a pretty good experience overall. I like the reporting we get out of the box (these only come into play if you do use TS for everything), and there is no question that as an extension of the IDE, having everything available in one familiar place is a big bonus.&lt;/p&gt; &lt;p&gt;The main point I wanted to bring up here is an early issue we had with getting our private workspaces&lt;a style="text-decoration: none" href="#footnote"&gt;*&lt;/a&gt; and build server to have all the right files from the repository. We do not share an overall folder structure, and I don't like forcing developers to have their files in any one place on disk on their machine. I am just too much of a libertarian for that. &lt;/p&gt; &lt;p&gt;Because this project included a couple of frameworks, we decided to install those on every machine, and depend upon the GAC for references. However, we wanted to share a signing key, a shared AssemblyInfo file, a test run configuration file, team build types, along with multiple assemblies not included in the installed frameworks. &lt;/p&gt; &lt;p&gt;For the shared files we decided to use the solution items folder for the solution. In order for the items here to be source controlled, and therefore downloaded from the repository, they had to exist beneath the root workspace folder. We decided that we would mimick the folder structure exactly on disk as it was in the solution items folder. Specifically, we created solution items folders, and then created their counterparts in the root solution folder on disk. &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="82" src="http://www.atgi.com/pensieve_images/solutionItems.bmp" width="207" border="0"&gt; &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="73" src="http://www.atgi.com/pensieve_images/fileFolders.bmp" width="199" border="0"&gt; &lt;/p&gt; &lt;p&gt;Assemblies were placed in an Assemblies directory and other files in a Common folder (unfortunately, this is still one area where the SCM can still be flakey and occasionally get latest version doesn't seem to pull new solution items). &lt;/p&gt; &lt;p&gt;Now, in each project we referenced the assemblies in the solution items folder rather than locally. We also needed to put links for the common key and sharedassemblyinfo.cs into each project. In order to do this, each csproj file was hand edited with a new "Compile" element:&lt;/p&gt; &lt;p&gt;&amp;lt;Compile Include="..\Common\SharedAssemblyInfo.cs"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Link&amp;gt;Properties\SharedAssemblyInfo.cs&amp;lt;/Link&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Visible&amp;gt;true&amp;lt;/Visible&amp;gt;&lt;br&gt;&amp;lt;/Compile&amp;gt;&lt;/p&gt; &lt;p&gt;The Link sub-element tells the project where to display this file relative to the project root.&lt;/p&gt; &lt;p&gt;We added a "None" element for the key:&lt;/p&gt; &lt;p&gt;&amp;lt;None Include="..\Common\ourkey.snk" /&amp;gt;&lt;/p&gt; &lt;p&gt;Finally, in order for the .testrunconfig file to work, and to see the team build files&amp;nbsp;they had to be included in the solution via the context menu 'include existing item' - for some reason these&amp;nbsp;references did not come along with updated versions of the solution file.&lt;/p&gt; &lt;p&gt;With this all in place, every developer can reliably get latest and build without issue.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font size="1"&gt;&lt;a name="footnote"&gt;*&lt;/a&gt;I mean this in the sense of the Configuration Management pattern given by &lt;a href="http://www.amazon.com/Software-Configuration-Management-Patterns-Integration/dp/0201741172/ref=pd_bbs_sr_1/105-8037708-8539659?ie=UTF8&amp;amp;s=books&amp;amp;qid=1181069528&amp;amp;sr=8-1"&gt;Berczuk&lt;/a&gt; which I think is probably normative for most developers - do your dev in a private workspace where you control the versions of the components you are using and the version of the code you developing against. You control when and how your environment changes. This is basically done by downloading a complete environment from the repository to your local workstation.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-5430906211540379215?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/06/private-workspace-config-mgmt-wteam.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-4260007396379692834</guid><pubDate>Tue, 05 Jun 2007 15:37:00 +0000</pubDate><atom:updated>2007-06-05T11:38:34.724-04:00</atom:updated><title>Generic Mock Factory</title><description>&lt;p&gt;I've been involved in VS integration work lately, and within the &lt;a href="http://www.koders.com/info.aspx?c=ProjectInfo&amp;amp;pid=TAVG4DC2Z7Q8EN66MX9BXDEDVD" target="_blank"&gt;unit testing framework&lt;/a&gt; provided by the integration SDK is an excellent mock factory for any interface based type.&lt;/p&gt; &lt;p&gt;If you are involved in unit testing where you need mocks, this is an excellent generic resource for any project - not just VS integration.&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.koders.com/csharp/fid6001AB2A29AC1F15E2ABB5B3F79479E7CD8207B0.aspx" target="_blank"&gt;GenericMockFactory.cs&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-4260007396379692834?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/06/generic-mock-factory.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-117538393256947891</guid><pubDate>Sun, 01 Apr 2007 00:32:00 +0000</pubDate><atom:updated>2007-03-31T20:32:12.633-04:00</atom:updated><title>Windows Communication Foundation - SOA</title><description>&lt;p&gt;I have spent time this week learning about the &lt;a title="Windows Communication Foundation" href="http://msdn2.microsoft.com/en-us/netframework/aa663324.aspx"&gt;WCF&lt;/a&gt; and it's place in jumpstarting SOA based application development while attending the SDWest Expo in Santa Clara. &lt;a href="http://idesign.net/"&gt;Juval Löwy&lt;/a&gt; provided most of the presentations on WCF; along with a few by his chief architect &lt;a title="Michele Bustamante Blog" href="http://www.dasblonde.net/Default.aspx#a99893f64-8c26-4425-b3cf-9433c803b801"&gt;Michele Bustamante&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;One of the main points Juval made was that WCF based development is an evolutionary shift from Component Oriented development to Service Oriented development. During an excellent history lesson on the growth of software development methodologies he made the case that services are the next major shift because they improve upon the goals of component development. The WCF improves&amp;nbsp;primarily in decoupling: technology from the service provided; transaction and concurrency management;&amp;nbsp;security; reliability, versioning, and&amp;nbsp;communication protocols&amp;nbsp;from the business logic. Because the WCF provides this great level of decoupling Juval declared with a mischevious smile, that coding in the CLR is coding in the stone-age. The WCF has arrived, and everything you code should now be coded as a service.&lt;/p&gt; &lt;p&gt;While we can't take this declaration entirely seriously - Mrs. Bustamante is more balanced -it is a fact that&amp;nbsp;transaction support, protocol independence,&amp;nbsp;security, reliability, versioning, and concurrency&amp;nbsp;are provided for free by the WCF. Obviously all services decouple the technology and platform from the service provided - that's why the industry is in love with services - but the WCF adds so much more. &lt;/p&gt; &lt;p&gt;All this goodness is provided by implementation of the &lt;a title="WS-* Specifications" href="http://www.oasis-open.org/committees/tc_cat.php?cat=ws"&gt;WS-*&lt;/a&gt; specifications by the WCF. That really makes it so much better in my opinion because it means that transactions, security, etc. can pass from a WCF service to any &lt;a href="http://java.sun.com/webservices/interop/reference/tutorial/doc/index.html"&gt;other which also implements those standards&lt;/a&gt; (IBM was part of the spec group, so I am sure their products will follow suit soon). You have to take some time to think about what this means to the way you can build software - we may have to agree with Juval that a fundamental shift is underway. This isn't about WCF causing a fundamental shift, SOA causes the fundamental shift. It's the easy use of the full range of WS-* standards which makes the WCF such an attractive reason to start thinking services more often than you ever have before - even if not for absolutely everything as Juval suggests.&lt;/p&gt; &lt;p&gt;If you aren't familiar with the WCF, the basics are very simple. The new &lt;a href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.aspx"&gt;ServiceModel&lt;/a&gt; namespace includes an attribute&amp;nbsp;for &lt;a href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.servicecontractattribute.aspx"&gt;ServiceContract&lt;/a&gt;&amp;nbsp;which is placed on an interface, making that the contract for the&amp;nbsp;web service. Each operation within the web service interface&amp;nbsp;is attributed as &lt;a href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.operationcontractattribute.aspx"&gt;OperationContract&lt;/a&gt;, exposing these members of the interface on the service. Every class type exposed in an operation signature must be attributed with DataContract to mark it as serializable. Given these few attributes, your classes are ready and you just need a little configuration. If you remember .net Remoting, then I suggest you forget it, but this will at least be familiar to you. I won't go into here, you can check out WCF configuration &lt;a href="http://msdn2.microsoft.com/en-us/library/ms734663.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;If you are going to design more services, you have to take some things into account during design. I won't discuss the normal service design issues that exist in all services. However in&amp;nbsp;WCF programming a couple of things got my attention. For instance,&amp;nbsp;while you cannot expose an interface type as a contract operation variable, you can expose "&lt;a href="http://msdn2.microsoft.com/en-us/library/system.servicemodel.serviceknowntypeattribute.aspx"&gt;well known types&lt;/a&gt;" which will enforce an object hierarchy. This&amp;nbsp;will be&amp;nbsp;slightly different from the pure OO interface and class design you might have used, but preserves the basic idea.&lt;/p&gt; &lt;p&gt;Also, when it comes to passing state data an object DAL is enforced by classes attributed as &lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx"&gt;DataContract&lt;/a&gt;. This ensures serialization capabilities by the Framework. As a design consideration it simply means you have to have classes that hold simple data elements to pass across the service boundary. This isn't a bad thing, it just may be different than you would design for internal business objects. Mix with LINQ (in the near future) within your .net classes and&amp;nbsp;you'll probably have these pure data objects in your design&amp;nbsp;anyhow.&lt;/p&gt; &lt;p&gt;One final consideration concerning services everywhere is the issue of performance. Obviously, if you are going across the wire as SOAP/HTTP, you're&amp;nbsp;subject to the inefficient payload as well as the potential wire latency.&amp;nbsp;This is no different from any other service call. But,&amp;nbsp;with every service call there is a serialize/deserialize operation&amp;nbsp;for every object. I haven't tested this hit, but it will be something compared with the nothing of in-memory object passing.&amp;nbsp; So, if you are configured for SOAP/HTTP performance is already a potential&amp;nbsp;problem and you'll never notice the performance of any other part of the WCF infrastructure code. If you are going binary/TCP, then the test would be worth the double-check.&lt;/p&gt; &lt;p&gt;Finally, if you are implementing WCF the folks at iDesign have a whole bunch of &lt;a href="http://idesign.net/idesign/DesktopDefault.aspx?tabindex=5&amp;amp;tabid=11#WCF"&gt;helper classes and utilities&lt;/a&gt; you should check out.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-117538393256947891?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/03/windows-communication-foundation-soa.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-117260676646413263</guid><pubDate>Tue, 27 Feb 2007 20:06:00 +0000</pubDate><atom:updated>2007-06-05T11:09:31.131-04:00</atom:updated><title>Helpful C# Class File Template Change</title><description>&lt;p&gt;Something which has annoyed me several times in VS2005 is that new classes are internal by default. I almost never want an internal class, so I went looking for the option to change. I never did find it, but a colleague has just pointed out the solution:&lt;/p&gt;&lt;p&gt;All new files come from various files in %InstallDir%/Common7/IDE/ItemTemplates&lt;/p&gt;&lt;p&gt;Find Class.zip and modify the class.cs file in this archive. Be sure to delete or modify the contents of the ItemTemplatesCache folder while you are at it.&lt;/p&gt;&lt;p&gt;&lt;em&gt;*InstallDir is [Program Files/Microsoft Visual Studio 8] by default.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-117260676646413263?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2007/02/helpful-c-class-file-template-change.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-116621715528499355</guid><pubDate>Fri, 15 Dec 2006 21:12:00 +0000</pubDate><atom:updated>2006-12-15T16:12:35.510-05:00</atom:updated><title>Community Server Paged Permissions Grids</title><description>&lt;p&gt;The default implementation of &lt;a href="http://communityserver.org/"&gt;Community Server&lt;/a&gt; assumes you will have only a handful of roles. This caused me some problems when I added 700 new roles to configure specific admin/user permissions on 350 forums. All of the permissions grids in the control panel are not paged, and neither IE nor Firefox like loading the massive permissions grids into memory.&lt;/p&gt; &lt;p&gt;Thankfully, the answer is quite simple. In order to add paging to all permissions grids in the control panel, you simply make a couple of minor changes to the BasePermissionsGridControl.cs file.&lt;/p&gt; &lt;p&gt;At the bottom of the&amp;nbsp;buildGrid() method you'll see a comment concerning paging just after the call to ApplyUserSettings(). You can delete each line from that point forward since we now want paging.&lt;/p&gt; &lt;p&gt;Next, you need to add an override of ConfigureGrid and add the following single line to the method:&lt;/p&gt; &lt;p&gt;AddGridPagerTemplate("Name");&lt;/p&gt; &lt;p&gt;Finally, set the Grid.PageSize property to whatever size you like in the BasePage_Load method (or leave it alone and let the default take over).&lt;/p&gt; &lt;p&gt;Viola! All permissions grids are now paged in the Control Panel.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-116621715528499355?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2006/12/community-server-paged-permissions.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-116596227103089229</guid><pubDate>Tue, 12 Dec 2006 22:24:00 +0000</pubDate><atom:updated>2008-08-19T09:46:02.006-04:00</atom:updated><title>Exchange Distribution Lists and WebDAV</title><description>&lt;p&gt;&lt;a href="http://mschnlnine.vo.llnwd.net/d1/ch9/6/4/7/0/5/2/265699_ExchangeDavExample.zip"&gt;Download Sample Code&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I encountered an interesting side project recently where I wanted to retrieve information about distribution lists on a local Exchange Server from a web-based application.&lt;/p&gt; &lt;p&gt;I didn't want to use CDO/MAPI directly&amp;nbsp;for various reasons, so I looked into the WebDAV api available for querying Exchange via web requests. I found some helpful information &lt;a href="http://gsexdev.blogspot.com/"&gt;here&lt;/a&gt;, and was quickly able to produce a class to consume distribution list data for use in my app.&lt;/p&gt; &lt;p&gt;The basic query for retrieving all distribution lists from a particular folder (where folder is the RootURI below) is:&lt;/p&gt; &lt;p class="xml"&gt;&amp;lt;?xml version=\"1.0\"?&amp;gt;&lt;/p&gt; &lt;p class="xml"&gt;&amp;lt;D:searchrequest &lt;a href="http://xmlns:D"&gt;xmlns:D&lt;/a&gt; = "DAV:" &amp;gt;&lt;/p&gt; &lt;p class="xml"&gt;&amp;lt;D:sql&amp;gt;SELECT "urn:schemas:contacts:cn\", "urn:schemas:contacts:members\", "DAV:displayname" FROM&amp;nbsp;RootURI&amp;nbsp;WHERE "DAV:ishidden" = false AND "DAV:isfolder" = false AND "DAV:contentclass" = 'urn:content-classes:group'&amp;lt;/D:sql&amp;gt;&lt;/p&gt; &lt;p class="xml"&gt;&amp;lt;/D:searchrequest&amp;gt;&lt;/p&gt; &lt;p&gt;DAV content-classes are found via mappings from PR_MESSAGE_CLASS and PR_CONTAINER_CLASS properties. The schema references to specific properties in Exchange are derived from the Exchange Server schema. In the above example, we want the property &lt;a href="http://msdn2.microsoft.com/en-us/library/ms872426.aspx"&gt;cn&lt;/a&gt; from the urn:schemas:contacts namespace. The uri we query should contain contact items whose content-class is of type group. &lt;/p&gt; &lt;p&gt;Now, in order to figure out where all these properties live, and what you can expect can be challenging. You can start with the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms985512.aspx"&gt;properties reference by namespace on MSDN&lt;/a&gt;. These will tell you the content-class. Or, as I did here, you can use a tool like IndependentDav to get a look at what is returned from the server. I don't think the tool is necessary once you have a handle on where things come from, but it can difficult to track some things down because mappings between Exchange Store schema content-classes and DAV content-classes are not 1:1 and the properties reference gives the content-class of the Exchange Store schema. Finally, you can query the store at a uri without limiting the return values, and look through the query results manually.&lt;/p&gt; &lt;p&gt;Getting on with the distribution lists then, I created a helper class to make the requests and manage the two part process of first constructing a DistributionList class, then filling the members of the list with a seperate query.&amp;nbsp;I pass the streamed response from the query directly to the constructor of the DistributionList class. The code is long and cumbersome, so it's better to &lt;a href="http://channel9.msdn.com/Photos/ZippedFiles/265699_ExchangeDavExample.zip"&gt;just look at it in the sample.&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The list members are actually not found via webDAV directly, but a query to the OWA server services as &lt;a href="http://gsexdev.blogspot.com/2004/09/scripting-contact-folder-distribution.html"&gt;described here&lt;/a&gt;. I created a ListMemberList class to hold ListMember classes. The constructor on the list parses each member in the response, and set it as a property on the DistributionList class.&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;When its all said and done, I can use the management class to get the DL's from the configured server with very little overhead, and - best of all - no interop.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-116596227103089229?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2006/12/exchange-distribution-lists-and-webdav.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-116404313182858092</guid><pubDate>Mon, 20 Nov 2006 17:18:00 +0000</pubDate><atom:updated>2006-11-20T12:20:23.183-05:00</atom:updated><title>Enable Domain Account As App Pool Identity</title><description>&lt;p&gt;While the answers are around already, the simplified listing of&amp;nbsp;what to do when you create a user in your domain to run an IIS 6.0 application pool on Windows Server 2003 is:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Add the user to the IIS_WPG on the web application server.&lt;/li&gt; &lt;li&gt;Run aspnet_regiis with the -ga flag and the domain qualified user name (ie. MyDomain\TheUser). This gives the app pool user the ability to read and write from appropriate files, etc. I thought this would be accomplished by adding the user to the group above, but it didn't work until I had completed both of these steps.&lt;/li&gt; &lt;li&gt;Run setspn on the domain controller (you'll need to have the toolkit installed) with the protocol name 'HTTP' and application server&amp;nbsp;name (ie. HTTP/myAppServer) and a second argument for the domain qualified username (ie. MyDomain\TheUser). All together that is 'setspn HTTP/MyAppServer MyDomain\TheUser'. It is also recommended that you run the same command again, but with the fully qualified name of the app server.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Some security minded folks will tell you that you shouldn't actually do this anyhow, but if you must this set of instructions will allow you to use a user with minimum permissions. Just make sure this user is not used for anything else - thus limiting the potential the user will have an increasing permission set over time that no one can remember.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-116404313182858092?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2006/11/enable-domain-account-as-app-pool.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-115766507398586695</guid><pubDate>Thu, 07 Sep 2006 21:37:00 +0000</pubDate><atom:updated>2006-09-07T17:43:44.633-04:00</atom:updated><title>Using Sandcastle</title><description>&lt;p&gt;You Mean I Actually Have to Use &lt;a href="https://blogs.msdn.com/sandcastle"&gt;Sandcastle&lt;/a&gt;? Yes, with the death of NDoc, if you want to generate a chm based on triple-slash comments then you will probably need the help of Sandcastle. &lt;/p&gt;&lt;p&gt;It was nice of MS to release this thing - really. It would have been nicer if they would have sent a team to help NDoc, but let's not dwell on what could have been.&lt;/p&gt;&lt;p&gt;Using the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=e82ea71d-da89-42ee-a715-696e3a4873b2&amp;DisplayLang=en"&gt;August CTP&lt;/a&gt; I quickly found myself in hell. It was one thing to follow the &lt;a href="https://blogs.msdn.com/sandcastle/archive/2006/07/29/682398.aspx"&gt;directions for the sample&lt;/a&gt;. It was a whole other thing to actually build docs for my own projects. I created a bit of the hell for myself by trying to build docs in the directory structure of the project for which the docs are meant to be a part. I am sure I am not alone in this desire - it makes source control and packaging so much simpler.&lt;/p&gt;&lt;p&gt;I'll skip to the end and let you know that the results are quite nice - I am glad to have the docs. Everyone acknowledges the problems, and in fact there are some great helper articles referenced in the comments - &lt;a href="https://blogs.msdn.com/sandcastle/archive/2006/08/06/690260.aspx"&gt;mostly here&lt;/a&gt;. Heck, one guy even created a nice &lt;a href="http://www.codeproject.com/useritems/SandcastleCreateBat.asp"&gt;batch file and configuration doc builder.&lt;/a&gt; Unfortunately, it doesn't actually create usable batch file - at least not for me. It was faster to fix the batch I was working on than to debug his tool. That tool would be a great thing to spend some free cycles on and fix - but then look what happened to NDoc, so we can be sure that will never happen.&lt;/p&gt;&lt;p&gt;Another guy created a serious batch file &lt;a href="http://www.esnips.com/web/allanschyttMyOpenSource"&gt;here&lt;/a&gt; - again I couldn't make it work for me.&lt;/p&gt;&lt;p&gt;There are a few morals to this story:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;1) Batch files and esoteric config files without good docs are always hell to work with. Be prepared to dig in.&lt;/li&gt;&lt;li&gt;2) Just hard code all the folder/file references in the sandcastle.config to full paths. You can try to be all fancy, but this is just a CTP and there are more robust versions to come. Besides, it's just install locations and that isn't too bad (in fact, the config doc creator tool mentioned above actually does a nice job on this).&lt;/li&gt;&lt;li&gt;3) Create all the content folders (html,scripts,art,styles) directly below the batch so BuildAssembler doesn't get confused&lt;/li&gt;&lt;li&gt;4) A much discussed batch line from the examples where the results of one transform are piped into another XslTransform statement is total BS - it never worked until I split the line into another statement with results from the first. Not sure why someone felt they needed the pipe to begin with.&lt;/li&gt;&lt;li&gt;5) Don't try to name any help doc transform results to anything other than test.[hhc,hhp,hhk]. I don't know anything about the hhc API, but it sure doesn't like to work with anything other than test. Just rename the output, test.chm, to something else at the end of your batch file.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-115766507398586695?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2006/09/using-sandcastle.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-13720715.post-115679899296007258</guid><pubDate>Mon, 28 Aug 2006 21:03:00 +0000</pubDate><atom:updated>2006-08-29T12:37:06.136-04:00</atom:updated><title>Community Server Customization - Expanded Member Search Part 2</title><description>&lt;p&gt;In &lt;a href="http://gabe19.blogspot.com/2006/08/community-server-customization.html"&gt;part 1&lt;/a&gt; of this subject I explained the basics of how to change the skins and controls to allow a custom member&amp;nbsp;profile&amp;nbsp;field&amp;nbsp;to be searched from the user/Members.aspx page. In fact, &lt;a href="http://communityserver.org/blogs/dailynews/archive/2006/08/23/545424.aspx"&gt;according to CS' Daily News&lt;/a&gt;, perhaps I said too much about various files and controls&amp;nbsp;without giving an overview of what I was trying to accomplish. To summarize the intent:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Additional fields have been added to the user profile in the database. This required a change to the view cs_vw_Users_FullUser in order to expose the property. My example is silly, but sufficient - Eye Color is now a profile property.  &lt;li&gt;We want to search by Eye Color as a distinct user property on the Members list page. We modify the search control on this page to include a drop down with various eye colors on which to search.  &lt;li&gt;When the search control receives the request, it must pass the selected&amp;nbsp;eye color in a query string which will actually drive the database query values. In order to pass this value along to the , we added the property "EyeColor" to the UserQuery object.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;With this level of change there are a number of classes which must be modified. I suggest you try very hard to work with custom versions of the classes in order to avoid upgrade problems and a later inability to find the custom code you wrote. In&amp;nbsp;order to make this customization I have created the following classes in my custom assembly:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;UserSearch - extends CS.Controls.UserSearch and implements OnInit, SearchButton_Click, GetUsersAndBindControl, and AttachChildControls mainly as copies of the original. I only call the base in OnInit after initializing a local copy of _isAdmin.  &lt;li&gt;ExtendedUserQuery - extends CS.UserQuery and adds only the single property value I wish to store.  &lt;li&gt;CustomCommonSqlDataProvider - extends CS.Data.SqlCommonDataProvider and overrides only the GetUsers method, along with a constructor that simply passes&amp;nbsp;its parameter values to the base. Don't forget this will require a provider reference change in communityserver.config under the&amp;nbsp;providers node where the name = "CommonDataProvider".&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;One caveat here where I broke my "customize it" rule - you would need to create a custom ForumMembersView as well in order to call the GetUsersAndBindControl on your UserSearch control because this method is not virtual. I decided to live dangerously and changed the base class to make this method virtual - but you could take the high road.&lt;/p&gt; &lt;p&gt;Now, I described what I did in UserSearch &lt;a href="http://gabe19.blogspot.com/2006/08/community-server-customization.html"&gt;last time&lt;/a&gt;. The changes required in the common data provider will fill out the rest of the story. If the query passed into this method is of the type ExtendedUserQuery, then we will need to generate our own member query clause (if not, we can just pass the work onto the base).&amp;nbsp;The member query clause is&amp;nbsp;a generated sql clause executed by the stored procedure "cs_users_Get". This is a good thing because it will keep us from modifying the stored procedure. In the provided method this clause is generated by the static method BuildMemberQuery on the SqlGenerator class. We'll need to copy this entire class to our custom code, and change query parameter to accept an ExtendedUserQuery (you can't extend the class or get at&amp;nbsp;its oddly protected static helpers). &lt;/p&gt; &lt;p&gt;We want to add our modification to the where clause, so look for the comment "// ORDER BY CLAUSE" in this method as it indicates the end of the where clause creation section where we will insert our new predicate. The where clause will have at least one predicate already, so our clause will start with " AND". The profile properties are exposed in the view mentioned above, cs_vw_Users_FullUser which has been given the alias "P". Thus, our predicate format is:&lt;/p&gt; &lt;p&gt;&lt;em&gt;" AND P.EyeColor = '{0}'"&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Finally then our new sql generator code is:&lt;/p&gt; &lt;p&gt;&lt;em&gt;if(query.EyeColor != null)&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sb.AppendFormat(" AND P.EyeColor = '{0}'",query.EyeColor);&lt;br&gt;}&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Once you have done this, the rest of the code in the GetUsers method remains unchanged. Finally, you should copy&amp;nbsp;the static method cs_PopulateUserFromIDataReader into your provider too in order to put the custom values into the created User object before passing it back. However, it isn't necessary to get the user search results.&lt;/p&gt; &lt;p&gt;I said previously that it would be even better to make a more generic property search mechanism. In order to do that we change the ExtendedUserQuery to have a StringDictionary rather than an individual property. For the query string you can either ignore it and pass values via another mechanism such as user Session, or add a delimited set of strings to a Property Name value such as ppn=EyeColor.Height.Weight&amp;nbsp;and a&amp;nbsp;Property Value value such as ppv=Blue.74in.175. Then your sql generation code would just need to iterate the values and add predicates as necessary.&lt;/p&gt; &lt;p&gt;Even better would be an enhancement to CS that used a more flexible means of manipulating the query. I am biased, but I really like the &lt;a href="http://www.hydrussoftware.com/docs/DataSetToolkit.htm#Where_Constraints.htm"&gt;WhereConstraint&lt;/a&gt; idea in &lt;a href="http://www.hydrussoftware.com/Intro.aspx"&gt;Hydrus' DataSetToolkit&lt;/a&gt; technology.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13720715-115679899296007258?l=gabe19.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://gabe19.blogspot.com/2006/08/community-server-customization_28.html</link><author>noreply@blogger.com (gabe19)</author><thr:total>0</thr:total></item></channel></rss>

