I'm trying to make a call inside a COM components from a custom domain. The problem is when I try to unwrap my ObjectHandle an Serialization exception is throw.
But if I use the current AppDomain to create the instance, it's working....
The exception message:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in ConsoleApp1.exe
Additional information: Type 'MyAddin.Main' in assembly 'MyAddin, Version=2019.0.1.5, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
And my code:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string addinPath = "C:\\sources\\MyAddin\\bin\\x64\\Debug\\MyAddin.dll";
string addinFolder = "C:\\sources\\MyAddin\\bin\\x64\\Debug\\";
string addinConfigPath = "C:\\sources\\MyAddin\\bin\\x64\\Debug\\MyAddin.dll.config";
System.AppDomainSetup setup = new System.AppDomainSetup();
setup.ApplicationBase = addinFolder;
setup.ConfigurationFile = addinConfigPath;
setup.ApplicationName = "MyAddin.dll";
string strClsid = "{2616ad89-f4d1-4dc7-9d9d-a5de101b9085}"; // CLSID of my COM addin
System.AppDomain customDomain = System.AppDomain.CreateDomain(strClsid, null, setup);
// The type of domain is System.Runtime.Remoting.Proxies.__TransparentProxy}
// The type of custom domain is
System.Type addinComType = System.Type.GetTypeFromCLSID(System.Guid.Parse(strClsid));
System.Runtime.Remoting.ObjectHandle addinInstanceObjectHandle = customDomain.CreateComInstanceFrom(addinPath, addinComType.FullName);
System.Object addinInstance = addinInstanceObjectHandle.Unwrap(); //Throw the Serialization exception when create COM instance from customDomain
// But working if I did System.AppDomain.CurrentDomain.CreateComInstanceFrom
System.Reflection.MethodBase myMethod = addinInstance.GetType().GetMethod("connectToEwAPI");
System.Object[] parameters = { null };
myMethod.Invoke(addinInstance, parameters);
}
}
}
So I do something stupid ? Do you know what I'm missing ?
Thanks in advance for your help
I have tried with more basic Assembly. So I have an C# assembly with just this code
namespace ClassLibrary2
{
public class Class1
{
public Class1()
{
}
public string MyMethod() => "OK";
}
}
And my exe code is just
static void Main(string[] args)
{
string basePath = @"C:\source\MyAddin\ConsoleApp1\ClassLibrary2\bin\Debug";
string dllName = @"ClassLibrary2";
string typeName = "ClassLibrary2.Class1";
string dllFullpath = $"{basePath}\\{dllName}.dll";
try
{
ObjectHandle objectHandle = AppDomain.CurrentDomain.CreateInstanceFrom(dllFullpath, typeName);
Object addinObject = objectHandle.Unwrap();
var myAddinMethod = addinObject.GetType().GetMethod("MyMethod");
string result = myAddinMethod.Invoke(addinObject, null) as string; // Working
AppDomainSetup setup = new AppDomainSetup()
{
ApplicationBase = basePath,
ApplicationName = dllName,
ConfigurationFile = dllName + ".dll.config",
PrivateBinPath = basePath
};
AppDomain customDomain = AppDomain.CreateDomain("MyDomain", null, setup);
ObjectHandle objectHandleFromCustomDomain = customDomain.CreateInstanceFrom(dllFullpath, typeName);
Object addinObjectFromCustomDomain = objectHandleFromCustomDomain.Unwrap(); // Exception thrown
var myAddinMethodFromCustomDomain = addinObjectFromCustomDomain.GetType().GetMethod("MyMethod");
string resultFromCustomDomain = myAddinMethodFromCustomDomain.Invoke(myAddinMethodFromCustomDomain, null) as string;
}
catch(Exception e)
{
var t = e.Message; // Exception thrown: 'System.Runtime.Serialization.SerializationException' by objectHandleFromCustomDomain.Unwrap()
}
}
So as you can see, it's working with the default domain but not with the custom one....
Do you have any idea ?
If you want to access an object across an AppDomain
boundary, you need to do one of two things:
Make the class Serializable
, e.g. by adding the [Serializable]
attribute. In this case, a copy of the object is serailized and passed across the AppDomain
boundary. Any membes you call will be on the copy, and will not affect the original object.
Make the class derive from MarshalByRefObject. In this case, a reference to the object is marshalled across the AppDomain boundary, and any members you call will affect the object in its original AppDomain.