正如很好地讨论here和here,您应该使用HttpContext.Current.Items
而不是ThreadStatic
变量来存储ASP.NET请求的数据,因为您的请求可能是由多个线程处理。
如果你想在后台线程上做某事怎么样?使用ThreadStatic
数据并设置Thread.CurrentPrincipal.Identity
以避免必须通过所有方法推送“全局”数据是否安全?我假设它很好,但我想确定。例如,我没有在后台线程上执行的代码中明确使用任何await
,但我调用的库可能是;可能ASP.NET使用我的线程做其他事情,而这样的同步代码不活动?如果是这样的话,在运行它之前在线程上设置一些“线程静态”数据和用户信息的安全方法是什么?
我很清楚ASP.NET中后台线程上运行代码的the pitfalls。但有时你必须做你必须做的事情。在我的情况下,我们尚未使用.NET 4.5.2,因此无法使用QueueBackgroundWorkItem,因此我们使用Nito.AspNetBackgroundTasks来运行后台任务。这在内部使用Task.Run()
。
例如,我会做这样的事情:
public class SomeController
{
public void AControllerMethod()
{
// Get the data set earlier on the HttpContext
var theData = HttpContext.Current.Items["importantKey"];
var thePrincipal = HttpContext.Current.User;
// Pass it to the background thread method
BackgroundTaskManager.Run(() => DoStuffInBackground(theData, thePrincipal));
}
private void DoStuffInBackground(string someData, IPrincipal user)
{
// Store the data & principal for use by logic classes later
Thread.CurrentPrincipal = user;
MyContextService.BackgroundData["importantKey"] = someData;
// do some things, some of which would call:
aLogicClass.DoSomethingDeepInLogicCode();
}
}
public class ExampleLogicClass
{
private void DoSomethingDeepInLogicCode()
{
// get the context info
var user = Thread.CurrentPrincipal;
var theData = MyContextService.GetContextData("importantKey");
// .. do stuff with user & data....
}
}
public static class MyContextService
{
[ThreadStatic]
public static ConcurrentDictionary<string,object> BackgroundData = new ConcurrentDictionary<string,object>();
// Gets data from HttpContext or from BackgroundData
public object GetContextData(string key)
{
if (HttpContext.Current != null)
{
var data = HttpContext.Current.Items[key];
if (data != null) return data;
}
if (BackgroundData.ContainsKey(key))
{
return BackgroundData[key];
}
return null;
}
}
更新
从bit more reading我想我应该使用CallContext.LogicalSetData()和LogicalGetData()来设置/获取ThreadLocal / ThreadStatic数据的等价物。 (或。{4.6}中的AsyncLocal<T>
。
正确认识这些东西的人会有更多的澄清。