我有一个asp.net web api,我们在全局操作过滤器的OnActionExecuting中使用TransactionScope(仅适用于POST、PUT和DELETE,但不适用于GET)启动事务,然后在OnActionExecuted中完成或回滚它。 最近我们决定进行更改,以便至少可以为 GET 调用添加 SqlAzureExecutionStrategy(因为它仅在没有用户启动的事务时起作用),以便可以处理数据获取的瞬时故障。我按照这篇文章here并在我们的应用程序中实现了同样的事情。下面是代码。
创建了一个新的数据库配置类
public class AzureDbConfiguration : DbConfiguration
{
public const string CallContextKey = "SuspendExecutionStrategy";
public AzureDbConfiguration()
{
this.SetExecutionStrategy("System.Data.SqlClient", () => SuspendExecutionStrategy
? (IDbExecutionStrategy)new DefaultExecutionStrategy()
: new SqlAzureExecutionStrategy());
}
public static bool SuspendExecutionStrategy
{
get
{
return (bool?)CallContext.LogicalGetData(CallContextKey) ?? false;
}
set
{
CallContext.LogicalSetData(CallContextKey, value);
}
}
}
每当我们需要启动事务时,将 suspendExecutionStrategy 设置为 true。
public override void OnActionExecuting(HttpActionContext actionContext)
{
//checks if it is not a GET call
if (RequiresTransactionInitiation(actionContext))
{
AzureDbConfiguration.SuspendExecutionStrategy = true;
var transactionCompleter = new TransactionCompleter(GetDependencyScope(actionContext));
transactionCompleter.UnitOfWork.StartTransaction(System.Data.IsolationLevel.ReadCommitted);
}
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
//checks if it is not a GET call
if (RequiresTransactionCompletion(actionExecutedContext))
{
var transactionCompleter = new TransactionCompleter(GetDependencyScope(actionExecutedContext));
if (actionExecutedContext.Exception == null)
{
transactionCompleter.Complete();
AddEventsToResponseHeader(transactionCompleter.MessageTransactions.OfType<IEventTransaction>(), actionExecutedContext.Response);
}
else
{
transactionCompleter.Rollback();
}
//*********** line is added to just test the value of the property .This always return false.**********
var testValue = AzureDbConfiguration.SuspendExecutionStrategy;
}
base.OnActionExecuted(actionExecutedContext);
}
问题是 SuspendExecutionStrategy 的值在 OnActionExecuting 中设置正确,但当代码进入控制器操作或 OnActionExecuting 时,它始终为 false。
我做了一些调查并意识到,当我们从过滤器操作转移到控制器操作时,执行上下文本身会发生变化。因此,如果在 OnActionExecuting 中检查 Thread.CurrentThread.ExecutionContext.ToStringJson() ,我会看到 SuspendExecutionStrategy 的值可用,但如果我在控制器操作中检查相同的值,则该值不可用,奇怪的是执行上下文中的其他所有内容仍然可用.
OnActionExecuting 中 Thread.CurrentThread.ExecutionContext.ToStringJson() 的值
{
"LogicalCallContext": {
"E2ETrace.ActivityID": "80000013-0003-fd00-b63f-84710c7967bb",
"ApplicationInsights.OwinExtensions.OperationIdContext": "1c218be6-1fbb-44bf-b994-4db84115b5a3",
"ApplicationInsights.OwinExtensions.OperationParentIdContext": "72d35ac6-a394-4205-8452-a95b36f8857a",
"SuspendExecutionStrategy" : True
})
Controller Action 和 OnActionExecuted 中 Thread.CurrentThread.ExecutionContext.ToStringJson() 的值
{
"LogicalCallContext": {
"E2ETrace.ActivityID": "80000013-0003-fd00-b63f-84710c7967bb",
"ApplicationInsights.OwinExtensions.OperationIdContext": "1c218be6-1fbb-44bf-b994-4db84115b5a3",
"ApplicationInsights.OwinExtensions.OperationParentIdContext": "72d35ac6-a394-4205-8452-a95b36f8857a",
})
所以我的问题是执行上下文如何从操作过滤器更改为控制器操作以及执行上下文中的所有其他值如何仍然保留。
以下代码似乎可以工作。
internal class MyActionFilter :FilterAttribute,IActionFilter
{
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation)
{
CallContext.LogicalSetData("Key", "Value");
return continuation();
}
}