我一直在尝试获取以下代码工作(在同一组件中定义了所有内容):

namespace SomeApp{

public class A : MarshalByRefObject
{
   public byte[] GetSomeData() { // }
}

public class B : MarshalByRefObject
{
   private A remoteObj;

   public void SetA(A remoteObj)
   {
      this.remoteObj = remoteObj;
   }
}

public class C
{
   A someA = new A();
   public void Init()
   {
       AppDomain domain = AppDomain.CreateDomain("ChildDomain");
       string currentAssemblyPath = Assembly.GetExecutingAssembly().Location;
       B remoteB = domain.domain.CreateInstanceFromAndUnwrap(currentAssemblyPath,"SomeApp.B") as B;
       remoteB.SetA(someA); // this throws an ArgumentException "Object type cannot be converted to target type."
   }
}

}

我要做的是将在第一个AppDomain中创建的“ A”实例的引用传递给子域,并使子域在第一个域上执行方法。在某个时候,我将在“ B”代码上调用'remoteObj.getSomedata()'。必须这样做,因为必须在第一个AppDomain上“计算”“ getomedata”方法的“字节[]”。我该怎么做才能避免例外,或者我该怎么做才能达到相同的结果?

有帮助吗?

解决方案

我可以复制该问题,并且似乎与testdriven.net和/或xunit.net有关。如果我将C.Init()作为测试方法运行,则会收到相同的错误消息。但是,如果我从控制台应用程序中运行c.init(),则我没有例外。

您是否看到同一件事,从单位测试中运行c.init()?

编辑:我还可以使用nunit和testdriven.net复制问题。我还可以使用Nunit Runner而不是TestDriven.net来复制错误。因此,问题似乎与通过测试框架运行此代码有关,尽管我不确定为什么。

其他提示

实际原因是您的DLL从两个不同应用程序域中的不同位置加载。这会导致.NET认为它们是不同的组件,这当然意味着类型是不同的(即使它们具有相同的类名称,名称空间等)。

通过单元测试框架运行时,Jeff的测试失败的原因是因为单元测试框架通常会创建带有ShadowCopy设置为“ True”的AppDomains。但是您手动创建的AppDomain将默认为ShadowCopy =“ false”。这将导致DLL从不同位置加载,从而导致“无法转换为目标类型”。错误。

更新:经过进一步的测试后,这两个应用程序之间的应用程序键确实不同。如果它们匹配,则上述方案有效。如果它们与众不同,则不会(即使我已经确认DLL使用windbg从同一目录中加载到两个应用程序中),如果我在我的两个应用程序中打开shadowcopy =“ true”,那么它会失败带有不同的消息:“ system.invalidcastException:对象必须实现图标”。

更新2:进一步阅读使我相信它与 负载上下文. 。当您使用一种“来自”方法之一(assembly.loadfrom或appdomain.createinstancefromandunwrap)时,如果在一个正常的负载路径之一(ApplicationBase或pocting Paths之一)中找到了组件,则将其加载到默认值中负载上下文。如果在那里找不到装配体,则将其加载到负载 - 弗罗姆上下文中。因此,当两个应用程序都具有匹配的应用程序键时,即使我们使用“来自”方法,它们都被加载到各自的AppDomain的默认加载上下文中。但是,当应用程序键不同时,一个AppDomain将在其默认加载上下文中具有汇编,而另一个AppDomain则在其负载 - 即可上下文中具有汇编。

这是对@russellmcclure的评论,但由于要评论很复杂,因此我将其作为答案:

我在ASP.NET应用程序中,并关闭Shadow-Copy(也可以解决问题)并不是一个选择,但我找到了以下解决方案:

AppDomainSetup adSetup = new AppDomainSetup();
if (AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles == "true")
{
    var shadowCopyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (shadowCopyDir.Contains("assembly"))
        shadowCopyDir = shadowCopyDir.Substring(0, shadowCopyDir.LastIndexOf("assembly"));

    var privatePaths = new List<string>();
    foreach (var dll in Directory.GetFiles(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, "*.dll"))
    {
        var shadowPath = Directory.GetFiles(shadowCopyDir, Path.GetFileName(dll), SearchOption.AllDirectories).FirstOrDefault();
        if (!String.IsNullOrWhiteSpace(shadowPath))
            privatePaths.Add(Path.GetDirectoryName(shadowPath));
    }

    adSetup.ApplicationBase = shadowCopyDir;
    adSetup.PrivateBinPath = String.Join(";", privatePaths);
}
else
{
    adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    adSetup.PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
}

这将使用主应用程序域的阴影副本目录作为应用程序库,如果启用了影子拷贝,将所有阴影式的组件添加到私人路径中。

如果有人有更好的方法,请告诉我。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top