如何在完成 "event" 时连接到 TransactionScope?
How do I hook into TransactionScope on completing "event"?
我想知道是否有一种方法可以连接到当前 运行 事务并在该事务完成时完成一些工作。
目前我正在实施使用 MassTransit/RabbitMQ 发布消息的 EventPublisher
,但我只想在 TransactionScope 完成时发布这些消息。
我会在 EventPublisher.PublishEvent()
方法中检查当前是否有交易 运行,如果没有,则触发消息,如果是,则收集消息并等待交易完成送走他们。
var ep = container.GetInstance<IEventPublisher>();
using(var scope = new TransactionScope())
{
... do some stuff
SaveEntity(entity);
ep.PublishEvent(new EntitySaved(entity.Id));
... do some more stuff ...
UpdateEntity(differentEntity);
ep.PublishEvent(new EntityUpdated(differentEntity.Id));
... do even more stuff ...
ep.PublishEvent(new UnrelatedMessage(someData));
scope.Complete(); // <- only want the actual sending off to RabbitMQ to happen here.
}
我在这里找到了这个 TransactionCompleted
活动 https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transaction.transactioncompleted
但它似乎只在 scope.Complete()
位结束并完成后才会被触发。
我可以用它来检查交易状态是否已完成,然后实际触发我在交易期间收集的那些消息。但我的问题是与 RabbitMQ 的连接可能已断开。然后我就不能发送那些消息了,但是上面的所有工作都已经完成了,但是我永远无法发送那些消息。
我真正想要的是以某种方式连接到事务当前正在完成的位,在该过程中我触发我的消息,如果失败我可以抛出一个异常并让那个仍然是 运行 事务出去了window。
也许 MassTransit 有办法做到这一点,但那里并没有真正提供文档。
下面是一些显示问题的示例代码。
internal class Program
{
private static void Main(string[] args)
{
const string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True";
var sql = @"insert into [SomeTable] (
[Id]
,[Name]
,[Index]
,[RelationId]
) values (@param1, @param2, @param3, @param4) ";
using (var scope = new TransactionScope())
{
Transaction.Current.TransactionCompleted += CurrentOnTransactionCompleted;
using (var con = new SqlConnection(connectionString))
{
con.Open();
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("@param1", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
cmd.Parameters.Add("@param2", SqlDbType.NVarChar, 128).Value = "Blah";
cmd.Parameters.Add("@param3", SqlDbType.SmallInt).Value = 1;
cmd.Parameters.Add("@param4", SqlDbType.UniqueIdentifier).Value = Guid.Parse("a401866d-3bdd-48a4-a78b-d40864c8471b");
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
scope.Complete();
}
}
private static void CurrentOnTransactionCompleted(object sender, TransactionEventArgs e)
{
// I want to do stuff here but if this stuff fails I need the whole transaction to roll back.
... do some stuff that can fail ...
e.Transaction.Rollback(new Exception("Bad transaction!"));
// or
throw new Exception("Bad transaction!");
}
}
我找错地方了。浏览 microsoft/referencesource 后,我在 TransactionContext.cs 中找到了我要找的东西。
您需要连接一个 IEnlistmentNotification
,如下所述:https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transaction.enlistvolatile
我需要将我的代码放入 Prepare 方法中,如果失败则调用 ForceRollback
。
我想知道是否有一种方法可以连接到当前 运行 事务并在该事务完成时完成一些工作。
目前我正在实施使用 MassTransit/RabbitMQ 发布消息的 EventPublisher
,但我只想在 TransactionScope 完成时发布这些消息。
我会在 EventPublisher.PublishEvent()
方法中检查当前是否有交易 运行,如果没有,则触发消息,如果是,则收集消息并等待交易完成送走他们。
var ep = container.GetInstance<IEventPublisher>();
using(var scope = new TransactionScope())
{
... do some stuff
SaveEntity(entity);
ep.PublishEvent(new EntitySaved(entity.Id));
... do some more stuff ...
UpdateEntity(differentEntity);
ep.PublishEvent(new EntityUpdated(differentEntity.Id));
... do even more stuff ...
ep.PublishEvent(new UnrelatedMessage(someData));
scope.Complete(); // <- only want the actual sending off to RabbitMQ to happen here.
}
我在这里找到了这个 TransactionCompleted
活动 https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transaction.transactioncompleted
但它似乎只在 scope.Complete()
位结束并完成后才会被触发。
我可以用它来检查交易状态是否已完成,然后实际触发我在交易期间收集的那些消息。但我的问题是与 RabbitMQ 的连接可能已断开。然后我就不能发送那些消息了,但是上面的所有工作都已经完成了,但是我永远无法发送那些消息。
我真正想要的是以某种方式连接到事务当前正在完成的位,在该过程中我触发我的消息,如果失败我可以抛出一个异常并让那个仍然是 运行 事务出去了window。
也许 MassTransit 有办法做到这一点,但那里并没有真正提供文档。
下面是一些显示问题的示例代码。
internal class Program
{
private static void Main(string[] args)
{
const string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True";
var sql = @"insert into [SomeTable] (
[Id]
,[Name]
,[Index]
,[RelationId]
) values (@param1, @param2, @param3, @param4) ";
using (var scope = new TransactionScope())
{
Transaction.Current.TransactionCompleted += CurrentOnTransactionCompleted;
using (var con = new SqlConnection(connectionString))
{
con.Open();
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("@param1", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
cmd.Parameters.Add("@param2", SqlDbType.NVarChar, 128).Value = "Blah";
cmd.Parameters.Add("@param3", SqlDbType.SmallInt).Value = 1;
cmd.Parameters.Add("@param4", SqlDbType.UniqueIdentifier).Value = Guid.Parse("a401866d-3bdd-48a4-a78b-d40864c8471b");
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
scope.Complete();
}
}
private static void CurrentOnTransactionCompleted(object sender, TransactionEventArgs e)
{
// I want to do stuff here but if this stuff fails I need the whole transaction to roll back.
... do some stuff that can fail ...
e.Transaction.Rollback(new Exception("Bad transaction!"));
// or
throw new Exception("Bad transaction!");
}
}
我找错地方了。浏览 microsoft/referencesource 后,我在 TransactionContext.cs 中找到了我要找的东西。
您需要连接一个 IEnlistmentNotification
,如下所述:https://docs.microsoft.com/en-us/dotnet/api/system.transactions.transaction.enlistvolatile
我需要将我的代码放入 Prepare 方法中,如果失败则调用 ForceRollback
。