blog.reis.se

It's all about looks

officeAs you might have seen in the Windows Phone 7 Office application there are small round buttons in the panorama. As you should never use the application bar in the panorama it’s a good way to get some navigation points into the panorama. There are a few versions of this button out, ranging from styling a button and up to complete controls. However the ones I have found have things I don’t like, mostly they work with black and white images or with paths for the icon.

So I started out with a few basic specifications, I wanted:

  • A simple control to use, no special content
  • Only mage for the button (white with alpha channel)
  • To be able to easily add content next to the button
  • Ability to re-skin the button

The goal was to be able to define a button with just a simple:

<jc:RoundButton Image="/icons/refresh.png" Content="refresh" />

For those that don’t want to find out about my journey towards the RoundButton control there is a zip with the code and a sample project at the very bottom of the post…

When I first started out with the basic design the approach was the same as for others out there, two images that was swapped on light theme and shifted on pressed state. But I didn’t like it, I wanted the control to handle the image inversion stuff so my next thought was to create a new image with Writable bitmap and do some pixel magic, but before I got that far I stumbled on a blog post on displaying an image in the accent color. This was brilliant, using the image as a opacity mask, I could have whatever color I liked. So the core of the control got to be something like this:

<Rectangle x:Name="ImageForeground" Height="48" Width="48"
  Fill="with_whatever_color_or_template_color">
  <Rectangle.OpacityMask>
    <ImageBrush ImageSource="image.png" Stretch="Fill" />
  </Rectangle.OpacityMask>
</Rectangle>

The code

On to the control design, first of was to create the code behind for the button, creating the attached properties. This code ended up looking like this:

public class RoundButton : Button
{
    private object _layoutRoot; 
    public static readonly DependencyProperty ImageProperty  = DependencyProperty.Register("Image", typeof(ImageSource), typeof(RoundButton), null); 

    public RoundButton() : base()
    {
        DefaultStyleKey = typeof(RoundButton);
    }
    

    [Description("The image displayed by the button in dark theme (and in normal mode)"), Category("Common Properties")]
    public ImageSource Image
    {
        get { return (ImageSource)GetValue(ImageProperty); }
        set { SetValue(ImageProperty, value); }
     }

    public override void OnApplyTemplate()
    {
        _layoutRoot = GetTemplateChild( "LayoutRoot" ) as Border;
        Debug.Assert( _layoutRoot != null, "LayoutRoot is null" );
        base.OnApplyTemplate();
    }
}

Hurdles and solutions

So the template stuff should be easy now right? Just add the Image to ImageSource for the Brush like this:

<ImageBrush ImageSource="{TemplateBinding Image}" Stretch="Fill" />


Wrong! Turns out you can’t bind to an ImageSource in an ImageBrush, because ImageBrush don’t inherit from FrameworkElement, as BMiloshevska pointed out. Argh, so close. Back to the drawing board until Derek Lakin pointed me at an article about using a converter as a workaround. Here is the converter stuff:

public class ImageBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        BitmapImage image = (BitmapImage)value;
        ImageBrush imageBrush = new ImageBrush();
        if (image != null)
        {
            imageBrush.ImageSource = image;
        }
        return imageBrush;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}


Getting closer, but still there are a few hurdles left as you will see. Now it seems you can bind the ImageBrush to the DependecyProperty with a Converter, like this:

<ImageBrush ImageSource="{TemplateBinding Image, Converter={StaticResource brushConverter}}" Stretch="Fill" />


Wrong again! You can’t use a converter on a TemplateBinding, sigh. Then a new angle: The DataContext. You can TemplateBind the image to the DataContext and then use a normal binding (with converter) for the brush. Success! The binding ended up looking like this:

<Rectangle x:Name="ImageForeground" Height="48" Width="48"
    Fill="{TemplateBinding Foreground}"
    DataContext="{TemplateBinding Image}"
    OpacityMask="{Binding Converter={StaticResource brushConverter}}" />

The template

So now it was the last part left, creating the template style with states for normal, pressed and disabled. The last one is a bonus, with the image approach you would now need three images, white, black and grey, no you can use whatever you like. The template was placed in Themes/generic.xaml and looks in part like this (the full xaml is included in the zip):

<Style TargetType="local:RoundButton">

  <!-- Basic template setters -->

  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="local:RoundButton">
        <Border x:Name="LayoutRoot" Background="Transparent" Padding="12" >
          <VisualStateManager.VisualStateGroups>

          <!-- The states Normal/Pressed/DIsabled/... -->

          </VisualStateManager.VisualStateGroups>

          <!-- The actual button template where the image and content goes -->
          <Grid>
            <StackPanel Orientation="Horizontal">
              <Border Height="48" Width="48" x:Name="ButtonBackground" BorderThickness="3" CornerRadius="24" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" >
                <Border.Resources>
                  <local:ImageBrushConverter x:Key="brushConverter"/>
                </Border.Resources>
                <Rectangle x:Name="ImageForeground" Height="48" Width="48" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}"
                    DataContext="{TemplateBinding Image}"
                    OpacityMask="{Binding Converter={StaticResource brushConverter}}" />
              </Border>
              <ContentControl VerticalAlignment="Center" Margin="0" HorizontalAlignment="Left" Padding="8,0,0,0" Content="{TemplateBinding Content}" />
            </StackPanel>
          </Grid>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

There, finally I reached my goal!

Improvements

So am I done now? Yes and no. The functionality is in place and the first four goals reached but there is more stuff I like to do:

  • I want to add some optional animation, for example the push behavior from the AppBar and the tilt effect (actually you can use the tilt effect that Peter Torr blogged about, as the control is based on a button)
  • I think there is a workaround to the Converter, I would like to eliminate that part.
  • Also create a round toggle button with two images (for example play/pause media button)

If anyone happen to have a solution or idea around those issues I would be happy to know.


The zip includes the control and a test project to try it out.


One of the major complaints on the Windows Phone 7 platform is that you can’t run third party applications in the background. I had the same complaint on iPhone for a long time but over the time I have started to think about the problem and I’m not sure background operation for third party application is the only way to solve all the problems.

Let’s look at two scenarios that I think are the most common for background operation: Music player services like Spotify or Last.fm and GPS related applications like the RunKeeper GPS tracker. In these two main scenarios I think a richer and more service oriented API within the phone could take care of the problem instead of background execution.

Lets focus on the audio service first

No doubt that you need it to continue playing music while you work on other stuff. That’s not what I suggest but instead I want you to think of the application that is native in the phone, the Zune media player. Why would I want to create a new player over and over again? Wouldn’t it be better to integrate with the current? If the API was richer, in the Spotify case it would be possible to:

  • Plug in the codec + DRM that’s used in Spotify
  • Create and use playlists from either streamed material or locally stored material – or both
  • Update the background image and access to all the data that is visible in the player
  • Add the playlists as your own into the Zune player and for example mark them with a Spotify icon fro branding

The benefit with this would be many: Apart from not taking up precious development resources for cloning the Zune player over and over, you could let Microsoft take care of creating the most effective background enabled audio/video player.

To the user there is also the benefit of using the familiar way of navigating the audio as always instead of a new one for each application.

Now over to the GPS application

Why do you need to run this in the background? Well there are lots of reasons, but mostly it’s to be able to track and later plot your location from the track you are currently running. This functionality could also be handled with a service similar to the audio service. Why not trigger the GPS service to start tracking and storing the points. This would actually give even more advantages. This way two GPS enable applications could be using the same GPS track store and bring up the points. Again this would let the developer focusing on delivering an awesome application and not how to handle the GPS API effective enough not to drain the battery.

Moving on to task scheduling

There are of course situations where this approach won’t solve your issue but it’s good start to think in other directions when it comes background execution. Why not support some kind of task scheduling instead of true background operation. Here’s an example of what I mean:

In the GPS tracker situation there is an other issue that should be solved. The RunKeeper application vocally reports information on speed, average speed, distance, etc. This would normally be handled with an application running in the background. But it would also be possible to let simple tasks or code snippets be triggered with a set of rules based on the GPS tracker, like time, speed or distance.

I wouldn’t call it multitasking as the application isn’t really running in the background. It is just providing the code that should be brought back to life on certain points and then go to rest again, it can even be fully exited instead of suspended. To the user it would be of no difference if the application is running, suspended or exited as long as it behaves as if it was running in the background.

Conclusion

I think that in many situations we tend to take the obvious solution. While an alternative and for the user actually better way can be achieved if you think twice about it.

And there is an embryo to this in the Zune application, you can let your application launch the Zune player with a URL (either a net stream or locally stored) and it works great. But the API needs to be richer as I would want to insert Metadata and create lists for this as well as be able to provide a codec for handling media streams that Zune cannot play out of the box.

The market will continue to demand background enabling, and Microsoft will probably support that sooner rather than later but I really think we would all benefit from this thinking, both as developers and users.


Microsoft MIX10 brain dump

Also cross-posted on my company blog

After three days of the Microsoft Mix10 event the brain tend to overflow. So I sit down at a Starbucks and try to summarize my thoughts before my mind explodes.

It’s easy to get caught up in positive buzz during events like this but I really think Microsoft is doing a lot of things right here with Windows Phone 7 series, the next level of .NET and Silverlight and Internet Explorer 9, among other things. Some of it, I believe, accounts to all the focus on User Experience and the influence that Bill Buxton have on this.

Also if you want to catch any of the sessions most of them are up at the mix10 site already.

Silverlight release pace

This was a big surprise to me; Silverlight 4 is going to be released as early as next month end the release candidate (RC) is out now. I was more in the lines of a beta and the an RC in the summer and a release late 2010. But it seems they try to align and do a big release with .NET 4, VS2010 and Silverlight 4. As a bonus the Pivot control will be in the controls toolkit so that’s going to be fun to play with.

Silverlight 4 Tools RC | .NET 4 RC | VS2010 RC

About the Windows Phone 7 series

The development platform for Windows Phone 7 series was, of course, one of the biggest news on the starting keynote and lot of sessions around it followed. I think they are on the right track with the platform. A few surprises surfaced, like the inclusion of DirectX to utilize HW backed video decoding and the Windows Phone development tools being released for free.

But a few questions and problems surfaced as well, as you can se all over the web it seems they are not including cut & paste and market place being the only application deployment channel. Other things I thought about was:

  • How is the user interface is going to perform in right to left markets.
  • What the possibilities are to hook in other services, like for example Pandora, to provide music streams for the native Zune player.
  • And I still have a few issues with lag in the interface as well as accidental clicks, lets just hope the will get this issues out the door before they release it.

The user experience work that has been put into the new OS is really cool, the decision to remove all chrome and go for a real clean and consistent look is really fresh. And the decision to let the back button work on all levels across the phone, in-applications as well as between was a stroke of genius.

Windows Phone Dev tools | UI Design guidelines

What about HTML 5 and IE 9

It was pretty obvious that they should release some news around Internet Explorer 9 and its take on HTML 5. It is just an early technology preview but I have to say I’m impressed by the results. They did tone down the JavaScript speed issues but quite frankly they were on par with the other browsers and at those speeds it really is less of an issue. What still is an issue is standards, and anything but a 100/100 score on Acid3 is a failure in my eyes.

What they did show was the brilliant work they have done on the GPU acceleration part. This really was amazing 720p HD video streaming on a netbook was blazing fast, they even manage to pump two 720p streams without a glitch, impressive. And rendering HMTL5, CSS3 and SVG with hardware acceleration really looks promising.

If anything it shows that the Internet Explorer team is still in the game and might really get a decent browser out the door.

IE9 platform preview

Expression Blend 4

The things I saw done with blend was quite cool, this tool has come a long way from the first release and is now a potent tool. The tight integration with Adobe was finally in place, just point to the assets and start editing it in Illustrator or Photoshop. What’s more impressive, if I got it right, was that you were able to bind to a text object from the imported Illustrator assets directly to the object in your ViewModel! This really puts design control back into the hands of the designer.

Expression Blend 4 beta

Get real

So what’s left for me now is to find the time to play with all these new toys and and experience for myself what they are capable of before it’s time to Get Real and start creating.

Have fun // Håkan Reis


In the first part I wrote about how to get the version number that is available in TeamCity into the assemblies that are built and also how to maintain the dynamic unit testing feedback. I will now continue to explain how to get the complete chain working up until naming the finished package.

Propagating the version number

I left out one bit of MSBuild script that is vital for the next step. How can you transfer a version number from one project to another? Well, it’s actually quite simple, just save it as a text file among your artifacts and you can read it back up in a property in your MSBuild files. This is what it looks like in the MSBuild script:

<WriteLinesToFile File="SoftwareVersion.txt"
Lines="$(BUILD_NUMBER)"
Overwrite="true" />

This gives you a file named SoftwareVersion.txt that you can save as an artifact and use in the following build projects, how simple some solutions are.

File renaming and creating a package

The good thing about about MSBuild is all the extra things around just executing builds, in combination to the WriteLinesToFile there is of course a ReadLinesFromFile, and as you guessed this will read lines from files. These lines can be stored in an item collection (for many lines) or a property (that’s what we are after) like this:

<ReadLinesFromFile File="$(ReleaseDir)\SoftwareVersion.txt">
<Output TaskParameter="Lines"
PropertyName="Version" />
</ReadLinesFromFile>

Now we have what we need to get the version that was built in one project to control the name of a file in another project. The renaming part is easy.Actually there are no rename task but you can of course execute a command directly with the Exec task so renaming will look like this:

<Exec Command="rename $(ReleaseDir)\SoftwareServiceSetup.msi
SoftwareServiceSetup-$(Version).msi" />

Transferring TeamCity versions to Subversion tags

Last is to get the labels created back into subversion (as it is that I’m currently working with, it is what I know well). It is easy to just add the labels in TeamCity. The settings are placed under Version control settings in Build Configuration step two.

However, there might be a mix-up on where you want to save your tags, this is set under the VCS root configuration. The default is set to trunk=>tags but this hasn’t worked for the setup I have. Instead I have to set this to /trunk=>/tags, and remember, don’t checkout the trunk locally it will be a big checkout…

So there you have it. Version numbers that follows every build from development, through testing and ending up on the subversion labels and the package names. Traceability that will make a configuration manager cry with joy.

// Håkan Reis


Last time I posted on MSBuild and TeamCity I showed how you could use it to deploy remotely in Deploy with MSBuild and custom targets Part 1 and Part 2. There are one issue that’s always a part of professional projects - version handling. I will show you a way to let the version get into the assemblies and trickle through all build steps all the way to the production package. In the first part I will concentrate on getting the version number into the assemblies while keeping unit test feedback, where currently running tests are directly visible in TeamCity.

Setting the version in TeamCity

First off is to set the version and build number in TeamCity. This is one of the easiest parts. Just go into the General settings for the project and set up the version number format and the build counter setting. like this:

versionNumber

Now we have something to base our versioning on, the first part 1.0.2. are static and you update that manually as you start a new release, etc. The last {0} will give you a build number, you get the idea.

Getting the version number to the assemblies

Next step is to make sure the version number from TeamCity is used to build the assemblies and added instead of the Assembly, File and Product Version set in the visual studio project properties. But first some background.

When the assemblies are built version values are automatically set from AssemblyInfo.cs files. If nothing is set, it will get the value of 0.0.0.0, file version will get the same version as in Assembly Version and application version will follow the file version. More about this in Assembly version, File version, Product version. The basics is that if we want to control the version we must make sure the AssemblyVersion attribute  is in there. I would suggest setting it to 0.0.0.0 to make it easy to identify if anything fails to update. You could even have safeguards for it in code, aborting execution if the version is zeroed.

Now you have to make sure you change this number after the checkout but before the build has started. This calls for a shift from solution building to using MSBuild. But for the basic solution to build you only need one line of MSBuild script:

<MSBuild Projects="Software.sln"

Targets="Rebuild"

Properties="Configuration=Release;" />

That’s easy enough. Moving on to the version, we first collect the AssemblyInfo.cs files in the solution and then rewrite the version number with the TeamCity number. As it happens, there are a build property available containing the TeamCity number: $(BUILD_NUMBER). To get the build number into the assembly info we can use a task called FileUpdate that is part of a collection of open source MSBuild tasks, it will look like this:

<!— Collect the Assembly info files in the solution –>

<ItemGroup>

<AssemblyInfoFiles

Include="**/Properties/**/AssemblyInfo.cs;" />

</ItemGroup>

 

<!—Identify current AssemblyVersion and replace -–>

<FileUpdate Files="@(AssemblyInfoFiles)"

Regex=’AssemblyVersion\(“.*”\)\]’

ReplacementText=’AssemblyVersion(“$(BUILD_NUMBER)”)]’ />

This will get the desired result, with all assemblies carrying the correct version number. However, it will also give as a new problem; we now loose the unit test feedback in TeamCity, but we can solve that in the next step.

Unit testing with feedback

When you move from solution based execution to MSBuild based, the first issue you come across is that the unit tests are missing. The natural step is to make the MSBuild script execute them. Normally you would call nunit-console or maybe the NUnit task. But that will only give you a file to display as an artifact. Not the direct and continuous feedback you get from TeamCity. Fortunately TeamCity will provide a unit test runner task that can be used instead. The following lines need to be in the MSBuild script:

<!-- Integreate with TC's nunit runner –>

<UsingTask TaskName="NUnit"

AssemblyFile="$(teamcity_dotnet_nunitlauncher_msbuild_task)" />

 

<!-- Select the assemblies to test –>

<ItemGroup>

<TestAssemblies Include="**/release/*UnitTest*.dll;"

Exclude="**\obj\**;" />

</ItemGroup>

 

<!-- Execute the tests –>

<NUnitTeamCity Assemblies="@(TestAssemblies)" />

Read more about the NUnitTeamCity task on the TeamCity wiki, where you find information on how to execute it in 32bit, categories, on specific versions of NUnit, etc. Now we have all the parts to handle versions and still get the feedback. This also opens up some more opportunities as we now execute the build from MSBuild. We can do some pre- and post-processing around the build like zipping up files or exchange files or data after checkout but before build.

Next step is to get the version numbers across to the next project and use it for packaging as well as labeling our builds in subversion.

// Håkan Reis


From the previous post we have these custom targets we want to create; MSI package building, Database deploy, Service installation, and Web deploy. I will go through each of them and give you some hints on how the targets were created.

MSI package building

For this part we need to know the solution name, the project containing the setup and where VisualStudio is installed. Remember the registry thing from the last post? Here it really comes in handy.

<PropertyGroup>
  <VS>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
    VisualStudio\9.0\@InstallDir)\devenv</VS>
</PropertyGroup>

<Target Name="BuildMsi">
  <Message Text="Building package $(Vdproj)" />
  <Exec Command='"$(VS)" "$(Sln)" /Build "Release|Any CPU"
    /project "$(Vdproj)" 
    /ProjectConfig "Release"'/>
</Target>

Never mind the extra line breaks, it’s for readability. But note the single quote that is used on the Command part, this makes it possible to use double quote in the command text for readability. The other option is to use &quote; but that really makes it very hard to read the scripts.

Database deploy

When we deploy a database you typically have five parameters involved; where, who and what. Oh, the who part is user and password and where includes both server and database, a total of five. Now, let us start with a simple target and a magic database task.

<Target Name="DeployDatabase">
  <Message Text="Deploying $(DBContent) to $(DB) on $(Server)" />
  <MagicTask DataPath="$(DBContent)"
    ConnectionString="Database=$(DB);Server=$(Server);
UID=$(User);PWD=$(Pass)"
DropDatabase="true" /> <Message Text="Database deployed on $(Server)" /> </Target>

The MagicTask is depending on how you deploy the database, we are using NHibernate and have written custom tasks to handle the deployment. There are a set of build tasks on CodePlex, created by a college of mine, that can help you with the specific tasks for database deployment.

Service installation

When it comes to service installation you have to get hold of a little bag of tricks to get all of it working. Locally there is not as big issue . Just call the MSI installer and execute it silently both for uninstall and install.

<Exec Command='msiexec /i "$(Msi)" /qn' />

$(Msi) holds the full path of the installer package. When it’s installed, it should be started and for that we use net start with the service name as parameter.

<Exec Command="net start $(Service)" />

But how do you do it remotely? Here’s where the bag of tricks come in handy. First you need a place on the remote system where you can transfer the files. Make sure the agent has access right to copy the files there. Then, use some magic from Sysinternals, named PsExec.exe. This little tool makes it possible to remotely execute net start and msiexec. his target we need the MSI, the Server, user and password and the name of the Service that is installed. You need to touch up the scripts with some of your own paths to make sure you have all the files in the right place to start with.

<PropertyGroup>
  <!-- The sysinternals tool -->
  <PsExec>$(MSBuildStartupDirectory)\Tools\psexec.exe</PsExec>
  <!-- Here is the new MSI package is placed -->
  <NewMsi>$(MSBuildStartupDirectory)\msi</NewMsi>
  <!-- Here is the currently installed MSI package placed -->
  <SharedMsi>$(server)\msi</SharedMsi>
</PropertyGroup>

<Target Name="InstallMsi">
  <Message Text="Installing and starting $(msi)/>

  <!-- First Uninstall the old service if the config is there -->
  <Exec Command='$(PsExec) -accepteula $(Server) 
        -u $(User) -p $(Pass) -w "$(OldMsi)" -n 60 
        msiexec /x "$(SharedMsi)\$(msi)" /quiet' />

  <!-- Copy and install the new service -->
  <Copy SourceFiles="$(NewMsi)\$(msi)" 
    DestinationFolder="$(OldMsi)" />
  <Exec Command='$(PsExec) -accepteula $(Server) 
        -u $(User) -p $(Pass) msiexec /i 
        "$(SharedMsi)\$(msi)" /qn' />

  <!-- and start the service -->
  <Exec Command='$(PsExec) $(Server) -u 
        $(User) -p $(Pass) -d net start $(Service)' />

  <Message Text="$(Service) installed and started" />
 </Target>

Hopefully this will give you the basic idea. For all the switches on PsExec, look into Sysinternals. But one that can be a real timeserver (often hangs the build) is the –accepteula switch, it auto accepts the EULA splash screen.

Web deploy

Maybe the simplest deployment is the web deployment. Most of the time there is nothing more to it than copy the files and you are up and running. However, you may need to set some configuration etc depending on how your environments are setup. But for now a simple target like this will do the trick for web deployment:

<ItemGroup>
  <WebContent Include="$(ContentPath)\**\*.*" />
</ItemGroup>
  
<Target Name="DeployWeb">
  <Message Text="Installing web on $(Server)" />
  <Copy SourceFiles="@(WebContent)" 
    DestinationFolder="$(Server)\$(WebFolder)\%(RecursiveDir)" />
</Target>

The ItemGroup here will produce a recursive list of files and folders from the ContentPath and it get placed in WebContent item group. The files will then be copied to the WebFolder on the Server. So here we have three properties to set for this target. Also make sure you have the correct access levels on the folders and you can do this remote as well.

Calling the targets

Now that we have the targets in place, how do we get all the properties into them? Well, custom targets can be accessed in a couple of different ways. You can import them and then call them as usual and all the properties you set in the calling script are set as if the target was in your current script.

<Import Project="CustomTargets.proj" />

<PropertyGroup>
  <Server>Srv01</Server>
  <User>Kalle</User>
  <Pass>Kula</Pass>
  <Msi>setup.msi</Msi>
</PropertyGroup>

<Target Name="default">
  <CallTarget Targets="InstallMsi" />
</Target>

But in this case I want to pass in more than one set of properties to the target to make it more flexible. And in that case it’s easier to use the MSBuild task. This will execute the target as if you were calling it from command line.

<MSBuild Projects="CustomTargets.proj" 
  Targets="DeployDatabase"
  Properties="Server=DbSrv01;User=sa;Pass=sa;DB=Base;DBContent=Data" />

All together now

All this is, in our case, trigged from TeamCity, but could of course be triggered from other build systems as well. Adding some initial parameters, like where to deploy things, makes it very easy for me to add more servers later on. For now I just execute MSBuild with the needed properties.

MSBuild deploy.msbuild /property:DB=DbSrv01;DeployOn=Srv01;Web=WwwRoot

You have to make a lot of choices where to trigger and store the properties to maximize flexibility and readability. Additionally, some smart naming of files and projects will help in minimizing the number of properties. All this is of course depending on the project you are deploying.

And one more thing, make sure the build agents are executing with the right access rights, or you will not be able to execute some of the commands. This is especially important when it comes to accessing the other systems through PsExec. It took me a while to fix that problem :)

// Håkan Reis


We use TeamCity not only for the development builds and test execution, but also deployment to test and demo environments. The ultimate goal is to make it all the way into the stage environment. If we ever will get there I cannot tell, there are a number of obstacles like firewalls, port restrictions and good old access rights in the way but there are ideas on the drawing table how to solve that. As I was going through the deployment scripts I found that it needed an overview so I too the time to extract a few custom targets.

Background

The application is depending on three mechanisms: web, services and database. Web is deployed into IIS, a number of services are installed using MSI, and a database that are deployed using custom MSBuild tasks. This concoction is installed to three different machines for test and demo. Additionally some prerequisites around this are:

  • As TeamCity uses its own internal checkout paths, if not specified, all paths should be relative. This will ensure that its really simple to add more agents later on.
  • Naturally the scripts work for both 32bit and 64bit environments.
  • The artifact handling in TeamCity should be used as much as possible.

Go for absolute relativity

You should always use relative paths, absolute paths always make a mess of things. Making it hard to move script or folder structure. But it means you sometimes need to be able to find the absolute path at a given moment. for example command line often need the current working directory. A few useful reserved properties can take care of that, and two of them are:

  • $(MSBuildStartupDirectory) – the directory where the MSBuild execution was started
  • $(MSBuildProjectDirectory) – the directory where the current executing script is placed

About the 32/64 bit problem; on 64bit VisualStudio is in Program Files (x86) but on 32bit its in Program Files. This is a problem as we currently use VisualStudio in command line for building MSI packages

Well, an easiest way to get the path right is the registry to find out. And we are in luck, there are registry access in MSBuild 3.5. So to get the path use this syntax:

$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
VisualStudio\9.0\@InstallDir)

Artifact handling in TeamCity we know about from a previous post so I will not go into detail around that. However, one problem I run into is that using VisualStudio to build the install packages, means that we are not using TeamCity artifacts all the way. We are rebuilding the assemblies in this step. But hopefully WIX can help out here.

Stay on target

So with this background the following targets surface:

  • MSI package building
  • Database deploy
  • Service installation
  • Web deploy

There reason for the selection of these parts was not only to avoid repetition. This will also give much more readable and maintainability of scripts. And if we move to WIX or change database deployment we only have one place to update the scripts.

In the title I promised you custom targets and deployment, and I will give you that, but not until the next part.

// Håkan Reis