在另一个域中创建instanceandunwrap



目前由于某种原因(之前正在工作),我遇到了CreateInstanceAndUnwrap问题。

我的过程是这样的:

我动态生成一些代码,它通过MEF从子目录加载DLL。然后这些应用程序(根据需要)从那些DLL加载不同的片段。我必须更新我的代码,现在包含一个AppDomainSetup,其中包含调用程序集的路径。

我正确地创建了新的AppDomain——没有问题。当我尝试运行这段代码时:

object runtime = domain.CreateInstanceAndUnwrap(
                typeof(CrossDomainApplication).Assembly.FullName,
                typeof(CrossDomainApplication).FullName);

我有大量的问题-运行时(以上变量)不再可以强制转换到CrossDomainApplication或microssdomainapplication。

实际对象看起来像:

public class CrossDomainApplication : MarshalByRefObject, ICrossDomainApplication

界面如下:

public interface ICrossDomainApplication
{
    void Run(CrossDomainApplicationParameters parameters);
}

参数如下:

[Serializable]
public class CrossDomainApplicationParameters : MarshalByRefObject
{
    public object FactoryType { get; set; }
    public Type ApplicationType { get; set; }
    public string ModuleName { get; set; }
    public object[] Parameters { get; set; }
}

运行时的本机类型似乎是MarshalByRefObject——它不喜欢转换为其他任何类型。

有什么问题吗?

编辑:以下是我运行它时得到的错误:

            ICrossDomainApplication runtime = (ICrossDomainApplication)domain.CreateInstanceAndUnwrap(
                     typeof(CrossDomainApplication).Assembly.FullName,
                     typeof(CrossDomainApplication).FullName);
            //Exception before reaching here
            runtime.Run(parameters);

系统。InvalidCastException:无法将透明代理类型转换为' infrastructure . microssdomainapplication '.

这是我创建的域的样子:

        AppDomain domain = AppDomain.CreateDomain(
                   Guid.NewGuid().ToString(),
                   null,
                   new AppDomainSetup()
                   {
                       ApplicationBase = GetPath(),
                       ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
                       ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
                       LoaderOptimization = LoaderOptimization.MultiDomainHost
                   });               

和GetPath()看起来像这样:

    private string GetPath()
    {
        Uri path = new Uri(Assembly.GetCallingAssembly().CodeBase);
        if (path.IsFile)
        {
            path = new Uri(path, Path.GetDirectoryName(path.AbsolutePath));
        }
        return path.LocalPath.Replace("%20", " ");
    }

出于帮助其他穷人的愿望,我在尝试了许多其他组合之后,终于找到了方法。

我必须改变一些事情…第一个:

            AppDomain domain = AppDomain.CreateDomain(
                    Guid.NewGuid().ToString(),
                    AppDomain.CurrentDomain.Evidence,
                    new AppDomainSetup()
                    {
                        ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
                        ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
                        LoaderOptimization = LoaderOptimization.MultiDomainHost,
                        PrivateBinPath = GetPrivateBin(AppDomain.CurrentDomain.SetupInformation.ApplicationBase)
                    });

PrivateBinPath是这里的真正的技巧,它使其他所有东西(最终)开始工作。PrivateBinPath(阅读文档)绝对需要是一个相对路径。如果你有一个名为"assemblies"的子文件夹,那么PrivateBinPath应该是"assemblies"。如果在它前面加上或绝对路径,它将无法工作。

通过这样做,它导致AssemblyResolve事件finally触发。我是这样做的(在创建新的子AppDomain之前):

            AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

和ResolveAssembly方法看起来像这样:

    private Assembly ResolveAssembly(object sender, ResolveEventArgs args)
    {
        var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assembly in loadedAssemblies)
        {
            if (assembly.FullName == args.Name)
            {
                return assembly;
            }
        }
        return null;
    }

这个方法可以用Linq更容易地编写,但我保持这种方式是为了让自己更清楚地了解为了调试目的而解析和加载的内容。

并且,总是,确保你断开你的事件(如果你正在加载一个AppDomain):

            AppDomain.CurrentDomain.AssemblyResolve -= ResolveAssembly;

那解决了一切。感谢所有帮助过我的人!

这不是答案,只是分享的示例代码

嗯,会是别的什么吗?这个样品,与你描述的不是1:1,可以工作。

#region
using System;
using System.Reflection;
using System.Threading;
#endregion
internal class Program
{
    #region Methods
    private static void Main(string[] args)
    {
        // Get and display the friendly name of the default AppDomain. 
        string callingDomainName = Thread.GetDomain().FriendlyName;
        Console.WriteLine(callingDomainName);
        // Get and display the full name of the EXE assembly. 
        string exeAssembly = Assembly.GetEntryAssembly().FullName;
        Console.WriteLine(exeAssembly);
        // Construct and initialize settings for a second AppDomain.
        var ads = new AppDomainSetup
                  {
                      ApplicationBase = Environment.CurrentDirectory,
                      DisallowBindingRedirects = false,
                      DisallowCodeDownload = true,
                      ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
                  };
        // Create the second AppDomain.
        AppDomain ad2 = AppDomain.CreateDomain("AD #2", null, ads);
        // Create an instance of MarshalbyRefType in the second AppDomain.  
        // A proxy to the object is returned.
        var mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, typeof(MarshalByRefType).FullName);
        // Call a method on the object via the proxy, passing the  
        // default AppDomain's friendly name in as a parameter.
        mbrt.SomeMethod(new MarshalByRefParameter{ModuleName =  callingDomainName});
        // Unload the second AppDomain. This deletes its object and  
        // invalidates the proxy object.
        AppDomain.Unload(ad2);
        try
        {
            // Call the method again. Note that this time it fails  
            // because the second AppDomain was unloaded.
            mbrt.SomeMethod(new MarshalByRefParameter { ModuleName = callingDomainName });
            Console.WriteLine("Successful call.");
        }
        catch (AppDomainUnloadedException)
        {
            Console.WriteLine("Failed call; this is expected.");
        }
    }

    #endregion
}
public interface IMarshalByRefTypeInterface
{
    void SomeMethod(MarshalByRefParameter parameter);
}
public class MarshalByRefType : MarshalByRefObject, IMarshalByRefTypeInterface
{
    //  Call this method via a proxy. 
    #region Public Methods and Operators
    public void SomeMethod(MarshalByRefParameter parameter)
    {
        // Get this AppDomain's settings and display some of them.
        AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation;
        Console.WriteLine("AppName={0}, AppBase={1}, ConfigFile={2}", ads.ApplicationName, ads.ApplicationBase, ads.ConfigurationFile);
        // Display the name of the calling AppDomain and the name  
        // of the second domain. 
        // NOTE: The application's thread has transitioned between  
        // AppDomains.
        Console.WriteLine("Calling from '{0}' to '{1}'.", parameter.ModuleName, Thread.GetDomain().FriendlyName);
    }
    #endregion
}
[Serializable]
public class MarshalByRefParameter : MarshalByRefObject
{
    public string ModuleName { get; set; }
}

但是,我只是抓取入口程序集,而你有一个得到动态编译。你会得到什么错误?

相关内容

  • 没有找到相关文章