从中间件

时间:2016-04-19 07:12:56

标签: c# asp.net-core asp.net-core-mvc middleware

我的中间件类在不同的类库项目中,控制器在不同的项目中。我想要做的是,如果特定条件不符合,那么从中间件重定向到自定义控制器/操作方法。

但是,我无法使用Response.Redirect方法执行此操作。

我如何在中间件类中执行此操作?

对此有任何帮助表示赞赏!

罗希特夏尔

3 个答案:

答案 0 :(得分:6)

似乎你出于错误的原因使用中间件。

我建议您让中间件返回(非常小)404,只需将其写入响应流(而不是转发到Next()),或者不要在中间件中执行此操作,而是在MVC应用程序中全局注册的IActionFilter

我在评论中已经解释了上述建议的基本原理,但我认为重要的是提升到实际的答案:

在中间件管道中,您希望每个组件尽可能独立。在OWIN中,有两件事可以实现这种松耦合:

  • 每个组件的输入和输出具有相同的格式,无论是之前还有10个其他中间件组件,还是根本没有;

  • 惯例是管道的每个部分都可以按以下顺序执行以下三个部分中的一个或多个:

    1. 读取(并修改)传入的请求。

    2. 决定完全处理请求,或将处理转发到下一个组件。

    3. 写入回复流。

当坚持这些约定时,从可重用的中间件组件中组合,分解和重新组合管道变得非常容易。 (想要请求记录吗?只需在管道的开头连接一个中间件组件。想要全面的一般认证逻辑吗?在管道的auth阶段添加一个组件。想要切换到不同的日志框架吗?替换日志记录想要在微服务生态系统中应用相同的日志记录吗?重新使用组件.Ethercetera,ad infinum ...)这很有效,因为组件都保持在他们的边界内,并与Web合同一起工作服务器本身可以理解。

ASP.NET WebAPI似乎是一个不同的野兽,但实际上它只是另一个OWIN组件,它总是被配置为处理请求,并且永远不会转发到下一个组件(因此它们使得它很难在管道中的WebApi之后注册一个组件......)。

你要做的是什么,打破了第二点的合同 - 你想告诉下一个组件如何处理请求。 但这不取决于你 - 这取决于下一个组件。

答案 1 :(得分:5)

这是检查请求和重定向的中间件。它适用于内联中间件或中间件类。

public void Configure(IApplicationBuilder app)
{
    // use inline middleware
    app.Use(async (context, next) =>
    {
        // if specific condition does not meet
        if (context.Request.Path.ToString().Equals("/foo"))
        {
            context.Response.Redirect("path/to/controller/action");
        }
        else
        {
            await next.Invoke();
        }
    });

    // or use a middleware class
    app.UseMiddleware<RedirectMiddleware>();

    app.UseMvc();
}

这是中间件类。

public class RedirectMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
        // if specific condition does not meet
        if (context.Request.Path.ToString().Equals("/bar"))
        {
            context.Response.Redirect("path/to/controller/action");
        }
        else
        {
            await _next.Invoke(context);
        }
    }
}

有关详细信息,请参阅Docs » Fundamentals » Middleware

答案 2 :(得分:0)

您可以使用“请求编辑中间件”来更改请求在管道中向下移动时的性质。这符合一般的“最佳实践”,并且比将重定向通知发送回浏览器更有效。

此示例重定向到一个操作方法,而不是返回一个图像:

public class ResolveImageMiddleware
{
    private readonly RequestDelegate _next;

    public ResolveImageMiddleware(RequestDelegate deg)
    {
        _next = deg;
    }

    public async Task InvokeAsync(HttpContext context, AppDbContext db)
    {
        var path = context.Request.Path;
        if (path.HasValue && path.Value.StartsWith("/imgs"))
        {
            context.Request.Path = "/Home/GetImageFromDb";
            context.Request.QueryString = new QueryString("?title=" + path.Value.Replace("/imgs/", ""));
        }

        await _next(context);
    }

}

创建一个采取查询并可以返回文件的操作方法:

public class HomeController : Controller
{
    private EFImageRepo imageRepository;
    public HomeController(EFImageRepo repo)
    {
        imageRepository = repo;
    }
    public FileResult GetImageFromDb([FromQuery]string title)
    {
        var img = imageRepository.GetImg(title);
        if (img != null)
        {
            byte[] contents = img.ImageBytes;
            return File(contents, "image/jpg");
        }
        return null;
    }
}

如果您在响应时使用重定向,则会导致用户的浏览器收到重定向通知,然后向您的应用发送新请求,而不是消耗原始请求并立即吐出文件。