.NET Core中的事务注释属性

Muf*_*lix 5 c# asp.net-core

我只是好奇,在Java中,@Transactional可以在方法名称上方放置一个属性,并且由于几乎每个应用程序服务方法都使用事务,因此可以简化代码。

// Java example
public class FooApplicationService {
    @Transactional
    public void DoSomething() 
    {
        // do something ...
    }
}
Run Code Online (Sandbox Code Playgroud)

目前,这是在.NET中完成的方式

// .NET example
public class FooApplicationService {
    public void DoSomething() 
    {
        using (var transaction = new TransactionScope())
        {
            // do something ...
            transaction.Complete();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

是否也可以通过.NET Core中的注释属性来管理事务的?

Ale*_*der 5

您可以为此创建动作过滤器

//filter factory is used in order to create new filter instance per request
public class TransactionalAttribute : Attribute, IFilterFactory
{
    //make sure filter marked as not reusable
    public bool IsReusable => false;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        return new TransactionalFilter();
    }

    private class TransactionalFilter : IActionFilter
    {
        private TransactionScope _transactionScope;

        public void OnActionExecuting(ActionExecutingContext context)
        {
            _transactionScope = new TransactionScope();
        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            //if no exception were thrown
            if (context.Exception == null)
                _transactionScope.Complete();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用

public class HomeController : Controller {
    //...    

    [Transactional]
    public IActionResult Test() { /*some code */ }

    //...
}
Run Code Online (Sandbox Code Playgroud)

注意

@cmart的评论中所述,有一种更优雅的解决方案可以通过使用IAsyncActionFilter

public class TransactionalAttribute : Attribute, IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        using (var transactionScope = new TransactionScope())
        {
            await next();
            transactionScope.Complete();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Alexander顺便说一句,另一个优雅的选择是实现“IAsyncActionFilter.OnActionExecutionAsync”。在那里你可以得到作为“next”参数执行的操作。所以你可以“await next()”,简单地用“using(varscope = new TransactionScope())”包围它,就应该是这样。 (3认同)
  • @cmart 嗯,我从未研究过“ASP.NET Core”中的异步过滤器,并且不了解这种中间件的性质。老实说,这看起来很酷。我想将此选项添加到答案中。如果你不介意的话? (3认同)
  • ActionFilter是Singletons。因此,并行请求会覆盖代码中的事务,这显然非常有害 (2认同)
  • @Alexander 是的,我认为在这种情况下这是一个非常优雅的解决方案。当然,请随意在您的答案中使用它 (2认同)
  • @notracs这是我忘记从我最初的答案中获取的内容。更新它并检查异常。谢谢 (2认同)