“Mastering” branding of SharePoint

16. April 2009

Ok, I am exaggerating here. This post will not be about “mastering” the branding but rather about branding through master pages. This post is another post in a series of posts where I try to learn SharePoint. When I found out that SharePoint is based on ASP.NET master pages I immediately thought it would be fun to create a SharePoint that would look exactly like my web pages. So, here is my target visual.

   SP_Master1_Target

 

Creating new master page

By looking at the default.master page (located at C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\GLOBAL\default.master) I got scared. This page is not simple, let me say it this way. I tried to come up with a clean minimal page. I found a minimal master page on MSDN. Unfortunately that page didn’t work and I had no clue why (I guess it’s because I don’t have MOSS but just WSS installed on my machine). I then tried to come up with my own minimal master page. Here is the result.

 

<%@Master language="C#"%>
<%@ Import Namespace="Microsoft.SharePoint" %> 
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" 
  Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" 
  Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" 
  Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="Welcome" src="~/_controltemplates/Welcome.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="DesignModeConsole" 
  src="~/_controltemplates/DesignModeConsole.ascx" %>

<html id="HTML1" dir="<%$Resources:wss,multipages_direction_dir_value%>" runat="server" 
  xmlns:o="urn:schemas-microsoft-com:office:office">

<head id="HEAD1" runat="server">
    <META Name="progid" Content="SharePoint.WebPartPage.Document">
    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    <META HTTP-EQUIV="Expires" content="0">
    <SharePoint:RobotsMetaTag ID="RobotsMetaTag1" runat="server"/>
    
    <Title ID="onetidTitle">
        <asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server"/>
    </Title>
    
    <SharePoint:CssLink ID="CssLink1" runat="server"/>
    <!-- remove support for themes <SharePoint:Theme ID="Theme1" runat="server"/> -->
    <SharePoint:ScriptLink ID="ScriptLink1" language="javascript" name="core.js" Defer="true" runat="server" />
    <SharePoint:CustomJSUrl ID="CustomJSUrl1" runat="server" />
    <SharePoint:SoapDiscoveryLink ID="SoapDiscoveryLink1" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderAdditionalPageHead" runat="server"/>
    <SharePoint:DelegateControl ID="DelegateControl1" runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true"/>
</head>
<body scroll="yes" onload="javascript:if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();">

    <form id="Form1" runat="server" onsubmit="return _spFormOnSubmitWrapper();">
        <WebPartPages:SPWebPartManager id="m" runat="Server" />

        <!-- MAIN CONTENT -->
        <div id="main">
            <asp:ContentPlaceHolder id="PlaceHolderMain" runat="server"/>
        </div>

	
<asp:Panel ID="HiddenPlaceholders" visible="false" runat="server">
    <asp:ContentPlaceHolder id="PlaceHolderBodyLeftBorder" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderBodyRightMargin" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderCalendarNavigator" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderFormDigest" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderGlobalNavigation" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderGlobalNavigationSiteMap" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderHorizontalNav" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderLeftActions" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderLeftNavBar" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderLeftNavBarBorder" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderLeftNavBarDataSource" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderLeftNavBarTop" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderMiniConsole" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderNavSpacer" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderPageDescription" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderPageImage" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderPageTitleInTitleArea" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderSiteName" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderTitleAreaSeparator" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderTitleBreadcrumb" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderTitleLeftBorder" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderTitleRightMargin" runat="server" />
    <asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server"/>
    <asp:ContentPlaceHolder ID="SPNavigation" runat="server" />
    <asp:ContentPlaceHolder ID="WSSDesignConsole" runat="server" />
</asp:Panel>            
            
        <input type="text" name="__spDummyText1" style="display:none;" size=1/>
        <input type="text" name="__spDummyText2" style="display:none;" size=1/>
    </form>
    
    <asp:ContentPlaceHolder id="PlaceHolderUtilityContent" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderBodyAreaClass" runat="server"/>
    <asp:ContentPlaceHolder id="PlaceHolderTitleAreaClass" runat="server"/>
</body>
</html>

This minimal master page leads to the following visual.

  SP_Master1_Minimal

 

At this point I took master page from my web server and put it in my minimal SharePoint master page. The trick is to play with SharePoint ContentPlaceHolders. These are all the available placeholders:

 

Placeholder Description
PlaceHolderAdditionalPageHead Additional content that needs to be within the tag of the page, for example, references to script in style sheets
PlaceHolderBodyAreaClass Additional body styles in the page header
PlaceHolderBodyLeftBorder Border element for the main page body
PlaceHolderBodyRightMargin Right margin of the main page body
PlaceHolderCalendarNavigator Shows a date picker for navigating in a calendar when a calendar is visible on the page
PlaceHolderFormDigest The "form digest" security control
PlaceHolderGlobalNavigation The global navigation breadcrumb
PlaceHolderHorizontalNav Top navigation menu for the page
PlaceHolderLeftActions Bottom of the left navigation area
PlaceHolderLeftNavBar Left navigation area
PlaceHolderLeftNavBarBorder Border element on the left navigation bar
PlaceHolderLeftNavBarDataSource Data source for the left navigation menu
PlaceHolderLeftNavBarTop Top of the left navigation area
PlaceHolderMain Page's main content
PlaceHolderMiniConsole A place to show page-level commands, for example, WIKI commands such as Edit Page, History, and Incoming Links
PlaceHolderNavSpacer The width of the left navigation area
PlaceHolderPageDescription Description of the page contents
PlaceHolderPageImage Page icon in the upper left area of the page
PlaceHolderPageTitle The page

 

With this information I have updated the “logo” element:

<!-- LOGO -->
<div id="logo" class="logo">
    <asp:ContentPlaceHolder id="PlaceHolderSiteName" runat="server">
        <SharePoint:SPLinkButton runat="server" NavigateUrl="~site/" id="onetidProjectPropertyTitle" CssClass="whiteLink" >
            David Pokluda's <SharePoint:ProjectProperty ID="ProjectProperty1" Property="Title" runat="server" />
        </SharePoint:SPLinkButton>
    </asp:ContentPlaceHolder>
</div>

 

Here is my “main content” element:

<!-- MAIN TEXT -->
<div id="main">
    <asp:ContentPlaceHolder id="PlaceHolderMain" runat="server" />
</div>

 

I have also added the simple “search” element:

<div id="sn1" class="sidenote">
    <div id="sn1header" class="sidenoteheader">
        Quick Search
    </div>
    <div id="sn1text" class="sidenotetext">
        <asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server">
          <SharePoint:DelegateControl ID="DelegateControl5" runat="server" ControlId="SmallSearchInputBox" />
        </asp:ContentPlaceHolder>
    </div>
</div>

 

After updating the CSS file (with styles from my web server) I saw the following visual:

   SP_Master1_Final

 

I think it is pretty good when you consider that it was a simple modification of the master page. (Ok, it is not as simple as I am trying to say here but it is not a rocket science.)

 

Applying the new master page

In the previous section I skipped the part of applying the new master page to the site. You have multiple options for that. The easiest is probably to use SharePoint Designer for that – see Apply the new master page. Another option is to do that programmatically. To do so use the following code:

 

public void ApplyCustomBrand() 
{
    SPWeb site = SPContext.Current.Web;

    string MasterUrlPath = site.ServerRelativeUrl;
    if (!MasterUrlPath.EndsWith(@"/"))
    {
        MasterUrlPath += @"/";
    }
    MasterUrlPath += @"_catalogs/masterpage/Pokluda.master";
    ApplyCustomBrandToWebs(MasterUrlPath, site);

    Response.Redirect(Request.RawUrl);
}

public void ApplyCustomBrandToWebs(string MasterUrlPath, SPWeb site) 
{
    site.ApplyTheme("");
    site.MasterUrl = MasterUrlPath;
    site.AlternateCssUrl = "/_layouts/1033/STYLES/Pokluda/PokludaWebStyle.css";
    site.SiteLogoUrl = "";
    site.Update();

    foreach (SPWeb child in site.Webs) 
    {
        ApplyCustomBrandToWebs(MasterUrlPath, child);
    }
}

 

The above mentioned code is based on CustomBranding project from Chapter 3 of Inside Microsoft Windows SharePoint Services 3.0 book from Ted Pattison and Daniel Larson.

More information:

SharePoint

Pulse virtual machines programmatically

8. April 2009

I use Hyper-V frequently for testing purposes. Virtualization has a lot of advantages. There is one thing (ok, there is more but let’s concentrate on a particular one today) that bothers me. All my machines joined our company Active Directory. The problem is that if a machine doesn’t run for a certain time (I guess something like 2 weeks) the machine account will be removed from Active Directory. It’s not a huge deal, you just have to:

  • login as administrator
  • remove your computer from the domain
  • restart
  • join the domain again
  • restart

Even thought it’s not such a big deal it annoys me every time I need to do that. I thought that if I would be able to automatically start each machine (let’s say at night when I’m not using the computer) it would solve this problem. Since I use PowerShell I wanted to be able to leverage PowerShell for this.

Retrieve all available VMs

To retrieve all available VMs we need to execute a WMI query. The trick with this query is that it will retrieve all machines including your host machine. That’s why you need to add additional filter where you ask to retrieve only machines which caption starts with “Virtual”.

 

function get-vms
{
    $query = "SELECT * FROM MsVM_ComputerSystem WHERE Caption Like 'Virtual%' "
    get-wmiobject -query $query -namespace "root\virtualization" -computername "." 
}

 

Retrieve a particular VM

Once we have a collection of all available VMs, we will execute some actions on them. As a helper I will also create a function that will retrieve VM object when provided a machine name:

 

function get-vm([string] $name)
{
    #Get the VM Object
    $query = "SELECT * FROM Msvm_ComputerSystem WHERE ElementName='" + $name + "'"
    get-wmiobject -query $query -namespace "root\virtualization" -computername "."
}

 

Starting VM

To start a VM, we just need to set RequestStateChange to value 2. The code to do so is very simple.

 

function start-vm([string] $name)
{
    $VM = get-vm $name
    
    #Request a state change on the VM
    $result = $VM.RequestStateChange(2)
}

 

Shutting down VM

To shutdown a VM, we need to get a special ShutdownComponent and call InitiateShutdown method. The code might seem complex but it isn’t. Most of the code bellow is just error handling code.

 

function shutdown-vm([string] $name)
{
    #Get the Shutdown Component for the VM
    $vm = get-vm $name
    $query = "SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='" + $vm.name + "'"
    $Shutdown = get-wmiobject -query $query -namespace "root\virtualization" -computername "." 
    
    if ($Shutdown -ne $null)
    {
        #Request a forced shutdown
        $result = $Shutdown.InitiateShutdown($true,"Shutdown initiated from PowerShell script")
        if ($result.returnValue -eq 0) 
        {
            write-host "Shutdown of '$name' started."
        } 
        else 
        {
            write-host "Attempt to shutdown 'name' failed with code $($result.returnValue)."
        } 
    }
    else  
    {
        write-host "Could not get shutdown component for '$name'."
    }
}

 

Final script

To put it all together we need to retrieve all VMs and call start and shutdown in a loop for each of the retrieved VMs.

 

$VMs = get-vms
foreach ($VM in $VMs)
{
    $name = $VM.ElementName
    write-host $name
    
    write-host "`tStarting...."
    start-vm $name
    
    write-host "`tWaiting to fully load for 7 minutes..."
    start-sleep -seconds 420
    
    write-host "`tShutdown..."
    shutdown-vm $name
}

write-host "Finished."

 

Let me note that in the previous script I added a sleep for 7 minutes. Why do I do that? I want to give the VM enough time to completely start all the services.

 

Remarks

Let me add that I found that shutdown can also be done using “associators”. In the above code we use the following query:

    $vm = get-vm $name
    $query = "SELECT * FROM Msvm_ShutdownComponent WHERE SystemName='" + $vm.name + "'"
    $Shutdown = get-wmiobject -query $query -namespace "root\virtualization" -computername "." 

The same can be done using “associators”.

 

    $vm = get-vm $name
    $query = "Associators of {$vm} Where AssocClass=Msvm_SystemDevice ResultClass=Msvm_ShutdownComponent"
    $Shutdown = get-wmiobject -query $query -namespace "root\virtualization" -computername "." 

I don’t know which one is better but both of them seems to work just fine on my machine. If you do know the difference then please let me know.

 

More information

More information can be found at:

 

Attachments:

PowerShell

Windows Live Writer Source Code plug-in

2. April 2009

I use Windows Live Writer for authoring my blog posts. It is very user friendly application that allows you to forget about the ugly web interface your blog engine has for authoring posts. As a developer I wanted to be able to paste source code samples into my posts and be able to format them accordingly. Fortunately Alex Gorbatchev wrote a simple JavaScript application that will format source code according to parameters in the PRE element in which the code is placed. All we need to do is:

  • add support for Alex Gorbatchev’s SyntaxHighlighter to your blog (server)
  • teach Windows Live Writer to enter the right parameters whenever you insert a source code snippet in one of your posts

There are solutions for all of these but none of them suited my needs (I will try to cover the reasons for that later). Rather than complain I thought I would try to solve my problems.

Source Code Plug-in on CodePlex

I have created SourceCodePlugin project on CodePlex to include my solution to the above mentioned needs. The project has two parts: SyntaxHighligher for BlogEngine.NET and SourceCode plug-in for Windows Live Writer.

SyntaxHighligter for BlogEngine.NET

This part of the project allows you to integrate an updated SyntaxHighlighter with the BlogEngine.NET system. The highlighter is based on Alex Gorbatchev's code with a couple of updates:

 

Product: SyntaxHighlighter 
Author: Alex Gorbatchev 
Version: 2.0.296 
Link: http://alexgorbatchev.com/wiki/SyntaxHighlighter

 

Updates from Alex's code:

  • added PowerShell script
  • added FSharp script

 

Why did I have to code it myself? I had to update SyntaxHighlighter to add support for PowerShell and F# because I am used them frequently. Support for other my languages is already part of the product (C#, C++, SQL, XML, JavaScript, etc.). I found an integration into BlogEngine.NET but the extension was not compatible with the latest release of SyntaxHighlighter.

I have decided to update SyntaxHightlighter scripts library and create a new extension component for BlogEngine.NET compatible with the latest release of SyntaxHighlighter.

 

Examples

Sample F# code (this is a snippet from Tutorial.fs):

// Types: records
// ---------------------------------------------------------------

type Card = { Name  : string;
              Phone : string;
              Ok    : bool }
              
let cardA = { Name = "Alf" ; Phone = "(206) 555-8257" ; Ok = false }
let cardB = { cardA with Phone = "(206) 555-4112"; Ok = true }
let ShowCard c = 
  c.Name + " Phone: " + c.Phone + (if not c.Ok then " (unchecked)" else "")

 

Sample PowerShell code (this is a function I use for my nightly job):

#This method starts Windows service. It doesn't throw in case of an error.
function Start-ServiceNotThrowing($service, [bool]$displayWarning = $true)
{
    start-service $service -ErrorVariable errs 2&gt;$null
    if (($errs -ne $null) -and ($displayWarning))
    {
        set-color "yellow"
        write-host "Warning: Service $service is not installed."
        set-color
    }
}

SourceCode plug-in for Windows Live Writer

This part of the project adds a SourceCode plug-in into Windows Live Writer to enable inserting code into your blog posts in a form compatible with SyntaxHighlighter.

To insert a code, click on Source code... item in Insert section (right side of the Windows Live Writer). The plug-in will use the currently selected text or (when configured accordingly) take the text from the clipboard.

 

SourceCodePlugin_MainForm

You can tweak the behavior of the plug-in by clicking Options button to update plug-in options. All values that you enter in this options dialog will be saved for future use (you don’t have to enter the same configuration over and over again).

 

SourceCodePlugin_Options

 

Why did I have to code it myself? I found several plug-ins for SyntaxHighlighter. One of them was not able to keep option values between invocations that led to a situation where you had to update your options every time you wanted to touch your source code. Another one saved the options but when I was editing source code that was already inserted into a post, the plug-in wouldn’t display the currently selected text. Instead I had to select the text, press Ctrl+C, open the plug-in and press Ctrl+V.

I have decided I will create a simple plug-in that behave the way I expected.

Resources

As I mentioned above the whole project is now available at CodePlex: http://sourceCodePlugin.codeplex.com. Feel free to check it out and if you find a problem, let me know or take the source code and fix it yourself.

Blog , , ,

Configuring TeamCity with SQL Server

1. April 2009

This is the second post in my two post mini series where I try to describe my development environment. I have already mentioned that I use TeamCity as my continuous integration and build system. In this post I will describe how to configure TeamCity to use SQL Server as a main configuration repository.

Installation of TeamCity

Run TeamCity installation to install the build server and build agent on your server. This will give you fully functional build system that is integrated with your development components. It will automatically (when configured appropriately) trigger build when a change is submitted into your VisualSVN Server repository. The build will use MSBuild to build all the artifacts of your project including running unit tests, generating source code documentation, etc. When finished the system will automatically label the source code after a successful build.

Currently all configuration is written into HSQLDB database.

 

Microsoft SQL Server as a configuration repository

Assumtions: You have 64-bit operating system and you have installed TeamCity into C:\Program Files (x86)\JetBrains\TeamCity and your build server configuration is at C:\BuildServer folder.

 

JDBC driver

TeamCity is written in Java and therefore we need Java drivers for Microsoft SQL Server. Download and install JDBC driver from Microsoft SQL Server JDBC Driver page. Copy sqljdbc.jar and auth/x64/sqljdbc_auth.dll into C:\Program Files (x86)\JetBrains\TeamCity\webapps\ROOT\WEB-INF\lib.

 

Configure SQL Server for JDBC driver

Open SQL Server Configuration Manager and make sure that SQL Server (MSSQLSERVER) is up and running and that TCP/IP protocol is enabled (using port 1433).

 

TeamCity_SqlProtocol

Create SQL Server database

Open SQL Server Management Studio and add a new Login named teamcity. In this example I will use SQL Server authentication with password teamcity (because I chose such a simple password I need to uncheck Enforce password policy).

Create a new database named TeamCity and add teamcity user to the newly created database as db_owner.

 

Configure TeamCity migration tool

Edit C:\Program Files (x86)\JetBrains\TeamCity\bin\dbMigration.properties file and make sure that sourceURL is set correctly:

sourceURL=jdbc:hsqldb:file:C:/BuildServer/system/buildserver

Now we need to add target configuration for the migration. This is where we add information about our newly created SQL Server database:

# MSSQL 2008 via JDBC 
targetDriver=com.microsoft.sqlserver.jdbc.SQLServerDriver targetURL=jdbc:sqlserver://dpokluda:1433;database=TeamCity; 
targetUser=teamcity 
targetPassword=teamcity

 

Configuration migration

To execute the migration follow these steps. Start PowerShell (or any other shell but you will need to change the bellow mentioned steps).

Add Java to your Path variable so that migration tool can run it. This step is only necessary when you don’t have Java installed on your system and you want to use the one that comes with TeamCity.

$env:Path += ";C:\Program Files (x86)\JetBrains\TeamCity\jre\bin"

Stop all TeamCity services.

stop-service TCBuildAgent 
stop-service TeamCity

Navigate to TeamCity bin folder and start the migration.

cd "C:\Program Files\JetBrains\TeamCity\bin"
migrateDB.bat migrate

(It is fine to press just [Enter] key here since we have entered the full path into the dbMigration.properties file - otherwise enter C:/BuildServer path.)

Start TeamCity services.

start-service TCBuildAgent 
start-service TeamCity

 

Verify functionality of the new repository

Navigate to your TeamCity web page and add a new user in TeamCity administration named Test.

Open TeamCity database in SQL Server Management Studio and you should see that there is a new user named Test in users table:

SELECT TOP 10 * FROM [TeamCity].[dbo].[users]

 

TeamCity_VerifyUsers

For more information see the following resources:

Coding , , ,

Configuring Development Environment

31. March 2009

As a .NET developer I have a set of development tools I frequently use. As a test-driven developer I prefer to have some kind of a continuous integration environment available. This is the first part of the two post series. This first post will list components I use. The second post will describe how to configure TeamCity to use SQL Server as a main configuration repository.

Source control system

I currently use Subversion as my source control system. I like the fact that I can work on my files (see diffs for example) even when I’m not connected to my source control server. This is a huge advantage for notebook users in my opinion.

I currently use VisualSVN Server. It comes with a VisualSVN Server Manager (snap-in to the Microsoft Management Console) where you can very easily configure your source server. You don’t need to tweak authz file any more.

 

Development environment

I don’t want to spend too much time in this section because it would make this post way too long. Let me just note that my primary IDE is Microsoft Visual Studio with JetBrains ReSharper plugin.

As a unit test framework I use xUnit.net with xUnit.net Contrib integration to ReSharper. Why do I use xUnit.net and not NUnit or MSTest? The answer is best described by Jim Newkirk at Why did we build xUnit. I like the fact that the framework is very simple. It has a limited number of custom attributes and it’s reasonably fast. Assert methods are generic based which makes the code more precise. I also like the fact that each test is run in it’s own test class instance and therefore it improves individual test isolation.

Note: My biggest complaint about MSTest was the fact that it was only available in a special suite of Visual Studio. With Visual Studio 2008, MSTest is now part of Professional version of Visual Studio. I think that it is still not enough. Unit testing is such a basic requirement that it should be part of the platform (.NET Framework) or it’s SDK. I should be forced to buy Visual Studio to get MSTest binaries!

 

Build scripts

I am a long time NAnt user. I have a library of snippets I use for my build scripts. I have even created a set of CodeSmith templates that help me generate the basic NAnt scripts.

Even though I like NAnt a lot, I am slowly moving away toward MSBuild based scripts. Most of my new development is based on MSBuild scripts. Why? I like the fact that Visual Studio shares the same project configuration as my build system.

 

Continuous integration & Build system

I prefer spending my time coding rather than tweaking XML files to configure my environment. That’s why I decided to use JetBrains TeamCity. TeamCity is continuous integration and build management system that is available for free for small teams (details are available at JetBrains web).

 

Configuration repository

As a configuration repository I prefer Microsoft SQL Server database. For very small systems like stand-alone development on a notebook I would stay with HSQLDB which is the default configuration repository in TeamCity.

 

Installation and Configuration

First I install Microsoft .NET Framework, Microsoft SQL Server 2008 and Microsoft Visual Studio 2008. After that I install JetBrains ReSharper and xUnit.net. The last component to install is JetBrains TeamCity. Read my next blog post about configuring TeamCity with SQL Server.

Coding , ,