.Net Core Action过滤器使用实例(自动启用事务)

文章介绍了如何在.NetCore中通过自定义Action过滤器TransactionScopeFilter来实现数据库操作的事务控制。当方法标记了NotTransactionalAttribute特性时,过滤器会跳过事务处理。否则,它会在操作方法执行前后管理TransactionScope,确保原子性,即所有操作要么全部成功,要么全部回滚。示例展示了在异常情况下事务的回滚机制。
摘要由CSDN通过智能技术生成

基于前面对Action Filter的介绍,本节通过实例来说明其用法。

.Net Core自定义Action过滤器

数据库事务有一个非常重要的特性,那就是“原子性”,它保证了我们对数据库的多个操作要么全部成功、要么全部失败,进而帮助我们保证业务数据的正确性。

下面代码将实现一个对于数据库操作的自动启用事务的操作筛选器。

使用TransactionScope简化事务代码的编写,TransactionScope是.Net中用来标记一段支持事务的代码的类。EF Core对TransactionScope提供了天然的支持,当一段使用EF Core进行数据库操作的代码放到TransactionScope声明的范围中的时候,这段代码就会自动被标记为“支持事务”。

大多数情况下,操作方法都需要有事务,当一个操作方法不需要自动启用事务控制时,可以给这些操作方法添加一个自定义的NotTransactionalAttribute特性。

NotTransactionalAttribute.cs代码如下:

    /// <summary>
    /// 自定义特性,在不需要自动启用事务控制的方法上添加该特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class NotTransactionalAttribute : Attribute
    {
    }

编写过滤器TransactionScopeFilter,代码如下:

using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Reflection;
using System.Transactions;

namespace CoreWebApi3
{
    /// <summary>
    /// 自动启用事务的操作筛选器
    /// </summary>
    public class TransactionScopeFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //判断操作方法上是否标记了NotTransactionalAttribute
            bool hasNotTransactionalAttribute = false;
            if (context.ActionDescriptor is ControllerActionDescriptor)
            {
                var actionDesc = (ControllerActionDescriptor)context.ActionDescriptor;
                hasNotTransactionalAttribute = actionDesc.MethodInfo.IsDefined(typeof(NotTransactionalAttribute));
            }

            //如果标记了,则直接执行next
            if (hasNotTransactionalAttribute)
            {
                await next();
                return;
            }

            using (var txScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                var result = await next();
                if (result.Exception == null)//操作方法执行没有异常
                {
                    txScope.Complete();//提交事务
                }
            }

           

        }
    }
}

在Program.cs中注册TransactionScopeFilter:

//设置全局的筛选器
builder.Services.Configure<MvcOptions>(option =>
{
    option.Filters.Add<TransactionScopeFilter>();
});

注册代码要写在builder.Build()之前。

最后,在EF CORE插入数据的代码中插入记录:

        [HttpPost]
        public async Task Save() {
            dbCtx.Book.Add(new Book { Id = Guid.NewGuid(), Name = "1", Price = 1 });
            await dbCtx.SaveChangeAsync();

            dbCtx.Book.Add(new Book { Id = Guid.NewGuid(), Name = "2", Price = 2 });
            await dbCtx.SaveChangeAsync();
        }

上面的代码能够正确的插入两条数据。如果在第一个SaveChangeAsync下面加入一行throw new Exception() 来抛出异常,再次执行SaveChangeAsync方法之后,就会发现数据库中没有插入记录。这说明第一个SaveChangeAsync执行后,虽然实现了插入数据,但是由于事务回滚,因此被插入的数据也被回滚了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值