Migrator.NET and MSBuild configuration tips

MSBuild allows you to create properties, key/value pairs that you can reference in other parts of the script using the $(key) syntax. So if we have a property called Foo, we can get its value using $(Foo). There are various ways to define properties. You will most often find properties declared inside a PropertyGroup element. You can also dynamically create a property using the CreateProperty task or pass in a property as a parameter to the MSBuild.exe command:

MSBuild.exe Project.csproj /p:Foo=Bar

This opens up the possibility of declaring a property with a default value in our script, and overriding the value only when necessary, thus simplifying our MSBuild commands. The MSBuild script becomes a bit more complex though.

Configuring MSBuild properties for Migrator.NET

The Migrate task expects a few parameters that might not always have the same value. One of those is the To parameter. Its value is used to determine which migrations will be executed. Usually its value should be -1 wich will execute all migrations up to and including the very last one. So let’s define the To property and set it to -1 so that we no longer have to pass it in ourselves:

<PropertyGroup>
    <To>-1</To>
</PropertyGroup>

It’s a simple as that. Now we can remove the /p:To=-1 from our external command and provide it only if we need it (this is why we have the external command configured to prompt for arguments). Whenever we want to migrate to a different version than the last, let’s say version 42, we append /p:To=42 to our command and it will override the property in the script.

Running migrations on different databases

Usually when developing software that includes a database you have a local copy of the database. That way, your work will not interfere with that of others on your team. So you can run the migrations on your local copy of the database. When it’s time to deploy the software, the remote database might need to be migrated to a newer version as well. In the case of web applications you often have two separate environments, one for staging prerelease software and the live environment. We can still use MSBuild to run our migrations on these servers. We can do that from the comfort of our own machine if these servers are avaliable through the network. To do this, we need to have the connection strings for the databases available in our MSBuild script, and a way to switch between them. It’s another case for using properties, but this is a little more complicated.

First, let’s add a property that can be used to switch between different connection strings. It determines the environment where the migration will take place, the default being Development, your local machine:

<PropertyGroup>
    <To>-1</To>
    <Env>Development</Env>
</PropertyGroup>

We have a property, and we can override it by passing /p:Environment=Staging for instance. But the property doesn’t do anything. We need to have the value of the Env property function as a condition for selecting the value of another property. Luckily for us, MSBuild has what is called conditions, which can be applied to a property declaration:

<PropertyGroup>
    <To>-1</To>
    <Env>Development</Env>
    <ConnectionString Condition="'$(Environment)'=='Development'">Data Source=$(MSBuildProjectDirectory)\Development.db</ConnectionString>
    <ConnectionString Condition="'$(Environment)'=='Staging'">Data Source=$(MSBuildProjectDirectory)\Staging.db</ConnectionString>
    <ConnectionString Condition="'$(Environment)'=='Production'">Data Source=$(MSBuildProjectDirectory)\Production.db</ConnectionString>
</PropertyGroup>

Now the actual value of the ConnectionString property depends on the value of the Environment property. Again, the default value will be used in most cases, but when it is time to deploy, it is very easy to run the migrations on the staging or live servers. We just have to use the property in the Migrate task:

ConnectionString="$(ConnectionString)"

Hope this helps!