Loc*_*cke 8 c# reflection appdomain
由于某种原因,我现在遇到了CreateInstanceAndUnwrap的问题(之前正在工作).
我的过程是这样的:
我动态生成一些代码,它通过MEF从子目录加载DLL.然后,这些应用程序从这些DLL加载不同的部分(按需).我不得不更新我的代码,现在包含一个包含调用程序集路径的AppDomainSetup.
我正确地创建了新的AppDomain - 没有问题.当我尝试运行此代码时:
object runtime = domain.CreateInstanceAndUnwrap(
typeof(CrossDomainApplication).Assembly.FullName,
typeof(CrossDomainApplication).FullName);
Run Code Online (Sandbox Code Playgroud)
我遇到了大量问题 - 运行时(上面的变量)不再可以转换为CrossDomainApplication或ICrossDomainApplication.
实际对象如下:
public class CrossDomainApplication : MarshalByRefObject, ICrossDomainApplication
Run Code Online (Sandbox Code Playgroud)
接口看起来像:
public interface ICrossDomainApplication
{
void Run(CrossDomainApplicationParameters parameters);
}
Run Code Online (Sandbox Code Playgroud)
参数看起来像:
[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; }
}
Run Code Online (Sandbox Code Playgroud)
本机类型的运行时似乎是MarshalByRefObject - 它不喜欢转换为其他任何东西.
什么可能出错?
编辑:这是我运行时出现的错误,如下所示:
ICrossDomainApplication runtime = (ICrossDomainApplication)domain.CreateInstanceAndUnwrap(
typeof(CrossDomainApplication).Assembly.FullName,
typeof(CrossDomainApplication).FullName);
//Exception before reaching here
runtime.Run(parameters);
Run Code Online (Sandbox Code Playgroud)
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
});
Run Code Online (Sandbox Code Playgroud)
和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", " ");
}
Run Code Online (Sandbox Code Playgroud)
Loc*_*cke 16
为了帮助其他穷人,穷人出去,我终于在尝试了很多其他组合之后想出来了.
我不得不改变一些事情......第一个:
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)
});
Run Code Online (Sandbox Code Playgroud)
PrivateBinPath是真正的技巧,它使其他所有东西(最终)开始工作.PrivateBinPath(阅读文档)ABSOLUTELY需要是一个相对路径.如果你有一个名为"assemblies"的子文件夹,那么PrivateBinPath应该是"程序集".如果在它前面加上\或绝对路径,它将无效.
通过这样做,它导致AssemblyResolve事件最终触发.我使用以下内容(在创建新的子AppDomain之前):
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
Run Code Online (Sandbox Code Playgroud)
并且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;
}
Run Code Online (Sandbox Code Playgroud)
使用Linq可以更轻松地编写该方法,但我保持这种方式,尝试使自己有点明显的是为了调试目的而解析和加载的内容.
并且,始终确保断开事件(如果您一次加载AppDomain):
AppDomain.CurrentDomain.AssemblyResolve -= ResolveAssembly;
Run Code Online (Sandbox Code Playgroud)
这解决了一切.感谢所有帮助过的人!
| 归档时间: |
|
| 查看次数: |
6459 次 |
| 最近记录: |