0
votes

IApplicationBuilder has a .Map method that all the examples online show you how to use when you are inlining your middleware configuration and using .Run or .Use directly.

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.2#use-run-and-map

Most of the examples then go on to say how this is a bad idea (rightly so for maintenance reasons alone) and show you how to make a middle ware component which looks something like this:

 public class CustomMiddleware: IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            ... do stuff.
            await next(context);
        }
    }

    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class CustomMiddlewareExtensions
    {
        public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<CustomMiddleware>();
        }
    }

What I can't see is how to combine the two. One thing I tried was this:

public static class CustomMiddlewareExtensions
    {
        public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
        {
            return builder.Map("/CustomPath", app => { 
                app.UseMiddleware<CustomMiddleware>(); });
        }
    }

But this is apparently not working as it is calling InvokeAsync for everything.

I could easily look at the HttpContext.Request.Path and skip my do stuff if it does not match but wanted to know if it was possible to use .Map before doing so.

1

1 Answers

1
votes

The code you provided in working as it should and yielding the result you desire; InvokeAsync is called only when the current request path starts with the one provided to Map -I'm not sure if this small detail is what might be causing the issue i.e. /CustomPath/anything will match and cause Map to invoke the different pipeline-.

For example using the following code in a new template:

  • Map will match /home, /home/privacy, /home/values etc.
  • Map won't match /anything_not_starting_with_home, and InvokeAsync won't be called.
public static class CustomMiddlewareExtensions {
    public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder appBuilder) {
        appBuilder.Map("/home", b => {
            b.UseMiddleware<CustomMiddleware1>();
            b.UseMiddleware<CustomMiddleware2>();
        });
        return appBuilder;
    }

    public class CustomMiddleware1 {
        private readonly RequestDelegate _next;

        public CustomMiddleware1(RequestDelegate next) {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context) {
            Debug.WriteLine($" ======== Response handled by {nameof(CustomMiddleware1)} ======== ");
            await _next.Invoke(context);
        }
    }

    public class CustomMiddleware2 {
        private readonly RequestDelegate _next;

        public CustomMiddleware2(RequestDelegate next) {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context) {
            Debug.WriteLine($" ======== Response handled by {nameof(CustomMiddleware2)} ======== ");
            await context.Response.WriteAsync("Custom Middleware used");
        }
    }
}