<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>My view on C#</title>
	<atom:link href="http://ilmatte.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://ilmatte.wordpress.com</link>
	<description>Just another C# weblog</description>
	<lastBuildDate>Tue, 03 Jan 2012 10:12:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='ilmatte.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>My view on C#</title>
		<link>http://ilmatte.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://ilmatte.wordpress.com/osd.xml" title="My view on C#" />
	<atom:link rel='hub' href='http://ilmatte.wordpress.com/?pushpress=hub'/>
		<item>
		<title>AutoComplete.Net</title>
		<link>http://ilmatte.wordpress.com/2011/06/18/autocomplete-net/</link>
		<comments>http://ilmatte.wordpress.com/2011/06/18/autocomplete-net/#comments</comments>
		<pubDate>Sat, 18 Jun 2011 22:44:35 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Extension Methods]]></category>
		<category><![CDATA[Asp.Net]]></category>
		<category><![CDATA[Asp.Net MVC]]></category>
		<category><![CDATA[AutoComplete]]></category>
		<category><![CDATA[JQuery UI]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=476</guid>
		<description><![CDATA[Suggested Books 1. Why AutoComplete.Net? 2. Download 3. Asp.Net Documentation 3.1. AutoCompleteTextBox 3.2. Tutorial 4. Asp.Net MVC Documentation 4.1. Extension Methods 4.2. Tutorial 1. Why AutoComplete.Net? In this article I will introduce my CodePlex project: AutoComplete.Net. Such project is made up of a library containing an Asp.Net WebControl and a bunch of Asp.Net MVC HtmlHelper [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=476&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a title="autocompletetop" name="autocompletetop"></a><br />
Suggested Books</p>
<table>
<tbody>
<tr>
<td><a href="http://www.amazon.com/gp/product/0470643188?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0470643188"><img src="http://ilmatte.files.wordpress.com/2010/11/professionalaspnetmvc2.jpg?w=510" alt="" border="0" /></a><img style="border:none!important;margin:0!important;" src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0470643188" alt="" width="1" height="1" border="0" /></td>
<td><a href="http://www.amazon.com/gp/product/073562609X?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=073562609X"><img src="http://ilmatte.files.wordpress.com/2010/12/architectingapplications.jpg?w=510" alt=".Net Architecting Applications For The Enterprise" border="0" /></a><img style="border:none!important;margin:0!important;" src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=073562609X" alt="" width="1" height="1" border="0" /></td>
<td><a href="http://www.amazon.com/gp/product/0321127420?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0321127420"><img src="http://ilmatte.files.wordpress.com/2010/12/fowlerpeaasmall.jpg?w=510" alt="Patterns of  Enterprise Application Architecture" border="0" /></a><img style="border:none!important;margin:0!important;" src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0321127420" alt="" width="1" height="1" border="0" /></td>
<td><a href="http://www.amazon.com/gp/product/0201633612?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0201633612"><img src="http://ilmatte.files.wordpress.com/2010/12/gof.jpg?w=510" alt="Design Patterns" border="0" /></a><img style="border:none!important;margin:0!important;" src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0201633612" alt="" width="1" height="1" border="0" /></td>
</tr>
</tbody>
</table>
<p><a href="#why">1. Why AutoComplete.Net?</a><br />
<a href="#download">2. Download</a><br />
<a href="#aspnetdocumentation">3. Asp.Net Documentation</a><br />
<span style="position:relative;left:10px;"><a href="#aspnetwebcontrol">3.1. AutoCompleteTextBox</a></span><br />
<span style="position:relative;left:10px;"><a href="#aspnettutorial">3.2. Tutorial</a></span><br />
<a href="#aspnetmvcdocumentation">4. Asp.Net MVC Documentation</a><br />
<span style="position:relative;left:10px;"><a href="#aspnetmvcextensions">4.1. Extension Methods</a></span><br />
<span style="position:relative;left:10px;"><a href="#aspnetmvctutorial">4.2. Tutorial</a></span></p>
<h3><a title="why" name="why"></a><span style="color:#993300;font-size:small;">1. Why AutoComplete.Net?</span></h3>
<p>In this article I will introduce my CodePlex project: <strong>AutoComplete.Net</strong>.</p>
<p>Such project is made up of a library containing an Asp.Net <strong>WebControl</strong> and a bunch of Asp.Net MVC <strong>HtmlHelper</strong> extension methods.<br />
Their purpose is to provide .Net developers with an easy interface to the cool JQuery UI Autocomplete Widget.</p>
<p>I will describe separately the Asp.Net WebControl and the Asp.Net MVC extension methods. </p>
<p><a href="#autocompletetop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a title="download" name="howtogetit"></a><span style="color:#993300;font-size:small;">2. Download</span></h3>
<p>Download the latest version of AutoComplete.Net <a title="autocompletedotnet" href="http://autocompletedotnet.codeplex.com/" target="_blank">here</a>.<br />
You will get a zip package containing the binary and few other files.<br />
Unzip the release package wherever you want,<br />
e.g. under <span style="color:#808080;">C:\Program Files\AutoComplete.Net</span>.<br />
For most of the time you will need only the <strong>AutoComplete.dll</strong> but in the following paragraphs you will be instructed about when you will need the other files included in the release package.</p>
<p><a href="#download"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#autocompletetop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a title="aspnetdocumentation" name="aspnetdocumentation"></a><span style="color:#993300;font-size:small;">3. Asp.Net Documentation</span></h3>
<h4><a title="aspnetwebcontrol" name="aspnetwebcontrol"></a><span style="font-size:x-small;color:#993300;">3.1. AutoCompleteTextBox</span></h4>
<p>The <strong>AutoCompleteTextBox</strong> WebControl found in the <strong>AutoComplete.dll</strong> assembly exposes the following properties:</p>
<p><strong>MinCharsRequired</strong></p>
<p>Specifies the minimum number of characters to digit before the autocomplete is fired and the ajax request to the server is started.<br />
The default value is: 2, so you can ignore this property if you feel confortable with such value.</p>
<p><strong>JsonDataSourceUrl</strong></p>
<p>This is the most important property.<br />
Here you must specify an Uri identifying a resource returned in Json format.<br />
The value you will specify will represent the place to retrieve the source data from.<br />
Tipically you will provide the address of an Http Handler.<br />
This is a <strong>required</strong> property so you have to provide a valid url.<br />
You can safely use the ~ (tilde) character in the url provided.</p>
<p>Example:<br />
<span style="color:#808080;">JsonDataSourceUrl=&#8221;~/CountriesHandler.ashx&#8221;</span></p>
<p><strong>HttpMethod</strong></p>
<p>Specifies the method to be used for the http invocation.<br />
It will be used to instruct JQuery about how to send the underlying ajax invocation.<br />
The legal values are: GET and POST.<br />
If a value is not specified for this property it will default to GET.<br />
I suggest not to use the POST option because the autocomplete widget works invoking an ajax request at each key pressed.<br />
Such an high number of ajax post requests causes Internet Explorer to receive an error 12030 from the server.<br />
I planned to refine the behavior of the control to do some more work on the client, in order to workaround this problem. In the meanwhile GET is the option to go with and also the natural choice when invoking an Http Handler.</p>
<p><strong>LabelField</strong></p>
<p>Specifies the name of a property of the returned object type that will be used to fill the suggestions displaied in the list.<br />
If this property is not set, the value in the property: <strong>ValueField</strong> will be used as <strong>LabelField</strong> as well.</p>
<p><strong>ValueField</strong></p>
<p>Specifies the name of a property of the returned object type.<br />
Such property will be used to fill the textbox once one of the items in the suggestions list has been selected.<br />
If a LabelField property is not specified, this property&#8217;s value will be used as LabelField value in the autocomplete initialization.<br />
This is a <strong>required</strong> property.</p>
<p><strong>OnClientSelection</strong></p>
<p>If you need some more client side processing of the data related to the item selected you can use this property to specify the name of a javascript function.<br />
The javascript function specified will be invoked when an item in the list is selected.<br />
You must define the javascript function with the following signature:</p>
<p><pre class="brush: jscript;">
function OnClientSelectionHandler(selectedItem)
</pre></p>
<p>The argument passed to this function: &#8216;selectedItem&#8217; is a client side representation of the server side object instance corresponding to the selected item.<br />
In this way you can access all the properties (and then retrieve all available information) about the selected item.<br />
You can, for example, set a hidden field as in the following sample code: </p>
<p><pre class="brush: jscript; wrap-lines: false;">
 // set hidden field with the value corresponding to the selected item.
 function OnClientSelectionHandler(selectedItem) {
	 var codeHiddenField = '&lt;%=(FindControl(&quot;SelectedCountryHiddenField&quot;).ClientID)%&gt;';
	 $('#' + codeHiddenField).val(selectedItem.Code);
	 alert(&quot;Code value is: &quot; + $('#' + codeHiddenField).val());
 }
</pre></p>
<p><strong>OnClientError</strong></p>
<p>If you want to notify errors happened during the ajax request to the server, you can set this property to specify the name of a javascript function.<br />
The javascript function specified will be invoked when an error occurs during the ajax request.<br />
You must define the javascript function with the following signature:</p>
<p><pre class="brush: jscript; wrap-lines: false;">
function NotifyError(error)
</pre></p>
<p>The argument &#8216;error&#8217; passed to this function is a message describing the error happened.</p>
<p><strong>RegisterJQueryAndJQueryUI</strong></p>
<p>Instructs the control wether to emit script tags to include references to jquery.js and to jquery-ui.js.</p>
<p><pre class="brush: xml; wrap-lines: false;">
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jQuery-1.4.1.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jquery-ui.js&quot;&gt;&lt;/script&gt;
</pre></p>
<p>By setting this property to &#8220;true&#8221; or &#8220;false&#8221; you can decide if a reference to the jquery and jquery UI javascript libraries is required or they&#8217;re already declared in the page.<br />
The versions bundled with the WebControl are: jquery 1.4.4 and JQuery UI 1.8.7.<br />
The default value is false, so the control won&#8217;t work unless you drop it in a page containing the required references or you explicitly set the property as below:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
RegisterJQueryAndJQueryUI=&quot;true&quot; 
</pre></p>
<p><strong>RegisterDefaultStyleSheet</strong></p>
<p>Instructs the control wether to emit a link reference to the default stylesheet for the autocomplete dropdownlist.<br />
The reference will be emitted if this property is set to &#8220;true&#8221; and it will point to a .css file embedded as resource in the AutoComplete.dll assembly.<br />
The Stylesheet has been built with the Jquery UI ThemeRoller.<br />
If a JQuery UI full theme has already been added to the page, setting this property is not necessary.<br />
Worse it could override the style set at page level.<br />
Default value is true.</p>
<p>If you want to have a look at the style rules applied to the AutoComplete widget you can find, in the release package, the file: <span style="color:#808080;">jquery-ui.css</span> and have a look.</p>
<p>The style relative to the Autocomplete widget starts at row: 304:</p>
<p><pre class="brush: css; wrap-lines: false;">
.ui-autocomplete { position: absolute; cursor: default; font: normal 82.5% inherit; }
.ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }

/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
</pre></p>
<p>In the rule:<br />
<pre class="brush: css; wrap-lines: false;">
.ui-autocomplete 
{ 
  position: absolute; cursor: default; font: normal 82.5% inherit; 
}
</pre><br />
the font style has been added by me in order to have a default style for the item in the dropdownlist of suggestions.</p>
<p>The rule: <strong>&#8216;ui-autocomplete-loading&#8217;</strong> has been removed in the stylesheet produced by recent versions of the ThemeRoller because the ThemeRoller itself is not able to produce the required image too.<br />
I modified the stylesheet by restoring this rule, retrieved from a previous version (JQuery UI 1.8.2).<br />
I also added to the package the corresponding image, retrieved from the same version (1.8.2).</p>
<p>If you want to see the spinner image in the textbox you need to place it in a folder named: &#8216;images&#8217; in the root of the web application.<br />
If you want to place it elsewhere you need to modify the stylesheet rule with the desired file path and rebuild the WebControl.</p>
<p>If you want to customize the stylesheet without recompiling the control, just set the<br />
<strong>RegisterDefaultStyleSheet</strong> property to &#8220;false&#8221; and place the <span style="color:#808080;">jquery-ui.css</span> file you find in the release package wherever you want in the website directory structure, e.g.: <span style="color:#808080;">{root}\Style</span>.<br />
Then add to the head of the page the following snippet:</p>
<p><pre class="brush: xml; wrap-lines: false;">
&lt;link href=&quot;/Style/jquery-ui.css&quot;
	  rel=&quot;stylesheet&quot; 
	  type=&quot;text/css&quot; /&gt;
</pre></p>
<p>You can then modify the stylesheet as you like.</p>
<p><strong>NoResultsMessage</strong></p>
<p>If the letters you typed in the textbox led to no results, the textbox will still be empty and no suggestion list will popup.<br />
With this property you can provide an informational message, to be displaied in the autosuggest list in case the ajax request returns an empty resultset, as you can see in the image below:</p>
<p><img src="http://ilmatte.files.wordpress.com/2011/06/noresults.png?w=510" alt="NoResults Message" /></p>
<p>Obviously if the user selects the item in the suggestion list, nothing will happen: the TextBox will not be filled with the value and the <strong>OnClientSelection</strong> handler will not be invoked.</p>
<p><strong>ErrorMessage</strong></p>
<p>This property specifies the text to be displaied in the autosuggest list when an error occurs during the ajax request.<br />
Such property will be used to display an informational message in the suggestions list, in case of error.<br />
The behavior is the same as in the previous property.</p>
<p><a href="#aspnetdocumentation"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#autocompletetop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="aspnettutorial" name="aspnettutorial"></a><span style="font-size:x-small;color:#993300;">3.2. Tutorial</span></h4>
<p>Let&#8217;s see how to create an example application to test the <strong>AutoCompleteTextBox</strong> WebControl for Asp.Net.</p>
<p>First of all create a new Visual Studio Solution and add a new Asp.Net Web Application project.<br />
Download the latest version of AutoComplete.Net and unzip the release package wherever you want.<br />
Browse to the folder in which you unzipped the release package and locate the <span style="color:#808080;">AutoComplete.dll</span> assembly. Copy and paste it in the folder in which you want your Visual Studio Solution to find it.<br />
You can then place it in a folder common to all projects on the machine (it can be even the same: <span style="color:#808080;">C:\Program Files\AutoComplete.Net</span>) or in a folder specific to the current solution.<br />
I usually create a <strong>Libs</strong> folder in the root of the solution and show its contents in Visual Studio by adding a Solution Folder with the same name.</p>
<p>Add a reference to the assembly in your web application project.</p>
<p>Go to the ToolBox and select the Tab in which you want the <strong>AutoCompleteTextBox</strong> to appear (create a new tab if you want), then select:</p>
<p><strong>Tools &#8211;&gt; Choose ToolBox Items&#8230;</strong>, browse to find the <span style="color:#808080;">AutoComplete.dll</span> and confirm.</p>
<p>Now you&#8217;re ready to drag and drop the AutocCompleteTextBox control.<br />
Go to the Web page in which you want to add the control, e.g.: Default.aspx.<br />
Place the cursor in the exact position in which you want to drop it, go to the ToolBox window and double click the control.</p>
<p><img src="http://ilmatte.files.wordpress.com/2011/06/selectintoolbox.png?w=510" alt="Select control in toolbox" /></p>
<p>As you can see in the image above you will find the control registered at the top of the page:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%@ Register Assembly=&quot;AutoComplete&quot; Namespace=&quot;AutoComplete&quot; TagPrefix=&quot;IM&quot; %&gt;
</pre></p>
<p>and a control instance declared at the row where you placed the cursor:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;IM:AutoCompleteTextBox ID=&quot;AutoCompleteTextBox1&quot; runat=&quot;server&quot; 
                        JsonDataSourceUrl=&quot;&quot;
                        ValueField=&quot;&quot; /&gt;
</pre></p>
<p>Maybe you need some formatting to see it exactly as above and maybe you want to change the ID (by removing the &#8217;1&#8242; at the end for example!).</p>
<p>The control instance requires you to provide a value at least for the two properties you find explicitly set in the control declaration:  <strong>JsonDataSourceUrl</strong> and <strong>ValueField</strong></p>
<p>If you run the page as is, you will get the following exception:</p>
<p><span style="color:#808080;"><strong>Required property: JsonDataSourceUrl for: AutoCompleteTextBox1</strong><br />
<strong>A value must be provided for the specified property.</strong></span></p>
<p>You need to provide an url address to a resource returning a result in JSon format, as a value for the property: <strong>JsonDataSourceUrl</strong>.<br />
Below you will se a simple way to provide such a resource just to test the WebControl.<br />
You can add few simple classes to your web application (remember to add using statements as needed).</p>
<p>First add an <strong>IHttpHandler</strong> to your project, name it <strong>CountriesHandler</strong> and replace the <strong>ProcessRequest</strong> method with the following code:</p>
<p><pre class="brush: csharp; wrap-lines: false;">

public void ProcessRequest(HttpContext context)
{
	context.Response.ContentType = &quot;application/json&quot;;
	context.Response.ContentEncoding = Encoding.UTF8;
	string startsWith = context.Request[&quot;startsWith&quot;];

	CountriesRepository repository = new CountriesRepository();
	IEnumerable&lt;Country&gt; countries = repository.GetCountriesStartingWith(startsWith);

	JavaScriptSerializer serializer = new JavaScriptSerializer();
	context.Response.Write(serializer.Serialize(countries));
}
</pre></p>
<p>then add a new class named: <strong>Country</strong> defined as below:</p>
<p><pre class="brush: csharp; wrap-lines: false;">

public class Country : IEquatable&lt;Country&gt;
{
	public Country(RegionInfo region)
	{
		Name = region.EnglishName;
		Code = region.TwoLetterISORegionName;
	}

	public string Name { get; set; }

	public string Code { get; set; }

	#region IEquatable&lt;Country&gt; Members

	public bool Equals(Country other)
	{
		if (ReferenceEquals(other, null)) return false;
		return Code.Equals(other.Code) &amp;&amp; Name.Equals(other.Name);
	}

	#endregion

	public override int GetHashCode()
	{
		return Name.GetHashCode() ^ Code.GetHashCode();
	}
}
</pre></p>
<p>The <strong>IEquatable</strong> implementation and the <strong>GetHashCode</strong> override are needed to avoid duplicate countries in the lists.<br />
Then add another class: <strong>CountriesRepository</strong> defined as below:</p>
<p><pre class="brush: csharp; wrap-lines: false;">

public class CountriesRepository
{
	readonly IEnumerable&lt;Country&gt; countries;

	public CountriesRepository()
	{
		countries = (from culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures)
			  select new Country (new RegionInfo(culture.LCID)))
			  .Distinct&lt;Country&gt;()
			  .OrderBy(n =&gt; n.Name);
	}

	public IEnumerable&lt;Country&gt; GetCountriesStartingWith(string startsWith)
	{
		var result = from country in this.countries
			  where country.Name.StartsWith(startsWith, StringComparison.InvariantCultureIgnoreCase)
			  select country;
		return result;
	}
}
</pre></p>
<p>Now you can set the first property as follows:<br />
<strong>JsonDataSourceUrl=&#8221;~/CountriesHandler.ashx&#8221;</strong></p>
<p>If you run  your application you still get an exception because the <strong>ValueField</strong> property is required too:</p>
<p><span style="color:#808080;"><strong>Required property: ValueField for: AutoCompleteTextBox1</strong><br />
<strong>A value must be provided for the specified property.</strong></span></p>
<p>By setting such property you tell the control wich property of the object returned will be used to fill the autosuggest list.<br />
Set the property as below:</p>
<p><strong>ValueField=&#8221;Name&#8221;</strong></p>
<p>Now the control is configured correctly and the page will load but you will get an alert, warning you that you forgot to add a reference to the JQuery library:</p>
<p><img src="http://ilmatte.files.wordpress.com/2011/06/jqueryalert.png?w=510" alt="Jquery not loaded alert" /></p>
<p>Now you have to made a choice: you can tell the WebControl to provide by itself a reference to the required javascript libraries (Jquery and JQueryUI) or to rely on the page in which it&#8217;s contained to include references to the right javascript libraries.</p>
<p>If you want to use the control in a page in which you already use JQuery for other purposes you will have your reference right in place in the head of the page:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">

&lt;head runat=&quot;server&quot;&gt;
    &lt;title&gt;&lt;/title&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jQuery-1.4.1.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jquery-ui.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
</pre></p>
<p>If this is not the case you can simply set another property of <strong>AutoCompleteTextBox</strong>:</p>
<p><strong>RegisterJQueryAndJQueryUI=&#8221;true&#8221;</strong></p>
<p>You&#8217;re ready to use your Page.<br />
Just type &#8216;in&#8217; in the textbox and you will get a list of country names starting with &#8216;in&#8217;.<br />
If you type few random letters, say: &#8216;ee&#8217; you won&#8217;t see any result.<br />
If you prefer to be prompted with a message you can set the following property:</p>
<p><strong>NoResultsMessage = &#8220;No results&#8221;</strong></p>
<p>Still you miss a pretty aesthetic functionality: you can have a loading image spinning inside the textbox while waiting that the information is retrieved.<br />
The WebControl already looks for such image. You only need to provide it in a path in which the control can find it.<br />
In the folder in which you unzipped the release package you can find the file:</p>
<p><span style="color:#808080;">ui-anim_basic_16x16.gif</span></p>
<p>In your Visual Studio Solution add a folder named: <span style="color:#808080;">Images</span> to the web application root folder and place the gif file inside it. That&#8217;s it!<br />
Reload the page, type <span style="color:#808080;">&#8216;un&#8217;</span> and you will see the spinner for a while before the results are presented.</p>
<p>If you want to place the spinner image elsewhere, for instance if you already have an images folder but with a different name, you can modify the default stylesheet as explained in the paragraph: <strong>RegisterDefaultStyleSheet</strong>.</p>
<p>You must download the source of the project, open the stylesheet <span style="color:#808080;">jquery-ui.css</span>, go to row: 305:</p>
<p><pre class="brush: css; wrap-lines: false;">
.ui-autocomplete-loading 
{ 
   background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; 
}
</pre></p>
<p>and replace the relative path in the url with the path you want.</p>
<p>If you want to customize the stylesheet without recompiling the control, just set the<br />
<strong>RegisterDefaultStyleSheet</strong> property to &#8220;false&#8221; and place the <span style="color:#808080;">jquery-ui.css</span> file you find in the release package wherever you want in the website directory structure, e.g.: <span style="color:#808080;">{root}\Style</span>.<br />
Then add to the head of the page the following snippet:</p>
<p><pre class="brush: xml; wrap-lines: false;">
&lt;link href=&quot;/Style/jquery-ui.css&quot;
	  rel=&quot;stylesheet&quot; 
	  type=&quot;text/css&quot; /&gt;
</pre></p>
<p>You can then modify the stylesheet as before.</p>
<p>By default the WebControl adds a reference to the default autocomplete stylesheet <span style="color:#808080;">jquery-ui.css</span> we saw above.<br />
The stylesheet has been built with the Jquery UI ThemeRoller.<br />
If a theme has already been added to the page, the WebControl&#8217;s default theme is not necessary and could override the style defined in the page.<br />
In this case you should disable the default stylesheet by setting the following property as below:</p>
<p><strong>RegisterDefaultStyleSheet=&#8221;false&#8221;</strong></p>
<p>After the user selects the chosen item in the list of suggestions, you can do whatever you want with all the data available about the selected item.<br />
In this case you have <span style="color:#808080;">&#8216;Code&#8217;</span> and <span style="color:#808080;">&#8216;Name&#8217;</span> of the selected <strong>Country</strong>.<br />
Say you want to save the <span style="color:#808080;">&#8216;Code&#8217;</span> in a hiddenfield in order to send it to the server during the next submit/postback.<br />
You can write your own javascript function and the <strong>AutoCompleteTextBox</strong> will provide the function with the information about the selected country.<br />
Just set the following property:</p>
<p><strong>OnClientSelection=&#8221;SaveCodeForLaterUse&#8221;</strong></p>
<p>add the following hidden field inside the form tag:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;asp:HiddenField ID=&quot;SelectedCountryHiddenField&quot; runat=&quot;server&quot; /&gt;
</pre></p>
<p>and add the following block of javascript immediately after the opening tag of the form element of the page:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">

&lt;script type=&quot;text/javascript&quot;&gt;
//&lt;![CDATA[

// set hidden field with the value corresponding to the selected item.
function SaveCodeForLaterUse(selectedItem) {
    var codeHiddenField = '&lt;%=(FindControl(&quot;SelectedCountryHiddenField&quot;).ClientID)%&gt;';
    $('#' + codeHiddenField).val(selectedItem.Code);
    alert(&quot;Code value is: &quot; + $('#' + codeHiddenField).val());
}

//]]&gt;
&lt;/script&gt;
</pre></p>
<p>The argument passed to the javascript function (<span style="color:#808080;">selectedItem</span>) represents an instance of a <strong>Country</strong> object and exposes the same properties as its server side counterpart: <strong>Name</strong> and <strong>Code</strong>.</p>
<p>The full declaration now is:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;IM:AutoCompleteTextBox ID=&quot;CountriesAutoCompleteTextBox&quot; runat=&quot;server&quot; 
			JsonDataSourceUrl=&quot;~/CountriesHandler.ashx&quot;
			ValueField=&quot;Name&quot; 
			RegisterJQueryAndJQueryUI=&quot;true&quot; 
			NoResultsMessage = &quot;No results&quot;
			OnClientSelection=&quot;SaveCodeForLaterUse&quot; /&gt;
</pre></p>
<p><strong>Note</strong>:<br />
If you place the above script in the head section, the control (and the page as well) won&#8217;t be able to manipulate the head anymore because the page header is readonly when there are codeblocks inside it.<br />
The control needs to manipulate the header to add the default stylesheet.<br />
If you don&#8217;t mind about it or if you are willing to add the stylesheet by yourself you can safely place your script in the page head section.<br />
If you won&#8217;t use code blocks in your javascript function you can place the script in the page header as well.</p>
<p><a href="#aspnettutorial"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#autocompletetop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a title="aspnetmvcdocumentation" name="aspnetmvcdocumentation"></a><span style="color:#993300;font-size:small;">4. Asp.Net MVC Documentation</span></h3>
<h4><a title="aspnetmvcextensions" name="aspnetmvcextensions"></a><span style="font-size:x-small;color:#993300;">4.1. Extension Methods</span></h4>
<p>WORK IN PROGRESS</p>
<p><a href="#aspnetmvcextensions"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#autocompletetop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="aspnetmvctutorial" name="aspnetmvctutorial"></a><span style="font-size:x-small;color:#993300;">4.2. Tutorial</span></h4>
<p>Let&#8217;s see how to create an example application to test the <strong>Asp.Net Mvc AutoComplete Extensions</strong>.</p>
<p>First of all create a new Visual Studio Solution and add a new Asp.Net Mvc Web Application project.</p>
<p>Download the latest version of AutoComplete.Net and unzip the release package wherever you want.<br />
Browse to the folder in which you unzipped the release package and locate the <span style="color:#808080;">AutoComplete.dll</span> assembly. Copy and paste it in the folder in which you want your Visual Studio Solution to find it.<br />
You can then place it in a folder common to all projects on the machine (it can be even the same: <span style="color:#808080;">C:\Program Files\AutoComplete.Net</span>) or in a folder specific to the current solution.<br />
I usually create a <strong>Libs</strong> folder in the root of the solution and show its contents in Visual Studio by adding a Solution Folder with the same name.</p>
<p>Add a reference to the assembly in your Asp.net Mvc Web Application project.</p>
<p>First of all make some room in our new project: delete the controllers and model classes created by the project template:</p>
<p><strong>AccountController.cs</strong> and <strong>HomeController.cs</strong> under the folder: <strong>Controllers</strong><br />
<strong>AccountModels.cs</strong> under the folder: <strong>Models</strong><br />
folders: <strong>Account</strong> and <strong>Home</strong> under the folder: <strong>Views</strong><br />
Remove the content of the <strong>Shared</strong> folder under the folder: <strong>Views</strong></p>
<p>Create a folder named: <strong>Countries</strong> under the folder: <strong>Views</strong>, right click it and choose: <strong>Add&#8230; &#8211;&gt; View</strong>.<br />
Name it: <strong>Search</strong> and uncheck: <span style="color:#808080;">&#8216;Select master page&#8217;</span>.</p>
<p>A new page: <strong>Search.aspx</strong> will open.<br />
Now you can add the markup for the AutoComplete control inside the main div of the page (together with a label):</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">

&lt;label for=&quot;country&quot;&gt;Country:&lt;/label&gt;

&lt;%= Html.AutoCompleteTextBox(&quot;country&quot;, 
			     new Uri(&quot;/Countries/SearchByFirstLetters&quot;, UriKind.RelativeOrAbsolute), 
			     &quot;Name&quot;) %&gt;
</pre></p>
<p>Visual Studio will warn you that it cannot find the <strong>AutoCompleteTextBox</strong> extension method.<br />
You need to instruct it about the namespace.<br />
You can do it once for all in the web.config of the application:<br />
Just open it and add:</p>
<p><pre class="brush: xml;">
&lt;add namespace=&quot;AutoComplete&quot;/&gt;
</pre></p>
<p>to the namespaces in the tag:</p>
<p><pre class="brush: xml;">
&lt;system.web&gt;
    &lt;pages&gt;
        &lt;namespaces&gt;
</pre></p>
<p>or you can do it page by page using the import directive at the top of the page:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%@ Import Namespace=&quot;AutoComplete&quot; %&gt;
</pre></p>
<p>In each case just rebuild the project and the Visual Studio error message will disappear.</p>
<p>The first argument we passed to the <strong>AutoCompleteTextBox</strong> extension method (&#8220;country&#8221;) will be the id of the html input field.<br />
The second argument is the uri of the resource that will be invoked and the third argument is the name of the property to be used, of the objects returned by the uri resource, to populate the suggestions list.</p>
<p>The uri: <span style="color:#808080;">&#8220;/Countries/SearchByFirstLetters&#8221;</span> invoked in an Asp.Net MVC Web Application with the default routes in place will cause a controller named: <strong>CountriesController</strong> to  be searched for.<br />
Let&#8217;s add such a controller in the folder <strong>Controllers</strong>.<br />
Let&#8217;s add to the controller the method that will be invoked when our view is loaded.<br />
The method, by convention, will be called: <strong>Search</strong> and we will replaced it to the method: <strong>Index</strong> created by the controller template.<br />
Here is the first method of our newly created controller:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
//
// GET: /Countries/Search/

public ActionResult Search()
{
	return View();
}
</pre></p>
<p>if you now type the url: <span style="color:#808080;">Countries/Search</span> you will get the following javascript alert:</p>
<p><img src="http://ilmatte.files.wordpress.com/2011/06/autocompletealert.png?w=510" alt="Autocomplete missing Message" /></p>
<p>In fact we still didn&#8217;t add the required javascript references in the head of the page.<br />
We need a reference to JQuery, a reference to JQueryUI and a reference to the IM.AutoComplete.js javascript library.<br />
Go to the folder in which you unzipped the release package and locate the following files:<br />
<span style="color:#808080;">jquery-ui.js</span><br />
<span style="color:#808080;">IM.AutoComplete.js</span></p>
<p>Copy and paste the 2 files in the <strong>Scripts</strong> folder of your project and add the following references to the head of the <strong>Search.aspx</strong> view:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jQuery-1.4.1.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jquery-ui.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/IM.AutoComplete.js&quot;&gt;&lt;/script&gt;
</pre></p>
<p>Still the autocomplete functionality won&#8217;t work unless we add to the controller a <strong>SearchByFirstLetters</strong> method returning a <strong>JsonResult</strong>, representing the required resource.<br />
Below you will see a simple way to provide such a resource just to test the Extension method.<br />
You need to add a couple of simple classes to your Asp.Net Mvc Web Application.<br />
First add a method named <strong>SearchByFirstLetters</strong> to your controller:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
public ActionResult SearchByFirstLetters(string startsWith)
{
	if (!Request.IsAjaxRequest())
	{
		return Content(string.Empty);
	}

	CountriesRepository repository = new CountriesRepository();
	IEnumerable&lt;Country&gt; countries = repository.GetCountriesStartingWith(startsWith);
	return Json(countries.ToList(), JsonRequestBehavior.AllowGet);
}
</pre></p>
<p><strong>Note</strong>:<br />
we&#8217;re allowing the <strong>SearchByFirstLetters</strong> method to be invoked by e GET request because<br />
internet explorer randomly causes HTTP errors when sending too many post requests to a server.</p>
<p>Now add the following two classes to the: <strong>Models</strong> folder.</p>
<p><pre class="brush: csharp; wrap-lines: false;">
public class Country : IEquatable&lt;Country&gt;
{
	/// &lt;summary&gt;
	/// Needed by Asp.Net Mvc framework.
	/// &lt;/summary&gt;
	public Country()
	{

	}
	
	public Country(RegionInfo region)
	{
		Name = region.EnglishName;
		Code = region.TwoLetterISORegionName;
	}

	public string Name { get; set; }

	public string Code { get; set; }

	#region IEquatable&lt;Country&gt; Members

	public bool Equals(Country other)
	{
		if (ReferenceEquals(other, null)) return false;
		return Code.Equals(other.Code) &amp;&amp; Name.Equals(other.Name);
	}

	#endregion

	public override int GetHashCode()
	{
		return Name.GetHashCode() ^ Code.GetHashCode();
	}
}
</pre></p>
<p>The <strong>IEquatable</strong> implementation and the <strong>GetHashCode</strong> override are needed to avoid duplicate countries in the lists.<br />
Then add another class: <strong>CountriesRepository</strong> defined as below:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
public class CountriesRepository
{
	readonly IEnumerable&lt;Country&gt; countries;

	public CountriesRepository()
	{
		countries = (from culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures)
			    select new Country (new RegionInfo(culture.LCID)))
			    .Distinct&lt;Country&gt;()
			    .OrderBy(n =&gt; n.Name);
	}

	public IEnumerable&lt;Country&gt; GetCountriesStartingWith(string startsWith)
	{
		var result = from country in this.countries
			    where country.Name.StartsWith(startsWith, StringComparison.InvariantCultureIgnoreCase)
			    select country;
		return result;
	}
}
</pre></p>
<p>Now you can run the web site and type the url: <span style="color:#808080;">Countries/Search</span>.<br />
You will get the page and can type the first 2 letters of a country to get suggestions.</p>
<p>Still the suggestions list is not very stylish. We forgot to add our default style sheet that was generated with the Jquery UI ThemeRoller (if you read the Asp.Net tutorial you know that the AutoCompleteTextBox WebControl added the reference by itself).<br />
Go to the folder in which you unzipped the release package and locate the file:<br />
<strong>jquery-ui.css</strong></p>
<p>Copy and paste it in the <strong>Content</strong> folder of your project and add the following reference to the head of the <strong>Search.aspx</strong> view:</p>
<p><pre class="brush: xml; wrap-lines: false;">
&lt;link href=&quot;/Content/jquery-ui.css&quot;
	  rel=&quot;stylesheet&quot; 
	  type=&quot;text/css&quot; /&gt;
</pre></p>
<p>If a theme has already been added to the page, this default theme is not necessary and could accidentally override the style defined in the page. </p>
<p>You can also have a loading image spinning inside the textbox while waiting for the information to be retrieved.<br />
In the release package you can find the file:</p>
<p><strong>ui-anim_basic_16x16.gif</strong></p>
<p>In your Visual Studio Solution add a folder named: <strong>Images</strong> under the <strong>Content</strong> folder and place the gif inside it.<br />
That&#8217;s it!<br />
Reload the page, type &#8216;un&#8217; and you will see the spinner for a while before the results are presented.</p>
<p>If you want to place the spinner image elsewhere, for instance if you already have an images folder but with a different name, you can modify the default stylesheet as explained in the ASP.NET WebControl section at the paragraph: <strong>RegisterDefaultStyleSheet</strong>.</p>
<p>You must modify the stylesheet file found in the release package: <span style="color:#808080;">jquery-ui.css</span>. Open the file and go to row: 305:</p>
<p><pre class="brush: css; wrap-lines: false;">
.ui-autocomplete-loading 
{ 
   background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; 
}
</pre></p>
<p>then replace the relative path in the url with the path you want.</p>
<p>There&#8217;s plenty of overloads to the <strong>AutoCompleteTextBox</strong> extension method we used but there&#8217;s another and more notable series of extension methods: the strongly typed ones, named: <strong>AutoCompleteTextBoxFor</strong>.</p>
<p>Let&#8217;s add another View under the <strong>Countries</strong> folder and call it: <strong>StronglyTypedSearch</strong>,<br />
check the <em>&#8216;Create a strongly-typed view&#8217;</em> checkbox and select:<br />
<strong>AspNetMvcAutoComplete.Models.Country</strong> as <em>&#8216;View data class&#8217;</em>,<br />
select the <em>&#8216;Edit&#8217;</em> <em>&#8216;View content&#8217;</em> and<br />
uncheck the <i>&#8216;Select master page&#8217;</i> checkbox.</p>
<p>Remove the fields related to the <strong>Code</strong> property and the Actionlink at the bottom of the page.<br />
Replace:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%= Html.TextBoxFor(model =&gt; model.Name) %&gt;
</pre></p>
<p>with:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%= Html.AutoCompleteTextBoxFor(model =&gt; model.Name, 
				new Uri(&quot;/Countries/SearchByFirstLetters&quot;, UriKind.RelativeOrAbsolute)) %&gt;
</pre></p>
<p>and place the label in the same div as the textbox.<br />
Add to the head of the page the same references as in the Search.aspx view:</p>
<p><pre class="brush: xml; wrap-lines: false;">
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jQuery-1.4.1.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jquery-ui.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/IM.AutoComplete.js&quot;&gt;&lt;/script&gt;
&lt;link href=&quot;/Content/jquery-ui.css&quot;
	  rel=&quot;stylesheet&quot; 
	  type=&quot;text/css&quot; /&gt;
</pre></p>
<p>The page will now look like the following:</p>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%@ Page Language=&quot;C#&quot; Inherits=&quot;System.Web.Mvc.ViewPage&lt;AspNetMvcAutoComplete.Models.Country&gt;&quot; %&gt;

&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; &gt;
&lt;head runat=&quot;server&quot;&gt;
    &lt;title&gt;StronglyTypedSearch&lt;/title&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jQuery-1.4.1.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/jquery-ui.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;/Scripts/IM.AutoComplete.js&quot;&gt;&lt;/script&gt;
    &lt;link href=&quot;/Content/jquery-ui.css&quot;
          rel=&quot;stylesheet&quot; 
          type=&quot;text/css&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;% using (Html.BeginForm()) {%&gt;
	&lt;%= Html.ValidationSummary(true) %&gt;
	
	&lt;fieldset&gt;
		&lt;legend&gt;Fields&lt;/legend&gt;
		
		&lt;div&gt;
			&lt;%= Html.LabelFor(model =&gt; model.Name) %&gt;            
			&lt;%= Html.AutoCompleteTextBoxFor(model =&gt; model.Name, 
							new Uri(&quot;/Countries/SearchByFirstLetters&quot;, UriKind.RelativeOrAbsolute)) %&gt;                
			&lt;%= Html.ValidationMessageFor(model =&gt; model.Name) %&gt;
		&lt;/div&gt;
		
		&lt;p&gt;
			&lt;input type=&quot;submit&quot; value=&quot;Save&quot; /&gt;
		&lt;/p&gt;
	&lt;/fieldset&gt;

&lt;% } %&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre></p>
<p>Add the <strong>DisplayNameAttribute</strong> to the <strong>Name</strong> property of the <strong>Country</strong> class if you want a meaningful label, e.g.:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
[DisplayNameAttribute(&quot;Country:&quot;)] 
public string Name { get; set; }
</pre></p>
<p>Add a method named <strong>StronglyTypedSearch</strong> to the controller (<strong>CountriesController</strong>):</p>
<p><pre class="brush: csharp; wrap-lines: false;">
public ActionResult StronglyTypedSearch()
{
	return View();
}
</pre></p>
<p>so that it will be invoked when typing the url: <i>&#8216;Countries/StronglyTypedSearch&#8217;</i>.</p>
<p>If you add the following method to the controller, to manage the submit of the page, you will be able to debug and see the selected value sent back to the server:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult StronglyTypedSearch(Country country)
{
	return View(country);
}
</pre></p>
<p>Now just run the website and type the above url.<br />
Type few letters in the textbox and select a country.<br />
Place a breakpoint in the method above and hit the save button.<br />
You can now watch the argument passed to the method and notice that the <strong>Name</strong> property is correctly set based on your selection.</p>
<p>You can download the full sample code: <strong>AutoCompleteNetExamples Source Code</strong> at the <a title="autocompletedotnet" href="http://autocompletedotnet.codeplex.com/" target="_blank">project home page</a>.</p>
<p><a href="#aspnetmvctutorial"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#autocompletetop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/476/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/476/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/476/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/476/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/476/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/476/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/476/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/476/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=476&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2011/06/18/autocomplete-net/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2010/11/professionalaspnetmvc2.jpg" medium="image" />

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0470643188" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/architectingapplications.jpg" medium="image">
			<media:title type="html">.Net Architecting Applications For The Enterprise</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=073562609X" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/fowlerpeaasmall.jpg" medium="image">
			<media:title type="html">Patterns of  Enterprise Application Architecture</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0321127420" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/gof.jpg" medium="image">
			<media:title type="html">Design Patterns</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0201633612" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2011/06/noresults.png" medium="image">
			<media:title type="html">NoResults Message</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2011/06/selectintoolbox.png" medium="image">
			<media:title type="html">Select control in toolbox</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2011/06/jqueryalert.png" medium="image">
			<media:title type="html">Jquery not loaded alert</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2011/06/autocompletealert.png" medium="image">
			<media:title type="html">Autocomplete missing Message</media:title>
		</media:content>
	</item>
		<item>
		<title>ASP.NET MVC: Panel HtmlHelper extension methods with using syntax</title>
		<link>http://ilmatte.wordpress.com/2010/11/16/asp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax/</link>
		<comments>http://ilmatte.wordpress.com/2010/11/16/asp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax/#comments</comments>
		<pubDate>Mon, 15 Nov 2010 23:28:48 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Extension Methods]]></category>
		<category><![CDATA[ASP.NET MVC Panel]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=319</guid>
		<description><![CDATA[Suggested Books 1. Introduction 2. Description 2.1. Implementation 2.2. Strongly Typed Extension Methods 3. Full Code 3.1. PanelExtensions 3.2. MvcPanel 3.3. TestView 3.4. StronglyTypedView 3.5. ViewModel 3.6. Controller 1. Introduction In this article I will describe, step by step, my implementation of a simple Panel widget to be used in ASP.NET MVC web applications. The [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=319&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a title="mvcpaneltop" name="mvcpaneltop"></a></p>
<fieldset>
<legend>Suggested Books</legend>
<table>
<tbody>
<tr>
<td><a href="http://www.amazon.com/gp/product/0470643188?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0470643188"><img src="http://ilmatte.files.wordpress.com/2010/11/professionalaspnetmvc2.jpg?w=510" border="0" alt="" /></a><img style="border:none!important;margin:0!important;" src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0470643188" border="0" alt="" width="1" height="1" /></td>
<td><a href="http://www.amazon.com/gp/product/073562609X?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=073562609X"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/architectingapplications.jpg?w=510" alt=".Net Architecting Applications For The Enterprise"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=073562609X" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" /></td>
<td>
<a href="http://www.amazon.com/gp/product/0321127420?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0321127420"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/fowlerpeaasmall.jpg?w=510" alt="Patterns of  Enterprise Application Architecture"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0321127420" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" />
</td>
<td>
<a href="http://www.amazon.com/gp/product/0201633612?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0201633612"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/gof.jpg?w=510" alt="Design Patterns"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0201633612" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" />
</td>
</tr>
</tbody>
</table>
</fieldset>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2filmatte.wordpress.com%2f2010%2f11%2f16%2fasp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%253a%252f%252filmatte.wordpress.com%252f2010%252f11%252f16%252fasp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax%252f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<p><a href="#mvcpanelintroduction">1. Introduction</a><br />
<a href="#mvcpanelimplementation">2. Description</a><br />
<span style="position:relative;left:10px;"><a href="#mvcimplementation">2.1. Implementation</a></span><br />
<span style="position:relative;left:10px;"><a href="#mvcstronglytyped">2.2. Strongly Typed Extension Methods</a></span><br />
<a href="#mvcpanelfullcode">3. Full Code</a><br />
<span style="position:relative;left:10px;"><a href="#mvcpanelextensions">3.1. PanelExtensions</a></span><br />
<span style="position:relative;left:10px;"><a href="#mvcpanelcode">3.2. MvcPanel</a></span><br />
<span style="position:relative;left:10px;"><a href="#testviewcode">3.3. TestView</a></span><br />
<span style="position:relative;left:10px;"><a href="#stronglytypedviewcode">3.4. StronglyTypedView</a></span><br />
<span style="position:relative;left:10px;"><a href="#viewmodelcode">3.5. ViewModel</a></span><br />
<span style="position:relative;left:10px;"><a href="#controllercode">3.6. Controller</a></span></p>
<h3><a title="mvcpaneltop" name="mvcpaneltop"></a><span style="color:#993300;font-size:small;">1. Introduction</span></h3>
<p>In this article I will describe, step by step, my implementation of a simple Panel widget to be used in ASP.NET MVC web applications.</p>
<p>The goal is to be able to wrap some markup in a content area with a describing title at the top.</p>
<p>The usual way to wrap logically related content when writing Html is to encapsulate it in a <strong>&lt;div&gt;</strong> tag, so my Panel will be little more than this.</p>
<p>I will try to underline the few main concepts I used in my implementation so that anyone could implement a similar helper method.</p>
<p><a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a title="mvcpanelimplementation" name="mvcpanelimplementation"></a><span style="color:#993300;font-size:small;">2. Description</span></h3>
<ul>
<li><a href="#mvcimplementation">2.1. Implementation</a></li>
<li><a href="#mvcstronglytyped">2.2. Strongly Typed Extensions Methods</a></li>
</ul>
<h4><a title="mvcimplementation" name="mvcimplementation"></a><span style="font-size:x-small;color:#993300;">2.1. Implementation</span></h4>
<p>I liked very much the smart use the ASP.NET MVC team made of <strong>IDisposable</strong> to support the using syntax in the BeginForm() helper method.</p>
<p>So I downloaded and browsed the source code trying to understand how the whole thing works.</p>
<p>I found the following two classes:</p>
<p><span style="color:#808080;">mvc3\src\SystemWebMvc\Mvc\Html\FormExtensions.cs</span></p>
<p><span style="color:#808080;">mvc3\src\SystemWebMvc\Mvc\Html\McvForm.cs</span></p>
<p>The <strong>FormExtensions</strong> class provides two extension methods:</p>
<p><strong>Html.BeginForm()</strong> (with a bunch of overloads) and</p>
<p><strong>Html.EndForm()</strong></p>
<p>Both the methods write directly to the <strong>HttpResponse</strong> output instead of returning an <strong>MvcHtmlString</strong>.</p>
<p>In fact all the <strong>BeginForm()</strong> overloads return an instance of <strong>MvcForm</strong> (more about it below) and the <strong>EndForm()</strong> method is void.</p>
<p>We can invoke the two methods at the right moment, at the beginning and at the end of the form, to render an opening <strong>&lt;form&gt;</strong> tag and a closing <strong>&lt;/form&gt;</strong> tag.</p>
<p><pre class="brush: csharp; html-script: true;">
&lt;% Html.BeginForm() %&gt;
   ...form contents
&lt;% Html.EndForm() %&gt;
</pre></p>
<p>But what I like most is the possibility to invoke the BeginForm method in an inline code block like the following:</p>
<p><pre class="brush: csharp; html-script: true;">
&lt;% using (Html.BeginForm()) { %&gt;
...form contents
&lt;% } %&gt;
</pre></p>
<p>This syntax is supported thanks to the fact that the <strong>BeginForm()</strong> methods return an instance of <strong>MvcForm</strong>.</p>
<p>This class implements <strong>IDisposable</strong> in a very particular way:</p>
<p>The body of the <strong>MvcForm.Dispose(bool disposing)</strong> method writes to the <strong>HttpResponse</strong> output a closing <strong>&lt;form&gt;</strong> tag as the <strong>FormExtensions.EndForm()</strong> does.</p>
<p>We can invoke the <strong>BeginForm()</strong> method inside a using block relying on the .Net Framework to invoke the <strong>Dispose()</strong> method on the instance of <strong>MvcForm</strong> returned by <strong>BeginForm()</strong> and so be sure that the form will be closed.</p>
<p>Based on what you read this far, we will create a <strong>PanelExtensions</strong> class in which we will add our<br />
extension methods and a <strong>MvcPanel</strong> class that will be the analogous of the <strong>MvcForm</strong> class seen above.</p>
<p>The core functionality of the extension methods will make use of the <strong>TagBuilder</strong> utility class to output Html.</p>
<p>That class allows us to build an html tag with an object oriented syntax.</p>
<p>Our method won&#8217;t return an <strong>MvcHtmlString</strong> but will write directly to the <strong>HttpResponse</strong> and it will return an instance of the <strong>MvcPanel</strong> class.</p>
<p>The <strong>MvcPanel</strong> class will implement IDisposable.</p>
<p>The following code is an example of what the body of an extension method could be (with hardcoded values at the moment), based on the assumption that it will render a <strong>&lt;div&gt;</strong> for the title of the panel and a <strong>&lt;div&gt;</strong> for the content:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
// title panel
TagBuilder titleTagBuilder = new TagBuilder(&quot;div&quot;);
titleTagBuilder.MergeAttributes(new RouteValueDictionary(new {title=&quot;title tooltip text&quot;}));
titleTagBuilder.AddCssClass(&quot;titleClass&quot;);
titleTagBuilder.SetInnerText(&quot;This is the title&quot;);

// content panel
TagBuilder tagBuilder = new TagBuilder(&quot;div&quot;);
tagBuilder.MergeAttributes(new RouteValueDictionary(new {title=&quot;content tooltip text&quot;}));
tagBuilder.AddCssClass(&quot;contentClass&quot;);

HttpResponseBase httpResponse = helper.ViewContext.HttpContext.Response;
httpResponse.Write(titleTagBuilder.ToString(TagRenderMode.Normal));
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));

return new MvcPanel(httpResponse);
</pre></p>
<p>As we can see the <strong>TagBuilder</strong> class exposes a constructor accepting a string with the name of the tag to write.</p>
<p>We then make use of the <strong>MergeAttributes()</strong> method. Such method accepts an <strong>IDictionary&lt;string, object&gt;</strong> that is supposed to contain pairs of key/values representing html attributes applicable to the tag specified in the constructor.</p>
<p>To invoke the <strong>MergeAttributes()</strong> method we create an instance of an anonymous type and then we pass it to a <strong>RouteValueDictionary</strong> class.</p>
<p>In this way we rely on it to parse correctly the anonymous type instance and to use it to initialize its own contents.</p>
<p>We then use  the <strong>RouteValueDictionary</strong> instance as the <strong>IDictionary</strong> to pass as parameter to the <strong>MergeAttributes()</strong> method.</p>
<p>The <strong>AddCssClass()</strong> method accepts the name of a css rule to apply to the rendered tag and, eventually, the <strong>SetInnerText()</strong> method accepts some text that will be contained between the open and close tag.</p>
<p>When it&#8217;s time to write in the <strong>HttpResponse</strong> we use the <strong>ToString()</strong> method of the <strong>TagBuilder</strong> class.</p>
<p>Such method accepts a parameter of type: <strong>TagRenderMode</strong>.</p>
<p><strong>TagRenderMode</strong> is an enumeration used to specify any of the four ways in which we can write a tag:</p>
<ul>
<li><strong>Normal</strong>: an open tag, some content and a close tag: &lt;div&gt;some content&lt;/div&gt;</li>
<li><strong>StartTag</strong>: only the open tag: &lt;div&gt;</li>
<li><strong>EndTag</strong>: only the closing tag: &lt;/div&gt;</li>
<li><strong>SelfClosing</strong>: a tag without content: &lt;br /&gt;</li>
</ul>
<p>We write to the <strong>HttpResponse</strong> the complete title <strong>div</strong> but only the opening tag of the content <strong>div</strong>.</p>
<p>Here you can see how the preceding code will be rendered:</p>
<p><pre class="brush: xml;">
&lt;div class=&quot;titleClass&quot; title=&quot;title tooltip text&quot;&gt;
This is the title
&lt;/div&gt;
&lt;div class=&quot;contentClass&quot; title=&quot;content tooltip text&quot;&gt;
</pre></p>
<p>The very last row in the code snippet returns to the caller an instance of the <strong>MvcPanel</strong> class, passing to the <strong>MvcPanel</strong> constructor an instance of the current <strong>HttpResponse</strong>.</p>
<p><strong>MvcPanel</strong> accepts an <strong>HttpResponse</strong> in the constructor in order to be able, later, to write the closing tag to the response at the right moment.</p>
<p><strong>MvcPanel</strong>, in fact, implements the <strong>IDisposable</strong> interface.</p>
<p>Its <strong>Dispose()</strong> method invokes a call to the <strong>HttpResponse.Write()</strong> method writing a div&#8217;s closing tag:</p>
<p><pre class="brush: csharp;">
protected virtual void Dispose(bool disposing)
{
	if (!this.disposed)
	{
		this.disposed = true;
		this.httpResponse.Write(&quot;&lt;/div&gt;&quot;);
	}
}
</pre></p>
<p>If invoking the extension method with the using statement, the .Net framework runtime, upon exiting the using block, will call <strong>Dispose()</strong> on the <strong>MvcPanel</strong> instance returned by the extension method. We will then obtain the end of the panel (i.e.: a closing div tag).</p>
<p>In the <strong>PanelExtensions</strong> class we provide many overloaded extension methods accepting different sets of arguments and all of them, in the end, will call the overload really doing the job.</p>
<p>Such overload is the one with the greatest number of arguments.</p>
<p>The body of this extension method will be analogous to the code snippet above but with the arguments passed to the <strong>TagBuilder</strong> class arriving as method parameters passed from callers of the method:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
public static MvcPanel BeginPanel(this HtmlHelper helper,
								  string title,
								  string titleCssClass,
								  string panelCssClass,
								  IDictionary&lt;string, object&gt; titleHtmlAttributes,
								  IDictionary&lt;string, object&gt; panelHtmlAttributes)
{
	// title panel
	TagBuilder titleTagBuilder = new TagBuilder(&quot;div&quot;);
	titleTagBuilder.MergeAttributes(titleHtmlAttributes);
	titleTagBuilder.AddCssClass(titleCssClass);
	titleTagBuilder.SetInnerText(title);

	// content panel
	TagBuilder tagBuilder = new TagBuilder(&quot;div&quot;);
	tagBuilder.MergeAttributes(panelHtmlAttributes);
	tagBuilder.AddCssClass(panelCssClass);

	HttpResponseBase httpResponse = helper.ViewContext.HttpContext.Response;
	httpResponse.Write(titleTagBuilder.ToString(TagRenderMode.Normal));
	httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
	return new MvcPanel(httpResponse);
}
</pre></p>
<p>The arguments represent:</p>
<ul>
<li>the title displaied in the title panel</li>
<li>the css class rule to apply to the title panel</li>
<li>the css class rule to apply to the content panel</li>
<li>a dictionary containing additional html attributes for the title div</li>
<li>a dictionary containing additional html attributes for the content div</li>
</ul>
<p>For each method accepting one or more <strong>IDictionary</strong> as parameters, an overload is provided accepting an instance of type <strong>object</strong>.</p>
<p>This is just a convenience to facilitate invoking the desired overload taking advantage of anonymous types.</p>
<p>In fact we gain the ability to pass the list of html attributes as an anonymous type like the following:</p>
<p><pre class="brush: csharp; light: true;">

new { title = &quot;panel's tooltip&quot; } 

</pre></p>
<p>In the last paragraph you can find the <a href="#mvcpanelfullcode">full Code</a> for <a href="#mvcpanelextensions">PanelExtensions</a> and <a href="#mvcpanelcode">MvcPanel</a>.</p>
<p>As you can see in the code, the first and simplest extension method accepts only a parameter: the title to be displaied in the title panel.</p>
<p>All the overloads not explicitly accepting css class rules as parameters, rely on the view using them to define a couple of default css class rules (whose names you can find in constants inside the PanelExtensions class).</p>
<p>The default css class rules names are:</p>
<ul>
<li>panelTitle</li>
<li>panel</li>
</ul>
<p>An example of usage is:</p>
<p><pre class="brush: csharp; html-script: true;">
&lt;% using (Html.BeginPanel(&quot;About&quot;)) 
{ %&gt;
    &lt;span&gt;Put content here.&lt;/span&gt;
&lt;% } %&gt;
</pre></p>
<p>You must remember to import your namespace in the view that will use your extension methods:</p>
<p><pre class="brush: csharp; html-script: true;">
&lt;%@ Import Namespace=&quot;MvcPanelExample.Models.Html&quot; %&gt;
</pre></p>
<p>Alternatively you can import the namespace for the whole web application adding it to the web.config:</p>
<p><pre class="brush: xml;">
&lt;pages&gt;
      &lt;namespaces&gt;
        &lt;add namespace=&quot;MvcPanelExample.Models.Html&quot;/&gt;
      &lt;/namespaces&gt;
&lt;/pages&gt;
</pre></p>
<p>At the paragraph 	<a href="#testviewcode">3.3. TestView</a> you can find the code for a view rendering  three panels obtained by invoking three different overloaded extension methods contained in the PanelExtensions class.</p>
<p>The view contains also the definition of two css class rules with the default names plus a pair of custom named css class rules:</p>
<ul>
<li>customPanelTitle</li>
<li>customPanel</li>
</ul>
<p>here is the result displaied by the browser:</p>
<p><a href="http://ilmatte.files.wordpress.com/2010/11/testview.jpg"><img class="alignnone size-medium wp-image-389" title="TestView" src="http://ilmatte.files.wordpress.com/2010/11/testview.jpg?w=300&#038;h=249" alt="Example View" width="300" height="249" /></a></p>
<p><a href="#mvcpanelimplementation"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="mvcstronglytyped" name="mvcstronglytyped"></a><span style="font-size:x-small;color:#993300;">2.2. Strongly Typed Extension Methods</span></h4>
<p>Eventually I added the strongly typed version of my extension methods.</p>
<p>I didn&#8217;t find much help on how to do it on the web, apart from this topic:</p>
<p><a title="strongly typed helpers" href="http://stackoverflow.com/questions/2122424/is-it-possible-to-create-a-custom-asp-net-mvc-strongly-typed-html-helper" target="_blank">Is it possible to create a custom ASP.NET MVC strongly typed HTML Helper?</a>.</p>
<p>Then I downloaded the ASP.NET MVC 3 beta version source code and had a look at how the strongly typed methods: <strong>TextBoxFor</strong> and <strong>LabelFor</strong> were implemented.</p>
<p>I had a look at the <strong>ModelMetadata</strong> class as well.</p>
<p>Starting from there I wrote my own strongly typed html helper method.</p>
<p>The content of the simplest overload is the following (as you can see at paragraph <a href="#mvcpanelextensions">3.1. PanelExtensions</a>):</p>
<p><pre class="brush: csharp; wrap-lines: false;">
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
return BeginPanel(html, metadata.Model as string);
</pre></p>
<p>The Asp.Net Mvc framework <strong>ModelMetaData</strong> class provides the utility method: <strong>FromLambdaExpression</strong> that parses the lambda expression passed as argument and returns an instance of ModelMetadata containing information about the model property returned by the lambda expression.</p>
<p>The <strong>Model</strong> property of <strong>ModelMetaData</strong> contains the value contained in such property, cast as <strong>object</strong>.</p>
<p>As we can see, the strongly typed overload delegates the actual rendering to the non strongly typed overload: <strong>BeginPanel</strong>.</p>
<p>We can than feel safe about XSS attacks because the values contained in the model are sanitized.<br />
In fact the model property will be output in the html via the TagBuilder&#8217;s method: <strong>SetInnerText()</strong> and such method encodes the argument passed.</p>
<p>From my views I can then call any of the strongly typed versions of the Panel extension methods:</p>
<p><pre class="brush: csharp; html-script: true;">
&lt;% using (Html.BeginPanelFor(m =&gt; m.Title, &quot;bluePanel&quot;))
{ %&gt;
	&lt;div&gt;
		Content of my strongly typed panel.
	&lt;/div&gt;
&lt;% } %&gt;
</pre></p>
<p>At the paragraph <a href="#stronglytypedviewcode">3.4. StronglyTypedView</a> you can find the code for a view rendering two panels obtained by invoking two different strongly typed extension methods contained in the PanelExtensions class.</p>
<p>here is the result displaied by the browser:</p>
<p><a href="http://ilmatte.files.wordpress.com/2010/11/stronglytypedview.jpg"><img class="alignnone size-medium wp-image-400" title="StronglyTypedView" src="http://ilmatte.files.wordpress.com/2010/11/stronglytypedview.jpg?w=300&#038;h=251" alt="" width="300" height="251" /></a></p>
<p>Obviously both the views in this article are accessible as long as I have the appropriate Controller action methods returning them as result.</p>
<p>For the strongly typed view I expect to have an action method like the following:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
public ActionResult StronglyTypedView()
{
	PanelModel model = new PanelModel();
	model.Title = &quot;Fake Title&quot;;
	model.SomeOtherText = &quot;SomeOtherText Property Content&quot;;
	return View(model);
}
</pre></p>
<p>you can find the full code for the controller at the paragraph <a href="#controllercode">3.6. Controller</a>.</p>
<p><a href="#mvcpanelimplementation"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a title="mvcpanelfullcode" name="mvcpanelfullcode"></a><span style="color:#993300;font-size:small;">3. Full Code</span></h3>
<ul>
<li><a href="#mvcpanelextensions">3.1. PanelExtensions</a></li>
<li><a href="#mvcpanelcode">3.2. MvcPanel</a></li>
<li><a href="#testviewcode">3.3. TestView</a></li>
<li><a href="#stronglytypedviewcode">3.4. StronglyTypedView</a></li>
<li><a href="#viewmodelcode">3.5. ViewModel</a></li>
<li><a href="#controllercode">3.6. Controller</a></li>
</ul>
<p>You can download the full source code <a href="http://www.box.net/shared/yqnlfoifzl">here</a> or copy the code in the following paragraphs.</p>
<h4><a title="mvcpanelextensions" name="mvcpanelextensions"></a><span style="font-size:x-small;color:#993300;">3.1. PanelExtensions</span></h4>
<p><pre class="brush: csharp; wrap-lines: false;">
namespace MvcPanelExample.Models.Html
{
    using System.Web;
    using System.Web.Mvc;
    using System.Collections.Generic;
    using System.Web.Routing;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq.Expressions;
    using System;


    public static class PanelExtensions
    {
        #region Constants

        const string TitleCssClass = &quot;panelTitle&quot;;
        const string PanelCssClass = &quot;panel&quot;;

        #endregion

        #region Methods

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title)
        {
            return BeginPanel(helper, title, new RouteValueDictionary(), new RouteValueDictionary());
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          object htmlAttributes)
        {

            return BeginPanel(helper, title, new RouteValueDictionary(), new RouteValueDictionary(htmlAttributes));
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          IDictionary&lt;string, object&gt; htmlAttributes)
        {

            return BeginPanel(helper, title, new RouteValueDictionary(), htmlAttributes);
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          object titleHtmlAttributes,
                                          object htmlAttributes)
        {

            return BeginPanel(helper, title, TitleCssClass, PanelCssClass, new RouteValueDictionary(titleHtmlAttributes), new RouteValueDictionary(htmlAttributes));
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          IDictionary&lt;string, object&gt; titleHtmlAttributes,
                                          IDictionary&lt;string, object&gt; htmlAttributes)
        {

            return BeginPanel(helper, title, TitleCssClass, PanelCssClass, titleHtmlAttributes, htmlAttributes);
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          string panelCssClass)
        {

            return BeginPanel(helper, title, TitleCssClass, panelCssClass);
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          string titleCssClass,
                                          string panelCssClass)
        {

            return BeginPanel(helper, title, titleCssClass, panelCssClass, new RouteValueDictionary(), new RouteValueDictionary());
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          string titleCssClass,
                                          string panelCssClass,
                                          object titleHtmlAttributes,
                                          object panelHtmlAttributes)
        {
            return BeginPanel(helper, title, titleCssClass, panelCssClass, new RouteValueDictionary(titleHtmlAttributes), new RouteValueDictionary(panelHtmlAttributes));
        }

        public static MvcPanel BeginPanel(this HtmlHelper helper,
                                          string title,
                                          string titleCssClass,
                                          string panelCssClass,
                                          IDictionary&lt;string, object&gt; titleHtmlAttributes,
                                          IDictionary&lt;string, object&gt; panelHtmlAttributes)
        {
            // title panel
            TagBuilder titleTagBuilder = new TagBuilder(&quot;div&quot;);
            titleTagBuilder.MergeAttributes(titleHtmlAttributes);
            titleTagBuilder.AddCssClass(titleCssClass);
            titleTagBuilder.SetInnerText(title);

            // content panel
            TagBuilder tagBuilder = new TagBuilder(&quot;div&quot;);
            tagBuilder.MergeAttributes(panelHtmlAttributes);
            tagBuilder.AddCssClass(panelCssClass);

            HttpResponseBase httpResponse = helper.ViewContext.HttpContext.Response;
            httpResponse.Write(titleTagBuilder.ToString(TagRenderMode.Normal));
            httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
            return new MvcPanel(httpResponse);
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html, Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string);
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             object htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, new RouteValueDictionary(), new RouteValueDictionary(htmlAttributes));
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             IDictionary&lt;string, object&gt; htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, new RouteValueDictionary(), htmlAttributes);
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             object titleHtmlAttributes,
                                                             object htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, TitleCssClass, PanelCssClass, new RouteValueDictionary(titleHtmlAttributes), new RouteValueDictionary(htmlAttributes));
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             IDictionary&lt;string, object&gt; titleHtmlAttributes,
                                                             IDictionary&lt;string, object&gt; htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, TitleCssClass, PanelCssClass, titleHtmlAttributes, htmlAttributes);
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             string panelCssClass)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, TitleCssClass, panelCssClass);
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             string titleCssClass,
                                                             string panelCssClass)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, titleCssClass, panelCssClass, new RouteValueDictionary(), new RouteValueDictionary());
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             string titleCssClass,
                                                             string panelCssClass,
                                                             object titleHtmlAttributes,
                                                             object panelHtmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, titleCssClass, panelCssClass, new RouteValueDictionary(titleHtmlAttributes), new RouteValueDictionary(panelHtmlAttributes));
        }

        [SuppressMessage(&quot;Microsoft.Design&quot;, &quot;CA1006:DoNotNestGenericTypesInMemberSignatures&quot;, Justification = &quot;This is an appropriate nesting of generic types&quot;)]
        public static MvcPanel BeginPanelFor&lt;TModel, TValue&gt;(this HtmlHelper&lt;TModel&gt; html,
                                                             Expression&lt;Func&lt;TModel, TValue&gt;&gt; expression,
                                                             string titleCssClass,
                                                             string panelCssClass,
                                                             IDictionary&lt;string, object&gt; titleHtmlAttributes,
                                                             IDictionary&lt;string, object&gt; panelHtmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            return BeginPanel(html, metadata.Model as string, titleCssClass, panelCssClass, titleHtmlAttributes, panelHtmlAttributes);
        }

        public static void EndPanel(this HtmlHelper helper)
        {
            HttpResponseBase httpResponse = helper.ViewContext.HttpContext.Response;
            httpResponse.Write(&quot;&lt;/div&gt;&quot;);
        }

        #endregion
    }
}

</pre></p>
<p><a href="#mvcpanelfullcode"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="mvcpanelcode" name="mvcpanelcode"></a><span style="font-size:x-small;color:#993300;">3.2. MvcPanel</span></h4>
<p><pre class="brush: csharp; wrap-lines: false;">
namespace MvcPanelExample.Models.Html
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Web;

    public class MvcPanel : IDisposable
    {
        #region Fields

        private bool disposed;
        private readonly HttpResponseBase httpResponse;

        #endregion

        #region CTOR

        public MvcPanel(HttpResponseBase httpResponse)
        {
            if (httpResponse == null)
            {
                throw new ArgumentNullException(&quot;httpResponse&quot;);
            }
            this.httpResponse = httpResponse;
        }

        #endregion

        #region Methods

        [SuppressMessage(&quot;Microsoft.Security&quot;, &quot;CA2123:OverrideLinkDemandsShouldBeIdenticalToBase&quot;)]
        public void Dispose()
        {
            Dispose(true /* disposing */);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                this.disposed = true;
                this.httpResponse.Write(&quot;&lt;/div&gt;&quot;);
            }
        }

        public void EndPanel()
        {
            Dispose(true);
        }

        #endregion
    }
}
</pre></p>
<p><a href="#mvcpanelfullcode"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="testviewcode" name="testviewcode"></a><span style="font-size:x-small;color:#993300;">3.3. TestView</span></h4>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%@ Page Language=&quot;C#&quot; Inherits=&quot;System.Web.Mvc.ViewPage&quot; %&gt;

&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; &gt;
&lt;head id=&quot;Head1&quot; runat=&quot;server&quot;&gt;
    &lt;title&gt;Example View&lt;/title&gt;
    &lt;style type=&quot;text/css&quot;&gt;
    /* Top bar containing the title of the panel */
    .panelTitle
    {
	    height:30px;
	    background-color:#333366;
	    color:white;
	    border-top:solid 1px #666699;
	    border-right:solid 1px #666699;
	    border-left:solid 1px #666699;
	    padding:5px 0px 0px 20px;
	    font-weight:bold;
	    font-size:large;
	    overflow:auto;
    }

    /* Section of the screen containing omogeneous information */
    .panel
    {
	    border:solid 1px #666699;
	    background-color:white;
	    padding:10px;
	    overflow:auto;
    }
    
    .customPanelTitle
    {
	    height:30px;
	    background-color:#333366;
	    color:white;
	    border-top:solid 1px #666699;
	    border-right:solid 1px #666699;
	    border-left:solid 1px #666699;
	    padding:5px 0px 0px 20px;
	    font-weight:bold;
	    font-size:large;
	    overflow:auto;
	    width:300px;
    }
    
    .customPanel
    {
	    border:solid 1px #666699;
	    background-color:Blue;
	    color:White;
	    border:solid 1px Blue;
	    padding:10px;
	    overflow:auto;
	    width:300px;
    }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
    &lt;% using (Html.BeginPanel(&quot;This is my first Panel&quot;))
       { %&gt;
        &lt;div&gt;
            Content of my first panel.
        &lt;/div&gt;
    &lt;% } %&gt;
    &lt;p&gt;
    &lt;/p&gt;
    &lt;% using (Html.BeginPanel(&quot;Panel with non default style class&quot;,
                              &quot;customPanelTitle&quot;,
                              &quot;customPanel&quot;))
       { %&gt;
        &lt;div&gt;
            Content of my second panel.
        &lt;/div&gt;
    &lt;% } %&gt;
    &lt;p&gt;
    &lt;/p&gt;
    &lt;% using (Html.BeginPanel(&quot;Panel obtained with all parameters&quot;,
                              &quot;customPanelTitle&quot;,
                              &quot;customPanel&quot;,
                              new { title = &quot;panel's tooltip&quot; },
                              null))
       { %&gt;
        &lt;div&gt;
            Content of my panel obtained specifying all parameters.
        &lt;/div&gt;
    &lt;% } %&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre></p>
<p><a href="#mvcpanelfullcode"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="stronglytypedviewcode" name="stronglytypedviewcode"></a><span style="font-size:x-small;color:#993300;">3.4. StronglyTypedView</span></h4>
<p><pre class="brush: csharp; html-script: true; wrap-lines: false;">
&lt;%@ Page Language=&quot;C#&quot; Inherits=&quot;System.Web.Mvc.ViewPage&lt;MvcPanelExample.Models.PanelModel&gt;&quot; %&gt;

&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; &gt;
&lt;head runat=&quot;server&quot;&gt;
    &lt;title&gt;StronglyTypedView&lt;/title&gt;
     &lt;style type=&quot;text/css&quot;&gt;
    /* Top bar containing the title of the panel */
    .panelTitle
    {
	    height:30px;
	    background-color:#333366;
	    color:white;
	    border-top:solid 1px #666699;
	    border-right:solid 1px #666699;
	    border-left:solid 1px #666699;
	    padding:5px 0px 0px 20px;
	    font-weight:bold;
	    font-size:large;
	    overflow:auto;
	    width:300px;
    }

    /* Section of the screen containing omogeneous information */
    .panel
    {
	    border:solid 1px #666699;
	    background-color:white;
	    padding:10px;
	    overflow:auto;
	    width:300px;
    }
    
    .bluePanel
    {
	    border:solid 1px #666699;
	    background-color:Blue;
	    color:White;
	    border:solid 1px Blue;
	    padding:10px;
	    overflow:auto;
	    width:300px;
    }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;% using (Html.BeginPanelFor(m =&gt; m.Title))
    { %&gt;
        &lt;div&gt;
            Content of my first panel.
        &lt;/div&gt;
    &lt;% } %&gt;
    &lt;p&gt;&lt;/p&gt;
    &lt;% using (Html.BeginPanelFor(m =&gt; m.SomeOtherText, &quot;bluePanel&quot;))
    { %&gt;
        &lt;div&gt;
            Content of my second panel.
        &lt;/div&gt;
    &lt;% } %&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre></p>
<p><a href="#mvcpanelfullcode"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="viewmodelcode" name="viewmodelcode"></a><span style="font-size:x-small;color:#993300;">3.5. ViewModel</span></h4>
<p>This is the view model used by the view in the previous paragraph:</p>
<p><pre class="brush: csharp; wrap-lines: false;">
namespace MvcPanelExample.Models
{
    public class PanelModel
    {
        public string Title { get; set; }

        public string SomeOtherText { get; set; }
    }
}
</pre></p>
<p><a href="#mvcpanelfullcode"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a title="controllercode" name="controllercode"></a><span style="font-size:x-small;color:#993300;">3.6. Controller</span></h4>
<p><pre class="brush: csharp; wrap-lines: false;">
namespace MvcPanelExample.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using MvcPanelExample.Models;

    [HandleError]
    public class HomeController : Controller
    {
        public ActionResult TestView()
        {
            return View();
        }

        public ActionResult StronglyTypedView()
        {
            PanelModel model = new PanelModel();
            model.Title = &quot;Title From the Model&quot;;
            model.SomeOtherText = &quot;Some other text from the model&quot;;
            return View(model);
        }
    }
}
</pre></p>
<p><a href="#mvcpanelfullcode"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#mvcpaneltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2filmatte.wordpress.com%2f2010%2f11%2f16%2fasp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%253a%252f%252filmatte.wordpress.com%252f2010%252f11%252f16%252fasp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax%252f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/319/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=319&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2010/11/16/asp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2010/11/professionalaspnetmvc2.jpg" medium="image" />

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0470643188" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/architectingapplications.jpg" medium="image">
			<media:title type="html">.Net Architecting Applications For The Enterprise</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=073562609X" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/fowlerpeaasmall.jpg" medium="image">
			<media:title type="html">Patterns of  Enterprise Application Architecture</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0321127420" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/gof.jpg" medium="image">
			<media:title type="html">Design Patterns</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0201633612" medium="image" />

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%253a%252f%252filmatte.wordpress.com%252f2010%252f11%252f16%252fasp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax%252f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2010/11/testview.jpg?w=300" medium="image">
			<media:title type="html">TestView</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2010/11/stronglytypedview.jpg?w=300" medium="image">
			<media:title type="html">StronglyTypedView</media:title>
		</media:content>

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%253a%252f%252filmatte.wordpress.com%252f2010%252f11%252f16%252fasp-net-mvc-panel-htmlhelper-extension-methods-with-using-syntax%252f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>
	</item>
		<item>
		<title>CruiseControl.Net Tutorial &#8211; Part 2</title>
		<link>http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/</link>
		<comments>http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#comments</comments>
		<pubDate>Sun, 15 Jun 2008 22:14:53 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[CruiseControl.NET]]></category>
		<category><![CDATA[Project Management]]></category>
		<category><![CDATA[ccnet]]></category>
		<category><![CDATA[Continuous Integration]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=88</guid>
		<description><![CDATA[1. Introduction (part 1) 2. Resources (part 1) 3. Installation (part 1) 3.1. Install CruiseControl.NET (part 1) 3.2. Create a CCNet Website in IIS (part 1) 3.3. Install Nunit (part 1) 4. CruiseControl.NET Server Configuration &#8211; General (part 1) 5. Structure of a &#8216;Project&#8217; Configuration File (part 1) 6. Source Control Block (part 1) 7. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=88&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a title="ccnettut2top" name="ccnettut2top"></a><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutintro">1. Introduction (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutresources">2. Resources (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutinstallation">3. Installation (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutinstallccnet">3.1. Install CruiseControl.NET (part 1)</a></span></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutiiscreatesite">3.2. Create a CCNet Website in IIS (part 1)</a></span></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutinstallnunit">3.3. Install Nunit (part 1)</a></span></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutconfiguration">4. CruiseControl.NET Server Configuration &#8211; General (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutprojectconfiguration">5. Structure of a &#8216;Project&#8217; Configuration File (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutsourcecontrolblock">6. Source Control Block (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettuttriggerblock">7. Trigger Block (part 1)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutlabellerblock">8. Labeller Block (part 1)</a></span><br />
<a href="#ccnettuttasksblock">9. Tasks Block</a><br />
<a href="#ccnettutmsbuildtask">10. MsBuild Task</a><br />
<span style="position:relative;left:10px;"><a href="#ccnettutreferencepath">10.1. MSBuild and ReferencePath &#8211; CruiseControl.NET not resolving reference to Nunit</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutrodemeyer">10.2. An Alternative MSBuild Logger &#8211; Christian Rodemeyer&#8217;s MsBuildToCCNet</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutwebdashboardimages">10.3. CruiseControl.NET Webdashboard fails in finding images if not installed in virtual directory</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutnumberofprojects">10.4. MSBuildToCCNET reports wrong number of compiled projects</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutassemblylinker">10.5. CruiseControl.NET, MsBuild Task and Resources &#8211; Assembly Linker</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutwebappprojects">10.6. CruiseControl.NET, MsBuild Task and Web Application projects</a></span><br />
<a href="#ccnettutnunittask">11. Nunit Task</a><br />
<span style="position:relative;left:10px;"><a href="#ccnettutnunittask1">11.1. Nunit Task</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutnunittask2">11.2. Executable Task</a></span><br />
<a href="#ccnettutpublishersblock">12. Publishers Block</a><br />
<a href="#ccnettutprebuildblock">13. PreBuild Block</a><br />
<span style="position:relative;left:10px;"><a href="#ccnettutinstallnant">13.1. Install Nant</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutnantfundamentals">13.2. Nant Fundamentals</a></span></p>
<p>This article is the second one of a series dedicated to CruiseControl.Net.<br />
In the first part (which you can find <a title="part1" href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/" target="_blank">here</a>) we installed it and had an overview of how to configure it.<br />
Then we started to configure a project file: we instructed the <strong>Source Control Block</strong> to use Subversion, the <strong>Trigger Block</strong> to check it periodically and the <strong>Labeller Block</strong> to use: svnRevisionLabeller<br />
In this second article we will see the <strong>Tasks Block</strong> and I will point out some issues that might arise and provide solutions as well.</p>
<p>Thanks to Frank Geerlings for making me aware of a casing problem with the xml samples.<br />
By talking with WordPress support it came out that there was a little bug and they suggested me<br />
how to fix the problem.</p>
<h3><a title="ccnettuttasksblock" name="ccnettuttasksblock"></a><span style="font-size:small;color:#993300;">9. Tasks Block</span></h3>
<p>The tasks block represents how the build of the project actually takes place.<br />
In our example we will use an <strong>MsBuild Task</strong> to accomplish the main purpose of our project, which is to compile the versioned Visual Studio solution.<br />
After that we will use an <strong>Executable Task</strong> to run our unit tests, if the build succeeds.<br />
Let&#8217;s see the <a title="ccnettutsamplexml" name="ccnettutsamplexml">whole Tasks Block</a>, at first:</p>
<p><pre class="brush: xml;">
&lt;tasks&gt;
&lt;!-- compiles working copy -- &gt;
  &lt;msbuild&gt;
    &lt;executable&gt;C:\WINDOWS\Microsoft.NET\Framework\
      v2.0.50727\MSBuild.exe
    &lt;/executable&gt;
    &lt;workingDirectory&gt;C:\develop\CCnet\project1WorkingDir
    &lt;/workingDirectory&gt;
&lt;projectFile&gt;DummySolution.sln&lt;/projectFile &gt;
    &lt;buildArgs&gt;/noconsolelogger /v:quiet
      /p:Configuration=Debug
      /p:ReferencePath=&quot;C:\Program Files\NUnit 2.4.7\bin&quot;
    &lt;/buildArgs&gt;
    &lt;targets&gt;ReBuild&lt;/targets &gt;
    &lt;timeout&gt;600&lt;/timeout &gt;
    &lt;logger&gt;c:\Program Files\CruiseControl.NET\server\
      Rodemeyer.MsBuildToCCNet.dll&lt;/logger &gt;
  &lt;/msbuild&gt;
&lt;!-- launches nunit tests on working copy -- &gt;
  &lt;exec&gt;
    &lt;executable&gt;C:\Program Files\NUnit 2.4.7\
      bin\nunit-console.exe
    &lt;/executable &gt;
    &lt;buildArgs&gt;/xml:..\project1CCnetArtifacts\nunit-results.xml
      /nologo Dummy.sln.nunit
      /exclude:LongRunning,AnotherCategoryName
    &lt;/buildArgs&gt;
  &lt;/exec&gt;
&lt;/tasks&gt;
</pre></p>
<p>Let&#8217;s focus on the <strong>MsBuild Task</strong> first and see how we can configure and customize it:</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettuttasksblock"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutmsbuildtask" name="ccnettutmsbuildtask"></a><span style="font-size:small;color:#993300;">10. MsBuild Task</span></h3>
<p>Let&#8217;s have a look at the meaning of the xml nodes children of the <strong>&lt;msbuild&gt;</strong> node:</p>
<p><strong>&lt;executable&gt;</strong>: contains the path to the msbuild executable file. You don&#8217;t really need to set it because the default value is the standard installation path: <span style="color:#808080;">C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</span>.<br />
I decided to set it explicitly just to be sure about it .<br />
<strong>&lt;workingDirectory&gt;</strong>: is the directory in which MsBuild will be run, so it must be the directory containing our project&#8217;s checked out working copy. You can provide a path relative to the current project&#8217;s workinDirectory but I preferred to provide the full path. Actually, the path to the CCNET checked out working copy is the same as the <strong>&lt;workingDirectory&gt;</strong> field of the <strong>Source Control Block</strong>.<br />
<strong>&lt;projectFile&gt;</strong>: is the name of the project to build. MsBuild accepts a Visual Studio solution file as the project file to build. Obviously the <strong>MsBuild Task</strong> accepts it as well.<br />
<strong>&lt;buildArgs&gt;</strong> This row provides additional command line arguments to MsBuild. We tell it not to log events to the console (<span style="color:#808080;">/noconsolelogger</span>), to build the Debug configuration (<span style="color:#808080;">/p:Configuration=Debug</span>) and to provide a reduced output (<span style="color:#808080;">/v:quiet</span>).<br />
As far as the <span style="color:#808080;">/p:ReferencePath</span> buildArg is concerned it is worth to talk extensively about a problem that could arise with Nunit, so have a look at <a href="#ccnettutreferencepath" target="_self">paragraph 10.1</a>.</p>
<h4><a title="ccnettutreferencepath" name="ccnettutreferencepath"></a><span style="font-size:x-small;color:#993300;">10.1 MSBuild and ReferencePath &#8211; CruiseControl.NET not resolving reference to Nunit</span></h4>
<p>It could happen that CCNET is not able to locate Nunit (or some other dependency assembly) depending on how your project file has been created by Visual Studio.<br />
Open your project file (<strong>DummyProject.csproj</strong>) with a text editor (e.g.: Notepad++). If you find an entry as follows in it:</p>
<p><pre class="brush: xml;">
&lt;Itemgroup&gt;
  &lt;Reference Include=&quot;nunit.framework, Version=2.4.7.0,
    Culture=neutral, PublicKeyToken=96d09a1eb7f44a77,
    processorArchitecture=MSIL&quot; /&gt;
      ....
&lt;/Itemgroup&gt;
</pre></p>
<p>with no &lt;HintPath&gt; associated to the Nunit &lt;Reference&gt; it could be that CCNET will not be able to resolve that reference if you don&#8217;t register nunit.framework.dll in the server&#8217;s GAC.</p>
<p>You can make sure that CCNET is able to resolve the dependency by providing an alternative search path in which to look for.<br />
Each assembly referenced in the Visual Studio project file needs to be located by MSBUild at compile time.<br />
The location of the referenced assemblies is resolved by MSBuild by looking in several locations in a particular search order (as explained <a title="reference path vs2005" href="http://blogs.msdn.com/manishagarwal/archive/2005/09/28/474769.aspx" target="_blank">here</a>).<br />
We could modify the .csproj file by providing a  value as a child node of the  node, e.g.:</p>
<p><pre class="brush: xml;">
&lt;Reference Include=&quot;DummyLibrary, Version=1.0.0.0,
    Culture=neutral, processorArchitecture=MSIL&quot;&gt;
  &lt;SpecificVersion&gt;False&lt;/SpecificVersion&gt;
  &lt;HintPath&gt;..\..\CommonReferencedDLLs\DummyLibrary.dll
  &lt;/HintPath&gt;
&lt;/Reference&gt;
</pre></p>
<p>This approach has two drawbacks:</p>
<ol>
<li> the hintpath is a relative path, thus making the build success depend on the location of the project relative to the referenced assembly (this could be a problem if we reference an external assembly);</li>
<li>we need to modify each Visual Studio project file by hand  and we don&#8217;t want to do it!</li>
</ol>
<p>Fortunately there&#8217;s an easy way out:<br />
We can override all the project specific settings for path resolving by passing a <strong>ReferencePath </strong>property from the MSBuild command line.<br />
Such property accepts as value a list of paths (<em>MSBuild DummySolution.sln  /p:&#8221;ReferencePath=&lt;Path1;Path2;Path3&gt;&#8221;</em>) and it is checked by the build process before checking other locations (<strong>HintPath</strong> for example).<br />
So the way to provide an alternative search path from the command line is to pass as argument a <strong>ReferencePath</strong> property.<br />
This is the reason why the command line provided in the &lt;buildArgs&gt; field contains the <strong>ReferencePath</strong> property pointing to the Nunit install path:<br />
<span style="color:#808080;">/p:ReferencePath=&#8221;C:\Program Files\NUnit 2.4.7\bin&#8221;</span>.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutmsbuildtask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><span style="font-size:x-small;color:#993300;">end of paragraph 10.1</span><br />
<span style="font-size:x-small;color:#993300;">continues paragraph 10. MsBuild Task</span></p>
<p>Let&#8217;s go on with the analysis of the xml nodes children of the &lt;msbuild&gt; node:<br />
<strong>&lt;targets&gt;</strong> specifies which targets to build in this msbuild project file. It represents the MSbuild&#8217;s /target command line argument. We set it to <strong>Rebuild</strong> (clean and build).<br />
<strong>&lt;timeout&gt;</strong> is the number of seconds before assuming that the process has hung. If timeout is exceeded the process will be killed.<br />
<strong>&lt;logger&gt;</strong> specifies the path to the assembly containing the logger to use to format the log output of MSbuild .<br />
If you don&#8217;t want to use the alternative logger that I used in the configuration shown above, you can rely on the default logger as explained here and skip the following<br />
<a href="#ccnettutrodemeyer" target="_self">paragraph 10.2</a>.<br />
To use the default logger:</p>
<ul>
<li>leave out the &lt;logger&gt; field,</li>
<li>download the assembly containing the default xml logger <a title="default logger" href="http://ccnetlive.thoughtworks.com/MSBuildXmlLogger%2DBuilds/" target="_blank">here</a> (find info <a title="loggers description" href="http://confluence.public.thoughtworks.org/display/CCNET/Using+CruiseControl.NET+with+MSBuild" target="_blank">here</a>),</li>
<li>copy the downloaded assembly (<strong>ThoughtWorks.CruiseControl.MSBuild.dll</strong>) to the folder: <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\server</span>.</li>
</ul>
<p>I suggest to use the alternative logger (by Christian Rodemeyer) as explained in the following paragraph. The RodeMeyer&#8217;s logger provide lighter msbuild output and his modified stylesheets provide much more readable display of such information.</p>
<h4><a title="ccnettutrodemeyer" name="ccnettutrodemeyer"></a><span style="font-size:x-small;color:#993300;">10.2. An Alternative MSBuild Logger &#8211; Christian Rodemeyer&#8217;s MsBuildToCCNet</span></h4>
<p>I chose to use a logger alternative to the default one: Christian Rodemeyer&#8217;s MsBuildToCCNet.<br />
You can find it at:  <a title="rodemeyer page" href="http://confluence.public.thoughtworks.org/display/CCNETCOMM/Improved+MSBuild+Integration" target="_blank">Improved MSBuild Integration</a>.  From there either you can download separately the assembly and all related stuff needed to correctly display the results from Rodemeyer&#8217;s logger or you can download a zip file with the whole project and source code.</p>
<p>In the page cited above you can find detailed instructions on how the logger works and how it should be configured.<br />
In the current paragraph I&#8217;ll illustrate the installation process and add some useful tips for making it work.<br />
I suggest to download the full project that comes in a zip file named: MsBuildToCCNet.zip (download <a title="download rodemeyer" href="http://confluence.public.thoughtworks.org/download/attachments/6253/MsBuildToCCNet.zip?version=5" target="_blank">here</a>).<br />
Unzipping the package you will have a directory named: MsBuildToCCNet. Inside this directory you will find, among the rest, a directory named <strong>Release</strong>, containing the assembly: <strong>Rodemeyer.MsBuildToCCnet.dll</strong>.<br />
Just copy the assembly to the <span style="color:#808080;">\CruiseControl.NET\server</span> folder (e.g.: <span style="color:#808080;">c:\Program Files\CruiseControl.NET\server\</span>).<br />
There&#8217;s another subdirectory of the <span style="color:#808080;">MsBuildToCCNet</span> folder, named <span style="color:#808080;">ccnet</span> where you can find the resources needed to correctly display the logs produced by Rodemeyer&#8217;s logger. Those resources are:<br />
<strong>cruisecontrol.css</strong> and<br />
<strong>msbuild2ccnet.xsl</strong>.</p>
<p>You need to use those two files and to configure the Webdshboard:</p>
<ol>
<li>Move into your CruiseControl.NET Webdashboard folder, under the path: <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\webdashboard</span> (e.g.: <span style="color:#808080;">c:\Program Files\CruiseControl.NET\webdashboard\</span>) and back up the file: <strong>cruisecontrol.css</strong>.<br />
Then replace it with the <strong>cruisecontrol.css</strong> file you found in the Rodemeyer&#8217;s MsBuildToCCNet folder (e.g.: copy <span style="color:#808080;">MsBuildToCCNet\ccnet\cruisecontrol.css</span> to <span style="color:#808080;">c:\Program Files\CruiseControl.NET\webdashboard\cruisecontrol.css</span>);</li>
<li>There&#8217;s a subdirectory of the CruiseControl.NET Webdashboard folder, named: <strong>xsl</strong>.<br />
You need to copy the other resource (<strong>msbuild2ccnet.xsl</strong>) you found in the <span style="color:#808080;">MsBuildToCCNet\ccnet</span> folder in that directory: <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\webdashboard\xsl\</span>;</li>
<li>You need to modify the <strong>dashboard.config</strong> file in the CruiseControl.NET Webdashboard folder in order to correctly show the output of the logger.<br />
Being that we&#8217;re talking about the Webdashboard configuration I will show you all the changes you will need to do to let it work with the following three components (even if we&#8217;ll see two of them only in the following paragraphs):</p>
<ul>
<li> MsBuildToCCNet</li>
<li> Nunit integration</li>
<li> FxCop integration</li>
</ul>
<p>First of all choose a 32 x 32 jpg image representing a smiling icon and place it in the CruiseControl.NET Webdashboard folder: <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\webdashboard</span>.<br />
Rename the image file: <em>your_happy_image.jpg</em> and, when a new build succeeds, you&#8217;ll obtain a smiling icon in the Webdashboard report! (you can find a sample image <a title="happy image" href="http://ilmatte.files.wordpress.com/2008/06/your_happy_image.jpg" target="_blank">here</a>).<br />
Then open <span style="color:#808080;">CruiseControl.NET\webdashboard\xsl\msbuild2ccnet.xsl</span> and go to line 24:</p>
<p><pre class="brush: xml;">
&lt;xsl :if test=&quot;@error_count = 0 and @warning_count = 0&quot;&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;/ccnet/your_happy_image.jpg&quot;
           alt=&quot;Happy Image :-)&quot; /&gt; Juchuu !!!&lt;/td&gt;
&lt;/tr&gt;
&lt;/xsl&gt;
</pre></p>
<p>replace the <em>img src</em> attribute: <span style="color:#808080;">/ccnet/your_happy_image.jpg</span> with <span style="color:#808080;">/your_happy_image.jpg</span> if you configured iis with a new website for the webdashboard instead of a virtual directory. If you&#8217;re usign the default virtual directory named <strong>ccnet</strong>, don&#8217;t modify that row.<br />
Next you need to locate the field: <strong>&lt;buildPlugins&gt;</strong> in <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\webdashboard\dashboard.config</span> and arrange or delete its children nodes in order to obtain the following configuration (remember to back up the file first):</p>
<p><pre class="brush: xml;">
&lt;buildplugins&gt;
  &lt;buildreportbuildplugin&gt;
    &lt;xslfilenames&gt;
      &lt;xslfile&gt;xsl\header.xsl&lt;/xslfile&gt;
      &lt;xslfile&gt;xsl\modifications.xsl&lt;/xslfile&gt;
      &lt;xslfile&gt;xsl\msbuild2ccnet.xsl&lt;/xslfile&gt;
      &lt;xslfile&gt;xsl\unittests.xsl&lt;/xslfile&gt;
      &lt;xslfile&gt;xsl\compile.xsl&lt;/xslfile&gt;
      &lt;xslfile&gt;xsl\fxcop-summary.xsl&lt;/xslfile&gt;
    &lt;/xslfilenames&gt;
  &lt;/buildreportbuildplugin&gt;
  &lt;buildlogbuildplugin /&gt;
  &lt;xslreportbuildplugin description=&quot;NUnit Details&quot;
       actionName=&quot;NUnitDetailsBuildReport&quot;
       xslFileName=&quot;xsl\tests.xsl&quot; /&gt;
  &lt;xslreportbuildplugin description=&quot;NUnit Timings&quot;
       actionName=&quot;NUnitTimingsBuildReport&quot;
       xslFileName=&quot;xsl\timing.xsl&quot; /&gt;
   &lt;xslreportbuildplugin description=&quot;FxCop Report&quot;
       actionName=&quot;FxCopBuildReport&quot;
       xslFileName=&quot;xsl\FxCopReport.xsl&quot; /&gt;
&lt;/buildplugins&gt;
</pre></p>
<p>As you can see, such configuration includes also stylesheet files for nunit and fxcop integration. We will soon configure the server to integrate those components.</li>
</ol>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutmsbuildtask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><span style="font-size:x-small;color:#993300;">end of paragraph 10.2</span><br />
<span style="font-size:x-small;color:#993300;">continues paragraph 10. MsBuild Task</span></p>
<p>While adding the smiling image in the previous paragraph we had to change the path in the xsl file.<br />
The same problem could arise with other stylesheet files if you configured the webdashboard to be a website instead that a virtual directory named ccnet.<br />
Have a look at the next paragraph for details:</p>
<h4><a title="ccnettutwebdashboardimages" name="ccnettutwebdashboardimages"></a><span style="font-size:x-small;color:#993300;">10.3. CruiseControl.NET Webdashboard Fails in Finding Images if Not Installed in Virtual Directory</span></h4>
<p>If you unchecked <span style="color:#808080;">&#8216;Create virtual directory in IIS for Web dashboard&#8217;</span> as shown in part 1 of this tutorial at <a title="install part 1" href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutinstallccnet" target="_blank">3.1. Install CruiseControl.NET</a> and installed the Webdashboard as a new website as shown in the paragraph: <a title="create iis website part 1" href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutiiscreatesite" target="_blank">3.2. Create a CCNet Website in IIS</a>, the webdashboard could have problems in resolving image paths.<br />
You will realize it as soon as you will configure the server to integrate nunit or fxcop (will see it in  following paragraphs).<br />
To make sure not to have this problems you must modify the following files:<br />
<strong>xsl\tests.xsl</strong><br />
<strong>xsl\fxcop-summary.xsl</strong><br />
under: <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\webdashboard\</span></p>
<p>you have to replace all the paths relative to the root of the website with relative paths, e.g:</p>
<p>in the file: <strong>xsl\tests.xsl</strong> you should replace all entries like:</p>
<p><pre class="brush: xml;">
eImg.src = &quot;&lt;xsl :value-of select=&quot;$applicationPath&quot;/&gt;/images/arrow_minus_small.gif&quot;;
</pre></p>
<p>with:</p>
<p><pre class="brush: xml;">
eImg.src = &quot;&lt;xsl :value-of select=&quot;$applicationPath&quot;/&gt;images/arrow_minus_small.gif&quot;;
</pre></p>
<p>and entries like:</p>
<p><pre class="brush: xml;">
&lt;img src=&quot;{$applicationPath}/images/fxcop-error.gif&quot;/&gt;
</pre></p>
<p>with:</p>
<p><pre class="brush: xml;">
&lt;img src=&quot;{$applicationPath}images/fxcop-error.gif&quot;/&gt;
</pre></p>
<p>that is, you simply need to delete the leading &#8216;forward slash&#8217; at the beginning of the path (just before the &#8216;images&#8217; folder name).</p>
<p>you need to accomplish the same task with the file <strong>xsl\fxcop-summary.xsl</strong>, e.g.:</p>
<p>you should replace entries like:</p>
<p><pre class="brush: xml;">
&lt;xsl :attribute name=&quot;src&quot;&gt;&lt;xsl :value-of select=&quot;$applicationPath&quot; /&gt;/images/fxcop-critical-error.gif&lt;/xsl&gt;
</pre></p>
<p>with:</p>
<p><pre class="brush: xml;">
&lt;xsl :attribute name=&quot;src&quot;&gt;&lt;xsl :value-of select=&quot;$applicationPath&quot; /&gt;images/fxcop-critical-error.gif&lt;/xsl&gt;
</pre></p>
<p>Actually, you should find all paths to images in those two files and delete the leading forward slash.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutmsbuildtask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><span style="font-size:x-small;color:#993300;">end of paragraph 10.3</span><br />
<span style="font-size:x-small;color:#993300;">continues paragraph 10. MsBuild Task</span></p>
<p>Back to the MSBuildToCCNET alternative Logger for MsBuild, I will explain now why I decided to recompile the source code instead of using the assembly provided: <span style="color:#808080;">MsBuildToCCNet\Release\Rodemeyer.MsBuildToCCnet.dll</span></p>
<h4><a title="ccnettutnumberofprojects" name="ccnettutnumberofprojects"></a><span style="font-size:x-small;color:#993300;">10.4. MSBuildToCCNET Reports Wrong Number of Compiled Projects</span></h4>
<p>I found that MsBuildToCCNet reported the wrong number of projects in the webdashboard in the page reporting the details of the last build.<br />
There&#8217;s a row that sounds like the following, displaied in that page:</p>
<p><span style="color:#0000ff;">&#8217;15 Projects built with 2 warnings&#8217;</span></p>
<p>Looking at the source code (in the file: <strong>Logger.cs</strong>) I realized that the list of <em>Project</em> type instances includes the solution file (<span style="color:#666699;">DummySolution.sln</span>) and a <em>Project</em> object named &#8220;<span style="color:#ff6600;">MSBuild</span>&#8220;, somehow representing the MsBuild process.<br />
Appearently this is the reason why the reported number of projects is wrong.<br />
I still haven&#8217;t tried to contact the author so I don&#8217;t know very well how the Logger is supposed to work as far as this count is concerned.<br />
As a workaround I modified the following row:</p>
<p><pre class="brush: csharp;">
w.WriteAttributeString(&quot;project_count&quot;,
                     XmlConvert.ToString(projects.Count));
</pre></p>
<p>turning it into:</p>
<p><pre class="brush: csharp;">
w.WriteAttributeString(&quot;project_count&quot;,
                     XmlConvert.ToString(projects.Count - 2));
</pre></p>
<p>in the &#8216;WriteLog(XmlWriter w)&#8217; method (file: <strong>Logger.cs</strong> at row 104).</p>
<p>This seems having fixed the problem with no side effects.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutmsbuildtask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><span style="font-size:x-small;color:#993300;">end of paragraph 10.4</span><br />
<span style="font-size:x-small;color:#993300;">continues paragraph 10. MsBuild Task</span></p>
<p>You could have problems running msbuild task if your server machine (the one in which you installed CruiseControl.NET) is not updated with all the software installed in a developer workstation. Let&#8217;s see which problems could arise:</p>
<h4><a title="ccnettutassemblylinker" name="ccnettutassemblylinker"></a><span style="font-size:x-small;color:#993300;">10.5. CruiseControl.NET, MsBuild Task and Resources &#8211; Assembly Linker</span></h4>
<p>If you want to provide localization for any of your projects or somehow use resources files (.resx) you will get an error during the build on the CruiseControl.NET server if MsBuild is not able to locate the Assembly Linker.<br />
The error should look something like:</p>
<p><span style="color:#ff0000;">C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets(1950,9): error MSB3011: &#8220;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\AL.exe&#8221; was not found. Either 1) Install the .NET Framework SDK, which will install AL.exe. Or 2) Pass the correct location of AL.exe into the &#8220;ToolPath&#8221; parameter of the AL task.</span></p>
<p>AL.exe is used to produce the satellite assemblies and the executable file is placed in the .NET framework directory.<br />
But Al.exe is a .Net Framework SDK tool. It is not included in .Net Framework 2.0 runtime installation.<br />
You need to install the .NET framework SDK on the server machine if you don&#8217;t want to encounter this problem.<br />
If you want to solve this particular issue in a tricky way without installing the whole SDK, you can copy <strong>al.exe.config</strong> e <strong>al.exe</strong> from a developer workstation and place them in the <span style="color:#808080;">C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727</span> directory on the server machine.<br />
This is how I solved the problem but I suggest you to install the .NET framework SDK on the server machine.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutmsbuildtask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h4><a title="ccnettutwebappprojects" name="ccnettutwebappprojects"></a><span style="font-size:x-small;color:#993300;">10.6. CruiseControl.NET, MsBuild Task and Web Application projects</span></h4>
<p>A particular note is due for Web projects.<br />
Updating Visual Studio 2005 you get the SP1. Together with the Service Pack 1 for Visual Studio you get the WebApplication project template.<br />
Such template lets us add a new kind of project to our solution: a web site project structured exactly like any other Visual Studio project.<br />
So you can quit creating new websites (<strong>File &#8211;&gt; New &#8211;&gt; Web Site&#8230;</strong>) and start creating new WebApplication projects (<strong>File &#8211;&gt; New &#8211;&gt; Project&#8230;</strong> and then choose &#8216;<strong>ASP.NET Web Application</strong>&#8216;).</p>
<p>In order to use WebApplication projects you need to have Visual Studio installed on your machine and the WebApplication project plugin (that comes with the Visual Studio 2005 SP1).<br />
If the server in which CruiseControl.NET server is running is not a develpment workstation you will get an error when trying to build a WebApplication project, beacuse you miss those two prerequisites.</p>
<p>You can easily fix this problem: you simply need to copy the file: <strong>Microsoft.WebApplication.targets</strong> that you can find under:<br />
<span style="color:#808080;">&#8220;C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0\WebApplications\&#8221;</span><br />
from a development workstation and paste it to the corresponding path on the server machine (creating the directories in the path if needed).</p>
<p>Additionally, if you&#8217;re using an ASP.NET AJAX Enabled WebApplication as the web project template you need to install the aspnet-ajax extensions as well.<br />
You can find the installer (ASPAJAXExtSetup.msi) for .NET framework 2.0 <a title="asp.net ajax download" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=ca9d90fa-e8c9-42e3-aa19-08e2c027f5d6&amp;displaylang=en" target="_blank">here</a></p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutmsbuildtask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutnunittask" name="ccnettutnunittask"></a><span style="font-size:small;color:#993300;">11. Nunit Task</span></h3>
<p>The second Task Block that you find in the xml fragment <a title="xml msbuild task" href="#ccnettutsamplexml" target="_self">above</a> is an Executable Task used to instruct CruiseControl.NET to run unit tests with Nunit.</p>
<p>At first I tried to use a <strong>Nunit Task Block</strong> but I soon realized that it was not good for me because it was not possible to provide arguments to the task that should be used as arguments of the Nunit command-line executable.</p>
<p>This is a problem because there&#8217;s no way to let the Nunit task be aware of Nunit categories.<br />
For those who don&#8217;t know, Nunit lets you specify a &#8216;<em>Category</em>&#8216; attribute in test methods, with the following syntax:</p>
<p><pre class="brush: csharp;">
[Test]
[Category(&quot;LongRunning&quot;)]
public void VeryLongTest()
{ /* ... */ }
</pre></p>
<p>This attribute allows you to instruct Nunit to treat all the methods belonging to the same category in the same way.<br />
Usually what we want to do is to exclude a cluster of tests from running.<br />
Typically we exclude tests that take too much to run, using the following syntax with the nunit command-line tool:</p>
<p><strong>nunit-console.exe /exclude:LongRunning,AnotherCategoryName</strong></p>
<p>You can configure excluded categories in nunit GUI as well, by clicking the &#8216;<strong>Categories</strong>&#8216; tab in the top left corner.<br />
A list of available categories will be shown. Just select the categories of interest and click the <strong>Add</strong> button.<br />
Then check the <strong>Exclude these categories</strong> checkbox at the bottom of the page and run the nunit project.</p>
<p>It is very useful to be able to exclude some categories of tests from the continuous integration environment, still being able to run them on developer machines.</p>
<p>This is the reason why I recently submitted a patch to CruiseControl.Net adding support for Nunit categories.<br />
It&#8217;s not included in the official release yet, because I submitted it too late for this purpose.<br />
However you can find it in the current build which is publicly available at: <a href="http://ccnetlive.thoughtworks.com/CCNet-builds/">ccnetlive</a>. The patch is included starting from build: <a href="http://ccnetlive.thoughtworks.com/CCNet-builds/1.4/1.4.0.3591/CruiseControl.NET-1.4.0.3591.zip">3591</a>.<br />
So now you have two chances to use categories:</p>
<ol>
<li>If you really want to use the last officially released version, read the <a href="#ccnettutnunittask2">paragraph 11.2</a> about how to use an Executable Task (the method described can be useful also if you want to use any other unsupported Nunit command line argument);</li>
<li><span style="text-decoration:underline;">Instead if you can download the latest build from ccnetlive you will be able to specify categories</span> inside the Nunit Task block, as explained in <a href="#ccnettutnunittask">paragraph 11.1</a></li>
</ol>
<h4><a title="ccnettutnunittask1" name="ccnettutnunittask1"></a><span style="font-size:x-small;color:#993300;">11.1. Nunit Task</span></h4>
<p>If you downloaded the most recent build and followed the installation instructions (see: <a href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#ccnettutinstallation">3. Installation</a>) you can go on reading this paragraph.<br />
If you installed the official release or a build older than 1.4.0.3591, you can still modify your installation with the following instructions:</p>
<p>download the zipped package (<a href="http://ccnetlive.thoughtworks.com/CCNet-builds/1.4/1.4.0.3591/CruiseControl.NET-1.4.0.3591.zip">here</a>) or source code. Unzip it in a temporary directory and locate the assembly: ThoughtWorks.CruiseControl.Core.dll (which, for the zip package, is in the directory: &#8216;server&#8217;).<br />
Copy and replace it to the original one in your CCNET installation directory (back up the original one first) that should be: <span style="color:#808080;">Program Files\CruiseControl.NET\server</span>.</p>
<p>That&#8217;s it! Now you can use the CruiseControl.NET&#8217;s Nunit Task Block also for specifying Nunit categories (see: <a href="http://www.nunit.org/index.php?p=category&amp;r=2.4.8">Nunit categories</a> for reference).</p>
<p>It is possible to specify a list of the categories of tests that we want to be excluded.<br />
It is possible, as well, to specify a list of the only categories that we want to be included as allowed by the Nunit Command-line or GUI interface.<br />
The configuration syntax for the Nunit task becomes:</p>
<p><pre class="brush: xml;">
&lt;nunit&gt;
&lt;path&gt;C:\Program Files\NUnit 2.4.7\bin\nunit-console.exe
&lt;/path&gt;
    &lt;assemblies&gt;
        &lt;assembly&gt;Dummy.sln.nunit&lt;/assembly&gt;
    &lt;/assemblies&gt;
    &lt;excludedCategories&gt;
        &lt;excludedCategory&gt;LongRunning&lt;/excludedCategory&gt;
	&lt;excludedCategory&gt;Category 2&lt;/excludedCategory&gt;
    &lt;/excludedCategories&gt;
&lt;/nunit&gt;
</pre></p>
<p>for excluded categories, or:</p>
<p><pre class="brush: xml;">
&lt;nunit&gt;
&lt;path&gt;C:\Program Files\NUnit 2.4.7\bin\nunit-console.exe
&lt;/path&gt;
    &lt;assemblies&gt;
        &lt;assembly&gt;Dummy.sln.nunit&lt;/assembly&gt;
    &lt;/assemblies&gt;
    &lt;includedCategories&gt;
        &lt;includedCategory&gt;LongRunning&lt;/includedCategory&gt;
	&lt;includedCategory&gt;Category 2&lt;/includedCategory&gt;
    &lt;/includedCategories&gt;
&lt;/nunit&gt;
</pre></p>
<p>for included categories. You can find the official reference at <a href="http://confluence.public.thoughtworks.org/display/CCNET/NUnit+Task" target="_blank">this page</a> on the official website.</p>
<p>The Nunit task output log file is automatically integrated in the CCNET build results.<br />
So you don&#8217;t need to specify the Merge task (needed if you use the procedure explaine in paragraph 11.2 instead of this one) in the Publishers block as explained in <a href="#ccnettutpublishersblock">paragraph 12</a>:</p>
<p><pre class="brush: xml;">
&lt;merge&gt;
  &lt;files&gt;
    &lt;file&gt;..\project1CCnetArtifacts\nunit-results.xml&lt;/file&gt;
  &lt;/files&gt;
&lt;/merge&gt;
</pre></p>
<p>Instead you still need to delete the previous Nunit log file before each build process as explained in the <a href="#ccnettutprebuildblock">paragraph 13 &#8211; PreBuild Block</a>.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutnunittask"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h4><a title="ccnettutnunittask2" name="ccnettutnunittask2"></a><span style="font-size:x-small;color:#993300;">11.2. Executable Task</span></h4>
<p>If you&#8217;re working with the official release of CruiseControl.Net (release 1.4) Nunit Task Block syntax only allows you to specify the target solution and little more. In our example it would be:</p>
<p><pre class="brush: xml;">
&lt;nunit&gt;
&lt;path&gt;C:\Program Files\NUnit 2.4.7\bin\nunit-console.exe
&lt;/path&gt;
	&lt;assemblies&gt;
		&lt;assembly&gt;Dummy.sln.nunit&lt;/assembly&gt;
	&lt;/assemblies&gt;
&lt;/nunit&gt;
</pre></p>
<p>where <strong>Dummy.sln.nunit</strong> is the Nunit project file for our solution.</p>
<p>The solution I strongly suggest is to replace the Nunit Task with an Executable Task like the one shown below:</p>
<p><pre class="brush: xml;">
&lt;exec&gt;
  &lt;executable&gt;
    C:\Program Files\NUnit 2.4.7\bin\nunit-console.exe
  &lt;/executable&gt;
  &lt;buildArgs&gt;/xml:..\project1CCnetArtifacts\nunit-results.xml
    /nologo Dummy.sln.nunit
    /exclude:LongRunning,AnotherCategoryName
  &lt;/buildArgs&gt;
&lt;/exec&gt;
</pre></p>
<p>You only need to specify the full path to the Nunit command-line executable file in the <strong>&lt;executable&gt;</strong> field and the command-line arguments in the <strong>&lt;buildArgs&gt;</strong> field.</p>
<p>In the <strong>&lt;buildArgs&gt;</strong> field you specify arguments as if provided directly to <strong>nunit-console.exe</strong>:</p>
<ol>
<li>specify the path to the file in which nunit will write its output: <span style="color:#808080;">/xml:..\project1CCnetArtifacts\nunit-results.xml</span>.<br />
The file should be produced in the artifactDirectory of the current CCNET project.<br />
By default the executable run by an executable task is run in the Project Working Directory, so the path to the output file is relative to such directory.</li>
<li> You can pass many things as Nunit targets (assemblies, Visual Studio projects or Nunit project files). I suggest to create an Nunit project and pass it as argument to <strong>nunit-console.exe</strong> as shown in the sample above (where the nunit project file is called: <strong>Dummy.sln.nunit</strong>).</li>
<li> you can then add: <span style="color:#808080;">/exclude:LongRunning,AnotherCategoryName</span> thus excluding unwanted tests.</li>
</ol>
<p>Specifying the name of the output file is not enough.<br />
In order to make the output written by nunit in the file nunit-results.xml (arbitrary name specified in the buildArgs tag), available to CruiseControl.NET we need to use a File Merge Task.<br />
If we used Nunit task the output file would have been automatically merged with other output for CruiseControl.NET.<br />
Using the Executable Task we need to explicitly configure CruiseControl.NET to merge the Nunit output file in the log file parsed by CruiseControl.NET.<br />
We will tell CruiseControl.NET to do it at the end of the build process, namely in the Publishers section.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutnunittask2"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutpublishersblock" name="ccnettutpublishersblock"></a><span style="font-size:small;color:#993300;">12. Publishers Block</span></h3>
<p>We will add a <strong>File Merge Task</strong> at the beginning of the Publishers section. You can see below the publishers section as it is defined in our project configuration file:</p>
<p><pre class="brush: xml;">
&lt;publishers&gt;
  &lt;merge&gt;
    &lt;files&gt;
      &lt;file&gt;..\project1CCnetArtifacts\nunit-results.xml
      &lt;/file&gt;
    &lt;/files&gt;
  &lt;/merge&gt;
  &lt;xmllogger /&gt;
  &lt;statistics /&gt;
  &lt;modificationHistory onlyLogWhenChangesFound=&quot;true&quot; /&gt;
  &lt;artifactcleanup cleanUpMethod=&quot;KeepLastXBuilds&quot;
    cleanUpValue=&quot;20&quot; /&gt;
      ...
&lt;/publishers&gt;
</pre></p>
<p>The File Merge Task specifies the paths to the files that we want to be merged by the <strong>Xml Log Publisher Task</strong> with the rest of its own output (you don&#8217;t need to specify nunit output file if you used the Nunit Task as in paragraph <a href="#ccnettutnunittask1">11.1. Nunit Task</a>).<br />
All of this output is placed by default in the <strong>buildlogs</strong> directory under the Project&#8217;s Artifact Directory.<br />
So the <strong>File Merge Task</strong> should appear before the <strong>Xml Log Publisher Task</strong> in the publishers section.<br />
The <strong>Xml Log Publisher Task</strong> (&#8216;<strong>xmllogger</strong>&#8216;) is needed for making the web dashboard work correctly.<br />
The &#8216;<strong>statistics</strong>&#8216; field collects and updates statistics for each build. You can see them clicking: <strong>View Statistics</strong> on the left side of the Web Dashboard.<br />
The &#8216;<strong>modificationHistory</strong>&#8216; field logs all the modifications for each build. With <strong>onlyLogWhenChangesFound</strong> you can choose to log info only for builds happened when changes take place (not for forced builds). You can see the modification history by clicking: <strong>View Modification History</strong> on the left side of the Web Dashboard.</p>
<p>I then added an &#8216;<strong>artifactcleanup</strong>&#8216; field in order to keep memory of the last 20 builds only.<br />
This task allows us to choose between two clean up modes of the past build logs:<br />
- deleting logs older than a specified number of days<br />
- keeping only a specified number of logs: the more recent ones (cleanUpMethod=&#8221;KeepLastXBuilds&#8221;)</p>
<p>In the sample above we typed the second choice specifying 20 as cleanUpValue thus telling CruiseControl.NET to keep the log files for the last 20 builds only.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutpublishersblock"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutprebuildblock" name="ccnettutprebuildblock"></a><span style="font-size:small;color:#993300;">13. PreBuild Block</span></h3>
<p>There&#8217;s another issue to solve when integrating Nunit using either an <strong>Exec Task</strong> or the <strong>Nunit Task</strong>: the Nunit log file is not deleted after the build succeeds or fails.<br />
So upon the next build we&#8217;ll still have the old Nunit log file until the Task running Nunit is executed.<br />
To understand what I&#8217;m going to explain now, keep in mind that if a task in the <strong>Tasks Block</strong> fails all the subsequent tasks in the block will be skipped while the tasks in the <strong>Publishers Block</strong> will be executed.</p>
<p>If, during the next build, the <strong>MSBuild Task</strong> fails, the <strong>Exec Task (Nunit Task)</strong> launching Nunit isn&#8217;t executed at all so the <strong>File Merge Task</strong> will merge the previous Nunit log file with the current <strong>Xml Log Publisher</strong> output, thus leading to an incorrect report: still displaying the Nunit results relative to the previous build.<br />
We would obtain the <span style="text-decoration:underline;">current</span> MSBuild report but the <span style="text-decoration:underline;">old</span> Nunit report.<br />
This behavior can lead to misunderstanding of the results so it is a good practice to delete the old Nunit log file before every new build takes place.</p>
<p>The place to accomplish this task is the <strong>PreBuild Block</strong>.<br />
I used a <strong>Nant</strong> build file to drive the steps needed to obtain the desired result (simply delete a file if it exists).</p>
<h4><a title="ccnettutinstallnant" name="ccnettutinstallnant"></a><span style="font-size:x-small;color:#993300;">13.1. Install Nant</span></h4>
<p>You need to install the <a title="nant homepage" href="http://nant.sourceforge.net/" target="_blank">Nant</a> Build tool on the server machine.<br />
Just download the zip package: nant-0.85-bin.zip from <a title="nant download" href="http://downloads.sourceforge.net/nant/nant-0.85-bin.zip?modtime=1160813010&amp;big_mirror=0" target="_blank">here</a> and unzip it into the folder: <span style="color:#808080;">C:\Program Files\Nant</span>.</p>
<h4><a title="ccnettutnantfundamentals" name="ccnettutnantfundamentals"></a><span style="font-size:x-small;color:#993300;">13.2. Nant Fundamentals</span></h4>
<p><strong>Nant</strong> is a build tool driven by xml configuration files (Nant build files).<br />
When you call nant.exe from the command line and you don&#8217;t specify a build file (you can specify one passing as argument: <span style="color:#ff6600;">-buildfile:pathToDir\FileName.build</span>) NAnt looks for a file ending with .build (e.g.: NAnt.build) in the current directory. If it finds such file, it uses it as the reference for the tasks to execute.</p>
<p>The file structure is shown in the following sample xml file:</p>
<p><pre class="brush: xml;">
&lt; ?xml version=&quot;1.0&quot;?&gt;
&lt;project name=&quot;dummy&quot; default=&quot;target1&quot; basedir=&quot;.&quot;&gt;
	&lt;description&gt;dummy project&lt;/description&gt;
	&lt;target name=&quot;target1&quot; description=&quot;target1 description&quot;&gt;
	    ... (a list of Nant tasks will be placed here)
	&lt;/target&gt;
	&lt;target name=&quot;target2&quot; description=&quot;target2 description&quot;&gt;
		&lt;delete file=&quot;pathToFile\FileName&quot;
                failonerror=&quot;false&quot; /&gt;
		... (a list of other Nant tasks will be placed here)
	&lt;/target&gt;
&lt;/project&gt;
</pre></p>
<p>A build file contains one <strong>&lt;project&gt;</strong> field with one or more children <strong>&lt;target&gt;</strong> fields each containing different Nant tasks (e.g.: the <strong>&lt;delete&gt;</strong> task).<br />
When invoking <strong>nant.exe</strong> you can specify the name of the target to be executed and Nant will execute all the tasks contained in that target. If you don&#8217;t provide a target, the default one will be executed (i.e. the one specified in the &#8216;<span style="color:#ff6600;">default</span>&#8216; attribute of the <strong>&lt;project&gt;</strong> field).</p>
<p><span style="font-size:x-small;color:#993300;">end of paragraph 13.2</span><br />
<span style="font-size:x-small;color:#993300;">continues paragraph 13. PreBuild Block</span></p>
<p>Once you&#8217;ve got Nant installed on the server machine you have to create a file named nant.build and place it, for convenience, in the directory in which you placed all the CruiseControl.NET related stuff (in this example: <span style="color:#808080;">C:\develop\CCnet</span>).</p>
<p>At the moment we need just one target to delete Nunit log files. Later we will add another target.<br />
The actual file content is the following:</p>
<p><pre class="brush: xml;">
&lt; ?xml version=&quot;1.0&quot;?&gt;
&lt;project name=&quot;Dummy&quot; default=&quot;cleanNunit&quot; basedir=&quot;.&quot;&gt;
  &lt;description&gt;CCNET Tasks&lt;/description&gt;
  &lt;target name=&quot;cleanNunit&quot;
         description=&quot;removes nunit log file&quot;&gt;
    &lt;delete file=&quot;${CCNetArtifactDirectory}\nunit-results.xml&quot;
          failonerror=&quot;false&quot; /&gt;
  &lt;/target&gt;
&lt;/project&gt;
</pre></p>
<p>When we tell Nant to execute the &#8216;<span style="color:#ff6600;">cleanNunit</span>&#8216; target, the delete task will be executed and the <strong>nunit-results.xml</strong> file will be deleted.<br />
We use one of the environment variables provided by CCNET to retrieve the path to the artifact directory: <span style="color:#ff6600;">${CCNetArtifactDirectory}</span> so this Nant build file will only work when run from CruiseControl.NET.</p>
<p>In the <strong>Prebuild Block</strong> we will instruct CruiseControl.NET to run a Nant task by adding a CruiseControl.NET <strong>Nant Task Block</strong>.<br />
Such block lets us instruct CruiseControl.NET to execute Nant and lets us specify a Nant build file and the list of Nant targets to execute.<br />
Remember that we named the build file: <strong>nant.build</strong> and we placed it in the directory: <span style="color:#808080;">C:\develop\CCnet</span>.<br />
Now we provide this information to the CruiseControl.NET <strong>Nant Task Block</strong> as shown in the following example:</p>
<p><pre class="brush: xml;">
&lt;prebuild&gt;
&lt;!-- clean nunit output to avoid CCNET reporting
       about previous build tests if current build fails --&gt;
  &lt;nant&gt;
    &lt;executable&gt;C:\Program Filse\Nant\bin\nant.exe
    &lt;/executable&gt;
    &lt;baseDirectory&gt;C:\develop\CCnet&lt;/baseDirectory&gt;
    &lt;nologo&gt;false&lt;/nologo&gt;
    &lt;buildFile&gt;nant.build&lt;/buildFile&gt;
    &lt;targetList&gt;
      &lt;target&gt;cleanNunit&lt;/target&gt;
    &lt;/targetList&gt;
  &lt;/nant&gt;
&lt;/prebuild&gt;
</pre></p>
<p>the <strong>&lt;executable&gt;</strong> field specifies the path to the version of nant.exe you want to run,<br />
the <strong>&lt;baseDirectory&gt;</strong> specifies the directory to run the NAnt process in,<br />
<strong>&lt;nologo&gt;</strong> passes the -nologo argument to the Nant command line,<br />
<strong>&lt;buildFile&gt;</strong> specifies the path to the build file to use (relative to the <strong>&lt;baseDirectory&gt;</strong>),<br />
<strong>&lt;targetList&gt;</strong> is used to specify a list of targets, each one in a <strong>&lt;target&gt;</strong> field.</p>
<p>Now we can be sure that each build has the Nunit log file deleted before being executed.</p>
<p><a href="#ccnettut2top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutprebuildblock"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><a title="tutorial part 1" href="http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/" target="_self">&lt;&lt; CruiseControl.Net Tutorial &#8211; Part 1</a></p>
<h2><span style="color:#ff0000;"><br />
As soon as possible I will post the third and last part of this tutorial<br />
</span></h2>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f06%2f15%2fcruisecontrolnet-tutorial-part-2%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f06%2f15%2fcruisecontrolnet-tutorial-part-2%2f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/88/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/88/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/88/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/88/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/88/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=88&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f06%2f15%2fcruisecontrolnet-tutorial-part-2%2f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>
	</item>
		<item>
		<title>CruiseControl.Net Tutorial &#8211; Part 1</title>
		<link>http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/</link>
		<comments>http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/#comments</comments>
		<pubDate>Sun, 01 Jun 2008 22:15:59 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[CruiseControl.NET]]></category>
		<category><![CDATA[Project Management]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[ccnet]]></category>
		<category><![CDATA[Continuous Integration]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=50</guid>
		<description><![CDATA[Suggested Books My AutoComplete Project on CodePlex 1. Introduction 2. Resources 3. Installation 3.1. Install CruiseControl.NET 3.2. Create a CCNet Website in IIS 3.3. Install Nunit 4. CruiseControl.NET Server Configuration &#8211; General 5. Structure of a &#8216;Project&#8217; Configuration File 6. Source Control Block 7. Trigger Block 8. Labeller Block 9. Tasks Block (part 2) 10. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=50&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a title="ccnettut1top" name="ccnettut1top"></a><br />
Suggested Books</p>
<table>
<tbody>
<tr>
<td>
<a href="http://www.amazon.com/gp/product/1590594851?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=1590594851"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/ccnet.jpg?w=510" alt="Expert .Net Delivery"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=1590594851" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" />
</td>
<td><a href="http://www.amazon.com/gp/product/073562609X?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=073562609X"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/architectingapplications.jpg?w=510" alt=".Net Architecting Applications For The Enterprise"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=073562609X" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" /></td>
<td>
<a href="http://www.amazon.com/gp/product/0321127420?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0321127420"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/fowlerpeaasmall.jpg?w=510" alt="Patterns of  Enterprise Application Architecture"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0321127420" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" />
</td>
<td>
<a href="http://www.amazon.com/gp/product/0201633612?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0201633612"><img border="0" src="http://ilmatte.files.wordpress.com/2010/12/gof.jpg?w=510" alt="Design Patterns"></a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0201633612" width="1" height="1" border="0" alt="" style="border:none!important;margin:0!important;" />
</td>
</tr>
</tbody>
</table>
<p>My AutoComplete Project on CodePlex</p>
<div>
<a href="http://autocompletedotnet.codeplex.com/"><br />
<img src="http://ilmatte.files.wordpress.com/2011/07/autocompletebanner.png?w=510" alt="Autocomplete Banner" /></a>
</div>
<p><a href="#ccnettutintro">1. Introduction</a><br />
<a href="#ccnettutresources">2. Resources</a><br />
<a href="#ccnettutinstallation">3. Installation</a><br />
<span style="position:relative;left:10px;"><a href="#ccnettutinstallccnet">3.1. Install CruiseControl.NET</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutiiscreatesite">3.2. Create a CCNet Website in IIS</a></span><br />
<span style="position:relative;left:10px;"><a href="#ccnettutinstallnunit">3.3. Install Nunit</a></span><br />
<a href="#ccnettutconfiguration">4. CruiseControl.NET Server Configuration &#8211; General</a><br />
<a href="#ccnettutprojectconfiguration">5. Structure of a &#8216;Project&#8217; Configuration File</a><br />
<a href="#ccnettutsourcecontrolblock">6. Source Control Block</a><br />
<a href="#ccnettuttriggerblock">7. Trigger Block</a><br />
<a href="#ccnettutlabellerblock">8. Labeller Block</a><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettuttasksblock">9. Tasks Block (part 2)</a><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutmsbuildtask">10. MsBuild Task (part 2)</a><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutreferencepath">10.1. MSBuild and ReferencePath &#8211; CruiseControl.NET not resolving reference to Nunit (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutrodemeyer">10.2. An Alternative MSBuild Logger &#8211; Christian Rodemeyer&#8217;s MsBuildToCCNet (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2#ccnettutwebdashboardimages">10.3. CruiseControl.NET Webdashboard fails in finding images if not installed in virtual directory (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2#ccnettutnumberofprojects">10.4. MSBuildToCCNET reports wrong number of compiled projects (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2#ccnettutassemblylinker">10.5. CruiseControl.NET, MsBuild Task and Resources &#8211; Assembly Linker (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2#ccnettutwebappprojects">10.6. CruiseControl.NET, MsBuild Task and Web Application projects (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutnunittask">11. Nunit Task (part 2)</a><br />
<span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutnunittask1">11.1. Nunit Task (part 2)</a></span><br />
<span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutnunittask2">11.2. Executable Task (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutpublishersblock">12. Publishers Block (part 2)</a><br />
<span style="background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutprebuildblock">13. PreBuild Block (part 2)</a><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2#ccnettutinstallnant">13.1. Install Nant (part 2)</a></span><br />
<span style="background-color:#ce9d84;"><span style="position:relative;left:10px;background-color:#ce9d84;"><a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2#ccnettutnantfundamentals">13.2. Nant Fundamentals (part 2)</a></span></span></p>
<h3><a title="ccnettutintro" name="ccnettutintro"></a><span style="font-size:small;color:#993300;">1. Introduction</span></h3>
<p>In this article series I will review the various steps needed to setup and configure a working CruiseControl.Net server.<br />
The goal is to set up a Continuous Integration process for a sample project as close as possible to a real-life project.<br />
I will point out several issues that might arise and I will provide solutions as well.<br />
I will try to underline all the details that you need to be aware of.</p>
<p>Thanks to Frank Geerlings for making me aware of a casing problem with the xml samples.<br />
By talking with the guys at WordPress support it came out that there was a little bug and they suggested me how to fix the problem.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a title="ccnettutresources" name="ccnettutresources"></a><span style="font-size:small;color:#993300;">2. Resources</span></h3>
<p>During the article I will guide you through the installation process of the following software:</p>
<p><a title="Subversion" href="http://subversion.tigris.org/" target="_blank">Subversion</a><br />
<a title="CCNET" href="http://ccnet.thoughtworks.com" target="_blank"> CruiseControl.NET</a><br />
<a title="Nunit" href="http://www.nunit.org/index.php" target="_blank">Nunit</a></p>
<p><a title="Nant" href="http://nant.sourceforge.net/" target="_blank">Nant</a><br />
<a title="Fxcop" href="http://blogs.msdn.com/fxcop/" target="_blank">FxCop</a><br />
<a title="nantcontrib" href="http://nantcontrib.sourceforge.net/" target="_blank">NantContrib</a></p>
<p>The following are optional:</p>
<p><a title="TortoiseSVN" href="http://tortoisesvn.tigris.org/" target="_blank">TortoiseSVN</a><br />
<a title="AnkhSVN" href="http://ankhsvn.open.collab.net/" target="_blank">AnkhSVN</a></p>
<p>You can find information about how to install: <a title="Subversion" href="http://subversion.tigris.org/" target="_blank">Subversion</a>, <a title="TortoiseSVN" href="http://tortoisesvn.tigris.org/" target="_blank">TortoiseSVN</a> and <a title="AnkhSVN" href="http://ankhsvn.open.collab.net/" target="_blank">AnkhSVN</a> in the article: <a title="subversion tutorial" href="http://ilmatte.wordpress.com/2008/04/27/guide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn/" target="_blank">Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN</a>.<br />
There you can also find a quick guide about how to create a Subversion repository and how to add a Visual Studio solution to source control.</p>
<p>This tutorial assumes that you have Subversion 1.4.6 installed and that you have configured a Subversion repository at the url: <span style="color:#808080;">svn://localhost/trunk</span> as shown in the article: <a title="subversion tutorial" href="http://ilmatte.wordpress.com/2008/04/27/guide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn/" target="_blank">Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN</a>.</p>
<p>If you already have a working environment with a repository and versioned files, you can go on reading and replace the paths and names in the examples with the paths and names in your environment.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutresources"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutinstallation" name="ccnettutinstallation"></a><span style="font-size:small;color:#993300;">3. Installation</span></h3>
<ul>
<li><a href="#ccnettutinstallccnet">3.1. Install CruiseControl.NET</a></li>
<li><a href="#ccnettutiiscreatesite">3.2. Create a CCNet Website in IIS</a></li>
<li><a href="#ccnettutinstallnunit">3.3. Install Nunit</a></li>
</ul>
<p>This tutorial will assume that you install CruiseControl.NET on the same machine on which you had installed the Subversion repository. So, first of all, let&#8217;s go through the steps needed to install CruiseControl.NET on your server machine.</p>
<h4><a title="ccnettutinstallccnet" name="ccnettutinstallccnet"></a><span style="font-size:x-small;color:#993300;">3.1. Install CruiseControl.NET</span></h4>
<p>Download the latest <a title="CCNET" href="http://ccnet.thoughtworks.com" target="_blank">CruiseControl.NET</a> release from: <a title="ccnet download" href="http://sourceforge.net/project/showfiles.php?group_id=71179&amp;package_id=83198" target="_blank">SourceForge</a> or the latest build from <a title="ccnet last build" href="http://ccnetlive.thoughtworks.com/CCNet-builds/" target="_blank">CCNetLive</a>.<br />
You can find release notes <a title="ccnet release notes" href="http://confluence.public.thoughtworks.org/display/CCNET/Download" target="_blank">here</a>. For this article I used the installer for version 1.4 (CruiseControl.NET-1.4-Setup.exe), downloaded from the CCNetLive website.</p>
<p>Run the setup executable file and, when prompted, you must specify your choices for a couple of actions:<br />
<span style="color:#808080;">&#8216;Install CC.Net server as windows service&#8217;</span> must be checked so that the setup will install CruiseControl as a Windows service.<br />
In the Services management console the CruiseControl service will be displayed with the name: <em>CruiseControl.NET</em>.<br />
<span style="color:#808080;">&#8216;Create virtual directory in IIS for Web dashboard&#8217;</span> will create a virtual directory named <em>ccnet</em> in the machine&#8217;s IIS web server. If you have an IIS server installation supporting multiple web sites (this is not the case for Windows XP Professional) and prefer to have a separate web site for the CCNet web dashboard you should uncheck this option. This is my choice. In the next paragraph I will show you how to create an IIS web site for the CruiseControl.NET web dashboard.</p>
<p>When the install process is finished all the content will be installed in the folder:<br />
<span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET</span> (e.g. <span style="color:#808080;">C:\Program Files\CruiseControl.NET</span>).<br />
Under this path you will find a directory called <em>server</em>, containing all the CCNet binary files and executables, and a directory called <em>webdashboard</em>, containing the CruiseControl.NET web interface.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutinstallation"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h4><a title="ccnettutiiscreatesite" name="ccnettutiiscreatesite"></a><span style="font-size:x-small;color:#993300;">3.2. Create a CCNet Website in IIS</span></h4>
<p>Here I will add and configure a Website in IIS for the CruiseControl.NET Webdashboard: the administrative interface of CruiseControl.NET.<br />
Open <strong>IIS Manager</strong> in <strong>Administrative Tools</strong>, right-click on the <strong>Web Sites</strong> node and select <strong>New Web Site</strong>.<br />
The Web site creation wizard will start.<br />
Click Next and you will be prompted for a Web Site Description.<br />
Type CCNet and click Next, leave Unassigned the IPAddress, choose a port number (say: 222) and leave empty the &#8216;Host Header for this site&#8217; field, then click Next.<br />
Choose <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\webdashboard</span> as the path for the Website and click Next.<br />
Allow &#8216;Read&#8217; and &#8216;Run scripts&#8217;, the default, and click Next. The wizard is finished and the new Website created.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutiiscreatesite"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h4><a title="ccnettutinstallnunit" name="ccnettutinstallnunit"></a><span style="font-size:x-small;color:#993300;">3.3. Install Nunit</span></h4>
<p>For the sake of our example we will need <strong>Nunit</strong> so, if you haven&#8217;t already done, install it on the same machine on which you have installed CruiseControl.NET.</p>
<p>You can find the latest <a title="nunit home" href="http://www.nunit.org/" target="_blank">Nunit</a> release <a title="nunit download" href="http://sourceforge.net/project/showfiles.php?group_id=10749&amp;package_id=89482" target="_blank">here</a> at SourceForge.<br />
This article is based on the release 2.4.6, currently the latest. You can install it by downloading: <a title="nunit 2.4.6 msi" href="http://prdownloads.sourceforge.net/nunit/NUnit-2.4.6-net-2.0.msi?download" target="_blank">NUnit-2.4.6-net-2.0.msi</a>.</p>
<p>After the installation you will have a new directory under <em>%ProgramFiles% </em>: <span style="color:#808080;">C:\%ProgramFiles%\NUnit 2.4.6</span>.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutinstallnunit"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutconfiguration" name="ccnettutconfiguration"></a><span style="font-size:small;color:#993300;">4. CruiseControl.NET Server Configuration &#8211; General</span></h3>
<p>All the configuration files we&#8217;re going to talk about are placed or are to be placed in:<br />
<span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\server</span>.</p>
<p>CruiseControl.NET comes with two server executables: <strong>ccservice.exe</strong> which is the windows service installed by the installation setup and <strong>ccnet.exe</strong> which is a console application included for testing purposes.<br />
It is much easier to debug a console application that a service so I strongly suggest to make your initial tests with ccnet.exe and carefully read the console output to get familiar with CCNet behavior.</p>
<p>Each of the two executables comes with a default configuration file (i.e.: <em>ccservice.exe.config</em> and <em>ccnet.exe.config</em>) that you don&#8217;t need to change at the moment.<br />
Moreover both the server processes (windows service or console application) look for a file named <strong>ccnet.config</strong> in which you will place all the actual information needed by CCNet to learn what it is supposed to do and how it is supposed to do it.</p>
<p><strong>ccnet.config</strong> is an xml file with a root element named <strong>&lt;cruisecontrol&gt;</strong> and a child element, named <strong>&lt;project&gt;</strong>, for each set of activities that we want CruiseControl.NET to execute, as shown in the following example:</p>
<p><pre class="brush: xml;">
&lt;cruisecontrol&gt;
&lt;project name=&quot;project1&quot;&gt;
    ...
  &lt;/project&gt;
&lt;project name=&quot;project2&quot;&gt;
    ...
  &lt;/project&gt;
&lt;/cruisecontrol&gt;
</pre></p>
<p>In this tutorial we will setup our CruiseControl.NET configuration with two logical sets of activities.<br />
For the sake of clarity we will benefit of the usage of xml entities.<br />
We&#8217;ll define each &#8216;project&#8217; configuration in a separate file and import all the files in &#8216;ccnet.config&#8217; by means of entity definitions and entity declarations:</p>
<p><pre class="brush: xml;">
&lt; !DOCTYPE cruisecontrol [
	&lt; !ENTITY project1 SYSTEM &quot;file:project1.xml.config&quot;&gt;
	&lt; !ENTITY project2 SYSTEM &quot;file:project2.xml.config&quot;&gt;
]&gt;
&lt;cruisecontrol&gt;
  &amp;project1;
  &amp;project2;
&lt;/cruisecontrol&gt;
</pre></p>
<p>Let&#8217;s focus, at first, only on the first project, so delete the second entity reference (i.e.: &amp;project2; ) thus obtaining:</p>
<p><pre class="brush: xml;">
&lt; !DOCTYPE cruisecontrol [
	&lt; !ENTITY project1 SYSTEM &quot;file:project1.xml.config&quot;&gt;
	&lt; !ENTITY project2 SYSTEM &quot;file:project2.xml.config&quot;&gt;
]&gt;
&lt;cruisecontrol&gt;
  &amp;project1;
&lt;/cruisecontrol&gt;
</pre></p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutconfiguration"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutprojectconfiguration" name="ccnettutprojectconfiguration"></a><span style="font-size:small;color:#993300;">5. Structure of a &#8216;Project&#8217; Configuration File</span></h3>
<p>What we need to do now is creating a file named: <strong>project1.xml.config</strong> in <span style="color:#808080;">C:\%ProgramFiles%\CruiseControl.NET\server</span><br />
and use it to setup CruiseControl.NET main activities.<br />
This file will contain what is called the &#8216;Project Configuration Block&#8217; for the first CCNet activity that we want to configure.<br />
First of all we need to assign a unique name to the root of the Project Configuration Block: the <strong>&lt;project&gt;</strong> tag.  We then write:</p>
<p><pre class="brush: xml;">
&lt;project name=&quot;1 - testProject&quot;&gt;
  &lt;webURL&gt;http://192.168.15.2:222&lt;/weburl&gt;
  &lt;workingDirectory&gt;C:\develop\CCnet\project1WorkingDir
  &lt;/workingDirectory&gt;
  &lt;artifactDirectory&gt;C:\develop\CCnet\project1CCnetArtifacts
  &lt;/artifactDirectory&gt;
  ...
&lt;/project&gt;
</pre></p>
<p>Let&#8217;s talk about the first three children nodes:</p>
<p><strong></strong> represents the URL at which the current project is available through the web interface. We will see later why it is useful.<br />
For now just make sure to set it to the IP of the server machine (in which you installed CCNet) and to the port that you chose for the WebDashboard website when you configured the web site in IIS (see: <a href="#ccnettutiiscreatesite">3.2. Create a CCNet Website in IIS</a>).</p>
<p><strong></strong> is the path to the main directory of this project and is meant to contain the checked out version of the project under integration<span style="color:#ff8433;">.</span><br />
This path will be accessible as an environment variable: <span style="color:#ff6600;">%CCNetWorkingDirectory%</span>, available to external scripts (we will see it later).<br />
I use to place all the projects managed with CCNET in folders under a common directory named: <span style="color:#808080;">C:\develop\CCnet</span>.<br />
For this test project I chose: <span style="color:#808080;">C:\develop\CCnet\project1WorkingDir</span>.</p>
<p>It is convenient to choose a directory in which to place all the stuff that will be used by CCNet (script files or executable files that you may want CruiseControl.NET to execute) as well as the <em>workingDirectory</em> in which CCNET will checkout the versioned files and the <em>artifactDirectory</em> in which it will output log files.<br />
In the example above I chose the directory: <span style="color:#808080;">C:\develop\CCnet</span> as the container of all CCNet related stuff.</p>
<p><strong></strong> is the path to the directory where all the build logs for this project will be placed.</p>
<p>Apart from the three tags described above, the main blocks that we&#8217;re going to add to the project configuration file are:</p>
<ul>
<li> <a href="#ccnettutsourcecontrolblock">Source Control Block</a></li>
<li> <a href="#ccnettuttriggerblock">Trigger Block</a></li>
<li> <a href="#ccnettutlabellerblock">Labeller Block</a></li>
<li> <a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettuttasksblock">9. Tasks Block</a></li>
<li> <a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutprebuildblock">13. PreBuild Block</a></li>
<li> <a href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/#ccnettutpublishersblock">12. Publishers Block</a></li>
</ul>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutprojectconfiguration"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutsourcecontrolblock" name="ccnettutsourcecontrolblock"></a><span style="font-size:small;color:#993300;">6. Source Control Block</span></h3>
<p>Source Control configuration block tells CruiseControl.NET that the project named &#8217;1 &#8211; testProject&#8217; is bound to a Subversion repository.<br />
This means that the task performed when executing this project depends on the status of that particular Subversion repository.<br />
As soon as CruiseControl.NET detects a new revision in the repository it updates its working copy and executes the tasks related to the current project.<br />
Here is the xml excerpt:</p>
<p><pre class="brush: xml;">
&lt;sourcecontrol type=&quot;svn&quot;&gt;
&lt;trunkUrl&gt;svn://localhost/trunk&lt;/trunkUrl&gt;
  &lt;workingDirectory&gt;C:\develop\CCnet\project1WorkingDir
  &lt;/workingDirectory&gt;
  &lt;username&gt;ccnet &lt;/username&gt;
&lt;password&gt; ccnet &lt;/password&gt;
&lt;/sourcecontrol&gt;
</pre></p>
<p><strong></strong> contains the url of the repository that we want to check for modifications (e.g., <span style="color:#808080;">svn://svnserver/pathToRepo</span>).<br />
As we saw in the post <a title="subversion tutorial" href="http://ilmatte.wordpress.com/2008/04/27/guide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn/" target="_blank">Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN</a>, Subversion could host several repositories under a common folder, say: <span style="color:#808080;">C:\develop\TestRepo</span>.<br />
But in that article, as well as in the current example, we set up only one repository and run svnserve with the command line: <strong>svnserve -d -r &#8220;C:\develop\test\repo&#8221;</strong>.<br />
So, specifying the server name (<em>localhost</em>) and the path to the particular repository we&#8217;re interested in, turns out to be simply: <span style="color:#808080;">svn://localhost/trunk</span> (instead of: <span style="color:#808080;">svn://localhost/SpecificRepositoryFolder/trunk</span>);<br />
<strong></strong> is the directory that will contain the working copy checked out by CCNET;<br />
<strong></strong> sets the timeout for the source control operation. It defaults to 10 minutes and you can set it to a different amount of time in milliseconds (default) or specifying units (&#8220;millis&#8221;, &#8220;seconds&#8221;, &#8220;minutes&#8221;, &#8220;hours&#8221;); I left it out thus accepting the default.<br />
If you want to set it to a different value remember to <strong><span style="text-decoration:underline;">not</span> choose a too short timeout value</strong> because if the timeout is exceeded the build will fail without providing information about the reason.<br />
In that case the only way you can retrieve the actual reason of the build failing is by analyzing CCNET log file in the <span style="color:#808080;">CruiseControl.NET\server</span> folder (if you set log4net to the debug log level)<br />
<strong></strong> and <strong></strong> must be set to a valid svn account that CCNET can use to access Subversion repository.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutsourcecontrolblock"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettuttriggerblock" name="ccnettuttriggerblock"></a><span style="font-size:small;color:#993300;">7. Trigger Block</span></h3>
<p>A trigger block is needed to specify when CruiseControl.NET will start a new integration cycle.<br />
We want to check for the repository status continuously so we need an &#8216;Interval Trigger&#8217; to tell CruiseControl.NET to perform integration periodically after a specified amount of time:</p>
<p><pre class="brush: xml;">
&lt;triggers&gt;
  &lt;intervalTrigger name=&quot;Subversion&quot; seconds=&quot;10&quot; /&gt;
&lt;/triggers&gt;
</pre></p>
<p>CruiseControl.NET, as far as project &#8217;1 &#8211; TestProject&#8217; is concerned, polls the repository every 10 seconds to see if any changes has been committed.<br />
The <span style="color:#ff9900;"><em>name</em> </span>attribute is used by CruiseControl.NET GUI to identify the trigger that requested the build;<br />
The <span style="color:#ff9900;"><em>seconds</em> </span>attribute is the amount of time before triggering the next integration cycle.</p>
<p>Each time the time interval elapses, CCNET checks for modifications and, by default, runs integration only if changes are detected.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettuttriggerblock"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<h3><a title="ccnettutlabellerblock" name="ccnettutlabellerblock"></a><span style="font-size:small;color:#993300;">8. Labeller Block</span></h3>
<p>A label is created, at each integration cycle, to identify the specific build occurred.<br />
Different labellers can be used to generate the label that CCNet will use to track the builds.</p>
<p>Other than the <em>Labeller Blocks</em> that come with the CruiseControl.NET distribution, many people provided plugin <em>Labeller Blocks</em> to target the generation of labels with specific formats.</p>
<p>A very good one, IMHO, is SvnRevisionLabeller by David Keaveny (much important to me because I recently contributed to the project).<br />
This plugin allows labelling CruiseControl.NET builds with Subversion&#8217;s repository revision numbers and I think this is a really useful feature.<br />
So this example will use SvnRevisionLabeller as the Labeller Block.<br />
For detailed information about this plugin see my post: <a title="svn revision labeller" href="http://ilmatte.wordpress.com/2008/03/05/cruisecontrolnet-and-subversion-svnrevisionlabeller/" target="_blank">CruiseControl.NET and Subversion &#8211; SvnRevisionLabeller</a>.</p>
<p>To use the SvnRevisionLabeller plugin in your installation of CruiseControl.NET you need to unzip the downloaded package and copy the assembly: <strong>ccnet.SvnRevisionLabeller.plugin.dll</strong> in the <em>server</em> folder directory under the CruiseControl.NET install path (e.g.: &#8216;C:\Program Files\CruiseControl.NET\server&#8217;).</p>
<p>Next you need to configure the <strong>Labeller Block</strong> in your project:</p>
<p><pre class="brush: xml;">
&lt;labeller type=&quot;svnRevisionLabeller&quot;&gt;
	&lt;major&gt;7&lt;/major&gt;
	&lt;minor&gt;11&lt;/minor&gt;
	&lt;url&gt;svn://localhost/trunk&lt;/url&gt;
&lt;/labeller&gt;
</pre></p>
<p>SvnRevisionLabeller will produce build labels in the format:</p>
<p><strong>major.minor.svnRevision.build</strong></p>
<p>where <strong>major</strong> and <strong>minor</strong> are the two values you set in the configuration block while <strong>svnRevision</strong> is the current version in the Subversion&#8217;s repository related to this project.<br />
The <strong>build</strong> number is automatically incremented each time a new build is forced if no further modification has been committed to the repository.</p>
<p><strong>&lt;url&gt;</strong> is the path to the repository used to retrieve the revision number (e.g. <span style="color:#808080;">svn://svnserver/pathToRepo/trunk</span>). Actually it should be filled with the same path used in the <strong>&lt;trunkUrl&gt;</strong> field of the Subversion <strong>Source Control Block</strong>.<br />
In our example it is:</p>
<p><pre class="brush: xml;">
&lt;url&gt;svn://localhost/trunk&lt;/url&gt;
</pre></p>
<p>Following is a configuration for <strong>SvnRevisionLabeller</strong> with the complete set of fields:</p>
<p><pre class="brush: xml;">
&lt;labeller type=&quot;svnRevisionLabeller&quot;&gt;
&lt;prefix&gt;Test-&lt;/prefix&gt;
  &lt;major&gt;7&lt;/major&gt;
  &lt;minor&gt;11&lt;/minor&gt;
  &lt;url&gt;svn://localhost/trunk&lt;/url&gt;
  &lt;username&gt;ccnet&lt;/username&gt;
&lt;password&gt;ccnet&lt;/password&gt;
&lt;/labeller&gt;
</pre></p>
<p>Such a configuration will produce a label with the following format: <strong>Test-major.minor.svnRevision.build</strong>.<br />
<strong>&lt;username&gt;</strong> and <strong>&lt;password&gt;</strong> are the username and password of a valid Subversion account for the repository specified in the <strong>&lt;url&gt;</strong> field.</p>
<p>You can use in an external script the build label produced, which is stored in an environment variable.<br />
It can be useful to flag release version of output dlls.<br />
You can access the build number from a script with the syntax: <span style="color:#ff6600;">%CCNetLabel%</span> or from a C# application with the following row:</p>
<p><pre class="brush: csharp;">
Environment.GetEnvironmentVariable(&quot;ccnetlabel&quot;);
</pre></p>
<p>If you used the SolutionInfo approach in your Visual Studio solution (see my post: <a title="solutioninfo" href="http://ilmatte.wordpress.com/2008/02/10/solutioninfo-and-partitioned-single-solution/#introductionsolutioninfo1" target="_blank">SolutionInfo and Partitioned Single Solution</a>) you can use the build label produced by <strong>SvnRevisionLabeller</strong> to update the <strong>AssemblyFileVersion</strong> attribute in the SolutionInfo.cs file.<br />
In this way you can provide consistent versioning of the released assemblies together with easy trackability of the corresponding source code&#8217;s revision.</p>
<p>Be careful not to use the &lt;prefix&gt; tag in this case because you need to set <strong>AssemblyFileVersion</strong> to a string in the format:<br />
<strong>major.minor.svnRevision.build</strong><br />
with all of the 4 fields being numerical values.</p>
<p><a href="#ccnettut1top"><span style="font-size:80%;color:red;">→ top of post</span></a><br />
<a href="#ccnettutlabellerblock"><span style="font-size:80%;color:red;">→ top of paragraph</span></a></p>
<p><span style="position:relative;left:50px;"><a title="tutorial part 2" href="http://ilmatte.wordpress.com/2008/06/15/cruisecontrolnet-tutorial-part-2/" target="_self">CruiseControl.Net Tutorial &#8211; Part 2 &gt;&gt;</a></span></p>
<p><a href="#ccnettutlabellerblock"></a><br />
<a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f06%2f01%2fcruisecontrolnet-tutorial-part-1%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f06%2f01%2fcruisecontrolnet-tutorial-part-1%2f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/50/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/50/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/50/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/50/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/50/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/50/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/50/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/50/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/50/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=50&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/06/01/cruisecontrolnet-tutorial-part-1/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/ccnet.jpg" medium="image">
			<media:title type="html">Expert .Net Delivery</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=1590594851" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/architectingapplications.jpg" medium="image">
			<media:title type="html">.Net Architecting Applications For The Enterprise</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=073562609X" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/fowlerpeaasmall.jpg" medium="image">
			<media:title type="html">Patterns of  Enterprise Application Architecture</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0321127420" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2010/12/gof.jpg" medium="image">
			<media:title type="html">Design Patterns</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0201633612" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2011/07/autocompletebanner.png" medium="image">
			<media:title type="html">Autocomplete Banner</media:title>
		</media:content>

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f06%2f01%2fcruisecontrolnet-tutorial-part-1%2f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>
	</item>
		<item>
		<title>Line Continuation Character</title>
		<link>http://ilmatte.wordpress.com/2008/05/01/line-continuation-character/</link>
		<comments>http://ilmatte.wordpress.com/2008/05/01/line-continuation-character/#comments</comments>
		<pubDate>Thu, 01 May 2008 09:18:03 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[Command line]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[bat]]></category>
		<category><![CDATA[batch]]></category>
		<category><![CDATA[caret]]></category>
		<category><![CDATA[line continuation character]]></category>
		<category><![CDATA[Makefile]]></category>
		<category><![CDATA[vbscript]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=85</guid>
		<description><![CDATA[In this post I list the new line character for batch scripts, Makefile files and VBScript scripts. A while ago I spent a lot of time for finding information about which character was the line continuation character in a Windows batch script. The line continuation character allows us to split a line of code in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=85&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In this post I list the new line character for batch scripts, Makefile files and VBScript scripts.</p>
<p>A while ago I spent a lot of time for finding information about which character was the line continuation character in a Windows batch script.<br />
The line continuation character allows us to split a line of code in multiple lines while letting the command interpreter know that the current command is not ending upon newline but is going on in the next line.<br />
This is particularly useful if you want to format your scripts to make them more readable.<br />
Here is a list of newline line continuation characters in few scripting languages:</p>
<ol>
<li><span style="color:#0000ff;">Batch (.bat):  ^ (caret)</span></li>
<li><span style="color:#0000ff;">Nmake (Makefile):  \ (backslash)</span></li>
<li><span style="color:#0000ff;">VBScript (.vbs):  _ (underscore)</span></li>
</ol>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/85/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/85/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/85/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/85/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/85/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=85&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/05/01/line-continuation-character/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>
	</item>
		<item>
		<title>Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN</title>
		<link>http://ilmatte.wordpress.com/2008/04/27/guide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn/</link>
		<comments>http://ilmatte.wordpress.com/2008/04/27/guide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn/#comments</comments>
		<pubDate>Sun, 27 Apr 2008 19:03:51 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[AnkhSVN]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[TortoiseSVN]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Studio 2005]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=52</guid>
		<description><![CDATA[1. Introduction 2. Resources 3. Prerequisites &#8211; Install Software 4. Setup a Subversion Repository with the Help of TortoiseSVN 4.1. Create a Repository 4.2. Set a Security Policy 4.3. Run Subversion Server Process 5. Checkout a Working Copy 6. Add content and Commit 6.1. Add a Text File to Versioning 6.2. Add a Visual Studio [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=52&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a title="svntuttop" name="svntuttop"></a><br />
<a href="#svntutintro">1. Introduction</a><br />
<a href="#svntutresources">2. Resources</a><br />
<a href="#svntutprerequisites">3. Prerequisites &#8211; Install Software</a><br />
<a href="#svntutsetuprepo">4. Setup a Subversion Repository with the Help of TortoiseSVN</a><br />
<span style="position:relative;left:10px;"><a href="#svntutcreaterepo">4.1. Create a Repository</a></span><br />
<span style="position:relative;left:10px;"><a href="#svntutpwd">4.2. Set a Security Policy</a></span><br />
<span style="position:relative;left:10px;"><a href="#svntutrunsvn">4.3. Run Subversion Server Process</a></span><br />
<a href="#svntutwk">5. Checkout a Working Copy</a><br />
<a href="#svntutcommit">6. Add content and Commit</a><br />
<span style="position:relative;left:10px;"><a href="#svntutcommittextfile">6.1. Add a Text File to Versioning</a></span><br />
<span style="position:relative;left:10px;"><a href="#svntutcommitvssolution">6.2. Add a Visual Studio Solution to Versioning (TortoiseSVN)</a></span><br />
<span style="position:relative;left:10px;"><a href="#svntutankh">6.3. Add a Visual Studio Solution to Versioning (AnkhSVN)</a></span><br />
<a href="#svntutservice">7. Install Subversion as a Service</a></p>
<h3><a title="svntutintro" name="svntutintro"></a><span style="color:#993300;font-size:small;">1. Introduction</span></h3>
<p>In this article I will describe the process of setting up a working Subversion server, creating a repository and add to versioning a Visual Studio solution to work with.</p>
<h3><a title="svntutresources" name="svntutresources"></a><span style="color:#993300;font-size:small;">2. Resources</span></h3>
<p>During this article I will guide you through the installation process of the following software:</p>
<p><a title="svn" href="http://subversion.tigris.org/" target="_blank">Subversion</a><br />
<a title="TortoiseSVN" href="http://tortoisesvn.tigris.org/" target="_blank">TortoiseSVN</a><br />
<a title="AnkhSVN" href="http://ankhsvn.open.collab.net/" target="_blank">AnkhSVN</a></p>
<p><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutresources"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></p>
<h3><a title="svntutprerequisites" name="svntutprerequisites"></a><span style="color:#993300;font-size:small;">3. Prerequisites &#8211; Install Software</span></h3>
<ul>
<li><a href="#installsvn">Install Subversion</a></li>
<li><a href="#installtortoise">Install TortoiseSVN</a></li>
<li><a href="#installankh">Install AnkhSVN</a></li>
</ul>
<h4><a title="installsvn" name="installsvn"></a><span style="color:#993300;font-size:x-small;">Install Subversion</span></h4>
<p>Download the latest Subversion release from the <a title="downloadpage" href="http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91&amp;expandFolder=91&amp;folderID=74" target="_blank">download page</a> and launch the installer. At the moment I&#8217;m writing the last available version is: <a title="svndownload" href="http://subversion.tigris.org/files/documents/15/41686/svn-1.4.6-setup.exe" target="_self">svn-1.4.6-setup.exe</a>.<br />
Subversion will be installed under: <span style="color:#808080;">C:\Program Files\Subversion</span>.</p>
<p>Make sure that <span style="color:#808080;">C:\Program Files\Subversion\bin</span> is included in the %PATH% environment variable, otherwise add it following these steps:<br />
right-click MyComputer and choose <strong>Properties </strong>&#8211;&gt; <strong>Advanced</strong>, then click the button: <strong>Environment Variables</strong>.<br />
Look for the name: <em>Path </em>between variable names (left column) in the bottom list.<br />
Once found double click it, add a semi-colon to the &#8216;<em>variable value</em>&#8216; field and paste the path to Subversion bin directory (<span style="color:#808080;">C:\Program Files\Subversion\bin</span>).<br />
Click ok three times to accept the changes.</p>
<p>Now open a command prompt and digit <strong>svn help</strong>. You should be able to see svn syntax information.<br />
The installation succeeded. Now go on to the next step: Install TortoiseSVN</p>
<p><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutresources"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></p>
<h4><a title="installtortoise" name="installtortoise"></a><span style="color:#993300;font-size:x-small;">Install TortoiseSVN</span></h4>
<p>Download the latest TortoiseSVN release from the <a title="tortoisesvnhome" href="http://tortoisesvn.net/downloads" target="_blank">download page</a>: <a title="tortoisesvn" href="http://downloads.sourceforge.net/tortoisesvn/TortoiseSVN-1.4.8.12137-win32-svn-1.4.6.msi?download" target="_blank">TortoiseSVN-1.4.8.12137-win32-svn-1.4.6.msi</a> and launch the installer.</p>
<p><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutresources"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></p>
<h4><a title="installankh" name="installankh"></a><span style="color:#993300;font-size:x-small;">Install AnkhSVN</span></h4>
<p>Download the latest AnkhSVN release: <a title="ankhsvn" href="http://ankhsvn.open.collab.net/servlets/OCNDownload?id=ANKHSVN102" target="_blank">AnkhSetup-1.0.2.2778-Final.msi</a> from the <a title="ankhsvndownloadpage" href="http://ankhsvn.open.collab.net/servlets/ProjectProcess?pageID=3794&amp;_=d" target="_blank">download page</a> and launch the installer.</p>
<p>Now that you have installed it, forget it for a while and step through the next paragraphs.</p>
<p><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutresources"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></p>
<h3><a title="svntutsetuprepo" name="svntutsetuprepo"></a><span style="color:#993300;font-size:small;">4. Setup a Subversion Repository with the Help of TortoiseSVN</span></h3>
<ul>
<li><a href="#svntutcreaterepo">4.1. Create a Repository</a></li>
<li><a href="#svntutpwd">4.2. Setup a Security Policy</a></li>
<li><a href="#svntutrunsvn">4.3. Run Subversion Server Process</a></li>
</ul>
<p>Now you have a very cool GUI for Subversion provided by TortoiseSVN.<br />
In the following paragraphs we will setup a Subversion repository on the local machine and we will start working with it.</p>
<h4><a title="svntutcreaterepo" name="svntutcreaterepo"></a><span style="color:#993300;font-size:x-small;">4.1. Create a Repository</span></h4>
<p>Create a new directory, e.g.: <span style="color:#808080;">C:\develop\test\repo</span>, right click it and choose: <strong>TortoiseSVN </strong>&#8211;&gt; <strong>Create repository here&#8230;</strong> (see: Figure 1).<br />
Accept the preselected option: <em>Native filesystem (FSFS)</em> at the prompt and click ok (see: Figure 2).<br />
The new repository will be created and an informational message will tell you that &#8216;<em>The Repository was successfully created</em>&#8216;.</p>
<p><img class="size-medium wp-image-53" src="http://ilmatte.files.wordpress.com/2008/04/createrepohere.jpg?w=300&#038;h=220" alt="Create repo here" width="300" height="220" /></p>
<div style="font-size:x-small;"><strong>Figure 1.</strong> Context menu for the &#8216;repo&#8217; directory</div>
<p><img src="http://ilmatte.files.wordpress.com/2008/04/repocreated.jpg?w=510" alt="choose file system type for Repository" /></p>
<div style="font-size:x-small;"><strong>Figure 2. </strong>Filesystem choice for the repository</div>
<p>Now let&#8217;s add some content. First of all prepare the standard layout: create a temporary directory next to the <em>repo</em> directory and call it <em>temp</em>: <span style="color:#808080;">C:\develop\test\temp</span>. Add three subdirectories inside it, named: <strong>trunk</strong>, <strong>tags</strong>, <strong>branches</strong>.<br />
The <strong>trunk</strong> directory will become the main directory of our project and it will contain all the versioned data.<br />
Right click on <span style="color:#808080;">C:\develop\test\temp</span> and choose: <strong>TortoiseSVN &#8211;&gt; Import&#8230;</strong> and the Import window will open. Click the button on the right of the combobox: &#8216;<em>URL of repository</em>&#8216; (as shown in Figure 3).</p>
<p><img class="alignnone size-full wp-image-59" src="http://ilmatte.files.wordpress.com/2008/04/importwindow.jpg?w=510" alt="import window"   /></p>
<div style="font-size:x-small;"><strong>Figure 3.</strong> Import window.</div>
<p>A <strong>browse</strong> pop up window will open. Browse to the repository directory: <span style="color:#808080;">C:\develop\test\repo</span> and click <strong>OK</strong>.<br />
The combobox will be filled with: <span style="color:#808080;">file:///C:/develop/Test/repo</span>.<br />
Write the comment &#8216;<em>Initial Repository Layout</em>&#8216; in the &#8216;<em>Import Message</em>&#8216; text area at the bottom of the Import window and click <strong>OK</strong> (see: Figure 4).<br />
Everything should be alright and the informational window shown in Figure 5 should appear. You can click <strong>OK</strong> and the repository layout is ready.</p>
<p><img class="alignnone size-full wp-image-60" src="http://ilmatte.files.wordpress.com/2008/04/importwindowset.jpg?w=510" alt="import window set"   /></p>
<div style="font-size:x-small;"><strong>Figure 4.</strong> Import window with with repository path set.</div>
<p><img class="alignnone size-medium wp-image-58" src="http://ilmatte.files.wordpress.com/2008/04/initialdirsadded.jpg?w=510&#038;h=278" alt="Trunk dir added" width="510" height="278" /></p>
<div style="font-size:x-small;"><strong>Figure 5.</strong> Import operation succeeded.</div>
<p>Now you can delete the temporary directory: <span style="color:#808080;">C:\develop\test\temp</span>.</p>
<div><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutsetuprepo"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></div>
<h4><a title="svntutpwd" name="svntutpwd"></a><span style="color:#993300;font-size:x-small;">4.2. Setup a Security Policy</span></h4>
<p>Before starting to use your freshly created repository you must set a security policy, that is, you must create user accounts for the repository.<br />
First of all open the file: <span style="color:#808080;">C:\develop\test\repo\conf\svnserve.conf</span>.<br />
Have a read to the file and notice that all lines are commented (the pound character: # is the comment character).<br />
Uncomment rows 12 and 13, remove any leading spaces at the beginning of the rows and change them to fit your security policy.<br />
You can, for instance, decide to deny access to the repository to anonymous users and to unauthorized ones while giving full access to authorized users.<br />
To obtain this result set those two lines as follows:</p>
<blockquote><p>anon-access = none<br />
auth-access = write</p></blockquote>
<p>Then uncomment row 18 to tell Subversion where the user accounts information will be stored:</p>
<blockquote><p>password-db = passwd</p></blockquote>
<p>where &#8216;<span style="color:#808080;">passwd</span>&#8216; is the name of a file in the same directory as &#8216;<span style="color:#808080;">svnserve.conf</span>&#8216; (<span style="color:#808080;">C:\develop\test\repo\conf\passwd</span>).<br />
Open the &#8216;<span style="color:#808080;">passwd</span>&#8216; file and you will find two example rows, at rows 7 and 8, showing the syntax to define users:</p>
<blockquote><p># harry = harryssecret<br />
# sally = sallyssecret</p></blockquote>
<p>The two lines are commented but they clearly show that the syntax is:</p>
<blockquote><p>user = password</p></blockquote>
<p>Add information about the account that you will use to access the repository (e.g.: test = test).</p>
<div><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutpwd"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></div>
<h4><a title="svntutrunsvn" name="svntutrunsvn"></a><span style="color:#993300;font-size:x-small;">4.3. Run Subversion Server Process</span></h4>
<p>You can simply start svn server process from the command line.<br />
Open a command prompt and digit:</p>
<blockquote><p>svnserve -d -r &#8220;C:\develop\test\repo&#8221;</p></blockquote>
<p>and you&#8217;re done!<br />
If you prefer to run Subversion in order to let it manage different repositories placed under a common directory, you can run the Subversion server process in that directory, e.g.:</p>
<blockquote><p>svnserve -d -r &#8220;C:\develop&#8221;.</p></blockquote>
<p>The row above will let Subversion be able to expose repositories placed in the paths:</p>
<blockquote><p>C:\develop\TestRepo1<br />
C:\develop\TestRepo2<br />
&#8230;</p></blockquote>
<p>If you prefer to run Subversion as a Windows service, have a look at the paragraph: <a title="install as a service" href="#svntutservice" target="_self">Install Subversion as a Service</a>.</p>
<div><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutrunsvn"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></div>
<h3><a title="svntutwk" name="svntutwk"></a><span style="color:#993300;font-size:small;">5. Checkout a Working Copy</span></h3>
<p>Now you can prepare your workin copy or, in Subversion language, checkout your working copy.<br />
Create a new directory named &#8216;wk&#8217;: <span style="color:#808080;">C:\develop\test\wk</span>.<br />
Right-click the directory: <span style="color:#808080;">C:\develop\test\repo</span> and choose: <strong>SVN Checkout&#8230;</strong>. The Checkout panel will open.<br />
Notice that the box: &#8216;<em>URL of repository</em>&#8216; is already filled with the path: <span style="color:#808080;">file:///C:/develop/test/repo</span> (see: Figure 6).</p>
<p><img class="alignnone size-full wp-image-61" src="http://ilmatte.files.wordpress.com/2008/04/checkout.jpg?w=510" alt="Checkout wk"   /></p>
<div style="font-size:x-small;"><strong>Figure 6.</strong> Checkout window.</div>
<p>You need to modify that path to match the exact path to the repository and you can do it in one of two ways:</p>
<ul>
<li>Just add &#8216;<em>trunk</em>&#8216; to the path, because we want that only the content under that directory is copied in our working copy.<br />
The &#8216;<em>URL of repository</em>&#8216; will then be: <span style="color:#808080;">file:///C:/develop/test/repo/trunk</span>.<br />
This choice doesn&#8217;t need to have svnserve running and it&#8217;s good for a local test environment.</li>
<li>If you want to use Subversion through your network (i.e. in a real environment) and if you want to take advantage of the Subversion security policy that we have set up in the previous paragraph, you&#8217;d better use this alternative option:<br />
Let&#8217;s assume that you have run svnserve with the following row: <span style="color:#888888;">svnserve -d -r &#8220;C:\develop\test\repo&#8221;</span> as explained in <a title="link to run svn" href="#svntutrunsvn" target="_self">paragraph 4.3.</a><br />
Delete the content of the &#8216;<em>URL of repository</em>&#8216; box and replace it with: &#8216;<strong>svn://localhost/trunk</strong>&#8216;.<br />
The example is provided assuming Subversion server installed on the local machine but you can replace <em>localhost</em> with the server machine name or IP address.<br />
We need to specify the path of the repository relative to the working directory of Subversion (svnserve), which is: <span style="color:#808080;">C:\develop\test\repo</span>, so the path that we specify is simply: <span style="color:#808080;">trunk</span>.</li>
</ul>
<p>In the rest of the article we will assume the second choice.<br />
After having set the &#8216;<em>URL of repository</em>&#8216; we must fill the &#8216;<em>Checkout directory</em>&#8216; box and we can do it browsing to <span style="color:#808080;">C:\develop\wk</span> by means of the adjacent button (see: Figure 7).<br />
Make sure that &#8216;<em>HEAD revision</em>&#8216; is checked and click <strong>OK</strong>.</p>
<p><img class="alignnone size-full wp-image-62" src="http://ilmatte.files.wordpress.com/2008/04/checkoutfilled.jpg?w=510" alt="Checkout box filled"   /></p>
<div style="font-size:x-small;"><strong>Figure 7.</strong> Checkout window filled.</div>
<p>If you have set the &#8216;<em>URL of repository</em>&#8216; to <span style="color:#808080;">svn://localhost/trunk</span> you will be prompted for username and password (see Figure 8).</p>
<p><img class="alignnone size-full wp-image-63" src="http://ilmatte.files.wordpress.com/2008/04/userpwprompt.jpg?w=510" alt="Prompt for username and password"   /></p>
<div style="font-size:x-small;"><strong>Figure 8.</strong> Prompt for username and password.</div>
<p>Fill both fields with: &#8216;<em>test</em>&#8216; or whatever account information you configured in the paragraph: <a href="#svntutpwd">4.2. Set a Security Policy</a> and flag the &#8216;<em>Save authentication</em>&#8216; checkbox, then click <strong>OK</strong>.<br />
An informational window will appear stating that the checkout was succesfully created (see: Figure 9).</p>
<p><img class="alignnone size-full wp-image-64" src="http://ilmatte.files.wordpress.com/2008/04/checkoutcomplete.jpg?w=510&#038;h=278" alt="Checkout complete info" width="510" height="278" /></p>
<div style="font-size:x-small;"><strong>Figure 9.</strong> Checkout completed.</div>
<p>Close that window and look inside the <span style="color:#808080;">C:\develop\wk</span> directory.<br />
The <strong>wk</strong> directory has been filled with the content from the repository&#8217;s trunk directory, that is the directory is empty.<br />
Actually it&#8217;s not quite empty: there&#8217;s a directory named <strong>.svn</strong> inside it.<br />
Such directory contains all the information needed by Subversion to keep track of the history of all the files that will be added to versioning inside this directory.<br />
Now let&#8217;s go to the following step and start adding content.</p>
<div><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutwk"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></div>
<h3><a title="svntutcommit" name="svntutcommit"></a><span style="color:#993300;font-size:small;">6. Add content and Commit</span></h3>
<ul>
<li><a href="#svntutcommittextfile">6.1. Add a Text File to Versioning</a></li>
<li><a href="#svntutcommitvssolution">6.2. Add a Visual Studio Solution to Versioning (TortoiseSVN)<br />
</a></li>
<li><a href="#svntutankh"></a><a href="#svntutankh">6.3. Add a Visual Studio Solution to Versioning (AnkhSVN)</a></li>
</ul>
<h4><a title="svntutcommittextfile" name="svntutcommittextfile"></a><span style="color:#993300;font-size:x-small;">6.1. Add a Text File to Versioning</span></h4>
<p>Let&#8217;s add a simple text file to versioning: create a file named &#8216;<em>test.txt</em>&#8216; inside <span style="color:#808080;">C:\develop\wk</span>.<br />
Right-click it and choose: <strong>TortoiseSVN &#8211;&gt; Add&#8230;</strong> (see: Figure 10), then click <strong>OK</strong> at the following two prompts and you will see an overlay blue plus icon above your file meaning that the file has been scheduled for inclusion in the repository upon the next commit.</p>
<p><img class="alignnone size-medium wp-image-65" src="http://ilmatte.files.wordpress.com/2008/04/tortoiseadd.jpg?w=281&#038;h=300" alt="Add new file" width="281" height="300" /></p>
<div style="font-size:x-small;"><strong>Figure 10.</strong> Add file to Versioning.</div>
<p>If you can&#8217;t see the overlay icon, just press F5 to refresh the screen.<br />
Now execute your first commit thus sending the new file to the repository. From now on, its changes will be tracked by the Subversion versioning system.<br />
If you want to commit the content of the directory all at once (only one file at the moment) just go up one level, right click on the directory: <span style="color:#808080;">C:\develop\wk</span> and choose: <strong>SVN &#8211;&gt; Commit&#8230;</strong> (see: Figure 11).<br />
If you checked the &#8216;<em>Save authentication</em>&#8216; checkbox when checking out the working copy (as shown in <a href="#svntutwk">5. Checkout a Working Copy</a>) you won&#8217;t be prompted, now, for username and password.</p>
<p><img class="alignnone size-medium wp-image-66" src="http://ilmatte.files.wordpress.com/2008/04/tortoisecommit.jpg?w=261&#038;h=187" alt="commit context menu" width="261" height="187" /></p>
<div style="font-size:x-small;"><strong>Figure 11.</strong> Commit working copy content with TortoiseSVN.</div>
<p>The Log Message window will open (see: Figure 12), waiting for you to provide a meaningful message. Write: &#8220;Added empty test file&#8221; and click <strong>OK</strong>.</p>
<div style="font-size:x-small;"><img class="alignnone size-medium wp-image-67" src="http://ilmatte.files.wordpress.com/2008/04/commitmessagedialog.jpg?w=280&#038;h=300" alt="commit message" width="280" height="300" /></div>
<div style="font-size:x-small;"><strong>Figure 12.</strong> Provide a meaningful message before committing.</div>
<p>Make sure that everything worked fine when the informational window titled: &#8216;<strong>wk &#8211; TortoiseSVN Commit&#8230; Finished!</strong>&#8216; will appear.<br />
It should state something like: &#8216;<em>Completed At revision: 1</em>&#8216;.<br />
If everything is alright then click <strong>OK</strong>.</p>
<p>Now you can start adding content to the file and commit the changes to the repository.</p>
<p><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutcommit"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></p>
<h4><a title="svntutcommitvssolution" name="svntutcommitvssolution"></a><span style="color:#993300;font-size:x-small;">6.2. Add a Visual Studio Solution to Versioning (TortoiseSVN)<br />
</span></h4>
<p>Let&#8217;s talk about versioning a Visual Studio solution (I won&#8217;t talk here about how to create Visual Studio solutions and projects).<br />
Open Visual Studio (I&#8217;m working with Visual Studio 2005) and create a new blank solution inside <span style="color:#808080;">C:\develop\wk</span>.<br />
Name the solution: <strong>DummySolution.sln</strong> and add two projects to the solution:<br />
<strong>DummyProject.csproj</strong> and <strong>DummyProject.Tests.csproj</strong>.<br />
The first is a Class Library project and the second is a <strong>Nunit</strong> Tests project referencing <strong>DummyProject</strong>.<br />
If you&#8217;re using Nunit and RhinoMocks you can take advantage of the project Template I provide with the <a title="TDDTemplatesDownload" href="http://www.box.net/shared/20nsbuego0" target="_blank">TDDTemplates.vsi</a> (see article: <a title="tddtemplates article" href="http://ilmatte.wordpress.com/2008/01/15/visual-studio-nunit-rhinomocks-templates/" target="_blank">Visual Studio Nunit &amp; Rhino Mocks Templates</a>) installer to easily create the unit tests project.<br />
Now you can add the solution to versioning in one of two ways:</p>
<ol>
<li>adding the solution file and the projects directories with TortoiseSVN;</li>
<li>installing AnkhSVN and versioning the solution directly from Visual Studio;</li>
</ol>
<p>In this paragraph we&#8217;ll see the first option while in the next paragraph we will repeat the same actions with AnkhSVN.</p>
<p>At first select the solution file: <em>DummySolution.sln</em> and the two project directories: <em>DummyProject </em>and <em>DummyProject.Tests</em>.<br />
Be careful not to select the file: <em>DummySolution.suo</em>, which contains solution-wide configuration data specific to every developer&#8217;s machine.<br />
Then right-click one of the selected items and choose: <strong>TortoiseSVN &#8211;&gt; Add&#8230;.</strong>.<br />
In the <strong>Add</strong> window (see: Figure 13) uncheck the directories: <strong>bin</strong> and <strong>obj</strong> of each project and the files: <em>DummyProject.csproj.user</em> and <em>DummyProject.Tests.csproj.user</em> if you find any of them in the list of checked items.<br />
Click <strong>OK</strong> and a report window, titled: <strong>TortoiseSVN Add&#8230; Finished!</strong>, should appear if everything worked well. Click <strong>OK</strong> again as you did for the &#8216;test.txt&#8217; file.<br />
Now all the content needed is scheduled to be added to versioning upon the next commit action.</p>
<p><img class="alignnone size-full wp-image-71" src="http://ilmatte.files.wordpress.com/2008/04/addtosvn.jpg?w=510" alt="Add with TortoiseSVN"   /></p>
<div style="font-size:x-small;"><strong>Figure 13.</strong> Add window.</div>
<p>Now you can commit the freshly added content to the repository: right click on the directory <span style="color:#808080;">C:\develop\wk</span> and choose: <strong>SVN &#8211;&gt; Commit&#8230;</strong> as you did when you added the <em>test.txt</em> file.</p>
<div><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutcommit"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></div>
<h4><a title="svntutankh" name="svntutankh"></a><span style="color:#993300;font-size:x-small;">6.3. Add a Visual Studio Solution to Versioning (AnkhSVN)</span></h4>
<p>As an alternative to previous paragraph, we can add the Visual Studio solution to versioning directly from the Visual Studio GUI with the help of AnkhSVN.</p>
<p>Before reading the current paragraph you need to install AnkhSVN as in <a href="#installankh">Install AnkhSVN</a>.</p>
<p>Open the solution file: <em>DummySolution.sln</em> with Visual Studio 2005.<br />
A little prompt window (see: Figure 14) will ask if you want to enable AnkhSVN for the current solution:</p>
<p><img class="alignnone size-full wp-image-72" src="http://ilmatte.files.wordpress.com/2008/04/ankhprompt.jpg?w=510" alt="Enable ankhsvn"   /></p>
<div style="font-size:x-small;"><strong>Figure 14.</strong> Enable AnkhSVN for current solution.</div>
<p>Click <strong>No</strong> and go to solution explorer. Right-click the solution item and choose:<br />
<strong>Ankh &#8211;&gt; Add solution to Subversion repository&#8230;</strong> as shown in Figure 15:</p>
<p><img class="alignnone size-full wp-image-73" src="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolution.jpg?w=510" alt="ankhsvn add solution"   /></p>
<div style="font-size:x-small;"><strong>Figure 15.</strong> AnkhSVN: add solution to subversion repository.</div>
<p>The appropriate window will pop up (see: Figure 16) asking you the repository url. Fill the <strong>URL</strong> textbox with: <span style="color:#808080;">svn://localhost/trunk</span> , leave &#8216;<em>Create subdirectory</em>&#8216; unchecked and click <strong>OK</strong>.</p>
<p><img class="alignnone size-full wp-image-74" src="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolution2.jpg?w=510" alt="ankh add solution prompt"   /></p>
<div style="font-size:x-small;"><strong>Figure 16.</strong> AnkhSVN: add solution prompt window.</div>
<p>You will be prompted for username and password (they are managed separately by <strong>TortoiseSVN</strong> and by <strong>AnkhSVN</strong>) as shown in Figure 17.<br />
Fill both the fields and check &#8216;<em>Save credentials</em>&#8216;.</p>
<p><img class="alignnone size-full wp-image-75" src="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolution3.jpg?w=510" alt="AnkhSVN username and password"   /></p>
<div style="font-size:x-small;"><strong>Figure 17.</strong> AnkhSVN: provide username and password.</div>
<p>Upon clicking the <strong>OK</strong> button one more window will popup showing you the files that AnkhSVN is going to add to the repository and waiting for you to add a meaningful log message for the commit (see: Figure 18).<br />
AnkhSVN already left out the directories: <strong>bin</strong>, <strong>obj</strong> and their content as well as files: <strong>DummyProject.csproj .user</strong> and <strong>DummyProject.Tests.csproj.user</strong> that you had to manually uncheck when using TorotoiseSVN.<br />
Write something like: &#8216;<em>Added Visual Studio solution</em>&#8216; and click the <strong>Commit</strong> button.</p>
<p><img class="alignnone size-full wp-image-78" src="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolutionlogmessage.jpg?w=510&#038;h=408" alt="ankh add log message" width="510" height="408" /></p>
<div style="font-size:x-small;"><strong>Figure 18.</strong> AnkhSVN: provide meaningful log message.</div>
<p>A <em>Committing</em> progress bar will appear and, upon success, the solution explorer will be updated with green icons before the names of versioned items (see: Figure 19).</p>
<p><img class="alignnone size-medium wp-image-79" src="http://ilmatte.files.wordpress.com/2008/04/ankhsolutionexplorergreen.jpg?w=277&#038;h=199" alt="ankh green solution explorer" width="277" height="199" /></p>
<div style="font-size:x-small;"><strong>Figure 19.</strong> AnkhSVN: Solution explorer.</div>
<p>Now that AnkhSVN is enabled for this solution, each time you add a new item to a project it will be marked with a question mark icon to let you know that the file is not added to versioning (see: Figure 20).<br />
Let&#8217;s see it in action by adding a new item in solution explorer:<br />
right-click on <strong>DummyProject</strong> and choose: <strong>Add &#8211;&gt; New Item&#8230;</strong>, select the <strong>Class</strong> item template, leave the default name (should be <em>Class2.cs</em>) and click the <strong>Add</strong> button.</p>
<p><img class="alignnone size-full wp-image-80" src="http://ilmatte.files.wordpress.com/2008/04/ankhnewitem.jpg?w=510" alt="Solution explorer with new item"   /></p>
<div style="font-size:x-small;"><strong>Figure 20.</strong> AnkhSVN: Solution explorer with new item.</div>
<p>If you right-click on the solution in solution explorer and choose: <strong>Ankh &#8211;&gt; Add&#8230;</strong> a new window will open, whose title is: <em>Select items to add</em> (see: Figure 21).<br />
It contains the list of non versioned files in the current solution, each prefixed by a checkbox.<br />
They are all checked by default, meaning that they will be scheduled to be added to versioning if you will click <strong>OK</strong>.<br />
<img class="alignnone size-full wp-image-81" src="http://ilmatte.files.wordpress.com/2008/04/ankhselectitemstoadd.jpg?w=510" alt="ankh select items to add"   /></p>
<div style="font-size:x-small;"><strong>Figure 21.</strong> AnkhSVN: select items to add to versioning.</div>
<p>After choosing<strong> OK</strong> the <em>Class2.cs</em> file in solution explorer will have a yellow plus icon beside (see: Figure 22), meaning that it is scheduled to be added at the next commit (the same is true for the project and solution items).<br />
<img class="alignnone size-full wp-image-82" src="http://ilmatte.files.wordpress.com/2008/04/ankhitemadded.jpg?w=510" alt="ankh new item added to versioning"   /></p>
<div style="font-size:x-small;"><strong>Figure 22.</strong> AnkhSVN: new item added to versioning.</div>
<p>Right-click the solution item and choose: <strong>Commit&#8230;</strong>. The <em>Commit</em> dialog will open.<br />
At the same time the icons beside the project and solution items become red squares (see: Figure 23), meaning that there are local modifications that need to be committed to the repository.<br />
Provide a meaningful message and click the <strong>Commit</strong> button (see: Figure 24).<br />
<img class="alignnone size-full wp-image-84" src="http://ilmatte.files.wordpress.com/2008/04/ankhcommit2.jpg?w=510" alt="ankh solution explorer before commit"   /></p>
<div style="font-size:x-small;"><strong>Figure 23.</strong> AnkhSVN: solution explorer upon commit.</div>
<p><img class="alignnone size-full wp-image-83" src="http://ilmatte.files.wordpress.com/2008/04/ankhcommit.jpg?w=510" alt="ankh commit dialog"   /></p>
<div style="font-size:x-small;"><strong>Figure 24.</strong> AnkhSVN: commit dialog.</div>
<p>Whenever you want to quit using AnkhSVN you can disable it for the solution you are using.<br />
Just right click the solution item and choose: <strong>Ankh &#8211;&gt; Disable Ankh for this solution</strong>.<br />
You can then work using TortoiseSVN or the Subversion command-line.<br />
If you want to enable Ankh again just choose: <strong>Ankh &#8211;&gt; Enable Ankh for this solution</strong>.</p>
<div><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutcommit"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></div>
<h3><a title="svntutservice" name="svntutservice"></a><span style="color:#993300;font-size:small;">7. Install Subversion as a Service</span></h3>
<p>If you want to Install Subversion as a Windows service you can use the utility: <strong>sc.exe</strong>, where sc stands for &#8220;Service Control&#8221;.<br />
Below you find a sample batch script to automate the install process.<br />
You can copy into a text file and save it, for example, as InstallSvnService.bat.<br />
Open a command prompt in the directory in which you placed the .bat file and run it by digiting<br />
InstallSvnService and pressing return.<br />
The service will be installed and configured to start automatically.</p>
<p><code><br />
sc create svnserve ^<br />
binpath= "\"C:\Program Files\Subversion\bin\svnserve.exe\" -r ^ \"C:\develop\test\repo\" --service" ^<br />
displayname= "Subversion" ^<br />
depend= Tcpip ^<br />
start= auto<br />
</code></p>
<p>Note that the caret symbol (^) in the script code is the line continuation character for batch scripts. It allows us to split the long command in multiple lines in order to make it more readable.<br />
The line continuation character tells to the command interpreter that the current command is not ending at the first newline but is going on in the next line.</p>
<p>It&#8217;s possible that you need to change the path:<br />
&#8220;C:\Program Files\Subversion\bin\svnserve.exe&#8221; depending on where is your copy of Subversion installed.<br />
The path: &#8220;C:\develop\test\repo\&#8221; in the example is the path to the location in which svnserve will find the repositories to host.<br />
Once the batch file has run open the administrative panel for services to make sure that the Subversion service exists and is running:<br />
go to: <strong>Start &#8211;&gt; Administrative Tools &#8211;&gt; Services</strong><br />
scroll down looking for a service named <strong>Subversion</strong> and if it is not running click on the <strong>Start</strong> link.</p>
<p><a href="#svntuttop"><span style="font-size:80%;color:#ff0000;">→ top of post</span></a><br />
<a href="#svntutservice"><span style="font-size:80%;color:#ff0000;">→ top of paragraph</span></a></p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f04%2f27%2fguide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f04%2f27%2fguide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn%2f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/52/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/52/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/52/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=52&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/04/27/guide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/createrepohere.jpg" medium="image">
			<media:title type="html">Create repo here</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/repocreated.jpg" medium="image">
			<media:title type="html">choose file system type for Repository</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/importwindow.jpg" medium="image">
			<media:title type="html">import window</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/importwindowset.jpg" medium="image">
			<media:title type="html">import window set</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/initialdirsadded.jpg?w=510" medium="image">
			<media:title type="html">Trunk dir added</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/checkout.jpg" medium="image">
			<media:title type="html">Checkout wk</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/checkoutfilled.jpg" medium="image">
			<media:title type="html">Checkout box filled</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/userpwprompt.jpg" medium="image">
			<media:title type="html">Prompt for username and password</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/checkoutcomplete.jpg?w=510" medium="image">
			<media:title type="html">Checkout complete info</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/tortoiseadd.jpg?w=281" medium="image">
			<media:title type="html">Add new file</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/tortoisecommit.jpg?w=261" medium="image">
			<media:title type="html">commit context menu</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/commitmessagedialog.jpg?w=280" medium="image">
			<media:title type="html">commit message</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/addtosvn.jpg" medium="image">
			<media:title type="html">Add with TortoiseSVN</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhprompt.jpg" medium="image">
			<media:title type="html">Enable ankhsvn</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolution.jpg" medium="image">
			<media:title type="html">ankhsvn add solution</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolution2.jpg" medium="image">
			<media:title type="html">ankh add solution prompt</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolution3.jpg" medium="image">
			<media:title type="html">AnkhSVN username and password</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhaddsolutionlogmessage.jpg" medium="image">
			<media:title type="html">ankh add log message</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhsolutionexplorergreen.jpg?w=277" medium="image">
			<media:title type="html">ankh green solution explorer</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhnewitem.jpg" medium="image">
			<media:title type="html">Solution explorer with new item</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhselectitemstoadd.jpg" medium="image">
			<media:title type="html">ankh select items to add</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhitemadded.jpg" medium="image">
			<media:title type="html">ankh new item added to versioning</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhcommit2.jpg" medium="image">
			<media:title type="html">ankh solution explorer before commit</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/04/ankhcommit.jpg" medium="image">
			<media:title type="html">ankh commit dialog</media:title>
		</media:content>

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2filmatte.wordpress.com%2f2008%2f04%2f27%2fguide-to-versioning-a-visual-studio-solution-with-subversion-tortoisesvn-and-ankhsvn%2f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>
	</item>
		<item>
		<title>CruiseControl.NET and Subversion &#8211; SvnRevisionLabeller</title>
		<link>http://ilmatte.wordpress.com/2008/03/05/cruisecontrolnet-and-subversion-svnrevisionlabeller/</link>
		<comments>http://ilmatte.wordpress.com/2008/03/05/cruisecontrolnet-and-subversion-svnrevisionlabeller/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:05:44 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[CruiseControl.NET]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[Build Labeller]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=48</guid>
		<description><![CDATA[1. Download 2. Description 3. Usage 3.1. Build Labels 3.2. Installation 3.3. Configuration 1. Download I recently contributed to a project that I find very useful: SvnRevisionLabeller (direct download link) plugin for CruiseControl.NET by David Keaveny. You can also find it having a look at the Contributions Page in the CruiseControl.Net official website (it&#8217;s the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=48&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a name="svnrevlabeltop" title="svnrevlabeltop"></a><br />
<a href="#downloadsvnrevlabel">1. Download</a><br />
<a href="#descriptionsvnrevlabel">2. Description</a><br />
<a href="#usagesvnrevlabel">3. Usage</a><br />
<span style="position:relative;left:10px;"><a href="#labelsvnrevlabel">3.1. Build Labels</a></span><br />
<span style="position:relative;left:10px;"><a href="#installsvnrevlabel">3.2. Installation</a></span><br />
<span style="position:relative;left:10px;"><a href="#configsvnrevlabel">3.3. Configuration</a></span></p>
<h3><a name="downloadsvnrevlabel" title="downloadsvnrevlabel"></a><font color="#993300" size="3">1. Download</font></h3>
<p>I recently contributed to a project that I find very useful:</p>
<p>SvnRevisionLabeller (<a href="http://code.google.com/p/svnrevisionlabeller/" title="svnrevisionlabellerzip" target="_blank">direct download link</a>) plugin for CruiseControl.NET by <a href="http://davidkeaveny.blogspot.com/" title="davidblog" target="_blank">David Keaveny</a>.<br />
You can also find it having a look at the <a href="http://confluence.public.thoughtworks.org/display/CCNETCOMM/Contributions" title="contributionsccnet" target="_blank">Contributions Page</a> in the CruiseControl.Net <a href="http://confluence.public.thoughtworks.org/display/CCNET" title="ccnetwebsite" target="_blank">official website</a> (it&#8217;s the third item under the title: <font color="#333399">Labeller Blocks</font>).</p>
<p><a href="#downloadsvnrevlabel"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#svnrevlabeltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="descriptionsvnrevlabel" title="descriptionsvnrevlabel"></a><font color="#993300" size="3">2. Description</font></h3>
<p>David Keaveny&#8217;s SvnRevisionLabeller lets CruiseControl.NET generate build labels based upon Subversion&#8217;s repository revision number.</p>
<p>I contributed to the project with a bug fix and by adding support for secure access to a Subversion repository (connecting with a repository&#8217;s particular account: username and password).</p>
<p>A file named Readme.txt comes zipped with the distribution.<br />
Inside that file you can find instructions about how to install and configure SvnRevisionLabeller as the <font color="#000080">Labeller Block</font> of choice in your CCnet configuration file.</p>
<p>In this article I will try to briefly guide you through these steps.</p>
<p><a href="#descriptionsvnrevlabel"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#svnrevlabeltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="usagesvnrevlabel" title="usagesvnrevlabel"></a><font color="#993300" size="3">3. Usage</font></h3>
<p>Let&#8217;s have a look at how to setup CruiseControl.NET server to work with the SvnRevisionLabeller plugin.</p>
<h4><a name="labelsvnrevlabel" title="labelsvnrevlabel"></a><font color="#993300" size="2">3.1. Build Labels</font></h4>
<p>SvnRevisionLabeller produces build labels in the format:</p>
<p><i>major.minor.svnRevision.build</i></p>
<p><i>major</i> and <i>minor</i> numbers are set in the configuration of the <font color="#333399">Labeller Block</font>,<br />
<i>svnRevision</i> number is retrieved from the Subversion repository,<br />
<i>build</i> is automatically incremented if a new build is forced when no further modification to the repository happened.</p>
<p>The label produced by whichever <font color="#000080">Labeller Block</font> is made available to the <font color="#000080">Task Blocks</font> by means of the environment variable: <font color="#ff6600">CCNetLabel</font>.<br />
That environment variable can then be accessed by NAnt or MSBuild (as <font color="#ff6600">${CCNetLabel}</font> or <font color="#ff6600">$(CCNetLabel</font><font color="#ff6600">)</font>) or by an External script with the usual syntax for environment variables on Windows Operating Systems: <font color="#ff6600">%CCNetLabel%</font>.</p>
<h4><a name="installsvnrevlabel" title="installsvnrevlabel"></a><font color="#993300" size="2">3.2. Installation</font></h4>
<p>Installing the SvnRevisionLabeller plugin is just a matter of unzipping the package (ccnet.SvnRevisionLabeller.plugin.zip) into a temporary directory and of copying the assembly:<br />
<font color="#808080">src\ccnet.SvnRevisionLabeller.plugin\bin\Release\ccnet.SvnRevisionLabeller.plugin.dll</font></p>
<p>that you find inside the temporary directory into the directory in which CruiseControl.NET has been installed (e.g.: <font color="#808080">C:\Program Files\CruiseControl.NET\server</font>).</p>
<p>Next you need to configure the <font color="#333399">Labeller Block</font> in your projects in order to let them use SvnRevisionLabeller.<br />
Let&#8217;s see how.</p>
<h4><a name="configsvnrevlabel" title="configsvnrevlabel"></a><font color="#993300" size="2">3.3. Configuration</font></h4>
<p>Following is the basic configuration for SvnRevisionLabeller. Only the required fields are set:<br />
<pre class="brush: xml;">
&lt;labeller type=&quot;svnRevisionLabeller&quot;&gt;
  &lt;major&gt;7&lt;/major&gt;
  &lt;minor&gt;11&lt;/minor&gt;
  &lt;url&gt;svn://localhost/repository/trunk&lt;/url&gt;
&lt;/labeller&gt;</pre><br />
where:&lt;major&gt; and &lt;minor&gt; are the first two numbers in the build label:<br />
<font color="#333399"> 7.11.svnRevision.build</font><br />
and &lt;url&gt; represents the path to the repository monitored by the current CruiseControl.net project. Actually the &lt;url&gt; field must be filled with the same path used in the &lt;trunkurl&gt; field of the Subversion <font color="#000080">Source Control Block</font>:<br />
<pre class="brush: xml;">
&lt;sourcecontrol type=&quot;svn&quot;&gt;
  &lt;trunkurl&gt;svn://localhost/repository/trunk&lt;/trunkurl&gt;
  ...
&lt;/sourcecontrol&gt;</pre><br />
Following is a configuration for the SvnRevisionLabeller with the complete set of fields:<br />
<pre class="brush: xml;">
&lt;labeller type=&quot;svnRevisionLabeller&quot;&gt;
  &lt;prefix&gt;Test-&lt;/prefix&gt;
  &lt;major&gt;7&lt;/major&gt;
  &lt;minor&gt;11&lt;/minor&gt;
  &lt;url&gt;svn://localhost/repository/trunk&lt;/url&gt;
  &lt;username&gt;ccnetuser&lt;/username&gt;
  &lt;password&gt;ccnetpassword&lt;/password&gt;
&lt;/labeller&gt;</pre><br />
where:&lt;prefix&gt; is a prefix added to the build label in the format:<br />
<font color="#000080">Test-major.minor.svnRevision.build</font><br />
&lt;username&gt; and &lt;password&gt; are the username and password of a valid Subversion account for the repository specified in the &lt;url&gt; field.<br />
<u> You&#8217;d better</u> create a specific account used only by CruiseControl.NET.That&#8217;s it! In this way CruiseControl.NET will flag its builds with the revision number from Subversion and you can retrieve such value if you want to use it to modify the AssemblyInfo.cs files in your Visual Studio projects or if you want to flag your administrative backup names. </p>
<p>
<a href="#usagesvnrevlabel"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#svnrevlabeltop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/48/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/48/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/48/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=48&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/03/05/cruisecontrolnet-and-subversion-svnrevisionlabeller/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>
	</item>
		<item>
		<title>Virtual Drive Letter Mapping with &#8216;subst&#8217; Command</title>
		<link>http://ilmatte.wordpress.com/2008/02/14/virtual-drive-letter-mapping-with-subst-command/</link>
		<comments>http://ilmatte.wordpress.com/2008/02/14/virtual-drive-letter-mapping-with-subst-command/#comments</comments>
		<pubDate>Thu, 14 Feb 2008 07:57:21 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[Command line]]></category>
		<category><![CDATA[Project Management]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=34</guid>
		<description><![CDATA[1. Introduction &#8211; Path to Common Assemblies 2. Subst Command 1. Introduction &#8211; Path to Common Assemblies When you need to place some common references in your solutions and you don&#8217;t want to register the referenced assemblies into the GAC (because they change frequently or for whatever other reason), you can decide to act as [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=34&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a name="substtop" title="substtop"></a><br />
<a href="#introductionsubst">1. Introduction &#8211; Path to Common Assemblies</a><br />
<a href="#commandsubst">2. Subst Command</a></p>
<h3><a name="introductionsubst" title="introductionsubst"></a><font color="#993300" size="3">1. Introduction &#8211; Path to Common Assemblies</font></h3>
<p>When you need to place some common references in your solutions and you don&#8217;t want to register the referenced assemblies into the GAC (because they change frequently or for whatever other reason), you can decide to act as suggested in the article <a href="http://msdn2.microsoft.com/en-us/library/ms998215.aspx#tdlg_ch4_useavirtualdriveletterforgreaterflexibility" title="virtualdrivemsdn"> Team Development with Visual Studio .NET and Visual SourceSafe</a> on msdn at the paragraph: <b>Use a Virtual Drive Letter for Greater Flexibility</b>.</p>
<p>The article presents an easy way to have a common environment on different machines.<br />
Often there&#8217;s the need, for a team, to agree a directory path to be reproduced on each developer machine.<br />
For example your team could agree in placing all third parties&#8217; assemblies in a directory named: <font color="#808080">C:\develop\common</font>.<br />
It will be care of each developer to create such directory on his machine and to keep it up to date with the new releases of the assemblies.</p>
<p>This approach requires that developers set up analogous directory structures in their working environment. They are at least required to have a directory named <font color="#808080">C:\develop\common</font>.<br />
What you can do is to reduce this constraint, at a certain level, by using virtual drive letter mapping.</p>
<p>Instead of agreeing a path that each develper is supposed to have on his own machine your team must simply agree on a drive letter name. Each developer will be free to choose the path he prefers and he will only have to map it to a virtual drive letter with the agreed name by using the <b>subst</b> command.</p>
<p><a href="#introductionsubst"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#substtop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="commandsubst" title="commandsubst"></a><font color="#993300" size="3">2. Subst Command</font></h3>
<p>The <b>subst</b> command serves the purpose of mapping a physical path on disk to a virtual drive letter.<br />
Just digit <i>subst /?</i> at a command prompt or visit <a href="http://technet.microsoft.com/it-it/library/bb491006(en-us).aspx" title="substsyntax">Microsoft technet command-line reference page</a> to learn more.</p>
<p>The syntax is: <i>subst [drive1: [drive2:]Path]</i></p>
<p>where <i>drive1</i> is the name of the virtual drive to which you want to map a path and <i>drive2:Path</i> represents the path itself.</p>
<p><b>e.g.</b>:  <font color="#808080">subst G: C:\develop\common</font></p>
<p>By mapping different paths on different machines to a common drive letter you can, from this moment on, let your project files reference common assemblies using paths relative to the virtual drive: <b>G:</b> (see again <a href="http://msdn2.microsoft.com/en-us/library/ms998215.aspx#tdlg_ch4_useavirtualdriveletterforgreaterflexibility" title="virtualdrivemsdn">Use a Virtual Drive Letter for Greater Flexibility</a>).</p>
<p><a href="#commandsubst"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#substtop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/34/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/34/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/34/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=34&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/02/14/virtual-drive-letter-mapping-with-subst-command/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>
	</item>
		<item>
		<title>SolutionInfo and Partitioned Single Solution</title>
		<link>http://ilmatte.wordpress.com/2008/02/10/solutioninfo-and-partitioned-single-solution/</link>
		<comments>http://ilmatte.wordpress.com/2008/02/10/solutioninfo-and-partitioned-single-solution/#comments</comments>
		<pubDate>Sun, 10 Feb 2008 13:07:44 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Project Management]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[Visual Studio 2005]]></category>
		<category><![CDATA[SolutionInfo]]></category>
		<category><![CDATA[Structuring Solutions]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/?p=25</guid>
		<description><![CDATA[1. Prerequisites 2. Introduction &#8211; SolutionInfo.cs 3. Introduction &#8211; Partitioned single solution 4. Partitioned single solution and SolutionInfo.cs &#8211; The problem 5. Partitioned single solution and SolutionInfo.cs &#8211; The Solution 6. Subversion Issue 695 and Release 1.5 7. Notes 7.1. Add a file as link 7.2. Set Build Action to None In this article I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=25&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a name="solutioninfotop" title="solutioninfotop"></a><br />
<a href="#prerequisitessolutioninfo">1. Prerequisites</a><br />
<a href="#introductionsolutioninfo1">2. Introduction &#8211; SolutionInfo.cs</a><br />
<a href="#introductionsolutioninfo2">3. Introduction &#8211; Partitioned single solution</a><br />
<a href="#problemsolutioninfo">4. Partitioned single solution and SolutionInfo.cs &#8211; The problem</a><br />
<a href="#thesolutionsolutioninfo">5. Partitioned single solution and SolutionInfo.cs &#8211; The Solution</a><br />
<a href="#subversionsolutioninfo">6. Subversion Issue 695 and Release 1.5</a><br />
<a href="#notessolutioninfo">7. Notes</a><br />
<span style="position:relative;left:10px;"><a href="#solutioninfonote1">7.1. Add a file as link</a></span><br />
<span style="position:relative;left:10px;"><a href="#solutioninfonote2">7.2. Set Build Action to None</a></span></p>
<p>In this article I will talk about possible issues when creating a SolutionInfo.cs file<br />
while using the Partitioned single solution development model.</p>
<h3><a name="prerequisitessolutioninfo" title="prerequisitessolutioninfo"></a><font color="#993300" size="3">1. Prerequisites</font></h3>
<p>While writing this article I was using the following software:</p>
<p>Visual Studio 2005<br />
<a href="http://subversion.tigris.org/" title="Subversion Home Page" target="_blank">Subversion</a> (<a href="http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91" title="Download page" target="_blank">Download the latest version</a>)</p>
<h3><a name="introductionsolutioninfo1" title="introductionsolutioninfo1"></a><font color="#993300" size="3">2. Introduction &#8211; SolutionInfo.cs</font></h3>
<p>Having multiple projects in a solution means having multiple assemblies, and having multiple assemblies could mean that you want to deploy them as separate assemblies.<br />
Each project generated by <b>Visual Studio 2005</b> contains, by default, an <i>AssemblyInfo.cs</i> file in which you can write assembly attributes.<br />
If you open <i>AssemblyInfo.cs</i> you will find a set of assembly attributes with default values.<br />
The values for some of these attributes could vary from project to project but others (such as <i>AssemblyVersion</i>) should be application wide.<br />
For this purpose a common choice is the <i>SolutionInfo.cs</i> pattern as illustrated by Juval Lowy (you can find his book: <a href="http://www.amazon.com/gp/product/0596102070?ie=UTF8&amp;tag=myvionc-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0596102070">Programming .NET Components, 2nd Edition</a><img src="http://www.assoc-amazon.com/e/ir?t=myvionc-20&amp;l=as2&amp;o=1&amp;a=0596102070" style="border:medium none !important;margin:0 !important;" border="0" height="1" width="1" /> at Amazon).<br />
It consists in grouping all the attributes common to all projects (solution wide attributes) in a separate file named <i>SolutionInfo.cs</i> that will be included as a solution item.<br />
Each project will contain, under the Properties directory, an <i>AssemblyInfo.cs</i> file and a link to the shared <i>SolutionInfo.cs</i> file (see note: <a href="#solutioninfonote1">Add file as link</a>).<br />
Adding that file as a link allows you to modify always the same file, no matter which link you open so having all the projects&#8217; properties updated at once.<br />
This approach is very useful for incrementing Version Number.</p>
<p><a href="#introductionsolutioninfo1"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="introductionsolutioninfo2" title="introductionsolutioninfo2"></a><font color="#993300" size="3">3. Introduction &#8211; Partitioned single solution</font></h3>
<p><b>References:</b></p>
<p><a href="http://msdn2.microsoft.com/en-us/library/ms998208.aspx" title="Structuring Solutions and Projects" target="_blank">Structuring Solutions and Projects (MSDN Article)</a><br />
or you can find an updated version of the preceding article in the book:<br />
&#8216;<i>Team development with visual studio team foundation server</i>&#8216;<br />
that you can freely download at: <a href="http://www.codeplex.com/TFSGuide" title="TFSGuide" target="_blank">http://www.codeplex.com/TFSGuide</a></p>
<p><b>Partitioned Single Solution:</b></p>
<p>As shown in the articles above, when you have a big application and want to allow developers to work on smaller portions of the appliction, you can consider using the &#8216;<i>partitioned single solution</i>&#8216; development model.<br />
It consists in creating a top solution containing all the projects in the application and then introducing separate solution files for subsets of related projects.<br />
Each solution file will contain all the projects a develper needs to work on and all the referenced projects.<br />
In this way it is possible to checkout only the projects actually needed on each developer&#8217;s workstation, thus obtaining a lighter build process during the development stage.</p>
<p>This approach requires additional work and time to keep all the solution files aligned but it provides a safer way to share work on the same application between different developers.</p>
<p><a href="#introductionsolutioninfo2"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="problemsolutioninfo" title="problemsolutioninfo"></a><font color="#993300" size="3">4. Partitioned single solution and SolutionInfo.cs &#8211; The problem</font></h3>
<p>This article aims to point out that there are a couple of drawbacks in combining the SolutionInfo pattern with the Partitioned single solution model.</p>
<p><b>Case Scenario 1:</b></p>
<p>First of all the SolutionInfo approach makes it impossible for a developer to copy the project as is to another location and import it into another solution file.<br />
At compile time he would get the following message:</p>
<p><font color="#ff0000">&#8216;Error	1	Source file &#8216;pathToSolution\SolutionInfo.cs&#8217; could not be opened &#8230;&#8217;</font></p>
<p>He will have to create a <i>SolutionInfo.cs</i> file in the same directory in which the copy of the project is placed in order to make the build succeed.</p>
<p>To understand why this fixes the problem let&#8217;s have a look at what happens behind the scenes:</p>
<p>Say that we created projects leaving the Visual Studio default behavior unchanged, that is, they are located in subdirectories of the directory containing the solution file.<br />
When we add a file as link to a project (<a href="#solutioninfonote1">see note</a>), the following lines will be added to the project file (<i>projectName.csproj</i>) under the &#8216;<b>ItemGroup</b>&#8216; tag:</p>
<p><pre class="brush: xml;">
&lt;compile Include=&quot;..\SolutionInfo.cs&quot;&gt;
    &lt;link&gt;Properties\SolutionInfo.cs&lt;/link&gt;
&lt;/compile&gt;</pre><br />
The &#8216;<b>Include</b>&#8216; attribute stores the path to the original file that we&#8217;re linking to.<br />
The &#8216;<b>Link</b>&#8216; tag stores the path in which the link will be shown in Solution Explorer (including possible solution directory e.g.: &#8216;<i>Properties</i>&#8216;).<br />
As you can see, the &#8216;<b>Include</b>&#8216; attribute stores the <u>relative</u> path to <i>SolutionInfo.cs</i> with respect to the <i>projectName.csproj</i> file location. This will end up in Visual Studio (and MSbuild) looking for a file named <i>SolutionInfo.cs</i> one level above with respect to the <i>projectName.csproj</i> file.So this is the reason for the error message shown above if copying a project directory anywhere else.Let&#8217;s go further and introduce the SolutionInfo method in a Partitioned Single Solution.The default Visual Studio behaviour of introducing relative paths (instead of using paths relative to the solution path) makes linking a file (e.g.: <i>SolutionInfo.cs</i>) in a Partitioned Single Solution structure an error prone procedure.<br />
In fact it can easily lead to the build error reported above, if we use nested directory structures.<br />
Let&#8217;s have a look at the possible situations:</p>
<div><b>Case Scenario 2:</b></div>
<p>We could decide to create a directory structure as shown in the following picture:<img src="http://ilmatte.files.wordpress.com/2008/02/case1.jpg?w=510" alt="PartitionedSolutionStructure1" /></p>
<div>If we place all the solution files in the top directory, as shown above, we won&#8217;t have any problem.<br />
In fact when a developer checks out the directory containing the solution file he needs, he will also get the <i>SolutionInfo.cs</i> file (remember that with Subversion you can only checkout directories).<br />
Practically speaking we will always checkout the top directory, no matter which solution file we will use.</div>
<p><b>Case Scenario 3:</b></p>
<p>What if we want to add a solution file for each project and we want to place it in the  project&#8217;s directory?</p>
<p><img src="http://ilmatte.files.wordpress.com/2008/02/case2.jpg?w=510" alt="PartitionedSolutionStructure2" /></p>
<p>A developer could checkout from the repository only a project&#8217;s directory and he would get the solution file too.<br />
But when he will try to build the solution he will get the file missing error!<br />
If he provides a copy of <i>SolutionInfo.cs</i> in the solution&#8217;s directory (which is the project&#8217;s directory too) it won&#8217;t work because MSbuild (as we said before) looks for the file up one level (..\<i>SolutionInfo.cs</i>).<br />
The developer should create a <i>SolutionInfo.cs</i> file outside of its working copy to make the build succeed.If we have a more complicated directory structure with different levels of directories, with project directories in some of this levels, and with solution files in some of these levels too, the situation is even worse.<br />
In fact the <i>SolutionInfo.cs</i> file is located more than one level up with respect to some of this project and solution files as you can see in the following image:</p>
<p><b></b><img src="http://ilmatte.files.wordpress.com/2008/02/case3.jpg?w=510" alt="PartitionedSolutionStructure3" /></p>
<p>Each time a developer checks out a solution directory that is not the root one he will miss the <i>SolutionInfo.cs</i> file and he&#8217;ll need to open a project file in a text editor to know were it is supposed to be.</p>
<p><a href="#problemsolutioninfo"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="thesolutionsolutioninfo" title="thesolutionsolutioninfo"></a><font color="#993300" size="3">5. Partitioned single solution and SolutionInfo.cs &#8211; The Solution</font></h3>
<p>In order to avoid uncertainty about where each project expects the <i>SolutionInfo.cs</i> to be placed, we need to reference it with a path relative to the solution location instead of the project&#8217;s directory. So we can open <i>projectName.csproj</i> in a text editor and modify the entry as follows:</p>
<p><b>SolutionDir variable</b></p>
<p><pre class="brush: xml;">
&lt;compile Include=&quot;$(SolutionDir)\SolutionInfo.cs&quot;&gt;
    &lt;link&gt;Properties\SolutionInfo.cs&lt;/link&gt;
&lt;/compile&gt;</pre><br />
In this way we let the projects be independent of their location in the directory structure.Let&#8217;s go one step further.<br />
If a developer doesn&#8217;t want to provide a <i>SolutionInfo.cs</i> file to its custom solution his solution won&#8217;t compile unless he sets <i>SolutionInfo.cs</i> &#8216;<b>Build Action</b>&#8216; to &#8216;<b>None</b>&#8216; (see note: <a href="#solutioninfonote2">Set Build Action to None</a>).<br />
The problem here is that the &#8216;<b>Build Action</b>&#8216; of a file is stored in the versioned <i>projectName.csproj</i> file. Changing this setting will impact on the working copies of all developers using that same project and even on the release build script.<br />
Luckily we can apply a work around to this problem:</p>
<div><b>The Condition attribute</b></div>
<p>the &#8216;<b>Compile</b>&#8216; tag in the <i>projectName.csproj</i> file supports another useful attribute: &#8216;<b>Condition</b>&#8216;.<br />
The condition specified by such attribute will be evaluated by MSBuild during the build process and the file will be compiled only if the condition is satisfied.<br />
We could add it to the row related to <i>SolutionInfo.cs</i> thus obtaining:<br />
<pre class="brush: xml;">
&lt;compile Include=&quot;$(SolutionDir)\SolutionInfo.cs&quot;
        Condition=&quot;Exists('$(SolutionDir)\SolutionInfo.cs')&quot;&gt;
    &lt;link&gt;Properties\SolutionInfo.cs&lt;/link&gt;
&lt;/compile&gt;</pre><br />
MSBuild will evaluate the condition and if it will not find the linked file in the specified path it won&#8217;t even try to compile it.<br />
This will allow developers to always have their projects successfully built even if a <i>SolutionInfo.cs</i> file is not present on disk.<br />
Solution Explorer will let the project build succeed but will show a broken link in the GUI to let the user know that something is missing.The assembly resulting from such a working copy build process will lack the solution wide assembly information but the continuous integration tools, as well as developers using solutions including a <i>SolutionInfo.cs</i> file, will have their projects build with the complete assembly information.</p>
<div><a href="#thesolutionsolutioninfo"><span style="font-size:80%;color:red;"></span></a><a href="#thesolutionsolutioninfo"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></div>
<h3><a name="subversionsolutioninfo" title="subversionsolutioninfo"></a><font color="#993300" size="3">6. Subversion Issue 695 and Release 1.5</font></h3>
<p>If you use Subversions as Version Control System you must be aware of a problem in which you may run into when working with a partitioned single solution model.<br />
If you organize your repository, say, like in the case scenario 2, and you want to checkout a solution (not the global one) and only the projects (and projects&#8217; directories) referenced by that solution you should do it in two separate steps:</p>
<p>first of all keep in mind that with Subversion you can only checkout directories, so you cannot have only the solution file you need but you&#8217;re forced to get in your working copy all the solution files defined in the root directory:</p>
<p>- checkout non-recursively the root directory (the one with the solution files),</p>
<p>next you can add to your working copy only the projects&#8217; directories you want:</p>
<p>- call svn update separately specifying the subdirectories you need.</p>
<p>This will seem to work at first but it is not true.<br />
There&#8217;s an old implementation issue in Subversion (see: <a href="http://subversion.tigris.org/issues/show_bug.cgi?id=695" title="issue695" target="_blank">issue 695</a>), related to checking out a directory non-recursively :</p>
<p>the issue consists in the fact that such a directory in the working-copy is not aware of being a partial checkout. So as long as anyone works on identical working copies everything works fine otherwise you will obtain a weird behavior.<br />
If someone commits changes to, say, a directory that you didn&#8217;t check out from the repository, the first time you will make a global update of your working copy you&#8217;ll get the following error message:</p>
<p>&gt;&gt; <font color="#ff0000">Error: Directory &#8216;pathToWorkingCopy\project3Dir&#8217; is missing</font><br />
&gt;&gt; <font color="#ff0000">Error: Please execute the &#8220;Cleanup&#8221; command.</font></p>
<p>If you execute the cleanup and try to update again, the whole root directory will be checked out in your working copy!</p>
<p>The bug has been fixed and sparse directory checkout should be allowed with the upcoming 1.5 version of Subversion.<br />
At the moment if you want to be safe with your working copy you have to checkout the whole root directory.</p>
<p><a href="#subversionsolutioninfo"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h3><a name="notessolutioninfo" title="notessolutioninfo"></a><font color="#993300" size="3">7. Notes</font></h3>
<p><span style="position:relative;left:10px;"><a href="#solutioninfonote1">7.1. Add file as link</a></span><br />
<span style="position:relative;left:10px;"><a href="#solutioninfonote2">7.2. Set Build Action to None</a></span></p>
<h4><a name="solutioninfonote1" title="solutioninfonote1"></a><font color="#993300" size="2">7.1. Add file as link</font></h4>
<p>When you want to add a file as link to a project simply right click on the project and choose<i> Add &#8211;&gt; Existing item</i>.<br />
In the choose file dialog box locate and select the file you want (say e.g. <i>SolutionInfo.cs</i>). Don&#8217;t click the Add button, you should click the little down arrow on the right edge of the Add button instead. A drop down menu will appear as shown in the picture. Choose Add as link and you&#8217;re done (then you can move the link anywhere else in the project directory structure simply dragging it in Solution Explorer).</p>
<p><img src="http://ilmatte.files.wordpress.com/2008/02/addlink2.jpg?w=510" alt="Add As Link" /></p>
<p><a href="#notessolutioninfo"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<h4><a name="solutioninfonote2" title="solutioninfonote2"></a><font color="#993300" size="2">7.2. Set Build Action to None</font></h4>
<p>To set the Build Action to None for a project item simply select the item in Solution Explorer (e.g.: <i>SolutionInfo.cs</i>) and look at the Properties Panel.<br />
A bunch of properties will be shown for the selected item through which you will see: &#8216;<b>Build Action</b>&#8216; with the value &#8216;<b>Compile</b>&#8216;. Just click on the value and a drop down list will appear as shown in the picture. Select &#8216;<b>None</b>&#8216; and you&#8217;re done.</p>
<p><img src="http://ilmatte.files.wordpress.com/2008/02/buildactionnone.jpg?w=510" alt="BuildActionNone" /></p>
<p><a href="#notessolutioninfo"><span style="font-size:80%;color:red;">→ top of paragraph</span></a><br />
<a href="#solutioninfotop"><span style="font-size:80%;color:red;">→ top of post</span></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/25/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/25/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/25/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/25/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/25/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/25/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/25/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/25/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/25/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/25/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=25&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/02/10/solutioninfo-and-partitioned-single-solution/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>

		<media:content url="http://www.assoc-amazon.com/e/ir?t=myvionc-20&#38;l=as2&#38;o=1&#38;a=0596102070" medium="image" />

		<media:content url="http://ilmatte.files.wordpress.com/2008/02/case1.jpg" medium="image">
			<media:title type="html">PartitionedSolutionStructure1</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/02/case2.jpg" medium="image">
			<media:title type="html">PartitionedSolutionStructure2</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/02/case3.jpg" medium="image">
			<media:title type="html">PartitionedSolutionStructure3</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/02/addlink2.jpg" medium="image">
			<media:title type="html">Add As Link</media:title>
		</media:content>

		<media:content url="http://ilmatte.files.wordpress.com/2008/02/buildactionnone.jpg" medium="image">
			<media:title type="html">BuildActionNone</media:title>
		</media:content>
	</item>
		<item>
		<title>WordPress SourceCode Tag And Themes</title>
		<link>http://ilmatte.wordpress.com/2008/01/17/wordpress-sourcecode-tag-and-themes/</link>
		<comments>http://ilmatte.wordpress.com/2008/01/17/wordpress-sourcecode-tag-and-themes/#comments</comments>
		<pubDate>Thu, 17 Jan 2008 12:52:15 +0000</pubDate>
		<dc:creator>ilmatte</dc:creator>
				<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://ilmatte.wordpress.com/2008/01/17/wordpress-sourcecode-tag-and-themes/</guid>
		<description><![CDATA[1. Sourcecode tag in WordPress 2. Not for all Themes 1. Sourcecode tag in WordPress Many of you already know that there&#8217;s this cool tag in wordpress allowing us to post code without worrying about formatting: [ sourcecode language='css']…[/sourcecode] In fact it takes care of syntax highligthing as well as preserving good indentation, like in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=10&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a name="sourcecodetop" title="sourcecodetop"></a><br />
<a href="#introsourcecode">1. Sourcecode tag in WordPress</a><br />
<a href="#noworksourcecode">2. Not for all Themes</a></p>
<h3><a name="introsourcecode" title="introsourcecode"></a><br />
<font color="#993300" size="3">1. Sourcecode tag in WordPress</font></h3>
<p>Many of you already know that there&#8217;s this cool tag in wordpress allowing us to post code without worrying about formatting:</p>
<table>
<tr>
<td>[</td>
<td>sourcecode language='css']…[/sourcecode]</td>
</tr>
</table>
<p>In fact it takes care of syntax highligthing as well as preserving good indentation, like in the following example of a CSS rule:</p>
<p><pre class="brush: css;">
.Test
{
    background-image:url('/images/Bckgrnd.jpg');
    background-color:#FFFFFF;
    border:solid 1px #7E7E81;
    cursor:pointer;
}</pre><br />
The supported language codes are:</p>
<ul>
<li>actionscript3</li>
<li>bash</li>
<li>coldfusion</li>
<li>cpp</li>
<li>csharp</li>
<li>css</li>
<li>delphi</li>
<li>erlang</li>
<li>fsharp</li>
<li>diff</li>
<li>groovy</li>
<li>javascript</li>
<li>java</li>
<li>javafx</li>
<li>matlab (keywords only)</li>
<li>objc</li>
<li>perl</li>
<li>php</li>
<li>python</li>
<li>powershell</li>
<li>r</li>
<li>ruby</li>
<li>scala</li>
<li>sql</li>
<li>vb</li>
<li>xml</li>
</ul>
<p>You can find info at the following link:</p>
<p><a href="http://faq.wordpress.com/2007/09/03/how-do-i-post-source-code/" title="How do I post source code?" target="_blank">How do I post source code?</a></p>
<h3><a name="noworksourcecode" title="noworksourcecode"></a><br />
<font color="#993300" size="3">2. Not for all Themes</font></h3>
<p>What you may not know is that this feature <u>does not work</u> with all the themes available, for example it doesn&#8217;t work with the default wordpress theme: Kubrick.</p>
<p>Hope this is a useful info for people trying to make it work right now.</p>
<p><a href="#sourcecodetop"><span style="font-size:80%;color:red;">→ go to top</span></a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/ilmatte.wordpress.com/10/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/ilmatte.wordpress.com/10/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ilmatte.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ilmatte.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/ilmatte.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/ilmatte.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ilmatte.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ilmatte.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ilmatte.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ilmatte.wordpress.com/10/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=ilmatte.wordpress.com&amp;blog=2402635&amp;post=10&amp;subd=ilmatte&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://ilmatte.wordpress.com/2008/01/17/wordpress-sourcecode-tag-and-themes/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3cb2e7cb9a15640aab9ac6639d9bc462?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">ilmatte</media:title>
		</media:content>
	</item>
	</channel>
</rss>
