C# 无法从自定义域中打开COM实例

C# 无法从自定义域中打开COM实例,c#,.net,com,appdomain,C#,.net,Com,Appdomain,我正在尝试从自定义域在COM组件内部进行调用。 问题是,当我尝试打开ObjectHandle时,会抛出序列化异常 但是如果我使用当前的AppDomain创建实例,它会工作 异常消息: An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in ConsoleApp1.exe Additional information: Type 'MyAddin.Main' i

我正在尝试从自定义域在COM组件内部进行调用。 问题是,当我尝试打开ObjectHandle时,会抛出序列化异常

但是如果我使用当前的AppDomain创建实例,它会工作

异常消息:

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.
我的代码是:

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);

        }
    }
}
所以我做了些蠢事? 你知道我错过了什么吗

提前谢谢你的帮助


编辑 我尝试了更基本的组装。 因此,我有一个C#程序集,只包含以下代码

namespace ClassLibrary2
{
    public class Class1
    {
        public Class1()
        {

        }
        public string MyMethod() => "OK";
    }
}
我的exe代码只是

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()
    }
}
如您所见,它使用的是默认域,而不是自定义域


你有什么想法吗?

如果你想跨
AppDomain
边界访问对象,你需要做两件事之一:

  • 使类可序列化,例如通过添加
    [Serializable]
    属性。在这种情况下,对象的副本被序列化并通过
    AppDomain
    边界传递。您调用的任何membe都将位于副本上,并且不会影响原始对象

  • 使类派生自。在这种情况下,对对象的引用将跨AppDomain边界封送,您调用的任何成员都将影响其原始AppDomain中的对象


从托管代码中使用[ComVisible].NET类或接口是一个非常糟糕的主意。IDE和类型库导入器会尽力阻止您这样做。但是它们可以被击败,当你使用后期绑定时没有保护。AppDomain的详细信息只是可能出错的一件事。这没有意义,只需添加对该程序集的引用即可。因此,首先感谢您的回答。事实上,这只是我问题的一个摘录(使问题更容易理解)。在“Real'”中,此代码是由C++ C++应用程序管理的C++调用。我尝试创建一个加载项加载程序,加载自定义域中的每个加载项(在加载项之间添加一些限制)。每个外接程序都可以随时添加或删除,因此我无法使用静态链接。@HansPassant在没有COM、完整C#解决方案、没有任何依赖性的情况下尝试过,但它仍然无法工作。。。你知道我错过了什么吗?为什么你要把每个加载项放在它自己的appdomain中?你到底想解决什么问题?@Ben我试图隔离插件有两个主要原因。第一个是允许每个加载项都有自己的配置文件(特别是自己的绑定重定向)。2.为了不允许加载项A破坏加载项B中的某些内容,并且每个加载项必须位于主应用程序的同一进程中(因此我无法在另一个进程中生成加载项),它是一个COM接口,因此我认为它已经可以序列化了。(COM内容无法序列化???)我无法从MarshalByRefObject派生,因为我已经从COM接口派生。@David,
…因为我已经从COM接口派生了
-为什么不?不能从>1个基类派生,但可以从任意多个接口派生。您的示例类
class
不是从任何东西派生出来的;您是否尝试将此派生自
MarshalByRefObject
?对不起,我弄错了,我完全理解您所说的。因此,我尝试了
[Serializable]
MarshallByRefObject
,但仍然存在相同的序列化异常…````[ComVisible(true)][Guid(“16c8ab2e-04b2-456-ade1-f4f69c213393”)[Serializable]公共类Class1:MarshalByRefObject,MyAPI.IAddIn{````@David,您的类应该继承自MarshalByRefObject,或者可以序列化(这意味着它将按值进行封送),但不是两者都有。在您的情况下,
MarshallByRefObject
是合适的。在这种情况下,确切的异常消息是什么?消息仍然是相同的
System.Runtime.Serialization.SerializationException:在程序集“ClassLibrary2,Version=1.0.0,Culture=neutral,PublicKeyToken=null”中键入“ClassLibrary2.Class1”alizable.a System.Runtime.Remoting.ObjectHandle.Unwrap()a ConsoleApp1.Program.Main(字符串[]args)dans C:\ConsoleApp1\ConsoleApp1\Program.cs:ligne 39