You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止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相关属性:

    1. 打开IIS管理器,找到目标应用池,右键选择「高级设置」。
    2. 在「进程模型」下,将「加载用户配置文件」设为True,确保应用池账户的完整COM安全配置被加载。
    3. 若使用自定义域账户运行应用池,需为该账户配置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:22:12