Customizing EF Core 2.0+ Entity/Table Mapping with IEntityTypeConfiguration

tldr;

In EF Core 2.0, you can now rip out your per-Entity Fluent API table customizations into separate classes instead of having them all in the OnModelCreating method of your DbContext.  You do this by inheriting from IEntityTypeConfiguration<T>.

 

Before In EF Core 1.x, note lines 13-33:

 

After in EF Core 2.0+, note lines 13, 14, and the 2 extra files:

 

The latter scales better to a big application with lots of entities.

 

The Problem

Let’s say you want to make a customization to one of your EF Core 2.0 properties and how it maps to your underlying database.  Some customization scenarios include changing the default table name, changing the max length of the column, etc.

 

There are two ways of doing this.  You could either choose the Data Annotations way or using the Fluent API.  I personally like the Fluent API, so that my models aren’t littered with attributes.  It also decouples my models from Entity Framework, in case I choose to use Dapper or another ORM down the road.

 

Prior to EF Core 2.0, to use the Fluent API you would have to “inline” any customizations in your OnModelCreating method.  This works ok for small projects, but as you add tons of tables to your DbContext, this becomes a little hard to manage.

 

This would look something like this:

It looks ugly just for two tables… imagine 10, 20, or even 100!  …Although maybe you should have multiple DbContexts at that point, but that’s beside the point.

 

This obviously doesn’t scale great.  You could rip out each configuration into your own custom classes or static methods, but now there is a built-in solution in EF Core 2.0+.

 

The Solution

With EF Core 2.0 and above, you can now implement the interface IEntityTypeConfiguration<T> where T is the Model you’re configuring.  After creating that class with the necessary customizations, you need to wire that up to your DbContext’s OnModelCreating method by calling builder.ApplyConfiguration(new ConfigClass).  It’s important to make sure that your customizations come after the base.OnModelCreating(builder) call.

 

It looks something like this, note lines 13, 14, and the two extra files:

 

That looks much better and scales much nicer.

If you use the “inline” way today, you should be able to convert to the IEntityTypeConfiguration way without impacting the rest of your app or changing any schema.  The API is the exact same in both formats (i.e. it’s HasKey in both spots to change the Primary Key).

 

Reverse Engineering from Existing Database

While you could handle your customization in EF Core 1 via custom static methods or your own hand rolled classes for maintainability purposes, now we have a consistent way of doing this across all EF Core Projects.  That enables awesome things.

Such as the EF team is starting to work on adding this as an option when you Reverse Engineer classes from an existing database and have it auto-generate your customizations for you into these separate IEntityTypeConfiguration<T> classes.  It’s currently slated for the EF Core 2.1 release that is likely to be released late this year or early next year.  Obviously no guarantees that EF Core 2.1 lands at that time or that it includes this feature.  However, it’s awesome that this is coming down the pipe.

 

This is also possible in EF 6

One final thing I’d like to mention is that you could do this same thing in EF 6.  You just have to inherit from the EntityTypeConfiguration<T> abstract class (not an interface like EF Core), and then put your configuration in the constructor.  There are many examples out there on how to do that and is outside of the scope of this post, but just thought I’d pass along in case you like this pattern and are using EF 6 today.

 

Hope this helps!

Fixing ASP.NET Core Feature Folders Causing Resharper Intellisense Issues

I’ve had a handful of people ask me about this, so I figured I’d just blog on it.

The Problem

If you use Feature Folders in ASP.NET Core you may see something like this where Resharper can’t figure out where your Views are.  It will outline like your View() calls in red.

2017-08-24_22-57-12

 

When you run the app it still works, but it leaves a little to be desired with the Developer experience.  Feature Folders are supported in Resharper and plain ASP.NET, but in Resharper has not added support for Feature Folders to ASP.NET Core yet.

 

The Fix

Luckily there’s a workaround, that I was first notified of by Bill Sorensen on my blog post on Feature Folders linked above.

  1. Install the JetBrains.Annotations NuGet package
  2. Add the following attributes to the top of your IViewLocationExpander file, above the namespace*
    https://gist.github.com/scottsauber/58a3fad558c9666b58ef1eabdc8f7936
  3. Re-open your Controller and everything should work

 

  • Note – if you have more custom paths in your IViewLocationExpander than just those, then you’ll have to add those routes as well.

 

So your final output should look something like this:

 

That’s it, now Resharper is happy!

 

2017-08-24_23-11-51

 

Hope this helps.

 

 

Fix for “Package Microsoft.AspNetCore 2.0.0 is not compatible with netcoreapp2.0”

If you’re on your build server and running into the problem like this that fails on the NuGet Restore

Package Microsoft.AspNetCore 2.0.0 is not compatible with netcoreapp2.0 (.NETCoreApp,Version=v2.0). Package Microsoft.AspNetCore 2.0.0 supports: netstandard2.0 (.NETStandard,Version=v2.0)

 

Double check that you have NuGet 4.3 or higher installed.  

 

To fix this on TeamCity 2017.1.2+:

  1. Go to Administration in the top right
  2. Tools on the left
  3. Click Install Version under NuGet.exe
  4. Choose 4.3 or higher in the dropdown and click Add

 

Hope this helps someone else on the bleeding edge.

.NET Full Framework issue when referencing .NET Standard 1.4 library

If you get an error message when you try to reference your .NET Standard 1.4 library from a .NET full framework app (like .NET 4.6.1) you may see this error message: System.IO.FileLoadException : Could not load file or assembly 'System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

The issue is there’s a bug with the System.Net.Http 4.3.0 package.  The fix then is to install System.Net.Http 4.3.1 in your .NET Standard library.  So your csproj should look like this:

<ItemGroup>
    <!-- Add 4.3.1 version explicitly. -->
    <PackageReference Include="System.Net.Http" Version="4.3.1" />
    <!-- Any other packages here. -->
</ItemGroup>

Now you should be good.

There are a lot of threads on GitHub about this on many different repos, but this fix is only in one of those threads and so I thought I’d post this to make it easier for the next person.

Exploring the Environment Tag Helper exclude and include attributes in ASP.NET Core 2

tldr;

A new exclude attribute on the EnvironmentTagHelper lets you easily tell the EnvironmentTagHelper to render in all Environments EXCEPT the one(s) you specify. There’s also a new  include attribute that behaves the same as names did in ASP.NET Core 1.

A comparison between ASP.NET Core 1 and 2:taghelpers

 

Environments in ASP.NET Core

In ASP.NET 4 (and previous versions), there was no concept of an Environment.  Even though in almost every job, there are the concepts of Environments such as Dev, Staging, UAT, QA, Production, etc.  You were essentially on your own to implement your concept of Environments.  Sometimes enlisting the help of something horrible like compiler directives.

In ASP.NET Core, they built the Environment concept right into the stack.  There are 3 Environments by default – Development, Staging, and Production, but you can add your own custom ones if you want.  The Environment is controlled by an Environment variable called ASPNETCORE_ENVIRONMENT.  This allows you to inspect the current Environment using an IHostingEnvironment and run code like this:

You can find more on Environments on the official documentation here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments.

 

Environment Tag Helpers in ASP.NET Core 1

Besides using IHostingEnvironment, In ASP.NET Core 1 you could conditionally load some markup based on the Environment you were in via an EnvironmentTagHelper.

But that was a little brittle, given you can make your own custom Environments, in addition to the built-in Development, Staging, and Production Environments.  Essentially, if you introduce a custom Environment, then you have to CTRL + F for all your EnvironmentTagHelpers and add in your new custom environment.  That’s a real pain.

 

Enter include and exclude attributes on the Environment Tag Helper in ASP.NET Core 2

To solve this, the ASP.NET team introduced the include and exclude attributes on the EnvironmentTagHelper.   Let’s look at exclude first.  

Exclude does about what you would think.  It will only render the contents of the EnvironmentTagHelper if the current environment does NOT match the Environment specified.  So <Environment exclude="Development"> would NOT render the contents in Development, but would render in any other Environment (such as Staging, Production, or a custom Environment you specified).

Include, on the other hand, operates the same as the names attribute we had in ASP.NET Core 1.  It’s just there to provide consistent naming as the opposite of ​exclude.  It will only run if the current environment DOES match the Environment specified.

So those used together would look a little something like this:

 

The names attribute still exists… but don’t use it

The names attribute still exists for backwards compatibility, but I don’t see a reason to use it anymore over include.  I don’t have a crystal ball, but I’d say it’s likely names will be removed in a later version of ASP.NET Core now that we have include and exclude.  Although the team seems committed to backwards compatibility at this point in time.

Personally, I think it’d be cool if the ASP.NET team shipped codemods in the form of Roslyn Analyzers to auto upgrade your code to the latest API’s, and then just make a clean break.  In this case, anywhere you’d use names would automatically upgrade to use include.  As a developer, you could still inspect the changes the Roslyn Analyzer made when reviewing your Commit/Pull Request to make sure the Analyzer did the right thing.  The React team at Facebook does this, but they also have a financial incentive to ship upgrade-friendly stuff like that when Facebook has over 10M lines of code.  So…. yeah…

 

What if I use include and exclude in the same Tag Helper and use the same Environment in both?

If you screw up like this, ASP.NET Core will do the “safe” thing by default and NOT render in that environment.  This is very similar to how NTFS works where a deny will take precedence over an allow.

So if you do something like this:

Then the content will not show in the Development or Production Environments, but it will show in Staging, since it is part of the include and not in the exclude.

In real life, I don’t know why you’d use both together.  I would always just pick a whitelist (include) or a blacklist (exclude).  But it’s probably a good thing to keep in mind.

 

Closing

This will make life so much simpler to deal with the EnvironmentTagHelper especially when used with custom Environments.

If you’re interested in the ideas they threw around to solve this problem, before ultimately landing on include and exclude, you can read the GitHub issue here. You can also see the commit that went into making this feature work.

I was playing around with ASP.NET Core 2.0 before I give a talk on what’s new on it in 4 days, and I came across this and just had to share… now it’s back to rehearsing!