ASP.NET 5 beta8, CI and Azure

This is the fourth post in a series about building Wedding Planner Tools Web App with ASP.NET 5, MVC 6 and Entity Framework 7. The previous post was about updating the project to use beta8 and the coreCLR runtime. This is the first post of the series.

I then tried to deploy to azure and see what happens (by pushing to VSO and letting the CI do it’s magic) and I got this error: The project being published does not support the run time ‘dnx-clr-win-x86.1.0.0-beta8’. This is apparently a known issue https://github.com/aspnet/Tooling/blob/master/known-issues.md. The workaround is to specifically set the target DNX version in the settings tab of the publish dialog. This helps with the problem when you publish from Visual Studio.

I then added the specific runtime and architecture int prebuild.ps1 file for dnvm install to ensure the correct sdk gets installed on the build agent vm. I wanted to remove the Visual Studio build step and replace it with executing dnu build as a command line step. The step was failing because of missing dnx. I then added -g to dnvm install to install it globally. https://github.com/aspnet/dnx/issues/2239 but this didn’t work either. It seems that changes to the path just aren’t carried over to the next execution step (this is weird but I don’t have the time to understand why it is so). So then I ran into this post and tried building and deploying via power shell script only in one step. I added the build and publish commands to Prebuild.ps1. http://www.brandonmartinez.com/2015/09/16/deploying-asp-net-5-beta-7-through-vso/. Power shell arguments for build step ended up looking like this:

-vsoProjectName "WeddingPlannerTools" -projectName "WeddingPlannerTools" -BuildConfiguration $(BuildConfiguration) -buildSourcesDirectory $(Build.SourcesDirectory)

Prebuild.ps1

param([string]$projectName="", [string]$BuildConfiguration="", [string]$vsoProjectName="", [string]$buildSourcesDirectory="")
# bootstrap DNVM into this session.
# load up the global.json so we can find the DNX version
$globalJson = Get-Content -Path $PSScriptRoot\global.json -Raw -ErrorAction Ignore | ConvertFrom-Json -ErrorAction Ignore

if($globalJson)
{
    $dnxVersion = $globalJson.sdk.version
	$dnxRuntime = $globalJson.sdk.runtime
	$dnxArchitecture = $globalJson.sdk.architecture
}
else
{
    Write-Warning "Unable to locate global.json to determine using 'latest'"
    $dnxVersion = "latest"
	$dnxRuntime = "coreclr"
	$dnxArchitecture ="x86"
}

$env:DNX_HOME="$ENV:USERPROFILE\.dnx"
$env:DNX_GLOBAL_HOME="$ENV:USERPROFILE\.dnx"

# install DNX
# only installs the default (x86, clr) runtime of the framework.
# If you need additional architectures or runtimes you should add additional calls
# ex: & $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -r coreclr
& $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -a $dnxArchitecture -r $dnxRuntime -Persistent

 # run DNU restore on all project.json files in the src folder including 2>1 to redirect stderr to stdout for badly behaved tools
Get-ChildItem -Path $PSScriptRoot\src -Filter project.json -Recurse | ForEach-Object { & dnu restore $_.FullName 2>1 }

& "dnu" "build" "$PSScriptRoot\src\$projectName" "--configuration" "$BuildConfiguration"
 
& "dnu" "publish" "$PSScriptRoot\src\$projectName" "--configuration" "$BuildConfiguration" "--out" "$buildSourcesDirectory\$vsoProjectName\artifacts\bin\$BuildConfiguration\Publish" "--runtime" "active"

Dnu publish is logging npm warnings as errors for some reason so I’ve set continue on error for this step for now. I just want to see it published!

npm WARN package.json ASP.NET@0.0.0 No description
npm WARN package.json ASP.NET@0.0.0 No repository field.
npm WARN package.json ASP.NET@0.0.0 No README data
npm WARN package.json ASP.NET@0.0.0 No license field.

This is how the build steps look on VSO:
Build steps

Finally follow this guide to make the up run on azure: https://github.com/aspnet/Hosting/issues/364#issuecomment-148567294, http://www.elanderson.net/2015/10/migration-from-asp-net-5-beta-7-to-beta-8/. With this changes you should be able o run the app in IISExpress also but for me it does not seem to work (HTTP Error 500.19 – Internal Server Error but I don’t have the energy to fight it:) ). It does however work in Azure! Success!
Success

links

ASP.NET 5 project content and beta8

This is the third post in a series about building Wedding Planner Tools Web App with ASP.NET 5, MVC 6 and Entity Framework 7. The previous post was about deploying the web app to Azure and CI. This is the first post of the series.

I decided to go through the project files and make some changes. The root solution folder has a file called global.json. This file sets the source code folders and the sdk to use. I went in here to change the sdk version to beta8 which is the latest version at the time of writing. I also want to change the runtime to CoreCLR -which is the new open source, cross-platform runtime- and architecture to x86. Visual Studio will ask you to download the new sdk when you save the file. If Visual Studio does not ask you to do that you can run:

dnvm install 1.0.0-beta8 -a x86 -r coreclr -OS win
dnvm list #to check installed runtimes

global.json

{
  "projects": [ "src", "test" ],
  "sdk": { 
    "version": "1.0.0-beta8", //changed this to beta8
    "runtime": "coreclr", //and this to coreclr
    "architecture": "x86"
  }
}

I’ve updated all the dependencies to beta8 also. Microsoft.AspNet.Server.IIS is no longer supported after beta7. I’ve added Microsoft.AspNet.Server.Kestrel https://github.com/aspnet/KestrelHttpServer instead of Microsoft.AspNet.Server.WebListener and Microsoft.AspNet.IISPlatformHandler http://wildermuth.com/2015/10/20/Upgrading_from_ASP_NET_5_Beta_7_to_Beta_8 instead of Microsoft.AspNet.Server.IIS. You need to do dnu restore after changing versions. I’ve also removed dnx451 from the frameworks list as I don’t want to support the old framework.

project.json

{
  "webroot": "wwwroot",
  "userSecretsId": "removed",
  "version": "1.0.0-*",

  "dependencies": {
    "EntityFramework.SqlServer": "7.0.0-beta8",
    "EntityFramework.Commands": "7.0.0-beta8",
    "Microsoft.AspNet.Mvc": "6.0.0-beta8",
    "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta8",
    "Microsoft.AspNet.Authentication.Cookies": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.Facebook": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.Google": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.MicrosoftAccount": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.Twitter": "1.0.0-beta8",
    "Microsoft.AspNet.Diagnostics": "1.0.0-beta8",
    "Microsoft.AspNet.Diagnostics.Entity": "7.0.0-beta8",
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta8",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-beta8", //new web server instead of WebListener
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-beta8", //instead of Microsoft.AspNet.Server.IIS
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta8",
    "Microsoft.AspNet.Tooling.Razor": "1.0.0-beta8",
    "Microsoft.Framework.Configuration.Abstractions": "1.0.0-beta8",
    "Microsoft.Framework.Configuration.Json": "1.0.0-beta8",
    "Microsoft.Framework.Configuration.UserSecrets": "1.0.0-beta8",
    "Microsoft.Framework.Logging": "1.0.0-beta8",
    "Microsoft.Framework.Logging.Console": "1.0.0-beta8",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta8"
  },

  "commands": {
    "web": "Microsoft.AspNet.Server.Kestrel", //this also changes to fire up Kestrel instead of WebListener
    "ef": "EntityFramework.Commands"
  },

  "frameworks": { //only using .net core
    "dnxcore50": { }
  },

  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ],
  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ],
  "scripts": {
    "prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ]
  }
}

Doing this will break your project into a million places as it seems they’ve changed some core stuff from beta5 to 8 without backwards compatibility. Hey it’s in beta! And to be fair it’s only in 37 places. Let’s have a look at the problems I needed to fix. You can ignore any errors in the Migrations folder and just delete for now. I had to rebuild the migrations files as they were no longer matching the identity context in beta8 (see below). http://www.elanderson.net/2015/10/migration-from-asp-net-5-beta-7-to-beta-8/

  • Microsoft.Data.Entity.Relational.Migrations namespace is gone. Use Microsoft.Data.Entity.Migrations instead.
  • Microsoft.Data.Entity.Relational.Migrations.Builders is gone. It’s Microsoft.Data.Entity.Migrations.Operations.Builders now.

In account controller

  • _signInManager.SignOut() changes to _signInManager.SignOutAsync()
  • replace context.Database.AsRelational().ApplyMigrations(); with context.Database.Migrate();
  • replace Context.User.GetUserId() with HttpContext.User.GetUserId()

In manage controller

  • replaced Context.User with HttpContext.User

In startup.cs

  • replace FacebookAuthenticationOptions with FacebookOptions
  • replace MicrosoftAccountAuthenticationOptions with MicrosoftAccountOptions
  • replace app.UseErrorPage(ErrorPageOptions.ShowAll); with app.UseDeveloperExceptionPage();
  • replace app.UseErrorHandler(“/Home/Error”); with app.UseExceptionHandler(“/Home/Error”);
  • replace Microsoft.Framework.Runtime with Microsoft.Dnx.Runtime;
  • replace ConfigurationBuilder(appEnv.ApplicationBasePath) with ConfigurationBuilder().SetBasePath(appEnv.ApplicationBasePath)

And after all that effort I deleted the existing database on my dev machine then hit F5. I lunched it using the web command not IISExpress. I tried to register a user and got a nasty database error.

error : [Microsoft.AspNet.Diagnostics.ExceptionHandlerMiddleware] An unhandled exception has occurred: Value cannot be null.
Parameter name: key
System.ArgumentNullException: Value cannot be null.
Parameter name: key
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at Microsoft.Data.Entity.Migrations.Internal.MigrationsAssembly.c__DisplayClass3_0.b__0()
at Microsoft.Data.Entity.Internal.LazyRef`1.get_Value()
at Microsoft.Data.Entity.Migrations.Internal.MigrationsAssembly.get_Migrations()
at Microsoft.Data.Entity.Migrations.Internal.Migrator.d__13.MoveNext()
at Microsoft.Data.Entity.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.Data.Entity.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade)
at WeddingPlannerTools.Controllers.AccountController.EnsureDatabaseCreated(ApplicationDbContext context) in C:\Work\Wedding Planner Tools\WeddingPlannerTools\src\WeddingPlannerTools\Controllers\AccountController.cs:line 448
at WeddingPlannerTools.Controllers.AccountController.d__10.MoveNext() in C:\Work\Wedding Planner Tools\WeddingPlannerTools\src\WeddingPlannerTools\Controllers\AccountController.cs:line 106
--- End of stack trace from previous location where exception was thrown ---
...rest removed for brevity...

Looking in the database I can see the database created but there’s not tables in it and no migrations have ran. I get this error while trying to update the database manually running the migration:

C:\Work\Wedding Planner Tools\WeddingPlannerTools\src\WeddingPlannerTools>dnx ef database update
Using context 'ApplicationDbContext'.
Using database 'removed' on server '(localdb)\mssqllocaldb'.
System.ArgumentNullException: Value cannot be null.
Parameter name: key
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
at Microsoft.Data.Entity.Migrations.Internal.MigrationsAssembly.c__DisplayClass3_0.b__0()
at Microsoft.Data.Entity.Internal.LazyRef`1.get_Value()
at Microsoft.Data.Entity.Migrations.Internal.MigrationsAssembly.get_Migrations()
at Microsoft.Data.Entity.Migrations.Internal.Migrator.d__13.MoveNext()
at Microsoft.Data.Entity.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.Data.Entity.Design.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
at Microsoft.Data.Entity.Commands.Program.UpdateDatabase(String migration, String context)
at Microsoft.Data.Entity.Commands.Program.c__DisplayClass7_2.b__5()
at Microsoft.Dnx.Runtime.Common.CommandLine.CommandLineUtilsExtensions.c__DisplayClass0_0.b__0()
at Microsoft.Dnx.Runtime.Common.CommandLine.CommandLineApplication.Execute(String[] args)
at Microsoft.Data.Entity.Commands.Program.Main(String[] args)
Value cannot be null.
Parameter name: key

The migrations generated under beta5 where no longer matching the identity tables in beta8. So I removed the migrations folder and regenerated the initial migrations. http://aspnetmvc.readthedocs.org/projects/mvc/en/latest/tutorials/mvc-with-entity-framework.html. The commands seem to be a bit different in beta8:

dnx ef migrations add Initial
dnx ef database update

I can now see the database tables look as they should and the migration was successfully applied. I can also register and login with a new user in the web app. Hurray! Join us next time for the CI and deploying beta8 to azure adventure:)

links
* ASP.NET 5
* MVC 6
* Entity Framework 7
* previous post
* first post
* CoreCLR
* https://github.com/aspnet/KestrelHttpServer
* http://wildermuth.com/2015/10/20/Upgrading_from_ASP_NET_5_Beta_7_to_Beta_8
* http://www.elanderson.net/2015/10/migration-from-asp-net-5-beta-7-to-beta-8/
* http://aspnetmvc.readthedocs.org/projects/mvc/en/latest/tutorials/mvc-with-entity-framework.html
* http://davidfowl.com/diagnosing-dependency-issues-with-asp-net-5/
* http://www.codeproject.com/Articles/1005145/DNVM-DNX-and-DNU-Understanding-the-ASP-NET-Runtime
* https://github.com/aspnet/EntityFramework/wiki/Design-Meeting-Notes–August-20,-2015#relationship-api-naming
* https://msdn.microsoft.com/en-us/library/bb386947(v=vs.110).aspx

Wedding Planner Tools Web App – deploying to Azure

This is the second post in a series about building an app with ASP.NET 5, MVC 6 and Entity Framework 7. The First Post was about setting up source control and creating the project. This post will discuss publishing to azure and setting up continuous deployment.

Publishing to Azure

Lets get to it. Right click the project name and select Publish. Go into Profile and choose Microsoft Azure Web Apps. If you choose to use Azure while creating the project you can choose the existing one. Otherwise you need to set-up a new one. The process is the same as when creating a new project (see First Post).

Publish profile

Go by the connection details as these should be already filled in.

Publish web app credentials

Settings can stay as they are. And then Publish.

Publish web app settings

And now it’s running fine in azure.

Running on azure

Azure dashboard

It’s running on the free tier. You can have up to 10 free web apps running on azure. Sql server is also provisioned automatically but on a retired tier and you have to change it yourself by going into Settings > Pricing tier. Sql server is not free but for 3£ per month you’re not going to go broke.

Sql Server

Continuous Deployment

You can set-up Visual Studio Online to automatically build and deploy when you check-in your code. There’s a good guide to follow for setting this up here https://msdn.microsoft.com/Library/vs/alm/Build/azure/deploy-aspnet5. I had a small problem at first because the build step was set to do a nuget package restore.

Build failed nuget

This was causing problems because the new project files are not compatible to the old way of using nuget. All nuget packages are restored in the pre build powershell script by invoking dnu restore. I went into the build step and unchecked the restore nuget package option. I also disabled the unit test step as it was throwing an error about a path length (we don’t have unit tests yet anyway). We will set that up when we write some. After that everything went fine.

Build success

You can check remaining free build time in the azure portal. You can also switch to a paid model if you need more time. That will eat up into your azure credit. Strangely enough the time spent by my builds is not showing up in azure so free builds!

VSO build minutes

You should be able to set-up the process automatically through azure portal by going into Settings > Continuous Deployment for the web app. Choose the source as Visual Studio Online. Choose the Team Project you want to connect to, the repository and the branch. I’ve set mine to build off the master branch. Azure will then set everything up for you. Each time you check-in into the selected branch you will see a build and deployment triggered. However it seems that build agent used by Visual Studio Online is not set-up for dnx (hence the manual set-up). I’m sure this will get fixed at some point in the future.

Missing DNX

Links
https://msdn.microsoft.com/Library/vs/alm/Build/azure/deploy-aspnet5
First Post
ASP.NET 5
MVC 6
Entity Framework 7