Wednesday, November 27, 2013

Continuous Deployment to Azure Web Sites via Visual Studio 2013 and VS Online

In principle, I appreciate the value of test-driven development (TDD) and continuous integration (CI) builds; I just didn’t think they would be entirely practical for my solo, side projects. Well, I don’t have any excuses anymore, I’ve been working on a quick project and in just a few hours, I had an AngularJS single page application (SPA) remotely building and deploying to an Azure web site. All for free. Every time I check-in a change, the source is copied to the cloud, my test runs and it triggers a CI build remotely and then is deployed automatically to the host server. Pretty slick.

image

One change was that testing web applications has come along from the dark days of having to wrangle with the HTTP context. Maybe the situation isn’t totally resolved, but it’s easier these days to write tests because the HTTP context isn’t so much of a stumbling block in newer frameworks.

I only ran into two issues setting everything up, and one was pretty much my fault. First, I created an ASP.NET MVC project using Visual Studio 2013 and added it to Visual Studio Online (which supports both Git and Team Foundation Services [TFS] online). As I wrote in a previous post, you can get free private Git repositories via Visual Studio Online.  I also created an Azure website and linked it to the project. I created a CI build profile and the build triggered correctly on check-in. No problems, no errors. However, the project was not being deployed. The issue was simple, I chose the wrong deployment template. I should have been using the AzureContinuousDeployment.11.xaml template.

The other issue was that the Visual Studio Online build machine wasn’t in sync with the NuGet updates, I had installed on my local box. To resolve these issues with package management, I Enabled NuGet Package Restore feature and then check-in the entire “packages” directory to resolve missing DLL errors.

To get this working for your project, you can start by reading the MSDN article about a continuous deployment setup.

BTW - If you don’t check in the package files, you’ll get error such as these (and more) because the remote build machine won’t be able to find the DLLs. To help with search, I'll paste in a bunch of the errors here.

Models\AccountModels.cs (11): The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)App_Start\WebApiConfig.cs (5): The type or namespace name 'Newtonsoft' could not be found Controllers\AccountController.cs (7): The type or namespace name 'DotNetOpenAuth' could not be found Controllers\TodoController.cs (3): The type or namespace name 'Infrastructure' does not exist in the namespace 'System.Data.Entity' Controllers\TodoListController.cs (4): The type or namespace nam 'Infrastructure' does not exist in the namespace 'System.Data.Entity' Filters\InitializeSimpleMembershipAttribute.cs (3): The type or namespace name 'Infrastructure' does not exist in the namespace 'System.Data.Entity' Areas\HelpPage\SampleGeneration\HelpPageSampleGenerator.cs (14): The type or namespace name 'Newtonsoft' could not be found (are you missing a using directive or an assembly reference?) Models\TodoListDto.cs (6): The type or namespace name 'Newtonsof' could not be found Models\TodoList.cs (6): The type or namespace name 'Newtonsoft' could not be found Models\TodoItemContext.cs (16): The type or namespace name 'DbContext' could not be found Models\AccountModels.cs (18): The type or namespace name 'DbSet' could not be found Models\TodoItemContext.cs (23): The type or namespace name 'DbSet' could not be found C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "EntityFramework". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "DotNetOpenAuth.OAuth". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "DotNetOpenAuth.OAuth.Consumer".
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "DotNetOpenAuth.OpenId". C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "DotNetOpenAuth.OpenId.RelyingParty". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors. C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "DotNetOpenAuth.Core".
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "EntityFramework.SqlServer". C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "Newtonsoft.Json". C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Could not resolve this reference. Could not locate the assembly "System.Web.Http.OData". C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1605): Found conflicts between different versions of the same dependent assembly.

1 comment:

Jd Stuart said...

What version of NuGet were you using locally? I have the problem that when NuGet adds the conditional Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> it doesn't work. When the Condition part above is removed the build actually restores the packages. Not sure why.