ASP.NET Core introduced some new ways to work with middleware in your web applications. Read on to learn more about it from an expert!

If you have a middleware that needs to work on a specific path, you should implement it by mapping it to a route in ASP.NET Core 3.0, instead of just checking the path names. This post doesn’t handle regular middlewares, which need to work all request, or all requests inside a Map or MapWhen branch.

At the Global MVP Summit 2019 in Redmond I attended the hackathon where I worked on my GraphQL middlewares for ASP.NET Core. I asked Glen Condron for a review of the API and the way the middleware gets configured. He told me that we did it all right. We followed the proposed way to provide and configure an ASP.NET Core middleware. But he also told me that there is a new way in ASP.NET Core 3.0 to use this kind of middleware.

Glen asked James Newton King, who works on the new Endpoint Routing, to show me how this needs to be done in ASP.NET Core 3.0. James pointed me to the ASP.NET Core Health Checks and explained to me the new way to go.

BTW: That’s kinda closing the loop: Four summits ago Damien Bowden and I where working on the initial drafts of the ASP.NET Core Health Checks together with Glen Condron. Awesome that this is now in production!
The new ASP.NET Core 3.0 implementation of the GraphQL middlewares is in the aspnetcore30 branch of the repository: https://github.com/JuergenGutsch/graphql-aspnetcore

About Endpoint Routing

The MVP fellow Steve Gordon had an early look into Endpoint Routing. His great post may help you to understand Entpoint Routing.

How it Worked Before

Until now, you used MapWhen() to map the middleware to a specific condition defined in a predicate:

Func<HttpContext, bool> predicate = context =>
{
    return context.Request.Path.StartsWithSegments(path, out var remaining) &&
                            string.IsNullOrEmpty(remaining);
};
return builder.MapWhen(predicate, b => b.UseMiddleware<GraphQlMiddleware>(schemaProvider, options));

(ApplicationBuilderExtensions.cs)

In this case, the path is checked. It is pretty common to not only map based on paths. This allows you to also map on all other kinds of criteria based on the HttpContext.

Also the much simpler Map() was a way to go:

builder.Map(path, branch => branch.UseMiddleware<GraphQlMiddleware>(schemaProvider, options));

How This Should Be Done Now

In ASP.NET Core 3.0, these kinds of mappings, where you may listen on a specific endpoint, should be done using the EndpoiontRouteBuilder. If you create a new ASP.NET Core 3.0 web application, MVC is now using a slightly different process in the Startup.cs than before:

app.UseRouting(routes =>
{
    routes.MapControllerRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
    routes.MapRazorPages();
});

The method MapControllerRoute() adds the controller based MVC and Web API. The new ASP.NET Core Health Checks, which also provide their own endpoint, will be added like this. This means we now have Map() methods as extension methods on the IEndpointRouteBuilder instead of Use() methods on the IApplicationBuilder. It is still possible to use the Use methods.

In case of the GraphQL middleware, it looks like this:

var pipeline = routes.CreateApplicationBuilder()
    .UseMiddleware<GraphQlMiddleware>(schemaProvider, options)
    .Build();
return routes.Map(pattern, pipeline)
    .WithDisplayName(_defaultDisplayName);

(EndpointRouteBuilderExtensions.cs)

Based on the current IEndpointRouteBuilder a new IApplicationBuilder is created, where we Use the GraphQL Middleware as before. We pass the ISchemaProvider and the GraphQlMiddlewareOptions as arguments to the middleware. The result is a RequestDelegate in the pipeline variable.

The configured endpoint pattern and the pipeline than gets mapped to the IEndpointRouteBuilder. The small extension Method WithDisplayName() sets the configured display name to the endpoint.

BTW: That’s kinda closing the loop: Four summits ago Damien Bowden and I where working on the initial drafts of the ASP.NET Core Health Checks together with Glen Condron. Awesome that this is now in production!
In ASP.NET Core 3.0, the GraphQL and the GraphiQl middleware can now added like this:

app.UseRouting(routes =>
{
    if (env.IsDevelopment())
    {
        routes.MapGraphiQl("/graphiql");
    }
    
    routes.MapGraphQl("/graphql");
    
    routes.MapControllerRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
    routes.MapRazorPages();
});

Conclusion

The new ASP.NET Core 3.0 implementation of the GraphQL middlewares is on the aspnetcore30 branch of the repository: https://github.com/JuergenGutsch/graphql-aspnetcore

This approach feels a bit different. In my opinion, it messes with the startup.cs a little bit. Previously, we added one middleware after another, line by line to the IApplicationBuilder method. With this approach we have some middlewares still registered on the IApplicationBuilder and some others on the IEndpointRouteBuilder inside a lambda expression on a new IApplicationBuilder.

The other thing is that the order isn’t really clear anymore. When will the middlewares inside the UseRouting() method be executed and in which direction? I will dig deeper into this in the coming months.

#asp.net #web-development

Implement Middlewares Using Endpoint Routing in ASP.NET Core 3.0
4 Likes29.90 GEEK