由于某种原因(之前正在工作),我现在遇到了CreateInstanceAndUnwrap的问题。
我的过程就是这样:
我动态生成一些代码,它通过MEF从子目录加载DLL。然后,这些应用程序从这些DLL加载不同的部分(按需)。我不得不更新我的代码,现在包含一个包含调用程序集路径的AppDomainSetup。
我正确创建了新的AppDomain - 没有问题。当我尝试运行此代码时:
object runtime = domain.CreateInstanceAndUnwrap(
typeof(CrossDomainApplication).Assembly.FullName,
typeof(CrossDomainApplication).FullName);
我遇到了大量问题 - 运行时(上面的变量)不再可以转换为CrossDomainApplication或ICrossDomainApplication。
实际对象如下:
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);
System.InvalidCastException:无法将透明代理强制转换为' Infrastructure.ICrossDomainApplication'。
以下是我创建域时的内容:
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", " ");
}
答案 0 :(得分:15)
为了帮助其他穷人,穷人出去,我终于在尝试了很多其他组合后想出来了。
我不得不改变一些事情......第一个:
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(阅读文档)ABSOLUTELY需要是一个相对路径。如果你有一个名为“assemblies”的子文件夹,那么PrivateBinPath应该是“程序集”。如果在它前面加上\或绝对路径,它就不起作用。
通过这样做,它导致AssemblyResolve事件最终触发。我使用以下内容(在创建新的子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 :(得分:0)
这不是一个答案,只是示例代码共享
嗯,这可能是别的吗?这个样本,与你描述的不完全相同,是有效的。#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; }
}
然而,我只是抓住入口集合,而你有一个动态编译。什么错误,你到底得到了什么?