ASP.Net Web应用调用MQ 9.1.4触发类型初始化异常问题排查
机器上同时安装了两个版本的MQ Client:
- 主版本为7.5.0.6(32位,安装路径
C:\Program Files (x86)\IBM\WebSphere MQ) - 9.1.4.0版本(未设为主版本,安装路径
C:\Program Files\IBM\MQ9Client)
安装信息详情
Name: WebSphere MQ Version: 7.5.0.6 Level: p750-006-160226 BuildType: IKAP - (Production) Platform: WebSphere MQ for Windows Mode: 32-bit O/S: Windows Ver 6.2 (7) Server Standard x64 Edition, Build 9200 InstName: Installation1 InstDesc: Primary: Yes InstPath: C:\Program Files (x86)\IBM\WebSphere MQ DataPath: C:\Program Files (x86)\IBM\WebSphere MQ MaxCmdLevel: 750 Name: WebSphere MQ Version: 9.1.4.0 InstName: MQ9client InstDesc: mq9.1 InstPath: C:\Program Files\IBM\MQ9Client Primary: No
为保留7.5为主版本,同时逐步迁移应用到9.1.4,配置了以下内容:
环境变量
DEVPATH C:\Program Files\IBM\MQ9client\bin
应用配置项
<runtime> <developmentMode developerInstallation="true"/> </runtime>
配置后,桌面应用可正常使用MQ 9.1.4,但所有ASP.NET Web应用(无论用IIS Express还是IIS)均抛出异常:
The type initializer for 'IBM.WMQ.Nmqi.UnmanagedNmqiMQ' threw an exception Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
堆栈跟踪
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) at IBM.WMQ.Nmqi.NmqiEnvironment.GetInstance(String name) at IBM.WMQ.Nmqi.NmqiEnvironment.GetMQI(Int32 id) at IBM.WMQ.MQQueueManager.Connect(String queueManagerName) at IBM.WMQ.MQQueueManager..ctor(String queueManagerName, Hashtable properties) at WebApplicationNewMW.Middleware.CreateQueueManager() in c:\Documents\Visual Studio 2013\Projects\WebApplication\WebApplication\Middleware.cs:line 43 at WebApplicationNewMW.Default.Page_Load(Object sender, EventArgs e) in c:\Documents\Visual Studio 2013\Projects\WebApplication\WebApplication\Default.aspx.cs:line 17 at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
桌面应用和Web应用的差异核心来自运行上下文、环境变量读取逻辑以及CLR对配置的处理规则,具体如下:
环境变量作用范围不同
桌面应用运行在当前用户会话中,能直接读取用户/系统级的DEVPATH变量,从而找到MQ 9.1.4的二进制文件;但IIS/IIS Express的应用池运行在独立的系统服务会话(默认是ApplicationPoolIdentity等系统账户),不会继承当前用户的环境变量,即便配置了系统级变量,也需确保应用池账户有路径读取权限,且重启IIS才会生效。developmentMode的适用限制
.NET的developmentMode配置默认仅对桌面应用程序域生效,ASP.NET Web应用的程序集会忽略该配置。这意味着Web应用不会通过DEVPATH加载指定路径的程序集,反而优先从GAC或应用bin目录加载——而GAC中注册的是MQ 7.5的程序集,直接导致版本冲突。32/64位架构不匹配
MQ 7.5是32位版本(安装路径在Program Files (x86)),MQ 9.1.4是64位版本(安装路径在Program Files)。若Web应用池开启了32位兼容模式,会尝试加载32位MQ库,但DEVPATH指向的是64位的9.1.4版本,加载失败后抛出空引用异常;即便应用池是64位,GAC中32位的MQ 7.5程序集也会干扰9.1.4版本的正常加载。
改用程序集绑定重定向
放弃DEVPATH和developmentMode方案,在Web应用的web.config中添加明确的版本绑定,强制指定使用MQ 9.1.4的程序集:<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="IBM.WMQ" publicKeyToken="9076fe74b76313da" culture="neutral"/> <bindingRedirect oldVersion="7.5.0.0" newVersion="9.1.4.0"/> </dependentAssembly> <!-- 需为IBM.WMQ.Nmqi、IBM.WMQ.Common等其他MQ相关程序集添加对应重定向 --> </assemblyBinding> </runtime>复制MQ 9.1.4程序集到应用
bin目录
将MQ 9.1.4的相关程序集直接复制到Web应用的bin文件夹,确保应用优先加载本地的9.1.4版本,避免GAC的干扰。检查应用池位数设置
若使用64位MQ 9.1.4,需确保应用池的“允许32位应用程序”设置为False;若需兼容32位环境,建议安装32位版本的MQ 9.1.4。重启Web服务器
任何环境变量或配置变更后,必须重启IIS/IIS Express才能使设置生效。
内容的提问来源于stack exchange,提问作者Frank Martin

