In this recipe, we take a look at how to host the application we have written so far on cloud services, such as on Windows Azure and AppHarbor. Both of these have PaaS solutions for running ASP.NET applications on their cloud infrastructure. In both cases, the application we've written so far is capable of running except for two things mentioned as follows:
The connection string for the data store has to be moved out of the code and into
web.config
. Hardcoding, as I have done so far, is a really bad idea, so moving the connection string to theweb.config
file is good anyway.Avoid running the integration tests during the cloud build.
The following steps will help you host the application you built on cloud services:
First go to AppHarbor (https://appharbor.com) and; just create an account with a free plan, since that should be fine for playing around with.
Follow the instructions on the AppHarbor website to create an application, but do not deploy your Nancy application yet.
Assuming that we are using MongoDB for the implementation of the
IDataStore
interface, add theMongoLab
add-on to your AppHarbor application. This gives you access to a cloud-hosted MongoDB database that we will have our AppHarbor-hostedTodosNancy
run against. If you have chosen another database for the data store, have a look through the AppHarbor add-ons—chances are there is an add-on for your type of database.Go to the
web.config
file inTodosNancy
and add the following line to the application settings section:<appSettings> <add key="webPages:Enabled" value="false" /> <add key="MONGOLAB_URI" value="mongodb://localhost:27017/todos"/> </appSettings>
Then change the
bootstrapper
class to use this configuration value while connecting to the database as follows:protected override void ConfigureApplicationContainer(TinyIoCContainer container) { base.ConfigureApplicationContainer(container); var connectionString = ConfigurationManager.AppSettings.Get("MONGOLAB_URI"); var mongoDataStore = new MongoDataStore(connectionString); container.Register<IDataStore>(mongoDataStore); }
For all the tests to still pass, add an
app.config
file to theTodosNancyTests
project and add the corresponding settings to it:<configuration> <appSettings> <add key="MONGOLAB_URI" value="mongodb://localhost:27017/todos"/> </appSettings> </configuration>
The last piece missing before being ready to deploy this to AppHarbor is make sure the integration tests, that is, the tests in
DocumentationTests
andTodosModuleTest
, are not run during the AppHarbor build and deploy pipeline. The reason for this is that we, on the one hand, want to take advantage of the fact that AppHarbor will run all unit tests it sees and only deploy if the tests pass, but on the other hand, we do not want to mess with setting up a test database on the cloud that can be used during test runs in AppHarbor. Note that if you use SQL Server for your data store, the xUnitAutoRollback
attribute can be used to roll back changes made in tests. In real life scenarios (especially continuous delivery scenarios), though, you will probably want to do that test setup and have all the tests run in AppHarbor before deploying. To avoid running the integration tests on the cloud, first write an implementation of theITestClassCommand
interface in xUnit.net that only allows tests to run if they are running on a known developer machine and then apply it to the integration tests. The implementation is as follows:public class KnownDevMachinesOnly : ITestClassCommand { private TestClassCommand command; private ITypeInfo typeInf; public int ChooseNextTest(ICollection<IMethodInfo> testsLeftToRun) { return command != null ? command.ChooseNextTest(testsLeftToRun) : -1; } public Exception ClassFinish() { return command != null ? command.ClassFinish() : null; } public Exception ClassStart() { return command != null ? command.ClassStart() : null; } public IEnumerable<ITestCommand> EnumerateTestCommands(IMethodInfo testMethod) { return command != null ? command.EnumerateTestCommands(testMethod) : new ITestCommand[0]; } public IEnumerable<IMethodInfo> EnumerateTestMethods() { return command != null ? command.EnumerateTestMethods() : new IMethodInfo[0]; } public bool IsTestMethod(IMethodInfo testMethod) { return command != null ? command.IsTestMethod(testMethod) : false; } public object ObjectUnderTest { get { return command != null ? command.ObjectUnderTest : null; } } public ITypeInfo TypeUnderTest { get { return typeInf; } set { typeInf = value; if (KnowDevMachineNames.Contains(Environment.MachineName)) command = new TestClassCommand(value); } } public IEnumerable<string> KnowDevMachineNames { get { yield return "HORSDAL"; yield return "DEV2"; } } }
Then apply it to the tests by adding an attribute that indicates to xUnit.net that it should use our custom
KnownDevMachinesOnly
class when trying to run the tests as shown in the following code:[RunWith(typeof(KnownDevMachinesOnly))] public class TodosModuleTests [RunWith(typeof (KnownDevMachinesOnly))] public class DocumentationTests
The only steps left now are to follow AppHarbors instructions on how to deploy the application. I will not repeat those here.
AppHarbor is built for automatically running ASP.NET application. So, as long as our Nancy application is also an ASP.NET application, AppHarbor can run it. Since we have chosen to use the Nancy.Hosting.Aspnet
NuGet package, our application runs on top of ASP.NET; so, from AppHarbor's standpoint, it is just an ASP.NET application.
Nancy applications can also run easily on Windows Azure. With the slight modifications we have done in this recipe, the application is almost ready to run on Azure. The remaining bit is to make our application connect to the MongoDB document database once deployed to Azure. The easiest way to do this is to take advantage of Web.config
transformations and add a Web.Release.config
file containing the connection string to use in Azure. In fact, AppHarbor also supports Web.config
transformations; so, this feature gives a solution that works in both cloud services.
Once the connection string issue is under control, just follow the instructions for deploying an ASP.NET MVC application to Windows Azure. The options for doing this include deploying from within Visual Studio using DropBox, TFS, Git, and more. All of these deployment paths work with Nancy applications too.