gpt4 book ai didi

c# - 如何从通过 Task.Factory.StartNew 创建的线程访问应用程序上下文

转载 作者:行者123 更新时间:2023-11-30 17:01:09 25 4
gpt4 key购买 nike

我有一个在主应用程序线程中运行的方法,但会创建新的 Task用于长时间运行和 await这就是结果。

public async Task<CalculatorOutputModel> CalculateXml(CalculatorInputModel input)
{
// 1
return await Task.Factory.StartNew(
new Func<CalculatorOutputModel> (() =>
{
// 2
using (var ms = Serializer.Serialize(input))
{
ms.Position = 0;
using (var rawResult = Channel.RawGetFrbXmlOutputs(ms)) // 3
{
var result = Parser.Parse(rawResult);
return result;
}
}
}),
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}

我的问题是第 (1) 点和 (2) 点中的 AppContext “有点”不同。在第 1 点中,通常的应用程序上下文在 Current 中属性,其中包含我需要的所有数据。在第 2 点,如您所知,有 null引用 AppContext.Current ,所以我无法访问任何数据。在第 2 点访问上下文的问题似乎很简单,只需在局部变量中“捕获”当前上下文或将其作为参数传递即可。这个问题对我来说更难,因为我需要访问标记为“3”的行深处某处的上下文。
该类本身派生自 System.ServiceModel.ClientBase<TChannel>我需要访问上下文的地方是实现 IClientMessageInspector 的类.

class CalculatorMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (AppContext.Current != null)
{
// never goes here
}
}
}

澄清一下,这是调用堆栈(我无法在所需方法中传递我的上下文): Call stack

所以:

  1. 我无法将上下文传递给 Channel的方法,因为它没有任何意义;
  2. 我无法从 Channel 中的上下文中保存所需的参数因为它是代理类;
  3. 我无法在 CalculatorMessageInspector 中保存必需的参数因为它是在当前上下文已经为空的地方创建的。

任何人都可以建议任何方法如何让我在另一个线程中保持在相同的上下文中?或者,至少,如何从方法层次结构中标记为“2”的位置传递参数?也许,我可以使用 SynchronizationContext以某种方式实现它?非常感谢任何建议。

更新

AppContext.Current考虑与 HttpContext.Current != null ? HttpContext.Current.Items[AppContextKey] : null 相同

更新 2所以看起来,在这种情况下,没有通用的解决方案来持久化上下文。因此,在这种具体情况下(非常具体)唯一适用的解决方案是使用闭包捕获所需的参数,然后保存在一个对象中,该对象将在所需的方法中可用(对我来说,向 IEndpointBehavior 的实现者添加属性) ,但该解决方案有点奇怪)。因此,最适用的解决方案是放弃对同步调用的异步包装,因此 AppContext永远不会“消失”。 Mark Stephen 的回答是对的。

最佳答案

要在 ASP.NET 上使用 asyncawait,您必须以 .NET 4.5 为目标并关闭 quirks 模式。最好的方法是在您的 web.config 中设置 /configuration/system.web/httpRuntime@targetFramework="4.5"

此外,您不应在 ASP.NET 上使用 Task.RunTask.Factory.StartNew。所以你的代码应该看起来更像这样:

public CalculatorOutputModel CalculateXml(CalculatorInputModel input)
{
using (var ms = Serializer.Serialize(input))
{
ms.Position = 0;
using (var rawResult = Channel.RawGetFrbXmlOutputs(ms))
{
var result = Parser.Parse(rawResult);
return result;
}
}
}

关于c# - 如何从通过 Task.Factory.StartNew 创建的线程访问应用程序上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21336224/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com