I have a asp.net core based web application (Blazor server side) with .NET6 (fully hosted in IIS). The app is running on a Windows Server 2019. In this app I want to establish connection to remote machine's OPC DA servers and read some values. I use a third party library for that. The third party library is working quiet well when it is used in C# console test app (again with .NET6) and some security parameters are set to some specific values (the test console app is executed on the same server for connecting to the same OPCDA server).
But when I use the same code with same security parameters I cannot overcome Errors at the connection like "Access Denied". We tried lot of things like changing OPC DA security parameters, changing the Windows account of the web app to all posibble alternatives (Local system, Network service...),running the app both as 32 and 64 bit.
After long trials and discussion with the company we came to the result, that the problem comes because, the IIS is probably initialising COM security settings before I do it in my web app code. The reason why we think so is the Error I get in EventLog of my server when I run my web app:
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.
Now back to my question:
Is it possible to prevent IIS initialising DCOM security settings or to ensure that IIS does the DCOM security settings in the way we want? Belowe you can see the code which I use in my app:
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 scurity 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
}
}