This tutorial describes the process of setting up a simple ASP.NET MVC Web Application with Entity Framework and Code First Migrations and a workflow for developing, testing, staging and deploying the application with full automation using GitHub, Jenkins and IIS.
First of all, make sure you have installed the following software:
Create a new repository in GitHub and clone it to your machine. Using your preferred Git client, add three branches – develop, test and production. You might add more, less or other ones depending on your branching strategy, but this will suffice for this example. For example, there may be multiple development, test and production branches, for example if you are maintaining and developing an older version of your software.
The develop branch is the common “snapshot” branch that developers merge their completed features or bug fixes into and it can be built on Jenkins. The test and production branches will be used to build your application for the corresponding environments and optionally publishing them automatically. Push all three branches to the remote GitHub repository.
(Optional) To prevent developers from merging untested code into test and production you can use the fork/pull request GitHub features. In that scenario, Jenkins will pull code from one GitHub account’s repository to which only certain developers and release managers have push access.
The drawback with this setup is that it requires developers to issue pull requests even when merging into develop. You could also create another repository where all developers has push access and pull develop from that repository.
Create and checkout a new branch called setup. Add a .gitignore file in the git root directory with the following rules and the ones in CSharp.gitignore.
Add .gitignore to index and commit.
In this part you can create a MVC Web Application, Intranet Application or Web API project. The examples will be a basic Web Application called MyApp. Feel free to commit changes in Git along the way.
Open Visual Studio and create a new MVC Web Application project. Make sure that the EntityFramework NuGet package is added. Open the Package Manager Console and run
Enable-PackageRestore or right-click your solution and click Enable NuGet Package Restore.
Create a model class Thing and a DbContext for your EF context. This is described in detail at Entity Framework Code First Migrations.
Open Web.config and locate the
<connectionStrings>...</connectionStrings> section. Add the following. Replace
SQLEXPRESS if you named your SQL Express instance to something else.
Add a default constructor to your DbContext class. The name in the constructor must be equal to the
name="..." attribute in the Web.config connection string. This explicitly tells the context to use the connection string you added in the previous step.
In the Package Manager Console, run
Enable-Migrations. This will scaffold a basic configuration under
AutomaticMigrationsEnabled = true in the constructor.
To use the configuration in your web application, add the following line to
Application_Start() in Global.asax.
Run Add-Migration in the Package Manager Console, enter a name (e.g. InitialMigration) and a DbMigration class is created. Use this method to create incremental migrations when you change persisted model classes. Read more on customizing migrations at MSDN’s Entity Framework Code First Migrations. Run
Update-Database to manually apply the migrations to your SQL Express database.
In this step you will create two publish profiles, one for each target environment, which will be used to publish the application from Jenkins once built and tested.
To be able to distinguish the environment in which your application is deployed, add the following to
<appSettings>...</appSettings> in your Web.config:
<add key="Environment" value="Development" />
Open Explorer, navigate to the web project’s root directory, create two copies of Web.Release.config and name them Web.Test.config and Web.Production.config. Go back to Visual Studio and toggle Show all files in the Solution Explorer. Select your two new files, right click and click Include In Project. You can now override properties in these new profiles. For example in Web.Test.config:
Right-click your web project and click Publish. Add a new profile and call it Test. Note that the name Test matches the Web.Test.config, which is a convention for transforms and profiles.
In the Connection tab, set Publish method to Web Deploy Package. Set Package location to
obj\Package\MyApp-Test.zip. This path is relative to the web project root and could be anything you like. Site/application can also be anything but must match the site name in IIS which you will setup later. Set it to MyApp.
Check Execute Code First Migrations [...]. If you don’t need any specific connection string for the deployment machine, uncheck Use this connection at runtime [...]. Also, the connection string can be set directly in IIS, which I think is a more clean solution.
Repeat these steps but call the configuration Production instead of Test.
By default, when you create a MVC Web Application, you get a test project which uses MSTest. To run these tests you must have Visual Studio (higher than Express) installed. This may work at your development machine but at the build server this can become quite clumsy. Instead, let’s use NUnit!
Add the NUnit and NUnit.Runners NuGet packages to your test project(s). If you have any MSTest cases, change the Attributes from the MSTest specific ones to NUnit Attributes (e.g.
If you have multiple projects in your solution (code libraries, web projects, test projects), or just want to customize your build, MSBuild is very handy.
NOTE! In this example MSBuild Extensions Pack is used. It’s possible to skip this and use the built in MSBuild tasks, but it can be convenient.
As this might become quite a large file, all details of how this works will not be covered in this example. To sum it up, the build.xml will contain a number of targets which aggregates the individual project targets. The following is the build.xml used to build the example project.
Using the Developer Command Prompt for VS20xx, navigate to the solution root directory and run:
msbuild build.xml /T:Package /P:PublishProfile=Test
NOTE! This might fail due to an issue with relative paths in NuGet.exe. To resolve this, set the SolutionDir property to the absolute path of your solution.
Before setting up Jenkins, make sure you have commited all you source files in Git and then merge branch setup into develop. You can go ahead and delete the setup branch when you’re done. Then merge develop into test and push it to GitHub so that Jenkins will be able to pull your new shiny setup.
The build server should be a Windows Server 2008 (or higher) with the following software installed:
NOTE! To let the NuGet command line tool restore packages, set the system environment variable EnableNuGetPackageRestore to true.
Make sure the Jenkins service is run by user with sufficient privilegies. Configure the GitHub Plugin with your GitHub account and repository.
Create a new Job in Jenkins and call it MyApp-Test. In the Source Code Management section, check Git and set Repository URL to your GitHub repository URL. Specify that the branch to build is test. In Build Triggers, check Build when a change is pushed to GitHub. This option is provided by the GitHub Plugin and all required configuration is created automatically by the plugin if you use the Automatic Mode. Make sure no firewall blocks GitHub from accessing Jenkins.
Add a MSBuild build step. MSBuild Build File should be set to build.xml and Command Line Arguments to
/T:Package /P:PublishProfile=Test;SolutionDir=C:\workspace\MyApp-Test. Change the SolutionDir property to match your Jenkins workspace path. To enable automated deployment to your IIS Server, add a Windows batch command build step. The Command should be something like (replace
.out\Package\Test\MyApp-Test.deploy.cmd /y /M:<URL>/msdeployagentservice /U:<USER> /P:<PASS> AllowUntrusted:True`
Add a NUnit test result report post-build action and set Test report XMLs to
.out/*.Results.xml which catches all files matching that string and generates a report in Jenkins. Add an Archive the artifacts post-build action and set Files to archive to
.out/**/*.* which will catch all files (with an extension) in .out recursively.
Save the configuration and try manually starting a build. This should fail, as you have not set up IIS with Web Deploy yet.
Repeat these steps for Production. If you do not want automatic deployment to your production environment, skip the step with deploy.cmd. Your built deployment packages will be archived by Jenkins and available for download.
You might also repeat these steps for the develop branch and perhaps schedule the builds differently if you are using a separate repository for develop, as discussed in the Setting up Github and Git chapter.
Follow the tutorial at Configuring a Web Server for Web Deploy Publishing (Remote Agent). Make sure you name your web site as you did in the Publish Profile or vice versa. The user you specified in the Jenkins configuration must be a valid user with permission for web deployment. This could be a AD/Windows user or a IIS Service Account. If you have a specific connection string for your SQL database, add it in the Connection Strings section.
NOTE! If needed, configure your firewall settings so that Jenkins can access the web server.
Now you should have all your infrastructure up and running. Try running a manual Jenkins build again and verify that it works. The code is pulled from GitHub, the project is built with MSBuild, the packaged web application is both archived and deployed to IIS, the database is updated using your Code First Migrations and the NUnit test results are collected.
This step involves creating a change in the model and the complete flow of deploying that change.
On your development machine, create and checkout a new branch called feature-thing-description and open Visual Studio. Edit Thing.cs and add a Description property:
Build the solution and run
Add-Migration ThingDescription in the Package Manager Console. A new Migration is created for you (and you may customize it). Run
Update-Database to check that it is working properly.
Commit your changes in Git, merge feature-thing-description into develop and then develop into test. Push your changes to GitHub.
Open Jenkins in your web browser and verify that the project is building. It might take a moment for Jenkins to receive the notification from GitHub and to start the build. When the build is done, the new package is deployed to your test web site and you can download the artifact in Jenkins. You may now celebrate!
This is a simple and efficient setup for Continuous Integration and Deployment of a ASP.NET MVC Web Application. In a large-scale project, with many developers, the branching and merging strategy might need to be more complex regarding release strategies and developer permissions. You might also consider a different setup for development, staging and production servers.
However, the basic ideas and techniques still applies and I believe the workflow can be customized to fit most needs.