【问题标题】:Pass Information to Middleware from Controller将信息从控制器传递到中间件
【发布时间】:2017-03-29 22:31:44
【问题描述】:

我在我的 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;
            }
        }
    }
}

但是,我有一个不应该在事务中运行的控制器方法(将来可能会更多)。让控制器操作“退出”中间件功能的最佳方法是什么?

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

【问题讨论】:

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


    【解决方案1】:

    我认为您正在寻找的是自定义过滤器。

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

    然后,您可以通过属性将过滤器添加到您想要运行它们的方法中。 [CustomFilter] 如果您将类命名为“CustomFilterAttribute”。

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

    [ServiceFilter(typeof(CustomFilter))]
    

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

    【讨论】:

    • 这听起来很有趣,但我不确定我是否理解该提议 - 这是否允许我在默认情况下为控制器操作进行系统范围的事务,然后使用该属性选择退出?
    • 我提出的解决方案最好采用选择加入方法并在过滤器代码中进行事务处理。要选择退出,请查看提供的链接中的“将过滤器用作全局过滤器”部分。您基本上可以将默认过滤器应用于所有控制器。然后,您可以添加一个布尔值作为参数来指定是否要创建事务,并在不希望创建事务的任何位置手动添加属性。
    • ActionFilter 的方法在您的方法的开头和结尾被调用,因此您需要使事务成为该类的成员。确保调用 transaction.Dispose() ;
    • 谢谢,我试试看!
    • FelschR 我还没有机会尝试这个(直到以后的产品迭代才需要选择退出功能)但我喜欢你的回答,我不想离开这个问题打开。感谢您的帮助!
    【解决方案2】:

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

    这是一个有点生硬的工具,但如果你别无选择,它可以工作。

    在控制器中:

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

    在中间件中:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      相关资源
      最近更新 更多