Asp.Net支持分布式事务
约 684 字大约 2 分钟
2025-02-12
创建全局的 ActionFilter
在将 Asp.Net 工程改造为微服务后,支持分布式事务是非常重要的。为了实现它,我们可以采用以下步骤:
1、创建全局的 ActionFilter:在 Asp.Net 工程中,我们可以创建一个全局的 ActionFilter,用于将数据库事务传递给底层的事务管理器。这个 ActionFilter 可以通过实现接口 IActionFilter 来创建,并且必须被注册到 Asp.Net 中。
2、依赖注入数据库类:为了在 ActionFilter 中获取当前的数据库对象,我们需要将数据库类以 AddScoped 方式进行依赖注入。这样,每次请求都会创建一个新的数据库对象,并且我们可以在 ActionFilter 中访问它。
下面来实际操作一下:(这里假设你的数据库类是 SystemDBContext,并且实现了 IStorageEngine)
services.AddScoped<SystemDBContext>();
Controller 的构造函数里,注入 SystemDBContext
[ApiController]
[Route("[controller]/[action]")]
public class MainController : ControllerBase
{
SystemDBContext _db;
public MainController(SystemDBContext db)
{
this._db = db;
}
}
然后新建一个 MyActionFilter.cs,实现 IActionFilter 接口
这个类会自动将数据库事务传递给底层的事务管理器
public class MyActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
//获取事务管理对象
var apiTransactionDelegate = context.HttpContext.RequestServices.GetService<ApiTransactionDelegate>();
//获取当前数据库对象
var db = context.HttpContext.RequestServices.GetService<SystemDBContext>();
if(context.Exception != null)
{
//发生异常
db.Database.CurrentTransaction?.Rollback();
return;
}
if (db.Database.CurrentTransaction == null)
return;
if(apiTransactionDelegate.TransactionId == null)
{
//访问来自浏览器,不是Mirage.RemoteClient,所以,应该提交事务
db.Database.CurrentTransaction.Commit();
}
else
{
//访问来自Mirage.RemoteClient,需要把事务交给ApiTransactionDelegate
apiTransactionDelegate.StorageEngine = db;
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
}
然后注册 MyActionFilter
services.AddMvc(option => {
option.Filters.Add<MyActionFilter>();
});
到这里,你的工程已经支持分布式事务了。在编写 controller 接口时,请注意首先调用 begintransaction 方法以开启事务。
[ApiController]
[Route("[controller]/[action]")]
public class MainController : ControllerBase
{
SystemDBContext _db;
public MainController(SystemDBContext db)
{
this._db = db;
}
[HttpGet]
public string TestMethod(string name)
{
//开启分布式事务
_db.Database.BeginTransaction();
...写一些操作数据库的代码,注意:不要提交事务
return "ok";
}
}
RemoteClient 如何调用
using ( var rc = new Mirage.RemoteClient(gateways))
{
//开启分布式事务
rc.BeginTransaction();
//假设Asp.Net注册的微服务名称为:MyAspNetService
var myAspNetService = await rc.GetMicroServiceAsync("MyAspNetService");
//调用MyAspNetService的MainController/TestMethod接口
var ret = await myAspNetService.InvokeAsync<string>("/Main/TestMethod");
//提交分布式事务
rc.CommitTransaction();
}
JavaScript 如何调用
使用 javascript 调用此服务与调用普通的 asp.net 没有区别,只需了解如何拼接 url。
拼接 url 的方式为:
http://webapi 地址/服务名称/asp.net 自身的路由路径。
假设您部署的 Mirage.WebApi 端口是 5002,那么根据上面 Controller 的示例,其 url 应为:
http://127.0.0.1:5002/MyAspNetService/Main/TestMethod
在 RegisterMirageService 注册微服务时,请确保将 allowGatewayProxy 参数设置为 true,否则 javascript 将无法通过 127.0.0.1:5002 进行访问。