如何阻止IIS初始化DCOM安全设置或自定义其配置以适配OPC DA连接?
我有一个基于ASP.NET Core的Blazor Server端应用(.NET 6),完全托管于IIS,运行在Windows Server 2019系统上。该应用需连接远程机器的OPC DA服务器并读取数据,使用第三方库实现。在同服务器上运行的.NET 6控制台测试应用中,设置特定安全参数后该库可正常工作,但将相同代码和参数移植到Web应用时,却出现“Access Denied”等连接错误。
我们尝试了修改OPC DA安全参数、更换Web应用的Windows账户(Local System、Network Service等)、切换32/64位运行模式等方法均无效。经与第三方库厂商沟通及排查服务器事件日志,发现问题根源可能是IIS在Web应用代码之前就初始化了COM安全设置,事件日志报错如下:
************************* COM security initialization (process "w3wp" Id 15544, application domain "WebApplication7" Id 1) for requestor 'ComSecurityInitializingEasyDAClient' failed; the initialization object was: (Default). CoInitializeSecurity failure (0x80010119): Security must be initialized before any interfaces are marshalled or unmarshalled. It cannot be changed once initialized. + This error (RPC_E_TOO_LATE) is not uncommon in hosted .NET applications. Depending on various factors, it might be possible to prevent it, or safely ignore it (if COM works as intended). Consult the product documentation. + Current thread name: "OpcLabs.Lazy2.Kick < [16] .NET ThreadPool Worker", from thread pool: no, managed thread Id: 18, apartment state: MTA. *************************
现咨询:是否可以阻止IIS初始化DCOM安全设置,或确保IIS按照我们的需求配置DCOM安全设置?
应用中使用的代码如下:
using OpcLabs.EasyOpc; using OpcLabs.EasyOpc.DataAccess; using OpcLabs.EasyOpc.DataAccess.AddressSpace; using OpcLabs.EasyOpc.OperationModel; using OpcLabs.EasyOpc.OperationModel; using OpcLabs.EasyOpc.DataAccess.OperationModel; using OpcLabs.BaseLib.Runtime.InteropServices; using System.Diagnostics; Connect_OPCDA(); static void Connect_OPCDA() { // setting COM security parameters ComManagement.Instance.Configuration.InstantiationParameters.OverrideDefaultSecurity = false; ComManagement.Instance.Configuration.SecurityParameters.UseCustomSecurity = true; ComManagement.Instance.Configuration.SecurityParameters.TurnOffCallSecurity = true; Browse_Servers(); Browse_nodes(); } static void Browse_Servers() { var client = new EasyDAClient(); ServerElementCollection serverElements; try { serverElements = client.BrowseServers("10.92.XXX.XXX"); } catch (OpcException opcException) { //Error handling return; } foreach (ServerElement serverElement in serverElements) { //some code } } static void Browse_nodes() { var client = new EasyDAClient(); DANodeElementCollection branchElements; try { branchElements = client.BrowseBranches("10.92.XXX.XXX", "OPC.IwSCP.1", ""); } catch (OpcException opcException) { //Error handling return; } foreach (DANodeElement branchElement in branchElements) { //some code } }
解决方案
无法直接阻止IIS初始化DCOM安全设置:IIS的w3wp进程启动时会自动初始化DCOM安全,这是系统级行为,无法通过应用层代码禁用,但可通过以下方式确保自定义COM安全配置优先生效。
将COM安全配置提前到应用启动最早期:
在Blazor Server的Program.cs中,把COM安全参数配置代码放在builder.Build()之前执行,确保在任何COM对象创建前完成设置。示例:using OpcLabs.BaseLib.Runtime.InteropServices; var builder = WebApplication.CreateBuilder(args); // 提前配置COM安全参数,确保在所有COM操作前执行 ComManagement.Instance.Configuration.InstantiationParameters.OverrideDefaultSecurity = false; ComManagement.Instance.Configuration.SecurityParameters.UseCustomSecurity = true; ComManagement.Instance.Configuration.SecurityParameters.TurnOffCallSecurity = true; // 其他服务注册逻辑 builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); // ... var app = builder.Build(); // ... 后续中间件配置配置IIS应用池的COM相关属性:
- 打开IIS管理器,找到目标应用池,右键选择「高级设置」。
- 在「进程模型」下,将「加载用户配置文件」设为
True,确保应用池账户的完整COM安全配置被加载。 - 若使用自定义域账户运行应用池,需为该账户配置DCOM权限:
- 打开
dcomcnfg(组件服务),展开「组件服务」→「计算机」→「我的电脑」,右键选择「属性」→「COM安全」选项卡。 - 在「启动和激活权限」中点击「编辑限制」,添加应用池账户并授予「本地启动」「本地激活」「远程启动」「远程激活」权限。
- 在「访问权限」中点击「编辑限制」,添加应用池账户并授予「本地访问」「远程访问」权限。
- 打开
利用OpcLabs库的延迟初始化特性:
根据OpcLabs文档,RPC_E_TOO_LATE错误可通过延迟COM对象创建规避。确保所有安全参数配置完成后,再实例化EasyDAClient,避免提前触发COM初始化。调整线程公寓状态:
日志显示线程处于MTA状态,部分OPC DA服务器要求STA线程。可尝试在STA线程中创建EasyDAClient并执行操作:var staThread = new Thread(() => { var client = new EasyDAClient(); // 执行服务器浏览或数据读取操作 }); staThread.SetApartmentState(ApartmentState.STA); staThread.Start(); staThread.Join();
内容的提问来源于stack exchange,提问作者Mdarende

