ASP.NET Core 2.1中间件返回404

时间:2018-10-03 14:10:45

标签: asp.net-core-webapi asp.net-core-2.1 asp.net-core-middleware

我决定为ASP.NET API核心2.1制作自定义中间件。

public class AuthorizeMiddleware
{
    private readonly RequestDelegate _next;
    private readonly AuthorizeOptions _options;

    public AuthorizeMiddleware(RequestDelegate next, AuthorizeOptions options)
    {
        _next = next;
        _options = options;
    }


    public async Task Invoke(HttpContext context)
    {
        bool hasRole = false;
        if (hasRole)
        {
            await context.Response.WriteAsync($"Not authorized, you need role: {_options.Role}");
        }
        else
        {
            await _next.Invoke(context);
        }

    }

}        
public struct AuthorizeOptions
{
    public AuthorizeOptions(string role)
    {
        Role = role;
    }
    public string Role { get; set; }
} 

当我尝试在Application.cs中使用此中间件

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
            app.UseHttpsRedirection();
        }

        app.UseRouter(AuthenticatedRoutes(app));

        app.UseMvc();
    }

    private IRouter AuthenticatedRoutes(IApplicationBuilder applicationBuilder)
    {

        IRouteBuilder builder = new RouteBuilder(applicationBuilder);

        builder.MapMiddlewareGet("/api/values", appBuilder =>
        {
            appBuilder.UseMiddleware<AuthorizeMiddleware>(new AuthorizeOptions("User"));
            appBuilder.UseMvc();
        });

        return builder.Build();
    }

这工作得很好,但是当我删除appBuilder.UseMvc();时。从MapMiddlewareGet获得,并且我的函数调用返回的特定路由为404。

我试图将appRouter放在app.useMvc()上方。没有成功,调用_next.Invoke()时,我的中间件next函数仍然返回404。

那么,当我在appBuilder中调用useMvc()时,为什么会起作用?我在做被认为是不好的做法吗?为什么我必须在MapMiddlewareGet()中使用app.useMvc()?

1 个答案:

答案 0 :(得分:0)

您的AuthenticatedRoutes()试图做的是使用中间件构建路由器,因此我们可以将最终返回的IRouter用作RouterMiddleware来处理请求。 但是,RouterMiddleware将永远不会继续路由,只要已经有匹配的处理程序即可。结果,它不会自动将请求从一个RouterMiddlware“分发”到另一个RouterMiddleware

让我们查看您的代码:

app.UseRouter(AuthenticatedRoutes(app));

您知道,这里的方法app.UseRouter()是扩展方法,仅使用RouterMiddlware 。因此,第一个问题将是:路由器中间件如何工作?让我们看一下源代码:

public class RouterMiddleware
{
    private readonly IRouter _router;

    // ...

    public async Task Invoke(HttpContext httpContext)
    {
        var context = new RouteContext(httpContext);
        context.RouteData.Routers.Add(_router);
        await _router.RouteAsync(context);
        if (context.Handler == null){
            _logger.RequestDidNotMatchRoutes();
            await _next.Invoke(httpContext);
        } else {
            httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature(){
                RouteData = context.RouteData,
            };
            await context.Handler(context.HttpContext);
        }
    }
}

如您在此处看到的,RouterMiddleware路由上下文,并检查是否有RouterHandler匹配:

  1. 如果不存在,请不执行任何操作,然后将请求分发到下一个中​​间件
  2. 否则,请使用RouterHandler处理请求。 请注意,它将永远不会将请求分发到下一个中​​间件

让我们回顾一下您的路由器和RouterHandler的工作原理:

private IRouter AuthenticatedRoutes(IApplicationBuilder applicationBuilder)
{

    IRouteBuilder builder = new RouteBuilder(applicationBuilder);

    builder.MapMiddlewareGet("/api/values", appBuilder =>
    {
        appBuilder.UseMiddleware<AuthorizeMiddleware>(new AuthorizeOptions("User"));
        appBuilder.UseMvc();
    });

    return builder.Build();
}

看到了吗?您的路线将检查HTTP方法是否为HttpGet,以及网址是否可以与/api/values匹配:

  1. 如果是,则表示路由已匹配,并且将调用特定的RouterHandler来处理请求。

    • RouterHandler首先将调用AuthorizeMiddleware的中间件
    • 如果您添加appBuilder.UseMvc();,它将调用匹配的动作
    • 如果没有appBuilder.UseMvc();,它将终止进一步的处理,并最终产生404响应。
  2. 如果不匹配,则表示此处的路由器不匹配,将不执行任何操作,然后将请求分派到下一个中​​间件。