当前位置: 首页 > news >正文

只在UnitTest和WebHost中的出现的关于LogicalCallContext的严重问题

最近一直在进行公司内部框架的升级工作,其中一个小的部分就是通过HttpSessionState和CallContext建立一套统一的、可扩展的用于管理上下文信息的框架。在为写好的程序编写Unit Test和QuickStart的时候,遇到了两个基于LogicalCallContext的严重问题。导致这两个问题的根源还没有来得及去追踪,或许是微软VS  Unit Test框架本身和WebHost本身的一个Bug。现在将其写出来,一来是希望读者在遇到相同情况的时候知道LogicalCallContext可能是影响因素之一,另一方面也希望借助社区的力量快速找到问题的症结。以下内容假定读者已经对CallContext有一个大概的了解,并且明白LogicalCallContext和IllogicalCallContext之间的区别。对此不了解的读者,可以参考我的文章《如何实现对上下文(Context)数据的统一管理 》。

一、在VS Unit Test下设置LogicalCallContext导致的序列化问题

为了演示在Unit Test下设置LogicalCallContext会导致怎样的问题,为此我写了一个非常简单的例子去重现它。首先我定义了如下一个形如Key-Value 的类型:LogicalContextItem<TValue>:

   1: [Serializable]
   2: public class LogicalContextItem<TValue>
   3: {
   4:     public string Key { get; private set; }
   5:     public TValue Value { get; set; }
   6:  
   7:     public LogicalContextItem(string key, TValue value)
   8:     {
   9:         if (string.IsNullOrEmpty(key))
  10:         {
  11:             throw new ArgumentNullException("key");
  12:         }
  13:         this.Key = key;
  14:         this.Value = value;
  15:     }
  16: }

然后通过如下一个TestMethod测试一个以LogicalCallContext的形式保存的上下文(通过调用CallContext的静态方法LogicalSetData)是否可以通过相同的Key被正常获取。

   1: [TestClass]
   2: public class LogicalSetDataFixture
   3: {
   4:     [TestMethod]
   5:     public void LogicaSetData()
   6:     {
   7:         LogicalContextItem<string> userName = new LogicalContextItem<string>("__userName", "Foo");
   8:         CallContext.LogicalSetData(userName.Key, userName);
   9:         Assert.AreEqual<string>("Foo", ((LogicalContextItem<string>)CallContext.LogicalGetData("__userName")).Value);
  10:     }
  11: }

但是运行上面的UnitTest的时候,在TestResult对话框中会出现一个Error。从下图中我们可以看出这是一个序列化的错误,具体的出错信息为:Unit Test Adapter threw exception: Type is not resolved for member 'UnitTests.LogicalContextItem`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],UnitTests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null',即我们自定义的类型无法解析。这就有点让人费解了,在这个实例中,LogicalContextItem<TValue>:类型本身是直接定义在UnitTest这个项目之中的,何来无法解析之理。image 

二、在VS ASP.NET WebHost下设置LogicalCallContext导致的序列化问题

我们知道,为了给基于ASP.NET的Web应用的开发者带来便利,Visual Studio内置了一个简单(和IIS比较而言)的Web应用承载工具,即WebHost。如果采用基于WebHost的承载方式(这是默认的承载方式),上面的错误同样会发生。为了演示,我们同样使用上面定义的LogicalContextItem<TValue>类型,然后在一个单纯的WebPage中的Load事件处理方法中编写了如下一段简单的代码:

   1: public partial class _Default : System.Web.UI.Page
   2: {
   3:     protected void Page_Load(object sender, EventArgs e)
   4:     {
   5:         LogicalContextItem<string> userNameContext = new LogicalContextItem<string>("__userName", "Foo");
   6:         CallContext.LogicalSetData(userNameContext.Key, userNameContext);
   7:         var userName = ((LogicalContextItem<string>)CallContext.LogicalGetData("__userName")).Value;
   8:         Response.Write(userName);
   9:     }
  10: }

直接运行上面的程序,SerializationException异常照常被抛出,从下图给出的错误对话框可以看出,该异常具有和上面完全一样的错误信息,即不能解析我们自定义的LogicalContextItem<TValue>类型。

image

为了找出抛出SerializationException异常的根源,我们可以来该异常的StatckTrace。从下面给出的内容,我们可以看出来该异常最终就是通过WebHost抛出来得。

   1: at Microsoft.VisualStudio.WebHost.Host.ProcessRequest(Connection conn)
   2: at Microsoft.VisualStudio.WebHost.Server.OnSocketAccept(Object acceptedSocket)
   3: at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
   4: at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   5: at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   6: at System.Threading.ThreadPoolWorkQueue.Dispatch()
   7: at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

三、采用IIS承载我们的Web应用可以解决上述问题

为什么我说这个问题只和内置于VS中的Web应用承载工具WebHost有关呢?一来是因为上面给出的异常StackTrace已经明显反映了异常最后总就是从WebHost跑出来的。另一个主要的原因就是,如果我直接采用IIS来承载的话,运行上述的代码后一切正常。有兴趣的读者可以从这里下载实例程序进行试验。你只需要该Web应用进行了如下配置,放弃使用Vistual Studio Development Server,而选用Local IIS Web Server即可。

image



作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文链接

相关文章:

  • SQL Server 2008使用LINQ进行数据访问(转载自IT168 [ http://www.it168.com/ ])
  • Windows中运行Python的两种运行方式
  • GNS3使用详解2
  • 数据类型测试及转换案例
  • VS2010编译Web项目要用 batch=false
  • 《WCF技术剖析》博文系列汇总[持续更新中]
  • 在linux中怎样用命令完全拷贝一个目录下的所有文件(包括隐藏文件以及文件夹)到另外一个目录下...
  • 传输层TCP
  • 模态对话框和非模态对话框的消息循环
  • 定制rpm包-Yum环境搭建
  • Visual.Studio.2010.简体中文旗舰版内置KEY
  • 高性能朋友圈
  • C# wnform 请求http ( get , post 两种方式 )
  • ubuntu重启不清除 /tmp 设置
  • windows 2003部署xp
  • [笔记] php常见简单功能及函数
  • CSS中外联样式表代表的含义
  • egg(89)--egg之redis的发布和订阅
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • JavaScript服务器推送技术之 WebSocket
  • Python学习之路16-使用API
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • Shell编程
  • 将回调地狱按在地上摩擦的Promise
  • 日剧·日综资源集合(建议收藏)
  • 如何利用MongoDB打造TOP榜小程序
  • 首页查询功能的一次实现过程
  • 数据可视化之 Sankey 桑基图的实现
  • 物联网链路协议
  • 做一名精致的JavaScripter 01:JavaScript简介
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​卜东波研究员:高观点下的少儿计算思维
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (10)ATF MMU转换表
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)原始图像数据和PDF中的图像数据
  • (转载)OpenStack Hacker养成指南
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .Net 8.0 新的变化
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET 事件模型教程(二)
  • .NET 指南:抽象化实现的基类
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
  • .net中的Queue和Stack