Scott Hanselman

ASP.NET Core Architect David Fowler's hidden gems in 2.1

June 11, '18 Comments [10] Posted in ASP.NET | DotNetCore
Sponsored By

ASP.NET Architect David FowlerOpen source ASP.NET Core 2.1 is out, and Architect David Fowler took to twitter to share some hidden gems that not everyone knows about. Sure, it's faster, builds faster, runs faster, but there's a number of details and fun advanced techniques that are worth a closer look at.

.NET Generic Host

ASP.NET Core introduced a new hosting model. .NET apps configure and launch a host.

The host is responsible for app startup and lifetime management. The goal of the Generic Host is to decouple the HTTP pipeline from the Web Host API to enable a wider array of host scenarios. Messaging, background tasks, and other non-HTTP workloads based on the Generic Host benefit from cross-cutting capabilities, such as configuration, dependency injection (DI), and logging.

This means that there's not just a WebHost anymore, there's a Generic Host for non-web-hosting scenarios. You get the same feeling as with ASP.NET Core and all the cool features like DI, logging, and config. The sample code for a Generic Host is up on GitHub.

IHostedService

A way to run long running background operations in both the generic host and in your web hosted applications. ASP.NET Core 2.1 added support for a BackgroundService base class that makes it trivial to write a long running async loop. The sample code for a Hosted Service is also up on GitHub.

Check out a simple Timed Background Task:

public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");

_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));

return Task.CompletedTask;
}

Fun!

Windows Services on .NET Core

You can now host ASP.NET Core inside a Windows Service! Lots of people have been asking for this. Again, no need for IIS, and you can host whatever makes you happy. Check out Microsoft.AspNetCore.Hosting.WindowsServices on NuGet and extensive docs on how to host your own ASP.NET Core app without IIS on Windows as a Windows Service.

public static void Main(string[] args)
{
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);

var host = WebHost.CreateDefaultBuilder(args)
.UseContentRoot(pathToContentRoot)
.UseStartup<Startup>()
.Build();

host.RunAsService();
}

IHostingStartup - Configure IWebHostBuilder with an Assembly Attribute

Simple and clean with source on GitHub as always.

[assembly: HostingStartup(typeof(SampleStartups.StartupInjection))]

Shared Source Packages

This is an interesting one you should definitely take a moment and pay attention to. It's possible to build packages that are used as helpers to share source code. We internally call these "shared source packages." These are used all over ASP.NET Core for things that should be shared BUT shouldn't be public APIs. These get used but won't end up as actual dependencies of your resulting package.

They are consumed like this in a CSPROJ. Notice the PrivateAssets attribute.

<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="" />
<PackageReference Include="Microsoft.Extensions.ObjectMethodExecutor.Sources" PrivateAssets="All" Version="" />

ObjectMethodExecutor

If you ever need to invoke a method on a type via reflection and that method could be async, we have a helper that we use everywhere in the ASP.NET Core code base that is highly optimized and flexible called the ObjectMethodExecutor.

The team uses this code in MVC to invoke your controller methods. They use this code in SignalR to invoke your hub methods. It handles async and sync methods. It also handles custom awaitables and F# async workflows

SuppressStatusMessages

A small and commonly requested one. If you hate the output that dotnet run gives when you host a web application (printing out the binding information) you can use the new SuppressStatusMessages extension method.

WebHost.CreateDefaultBuilder(args)
.SuppressStatusMessages(true)
.UseStartup<Startup>();

AddOptions

They made it easier in 2.1 to configure options that require services. Previously, you would have had to create a type that derived from IConfigureOptions<TOptions>, now you can do it all in ConfigureServices via AddOptions<TOptions>

public void ConfigureServicdes(IServiceCollection services)
{
services.AddOptions<MyOptions>()
.Configure<IHostingEnvironment>((o,env) =>
{
o.Path = env.WebRootPath;
});
}

IHttpContext via AddHttpContextAccessor

You likely shouldn't be digging around for IHttpContext, but lots of folks ask how to get to it and some feel it should be automatic. It's not registered by default since having it has a performance cost. However, in ASP.NET Core 2.1 a PR was put in for an extension method that makes it easy IF you want it.

services.AddHttpContextAccessor();

So ASP.NET Core 2.1 is out and ready to go

New features in this release include:

Check out What's New in ASP.NET Core 2.1 in the ASP.NET Core docs to learn more about these features. For a complete list of all the changes in this release, see the release notes.

Go give it a try. Follow this QuickStart and you can have a basic Web App up in 10 minutes.


Sponsor: Check out JetBrains Rider: a cross-platform .NET IDE. Edit, refactor, test and debug ASP.NET, .NET Framework, .NET Core, Xamarin or Unity applications. Learn more and download a 30-day trial!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Monday, 11 June 2018 09:46:32 UTC
Cool stuff! I've been looking for a generic host that can be used in any type of app. I like the pattern, and might be using it in mobile and console apps that depend on services being configured and injected.
Robert Sundström
Monday, 11 June 2018 11:27:14 UTC
I like the direction of travel for .net Core, adding running a site from a windows services make sense as desktop and web are becoming less siloed. How will this work in a non-Windows environment?
Monday, 11 June 2018 21:30:47 UTC
This is an awesome direction. Will this also work on Linux?
Tuesday, 12 June 2018 05:26:01 UTC
Does identity support multi-tenant databases out of the box without special extra coding?

EF filter interceptors are not a good solution, just having been through that mess on a large project in Azure SQL Server.

This is multi-tenant where 90% of the tables/EF entities have a tenantID which must be filtered on based on the currently logged in user; and 10% of the entities/tables are shared amongst all tenants.
Greg
Tuesday, 12 June 2018 14:30:39 UTC
So shared source packages seem like a spin on write a class library & stick it in NuGet, Now if only it were possible to figure out how to create one a legitimate comparison could be made. The GitHub link for that shows well over a dozen folders of code, but the solution only has 6 projects and none are in the Shared folder. And Bing just brings back stuff on creating class libraries like we've been doing since .NET 1.0
John Meyer
Wednesday, 13 June 2018 18:51:57 UTC
Typo: ConfigureServicdes -> ConfigureServices
Joel Weiss
Thursday, 14 June 2018 02:33:31 UTC
Peter Campbell,

You should read this article on the Generic Host Builder

I think that might answer your questions about non-windows services. I have been using it for a few months and it seems to work well for me.

One other thing which I think is cool related to Razor Views being in assemblies is being able to put your MVC controllers in the same assembly with them. I doubt that part is new, but it makes a nice combo if you want to keep sections your app together. Instead of having to deal with the default Controller/View folders in a normal mvc project. Again this is probably not new but you can do that same thing with API Controllers. If you want your input/output models living next to your api controllers you can easily do that too. There are a lot of great features in .Net Core 2.1 , but being able to separate concerns so cleanly in assmeblies/projects is great. I have a project with Blazor, MVC, APIs, and Services all in separate source assemblies but ultimately running in a single .NET core host project. It is a beautiful thing. I'm loving .NET these days. These kinds of things are a great reason to use .NET core vs .NET Framework.

Adam Wright
Thursday, 14 June 2018 22:37:25 UTC
I also like the new IWebHostBuilder.ConfigureTestServices() for unit testing in 2.1.

var webHostBuilder = WebHost.CreateDefaultBuilder(args)
.ConfigureTestServices(s => s.AddSingleton(persistence))
.UseStartup<Startup>();
Mike C
Saturday, 16 June 2018 06:39:44 UTC
Adam Wright

I am all with you. I really like the direction .NET Core is moving on. Especially about features that you can easily extend and configure in a various ways.

The new Generic Host Builder class is a great example of this. I event actually wrote an extension for it to for configuration of Service Fabric reliable services and the greatest thing is that generic host builder provided all I need to seamlessly integrate with him.

Such things where really rare in .NET Framework.

Sunday, 17 June 2018 15:09:16 UTC
John Meyer,

Yes documentation on that front is lacking, but they are just using contentFiles capability: https://blog.nuget.org/20160126/nuget-contentFiles-demystified.html
Also you can see the published packages in myget: https://dotnet.myget.org/gallery/aspnetcore-dev, for example: https://dotnet.myget.org/feed/aspnetcore-dev/package/nuget/Microsoft.AspNetCore.BenchmarkRunner.Sources
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.