ProudMonkey

Converting ASP.NET 5 Beta 8 App to ASP.NET Core RC2

Few months ago I wrote an article about "Upgrading Existing ASP.NET 5 previous versions to Beta8". Since then I stick to using Beta 8 version for building ASP.NET Core app prototypes. Besides being lazy, it was my intent not to upgrade my existing projects to RC1 because I know that RC2 will be released in the near future.

Few days ago Microsoft announced the release of ASP.NET Core RC2. This release succeeds the ASP.NET 5 RC1 release and features a number of updates to enhance compatibility with other .NET frameworks and an improved runtime.

A key change that occurred between Betas and RC2 is the introduction of the .NET command-line interface (CLI). This tool replaces the dnvm, dnx, and dnu utilities with a single tool that handles the responsibilities of these tools. To learn more about the .NET CLI, check out Announcing .NET Core RC2 and .NET Core SDK Preview 1.

If you are working with ASP.NET 5 Beta 8 versions up to this moment and wanted to migrate your app to the latest release which is RC2 as of this writing then this article is for you. Though this article doesn’t list down all the changes, this would somehow list the changes for the most basic part so your app can run under RC2 version.

Warning: Spoiler Ahead!

There will be big changes under the hood with the release of ASP.NET Core RC2 so expect a longer list for this conversion. :)

Let's get Cracking!

First thing you need to do is upgrade your Visual Studio 2015 with Update 2. You can check the release and download the update for Visual Studio here.

Once the setup and configuration is applied in Visual Studio then download the ASP.NET Core RC2 here.

After the installation, make sure to restart your machine to ensure updates will take effect.

In this conversion I’m going to use the ASP.NET MVC 6 project that I’ve demonstrated before. Now let’s start modifying.

global.json Changes

Change your global.json to this (if you have any):

{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-preview1-002702"
  }
}

Two things we’ve changed there, first was to replace “sources” node to “projects” and then replaced the version from “1.0.0-beta8” to “1.0.0-preview1-002702” – the latest RC2 version as of this writing.

project.json Changes
dependencies

Add the runtime as a dependency:

"dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0-rc2-3002702",
      "type": "platform"
    },
  • Replace all “Microsoft.AspNet.” dependencies to “Microsoft.AspNetCore.
  • Then replace version suffix from “-beta8” to “-rc2-final”.
  • Note: if you are referencing “Microsoft.AspNet.Mvc": "6.0.0-beta8" then make sure to change the version to “1.0.0” so it would look like this "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final"
  • Next, change the name of all “Microsoft.Framework.” references to “Microsoft.Extensions.”.
  • If you are using SQL Server, you will need to change the reference of “EntityFramework.SqlServer” to “Microsoft.EntityFrameworkCore.SqlServer”.
  • After that, change existing assemblies with new names for example: "Microsoft.AspNet.IISPlatformHandler" > "Microsoft.AspNetCore.Server.IISIntegration" "Microsoft.AspNet.Identity.EntityFramework" > "Microsoft.AspNetCore.Identity.EntityFrameworkCore"
  • Add the following configuration and diagnostics references:
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc2-final",
"Microsoft.AspNetCore.Diagnostics": "1.0.0-rc2-final",
frameworks

Change your frameworks section with the following new naming structure:

"frameworks": {
    "netcoreapp1.0": {
      "imports": [
        "dotnet5.6",
        "dnxcore50",
        "portable-net45+win8"
      ]
    }
  },
tools

You will need to rename the existing “command” section to “tools” and add the following tools config from the preview like this:

"tools": {
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": [
        "portable-net45+win8+dnxcore50",
        "portable-net45+win8"
      ]
    },
    "Microsoft.Extensions.SecretManager.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": [
        "portable-net45+win8+dnxcore50",
        "portable-net45+win8"
      ]
    }
  },
publishOptions

Next remove the existing “bundleExclude” and “bundle” config section and replace them with the new publishOptions section like:

"publishOptions": {
    "include": [
      "wwwroot",
      "Views",
      "appsettings.json",
      "web.config"
    ]
  }

Add the buildOptions and runtimeOptions sections like so:

"buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "gcServer": true
  },

Setting the “preserveCompilationContext” to “true” will compile Views. This setting is important especially if you are using a strongly-typed view that needs to be compiled.

Add the new “Scripts” section:
"scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
Wrapping all Changes

Here’s my updated project.json file after putting together the changes:

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0-rc2-3002702",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
    "Microsoft.Extensions.DependencyInjection.Abstractions": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
      "version": "1.0.0-preview1-final",
      "type": "build"
    },
    "Microsoft.AspNetCore.StaticFiles": "1.0.0-rc2-final"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": [
        "dotnet5.6",
        "dnxcore50",
        "portable-net45+win8"
      ]
    }
  },

  "tools": {
    "Microsoft.AspNetCore.Razor.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": [
        "portable-net45+win8+dnxcore50",
        "portable-net45+win8"
      ]
    },
    "Microsoft.Extensions.SecretManager.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    },
    "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": [
        "portable-net45+win8+dnxcore50",
        "portable-net45+win8"
      ]
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "Views",
      "appsettings.json",
      "web.config"
    ]
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "gcServer": true
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }

}

Now save the file so it will restore the required packages for your app.

xproj File Changes

Unload your project first and then right-click on it to edit the project file. We will need to manually change some configuration in the file because your existing xproj file has references to the old Beta 8 tools which uses DNX. In this case we will need to change the string "DNX\Microsoft.DNX.Props" to "DotNet\Microsoft.DotNet.Props". Basically the “DNX” reference will now be changed to “DotNet”. So your import tag should now look like this:

<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />  

You also need to change the string "DNX\Microsoft.DNX.targets" to "DotNet.Web\Microsoft.DotNet.Web.Props". Your other import tag would now look like this:

<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />  

You may also want to change BaseIntermediateOutputPath and OutputPath to:

<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>  
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>  

And finally, add a TargetFrameworkVersion below the OutputPath element:

<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>  

Now save your .xproj file and then reload your project in Visual Studio.

Code Changes
Adding Program.cs File

Adding this class is not really a requirement because you can just add an entry point to your existing startup.cs file. But just to follow the new project templates for RC2, I’ve decided to generate a separate file called “Program.cs” to put our main entry point – the static void Main() method.

The Program.cs file contains the Main method of an ASP.NET Core RC2 app, which is responsible for configuring and running the app. Here’s how it would look like:

using System.IO;  
using Microsoft.AspNetCore.Hosting;

namespace MVC6Demo  
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();

            host.Run();
        }
    }
}
Modifying Startup.cs

Here are the changes for my Startup.cs file:

public Startup(IHostingEnvironment env)  
{
    var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath);

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
Renaming Namespaces

Since our project.json package references was changed then we also need to change the namespaces that are being used. For example do a “find and replace” and then change “using Microsoft.AspNet” to “using Microsoft.AspNetCore”. Following are the affected changes in my project:

using Microsoft.AspNetCore.Builder;  
using Microsoft.AspNetCore.Hosting;  
using Microsoft.AspNetCore.Mvc;  

You also need to change the namespace reference of the following:
"using Microsoft.Framework.DependencyInjection" > "using Microsoft.Extensions.DependencyInjection" "Microsoft.Data.Entity" > "Microsoft.EntityFrameworkCore"

launchSettings.json Changes

Under Properties, open up the launchSettings.json file. Find the “web” section and replace it with the new “DotNet” stuff below:

"MVC6Demo": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }

The “ASPNETCORE_ENVIRONMENT” replaces the old “Hosting:Environment” and is the new environment variable for RC2.

You may also want to change the port number used in IIS Express. In my case I have this configuration:

"iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:50295/",
      "sslPort": 0
    }
  },
ViewComponent Changes

InvokeAsync now takes anonymous object instead of separate parameters. With this change you would need call @Component.InvokeAsync(“Name of View Component”,) from your View. In my previous example I needed to change this call:

@await Component.InvokeAsync("HeroList", "strength")

to this:

@await Component.InvokeAsync("HeroList", new { type = "strength" })

Now save and compile your project. Here’s a sample screenshot of the converted ASP.NET MVC 6 App to ASP.NET Core MVC RC2:

Note: I know there are few changes that I didn't cover in this article because I’m just basing a simple project to convert. To learn more about the RC2 conversion please refer the following articles below:

That’s it! I hope someone find this post useful.