Search code examples
.netcom-interopremotingcom+

.Net COM+ from .Net project: System.IO.FileNotFoundException


I've written a .Net component that runs in a COM+ application. The component inherits from ServicedComponent and is marked to run as a server process (because I need to maintain static data through activations from multiple consumers).

Registration is done using RegAsm.exe:

c:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe /codebase MyObject.dll

The COM+ application was created manually and the component added after creation.

If I instantiate my component from PHP the code works as expected: the instance is created in a separate process which is listed in the Component Services Console.

<?php
    $obj = new COM("MyObject.Sender");
    $obj->SendMessage("Hello world");
?>

However, when I try to instantiate the component from a .Net test executable, I get a "Cannot create ActiveX component" exception:

Try
    Using gw = CreateObject("MyObject.Sender") 'Exception thrown HERE
        Dim gwsender As IMsgSender = gw
        gwsender.SendMessage("Hello world")
    End Using
Catch ex As Exception
    MsgBox(ex.ToString)
End Try

The test executable is a simple WinForm application.

Setting the debugger to stop at all exceptions I was able to get the following MDAs:

The assembly named 'MyObject' was loaded from 'file:///c:/MyObject/bin/Debug/MyObject.dll' using the LoadFrom context. The use of this context can result in unexpected behavior for serialization, casting and dependency resolution. In almost all cases, it is recommended that the LoadFrom context be avoided. This can be done by installing assemblies in the Global Assembly Cache or in the ApplicationBase directory and using Assembly.Load when explicitly loading assemblies.

Which I expected because it was registered using /CodeBase instead of using the GAC. But then:

The assembly with display name 'MyObject' failed to load in the 'LoadFrom' binding context of the AppDomain with ID 1. The cause of the failure was: System.IO.FileNotFoundException: Could not load file or assembly 'MyObject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=92a84ff3d67c82b9' or one of its dependencies. The system cannot find the file specified.

The MyObject component (which loads perfectly if invoked from PHP) has no special dependencies (only .Net). Tracing from sysinternal's process monitor I couldn't see anything failing, and the access to my .dll is successful (CreateFileMapping, Load Image, etc.). It doesn't look like it is a file access problem but some runtime check made by the framework.

Both the test .net client and the COM+ component were compiled from the same compiler; all relevant options look the same (platform set to x86, .Net Framework 4). As an extra debugging measure I log the framework version to a file both in the component and in the test program, although they are the same (4.0.30319.34209). Everything is run on the same machine.

The Fusion log suggests that the runtime attempts to load the binary directly (without invoking the COM+ instance).

I need this twisted interaction (.Net-->COM+-->.Net) for legacy reasons, but I cannot make it work. What could be happening?


Solution

  • It turns out registration using RegAsm.exe is not the correct procedure for this operation. The assembly must be added to the GAC first and then the COM+ application must be created using the regsvcs utility. Otherwise, .Net doesn't look into the COM+ catalog at all:

    "c:\Windows\Microsoft.NET\Framework\v4.0.30319\regsvcs.exe" MyObject.dll
    "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\gacutil.exe" /i MyObject.dll
    

    Note: the utilities' path may be different in your system.