线程上下文切换 多线程下的调用上下文 : CallContext( 三 )


4、子线程中使用LogicalSetData改变数据槽的值,不会影响父线程的数据槽,即使他们的key是同一个;
3 .NET Core下没有CallContext
在.NET Core下没有CallContext类,取而代之的是使用AsyncLocal代替,实现的是CallContext.LogicalGetData 和 CallContext.SetLogicalCallContext 。
例如,下面是一个示例代码,我们可以借助AsyncLocal来自己实现一个CallContext类 。如果你是将.NET Framework升级为.NET Core,那么你可能需要自己实现一个CallContext类来代替之前的CallContext:
public static class CallContext{static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();public static void SetData(string name, object data) =>state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = http://hnpxn.com/IT/data;public static object GetData(string name) =>state.TryGetValue(name, out AsyncLocal data) ? data.Value : null;}4EF DbContext场景
对于像UnitOfWork这种操作模式,是比较适合于CallContext发挥的地方,让EF DbContext在线程上下文内保持唯一 。
注意:这里提到的EF均指EF 而非 EF Core 。
因此,我们经常可以看到如下所示的示例代码:
public class DbContextFactory{public static DbContext CreateDbContext(){DbContext dbContext = (DbContext)CallContext.GetData("dbContext");if (dbContext == null){dbContext = new WebAppEntities();CallContext.SetData("dbContext", dbContext);}return dbContext;}}此用法像极了 Cache(缓存)的使用 。
But,鉴于目前广泛使用线程池的前提,线程在处理完一个请求之后,并没有被销毁,存储在CallContext中的上下文对象也一直存在,如果是下一次拿出这个线程去处理另一个请求,这个上下文对象其实也在不断的膨胀,只不过比全局的膨胀的稍微慢一些 。而且,有时候一个线程并不一定是拿去处理请求了,如果是服务器拿去处理其他的业务,那就可能引发一些其他的问题 。
这时,或许我们可以考虑另一个方案,在ASP.NET中的HttpContext中有一个Items属性,它也可以用来保存key-value,这就完美了,一次请求正好对应着一个HttpContext,请求结束,它自动释放,EF上下文也就不存在了 。
因此,这里把上面代码中的CallContext改为HttpContext.Current.Items:
public class DbContextFactory{public static DbContext CreateDbContext(){DbContext dbContext = HttpContext.Current.Items["dbContext"] as DbContext;if (dbContext == null){dbContext = new WebAppEntities();         HttpContext.Current.Items["dbContext"] = dbContext;}return dbContext;}}其实,HttpContext这个类和CallContext是有关联的,查看源码我们可以发现:HttpContext.Current是通过CallContext.HostContext实现的 。
internal static Object Current {get {return CallContext.HostContext;}[SecurityPermission(SecurityAction.Demand, Unrestricted = true)]set {CallContext.HostContext = value;}}关于HttpContext.Current:ASP.NET会为每个请求分配一个线程,这个线程会执行我们的代码来生成响应结果,即使我们的代码散落在不同的地方(类库),线程仍然会执行它们 。所以,我们可以在任何地方访问HttpContext.Current获取到与当前请求相关的HttpContext对象,毕竟这些代码是由同一个线程来执行的嘛,所以得到的HttpContext引用也就是那个与请求相关的对象 。因此,将HttpContext.Current设计成与当前线程相关联是合适的 。有关CallContext.HostContext的知识可以自行查阅资料,这里就不再赘述 。
刚刚提到UnitOfWork模式,我们完成了DbContext的线程上下文内的唯一性,那么SaveChanges呢?嗯,我们可以基于之前的唯一性保证,来写一个SaveChanges的唯一入口 。


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: