我已经在我的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()方法,确切将调用哪个控制器操作(这将使我能够从该方法中提取属性并确定是否创建事务。)执行此操作的正确方法是什么?
答案 0 :(得分:2)
我认为您正在寻找的是自定义过滤器。
您可以创建一个派生自ActionFilterAttribute的新类。 然后,您可以覆盖OnActionExecuting和OnActionExecuted方法以添加事务处理。
然后,您可以将过滤器属性添加到要运行它们的方法中。 [CustomFilter]
以防您为自己的班级命名" CustomFilterAttribute"。
如果您需要更多地控制过滤器类的生命周期,可以将ActionFilter用作ServiceFilter。它需要将其注册为服务,并允许您使用依赖注入。 ServiceFilter属性看起来略有不同:
[ServiceFilter(typeof(CustomFilter))]
对此的一个很好的参考是: https://damienbod.com/2015/09/15/asp-net-5-action-filters/
答案 1 :(得分:0)
要回答标题中的问题,还有另一种方法可以将任何对象传递给中间件组件:HttpContext.Items
这是一个有点钝的工具,但是如果您没有其他选择,它就可以工作。
在控制器中:
ControllerContext.HttpContext.Items["variable"] = "value";
在中间件中:
app.Use(async (context, next) =>
{
if ((string)context.Items["variable"] == "value")
{
// do stuff
}
await next.Invoke();
});
显然,最好避免使用它,因为它会绕过类型安全性,并且通常还有其他更好的方法来解决此问题。