If you are a Visual Studio user you can get .NET Core 3.0 by installing at least Visual Studio 16.4. For those not using Visual Studio, you can download and install .NET Core 3.1 SDK from here. As with previous versions, the SDK is available for Windows, Linux, and Mac.
After installation is complete you can run the following command from a command prompt to see all the versions of the .NET Core SDK you have installed.
dotnet --list-sdks
You should see 3.1.100 listed at a minimum.
Project File Changes
Right-click on the project and select Edit projectName.csproj.
Change the TargetFramework to netcoreapp3.1.
Before:
<TargetFramework>netcoreapp3.0</TargetFramework>
After
<TargetFramework>netcoreapp3.1</TargetFramework>
Next, update all your packages to the new versions. This is going to vary greatly based on your project. This can be done manually in the csproj file or via the NuGet UI if you are using Visual Studio. The following are the changes from the sample project.
The move from 3.0 to 3.1 is drop-dead simple which is not surprising since it has only been a few months since the release of 3.0. It is important to move to 3.1 as soon as you can since it is the long term service version and will be supported for at least the next 3 years where 3.0 will lose support within months.
On September 23rd .NET Core 3.0 was released including ASP.NET Core 3.0 and Entity Framework Core 3.0. This post will be taking the Contacts project used in the ASP.NET Basics series and migrating it from .NET Core 2.2 to .NET Core 3.0. Most of the information used for this migration comes from the Microsoft docs which will cover way more scenarios than this post will.
The code before any changes can be found in this GitHub repo. A reminder that the Contacts project is the only project being updated with this post the projects in the repo will remain on ASP.NET Core 2.2 for now.
Installation
If you are a Visual Studio user you can get .NET Core 3.0 by installing at least Visual Studio 16.3. For those not using Visual Studio, you can download and install .NET Core 3.0 SDK from here. As with previous versions, the SDK is available for Windows, Linux, and Mac.
After installation is complete you can runt the following command from a command prompt to see all the versions of the .NET Core SDK you have installed.
dotnet --list-sdks
You should see 3.0.100 listed. If you are like me you might also see a few preview versions of the SDK that can be uninstalled at this point.
Project File Changes
Right-click on the project and select Edit projectName.csproj.
The packages section has a lot of changes. Microsoft.AspNetCore.App is now gone and part of .NET Core without needing a specific reference. The other thing to note is that Entity Framework Core is no longer “in the box” so you will see a lot of references add to make Entity Framework Core usable.
The last thing to note is that Swashbuckle doesn’t have a final version ready for .NET Core 3 so you will have to make sure you are using version 5 rc2 at a minimum.
The following is my full project file for reference.
In Program.cs some changes to the way the host is constructed. The over version may or may not have worked, but I created a new app and pulled this out of it just to make sure I’m using the current set up.
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace Contacts
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Startup Changes
In Startup.cs we have quite a few changes to make. As long as you haven’t do any customization in the constructor you can replace it with the following.
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
Next, they type on the configuration property changed from IConfigurationRoot to IConfiguration.
Before:
public IConfigurationRoot Configuration { get; }
After:
public IConfiguration Configuration { get; }
Moving on to the ConfigureServices function has a couple of changes to make. The first is a result of updating to the newer version of the Swagger package where the Info class has been replaced with OpenApiInfo.
Before:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Contacts API", Version = "v1"});
});
After:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Contacts API", Version = "v1" })
});
Next, we are going to move from using UserMvc to the new AddControllersWithViews which is one of the new more targeted ways to add just the bits of the framework you need.
Now in the Configure function, the function signature needs to be updated and the logging factory bits removed. If you do need to configure logging that should be handled as part of the HostBuilder.
Before:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
After:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
For the next set of changes, I’m just going to show the result and not the before. The UseCors may or may not apply but the addition of UserRouting and the replacement of UseMvc with UserEndpoint will if you want to use the new endpoint routing features.
The only other change I had was the removal of @using Microsoft.AspNetCore.Http.Authentication in a few cshtml files related to login.
Wrapping Up
The migration from 2.2 to 3.0 is a bit more involved than the move from 2.1 to 2.2, but that isn’t surprising with all the changes in this release. Remember to check out the official migration guide for more details.
The code for the Contacts project after the above changes can be found on GitHub.
As with the migration to 2.1 the move to 2.2 is really easy to do. Make sure you check out the official migration guide for more details that may have not been covered by this project.
I am taking some time to explore some of the new features that came out with the .NET Core 2.1 release and this post is going to be a continuation of that process. The following are links to the other posts in this same vein.
Today we are going to be looking at a new feature added to Entity Framework to allow for data seeding. I am using the official docs for this feature as a reference.
Sample Application
We are going to use the .NET CLI to create a new application using the MVC template with individual authorization since it is one of the templates that come with Entity Framework already set up. If you have an existing project and need to add Entity Framework you can check out this post. The following is the command I used to create my project.
dotnet new mvc --auth Individual
Model
Before we get to data seeding we need to create an entity to seed. In this example, we will be creating a contact entity (surprise!). In the Models directory, I created a Contacts.cs file with the following contents.
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
Next, in the Data directory, we are going to open the ApplicationDbContext class and add a DbSet for our new Contact entity. Added the following property to the class.
public DbSet<Contact> Contacts { get; set; }
Now that we have our DbContext setup lets add a migration for this new Contact entity using the following .NET CLI command.
dotnet ef migrations add Contacts -o Data/Migrations
Finally, run the following command to create/update the database for this application.
dotnet ef database update
Data Seeding
Now that our project is setup we can move on to actual data seeding. In Entity Framework Core data seeding is done in the OnModelCreating function of your DbContext class. In this example that is the ApplicationDbContext class. The following example shows using the new HasData method to add seed data for the Contact entity.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Contact>().HasData(
new Contact
{
Id = 1,
Name = "Eric",
Address = "100 Main St",
City = "Hometown",
State = "TN",
Zip = "153789"
}
);
}
Data seeding is handled via migrations in Entity Framework Core, which is a big difference from previous versions. In order to get our seed data to show up, we will need to create a migration which can be done using the following command.
dotnet ef migrations add ContactSeedData -o Data/Migrations
Then apply the migration to your database using the following command.
dotnet ef database update
Looking at the code that the migration created you can see that it is just inserting the data.
The above works great on new databases or new tables but can cause issues if you are trying to add seed data to an existing database. Check out Rehan’s post on Migrating to Entity Framework Core Seed Data for an option on how to deal with this.
Wrapping up
I am very happy to see that we have a way to prepopulate data in Entity Framework Core it will make some scenarios, such as mostly static data, much easier to deal with. One downside I see to the migration approach is the inability to have some built-in test data since the migrations will always be applied to your databases.
On May 30th .NET Core 2.1 was released including the corresponding version of ASP.NET Core 2.1 and Entity Framework Core 2.1. In this post, I will be taking one of the projects used in my ASP.NET Basics series and converting it from its current 2.0.x version into the newly released 2.1 version. The starting point for the code can be found here. This is all based on the official migration guide.
If you are looking at the sample solution it is the Contacts project that this post is going to be dealing with.
Installation
Thankfully the download page is much improved over the last time there was a release. Head here and to download and install the .NET Core 2.1 SDK. It is available for Windows, Linux, and Mac. The link should drop you on the appropriate page for your OS.
After installation, open a command prompt and run the following command. If all worked well you should see version 2.1.300 listed.
I did a bit more digging and it turns out that the project file can be greatly simplified from the version I had for this application. The following is the full project file will all the bits that were not required removed and the two changes above already made.
There have been changes to how what the Main function looks like to better allow for integration tests. This is the original code in the Program.cs file.
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
And the following is the new version.
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
Startup Changes
Startup.cs has one change that is required which is the removal of the following line from the Configure function.
app.UseBrowserLink();
In the ConfigureServices function if you want to use the new features in 2.1 change the services.AddMvc() to set the compatibility version. This allows you to upgrade the version of the SDK without having to change your whole application since you have to opt into the version you want to target.
If you check out the official migration guide they also point out how to enable a couple more features such as HTTPS and some things to help with GDPR. Neither of these is needed in this application so I’m skipping them in this guide.
Identity Changes
I had to make one change in ManageLogins.cshtml to get my project to build because of a rename/removal AuthenticationScheme to DisplayName.
Before:
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button>
After:
<button type="submit" class="btn btn-default" name="provider" value="@provider.DisplayName" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
If you haven’t made many changes to the identity code in your project you might consider using the new identity razor class library. You can find the details here.
Wrapping Up
Migrations between versions of ASP.NET Core have gotten easier over time as you can tell by the smaller length of these posts. One thing to note is while this will get you targeting 2.1 with all the performance benefits and access to a lot of the new features there will still be work needed if you want to do everything the new 2.1 style. I highly recommend creating a new 2.1 application to get a feel for the other changes you might want to make to your existing applications.
The code with all the changes can be found here. Remember that the only project that was upgraded was the Contacts project.
Version 2.1 of Identity Server 4 was released a few weeks and this post is going to cover updating my sample project to the latest version. The starting point of the code can be found here. We are going to tackle this in sections as there are updates needed for an ASP.NET Core Update, Identity Server Update, and some broken bits in Angular.
ASP.NET Core Update
The sample projects were all on ASP.NET Core version 2.0.0. For each project right-click and select Edit ProjectName.csproj. Make the following change.
Next, need to add a couple of Entity Framework migrations to see if there were any data changes with the following commands from a command prompt in the Identity App project directory.
dotnet ef migrations add Configration21 -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration
dotnet ef migrations add PersistedGrant21 -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrant
Turns out that there were no data changes for this version so if you are on version 2.0.0 you can skip this step.
Angular Issues
I’m not sure how I didn’t hit this issue on the last update post, but the Client App needs to be changed to use the new Angular HttpClient. I got the following error when trying to run the client application.
An unhandled exception occurred while processing the request.
NodeInvocationException: No provider for PlatformRef!
Error: No provider for PlatformRef!
at injectionError
After some digging, I tracked the issue down to using HttpModule instead of HttpClientModule. To make this transition we need to make a few changes. In the app.module.shared.ts make the following changes to the imports section.
Before:
import { HttpModule } from '@angular/http';
After:
import { HttpClientModule } from '@angular/common/http';
Next, in the imports array make the following change.
Before:
HttpModule
After:
HttpClientModule
Next, in the webpack.config.vendor.js fille add the following to the vendor array.
'@angular/common/http'
The last changes are to the auth.service.ts and they are extensive so instead of going through them I’m just going to post the full class after all the changes.
The Identity App that is part of my IdentityServer sample project is the last application I have on GitHub (of the ones that will get upgraded) that needs an upgrade to ASP.NET Core. The starting point of the project before any changes can be found here. This post assumes that you have already followed my generic ASP.NET Core 2 migration post, which can be found here, on the project you are migrating. One final note of caution this post has been written using the RC1 version of the Identity Server NuGet packages and then moved to the final version so there will be two different related pull requests that will have to be looked at to get the full picture of all the changes.
Package Changes
The first change is to get a version of the Identity Server packages what will work from ASP.NET Core 2.
We still need the database initialization code to run, but where should that be done? In the Main function of the Program class seems to be the new recommended location. The following is the new Main function.
public static void Main(string[] args)
{
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
IdentityServerDatabaseInitialization.InitializeDatabase(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred Initializing the DB.");
}
}
host.Run();
}
InitializeDatabase now needs to take an IServiceProvider instead of an IApplicationBuilder. This forced a lot of lines to change so the following is the full class.
public static class IdentityServerDatabaseInitialization
{
public static void InitializeDatabase(IServiceProvider services)
{
PerformMigrations(services);
SeedData(services);
}
private static void PerformMigrations(IServiceProvider services)
{
services
.GetRequiredService<ApplicationDbContext>()
.Database.Migrate();
services
.GetRequiredService<ConfigurationDbContext>()
.Database.Migrate();
services
.GetRequiredService<PersistedGrantDbContext>()
.Database.Migrate();
}
private static void SeedData(IServiceProvider services)
{
var context = services.GetRequiredService<ConfigurationDbContext>();
if (!context.Clients.Any())
{
foreach (var client in Config.GetClients())
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.GetIdentityResources())
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiResources.Any())
{
foreach (var resource in Config.GetApiResources())
{
context.ApiResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
}
Startup Changes
Most of the changes to the Startup class are in the ConfigureServices function, but some cross with the Configure function as well. The existing AddIdentityServer extension has multiple changes especially if you are using Entity Framework for your configuration data. AddTemporarySigningCredential is now AddDeveloperSigningCredential. The following is the new version including configuration data.
The way to handle registration of external authentication has changed as well. For example, this application uses Twitter. The UseTwitterAuthentication call in the Configure function needs to be removed. The following added to the bottom of the ConfigureServices is now the proper way to add external authentication providers.
The new changes in Identity from the ASP.NET Core team included a new foreign key which is one of the things that Sqlite migrations can’t actually do. Since I don’t really have any data I care about I just deleted the database and the existing migrations and snapshots and regenerated everything. If you are using Sqlite and this isn’t an option for you check out this post for some options. If you aren’t using Sqlite then the migrations should work fine. The following are the commands to generate migrations for the 3 contexts that the Identity Application uses.
dotnet ef migrations add InitConfigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration
dotnet ef migrations add InitPersistedGrant -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrant
dotnet ef migrations add InitApplication -c ApplicationDbContext -o Data/Migrations
Quick Start UI Changes
As part of going from the RC1 version to the Final version, the Identity Server team updated the UI and related bits to be in line with the new features added in the ASP.NET Core 2.0 release. Turns out that resulted in a lot of changes. Since I haven’t done any custom work in this area of my Identity Application I deleted the related files in my local project and pulled from the ASP.NET and Entity Framework Combined sample. I am going to give a good idea of all the files I replace, but in case I miss something GitHub will have the full story.
In the Controllers folder replace AccountController.cs and ManageController.cs. Add or replace the following folders:  Extensions, Models, Quickstart, Services, and Views.
Application Insights Error
I ran into the following error.
System.InvalidOperationException: No service for type ‘Microsoft.ApplicationInsights.AspNetCore.JavaScriptSnippet’ has been registered.
You may or may not see it, but if you do open the _Layout.cshtml and remove the following two lines.
If you hit any issues not covered above make sure and check out the breaking changes issue. The completed code can be found here for part 1 and here for part 2.
While trying to deploy my sample Identity Server set of applications to Azure I got the following error when the Entity Framework migrations attempted to run.
System.Data.SqlClient.SqlException (0x80131904): Column 'Id' in table 'AspNetRoles' is of a type that is invalid for use as a key column in an index
This was not something I would get when attempting to run locally, but it failed every time when using SQL Azure. Long store short is that the migrations that were trying to be applied were created when I was using Sqlite as a backing store (UseSqlite).
I deleted all the migrations and recreated them with the app being aware that it would be running on SQL Server (UseSqlServer) and all worked as it should. It makes total sense that the migrations would vary based on the data provider being used, but not something I had really thought about. Not something I will forget again.
Forgive the long title, but this is an issue I have been fighting trying to upgrade an Identity Server 4 project to ASP.NET Core 2. There is an issue on GitHub dedicated to this exact error which can be found here. Before you go down the route of trying all the suggestions in the issue take a moment and make sure that nothing in the Startup class is doing anything that would try to hit the database with Entity Framework.
There is a nice section in the official migration docs titled “Move database initialization code” which I seemed to have missed. So before you head down any rabbit holes like I did make sure this isn’t what is causing your need to add an implementation of IdesignTimeDbContextFactory.
As stated in the migration docs move database related code out of the Configure function of the Startup class and into the Main function. The following is the example of this from the docs.
var host = BuildWebHost(args);
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
// Requires using RazorPagesMovie.Models;
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
This will keep Entity Framework tooling from accidentally running code you didn’t expect. With version 2 all the code in the Configure function gets run.
In this post, I will be covering taking the project used for the ASP.NET Basics series from 1.1.x to the 2.0 release. The starting point of the code can be found here. This post is only going to cover conversion of the Contacts project.
Installation
If you are a Visual Studio user make sure you have the latest version of Visual Studio 2017, which can be found here and at a minimum should be version 15.3.
Next, install the SDK for your operating system. The list of installs can be found here. For development, it is key that you install the SDK, not just the runtime. The following is a preview of what to expect on the download page.
Csproj
The csproj file of the project being upgraded is the best place to start the conversion. The TargetFramework needs to be changed to 2.0.
There is a new Microsoft.AspNetCore.All package that bundles up what used to be a huge list of individual packages. Those individual packages still exist, but this new one wraps them and makes it much easier to get started. The following is the package list before and after.
Program.cs is another area that has been simplified by creating a default builder that does all the same things that were happening before but hide the details. Keep in mind the old version still works and is valid to use if you use case needs it.
Before:
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
After:
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
Identity
The remaining changes I had to make were all related to Identity. In the Startup class’s Configure function the following change was needed.
Next, in the ManageLoginsViewModel class, the type of the OtherLogins property changed.
Before:
public IList<AuthenticationDescription> OtherLogins { get; set; }
After:
public IList<AuthenticationScheme> OtherLogins { get; set; }
The SignInManager dropped the GetExternalAuthenticationSchemes function in favor of GetExternalAuthenticationSchemesAsync. This caused changes in a couple of files. First, in the ManageController the following change was made.
The second set of changes were in the Login.cshtml file. First the function change.
Before:
var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList();
After:
var loginProviders = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToList();
Then the change to deal with the changed property names.
Before:
<button type="submit" class="btn btn-default"
name="provider" value="@provider.AuthenticationScheme"
title="Log in using your @provider.DisplayName account">
@provider.AuthenticationScheme
</button>
After:
<button type="submit" class="btn btn-default"
name="provider" value="@provider.Name"
title="Log in using your @provider.DisplayName account">
@provider.Name
</button>
Wrapping up
With the changes in the Contacts project now works on ASP.NET Core 2.0! Make sure to check out Microsoft’s regular migration guide. as well as their identity migration guide. A full list of breaking changes for this release can be found here.
There is a lot more to explore with this new release and I have a lot of projects to update. Don’t worry I won’t be doing a blog post on all of them, but if I do hit any issues I will create a new post of update this one with the fixes. The finished code can be found here.