从控制器向中间件传递信息

Pass Information to Middleware from Controller

我在我的 asp.net 核心应用程序中设置了一个中间件来自动将控制器操作包装在事务中。

public async Task Invoke(HttpContext context, MyDataContext dbContext)
{
    if (context.Request.Method == "GET")
    {
        await _next(context);
    }
    else
    {
        using (var transaction = await dbContext.Database.BeginTransactionAsync())
        {
            try
            {
                await _next(context);
                transaction.Commit();
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
        }
    }
}

但是我有一个控制器方法(将来可能会更多)不应在交易中 运行。将控制器操作用于中间件功能的 "opt-out" 的最佳方法是什么?

最好在控制器方法上放置一个自定义属性,如 [NoTransaction]。但是,我无法确定是否有任何方法可以从我的中间件的 Invoke() 方法中确定将调用 哪个 控制器操作(这将使我能够提取属性从该方法并确定是否创建交易。)执行此操作的正确方法是什么?

我认为您要找的是自定义过滤器。

您可以创建一个派生自 ActionFilterAttribute 的新 class。 然后您可以覆盖 OnActionExecuting 和 OnActionExecuted 方法来添加您的事务处理。

然后您可以将 filter via 属性添加到您想要 运行 它们的方法中。 [CustomFilter] 如果您将 class 命名为 "CustomFilterAttribute"。

如果您需要更好地控制过滤器的生命周期class,您可以将 ActionFilter 用作 ServiceFilter。它需要将其注册为服务,并且还允许您使用依赖注入。 ServiceFilter 属性看起来略有不同:

[ServiceFilter(typeof(CustomFilter))]

一个很好的参考是: https://damienbod.com/2015/09/15/asp-net-5-action-filters/

要回答标题中的问题,还有另一种方法可以将任何 object 传递给中间件组件:HttpContext.Items

它有点生硬,但如果您别无选择,它也可以。

在控制器中:

ControllerContext.HttpContext.Items["variable"] = "value";

在中间件中:

app.Use(async (context, next) =>
{
    if ((string)context.Items["variable"] == "value")
    {
        // do stuff
    }
    await next.Invoke();
});

显然最好避免这种情况,因为它会绕过类型安全,通常还有其他更好的方法来处理这个问题。