基本上,根据我对小网的了解,我设法在互联网上搜索,线程可以在AppDomains之间传递.现在,我编写了以下代码:
const string ChildAppDomain = "BlahBlah";
static void Main()
{
if (AppDomain.CurrentDomain.FriendlyName != ChildAppDomain)
{
bool done = false;
while (!done)
{
AppDomain mainApp = AppDomain.CreateDomain(ChildAppDomain, null, AppDomain.CurrentDomain.SetupInformation);
try
{
mainApp.ExecuteAssembly(Path.GetFileName(Application.ExecutablePath));
}
catch (Exception ex)
{
// [snip]
}
AppDomain.Unload(mainApp);
}
}
else
{
// [snip] Rest of the program goes here
}
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,一切都在点击...主线程进入我的程序的新版本,并开始在主应用程序正文中运行.我的问题是,如何才能让它回到父母身边AppDomain?这可能吗?我想要实现的是在两个域之间共享一个类的实例.
我想更好地了解appDomains.据我所知,Windows在一个进程中运行所有应用程序.每个应用程序都封装在它自己的对象中,该对象位于此进程中.此对象还包含一些无法共享的全局变量.进程中的所有对象都不能彼此共享任何数据.我理解的appDomain是一个位于windows进程中的特殊对象.它所做的只是保留对分配给它的所有程序集的引用.如果有人可以详细说明或纠正我,如果我错了.任何好的资源也都可以.
我正在尝试创建一个沙盒AppDomain来加载扩展/插件.我有一个MarshalByRefObject,它在appdomain中实例化以加载dll.我在尝试加载dll时遇到SecurityExceptions,我无法弄清楚如何绕过它们,同时仍然限制第三方代码可以做什么.我的所有项目都是.net 4.
InDomainLoader类位于完全受信任的域中,该方法标记为SecuritySafeCritical.从我读过的所有内容来看,我认为这应该有效.
这是我的Loader类,它创建AppDomain并跳转到它:
public class Loader
{
public void Load(string dll, string typeName)
{
Log.PrintSecurity();
// Create new AppDomain
var setup = AppDomain.CurrentDomain.SetupInformation;
var permissions = new PermissionSet(null);
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
var strongname = typeof(InDomainLoader).Assembly.Evidence.GetHostEvidence<StrongName>();
var strongname2 = typeof(IPlugin).Assembly.Evidence.GetHostEvidence<StrongName>();
AppDomain domain = AppDomain.CreateDomain("plugin", null, setup, permissions, strongname, strongname2);
// Create instance
var loader = (InDomainLoader)domain.CreateInstanceAndUnwrap(
typeof (InDomainLoader).Assembly.FullName, typeof (InDomainLoader).FullName);
// Jump into domain
loader.Load(dll, typeName);
}
}
Run Code Online (Sandbox Code Playgroud)
这是在域中运行的引导加载程序:
public class InDomainLoader : MarshalByRefObject
{
[SecuritySafeCritical]
public void Load(string dll, string …Run Code Online (Sandbox Code Playgroud) 我们正在构建一个应用程序(WinForms,.NET 3.5),它将"插件"DLL加载到辅助AppDomain中.辅助AppDomain需要偶尔与第一个AppDomain通信(更具体地说,从主AppDomain中创建的对象调用或获取数据).
我已经阅读了有关AppDomains的大部分内容以及它们之间的通信.
到目前为止,我见过的唯一简单的解决方案是继承MarshalByRefObject并将TransparentProxy传递到第二个AppDomain,在Proxy上调用方法.
此方法有其缺点(例如,在框架类型的情况下,或者从已经从其他类继承的类型,静态字段/类等等,并不总是可以从MBRO继承).
由于当前的通信点非常不变(只有2-3个需要通信的场景),我考虑创建一个具有以下属性的简单Mediator类:
将调用此代理对象上的方法,然后调用第一个AppDomain中"真实"对象上的方法.
我的问题 -
A)动态编译C#EXE和DLL是相对容易的.
B)执行EXE意味着运行新的应用程序.加载DLL意味着可以在可以在应用程序或项目之间共享的情况下使用方法和函数.
现在,可以从MSDN或为方便起见,找到编译EXE(或轻微修改,DLL)的最快最简单的方法:
private bool CompileCSharpCode(string script)
{
lvErrors.Items.Clear();
try
{
CSharpCodeProvider provider = new CSharpCodeProvider();
// Build the parameters for source compilation.
CompilerParameters cp = new CompilerParameters
{
GenerateInMemory = false,
GenerateExecutable = false, // True = EXE, False = DLL
IncludeDebugInformation = true,
OutputAssembly = "eventHandler.dll", // Compilation name
};
// Add in our included libs.
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
// Invoke compilation. This works from a string, but you can also load from a file using …Run Code Online (Sandbox Code Playgroud) 我得到了奇怪的错误,不知道为什么.
Type names passed to Assembly.GetType() must not specify an assembly.
Run Code Online (Sandbox Code Playgroud)
奇怪的是我自己不使用方法GetType().它是由以下行引起的:
var domainCommunicator = (DomainCommunicator)dmn.CreateInstanceAndUnwrap(typeof(DomainCommunicator).FullName, "DomainCommunicator");
Run Code Online (Sandbox Code Playgroud)
domainCommunicator继承自MarshalByRefObject.它是公开的,但是当我将其更改为私有时,我得到了无法加载程序集的例外情况.当我在我的解决方案中创建其他项目并完全外部.dll没有任何变化.可能是因为我必须在我的新AppDomain中引用主项目.
对我来说最好的事情是在反射中跳过DomainCommunicator类.它应该是私人的,就是这样.究竟是什么导致了例外?
我在C#AppDomain遇到了一个大问题.
我需要在.dll文件中加载一个静态类并执行它的方法:
当我尝试加载它们时
Assembly.LoadFrom("XXXXX") // (XXXXX is the full path of dll)
Run Code Online (Sandbox Code Playgroud)
.dll不会自动或以编程方式卸载.
当我尝试在AppDomain中加载它们时
adapterDomain = AppDomain.CreateDomain("AdapterDomain");
(a)adapterDomain.CreateInstanceFrom(this.AdapterFilePath, this.AdapterFullName);
(b)adapterAssembly=adapterDomain.Load(AssemblyName.GetAssemblyName(this.AdapterFilePath));
Run Code Online (Sandbox Code Playgroud)
如果我使用方法(a),因为目标类是静态类,它不起作用.
如果我使用方法(b),因为目标.dll与我的项目不是同一个目录,我将得到一个例外.
如何加载.dll和静态类,然后在使用后卸载.dll?
这不是一个重要的问题,但我想知道为什么Thread类公开一个属性来获取当前的Context(Thread.CurrentContext)和一个获取当前AppDomain(Thread.GetDomain())的方法.
知道Process> AppDomain> Context> Thread的层次结构,我的假设是在当前时间点知道线程的上下文,并且需要根据当前上下文搜索域.
但我想听听更明智的答案.谢谢!
在我们的应用程序(具有65个项目的解决方案)中,将在运行时分析所有引用的程序集是否存在Ninject模块(也应用了一些过滤)。这些模块稍后会加载到Ninject内核中,并且每个模块都声明该内核的绑定。
我们采用了一种加载程序,该加载程序以“仅反射”模式将引用的程序集加载到单独的程序集中。与Ninject可以从目录中加载程序集的方式的不同之处在于,该目录可以包含带有不应加载的模块的程序集。而且从一开始,并不是所有引用的程序集都已加载。
问题在于,加载程序(贷给Sacha Barber)无法加载带有
System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information
Run Code Online (Sandbox Code Playgroud)
并LoaderExceptions带有一个条目:
Method 'BeforeLoad' in type 'Lekis.AppBase.Core.BLLBaseCore' from assembly 'AppBaseCore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
Run Code Online (Sandbox Code Playgroud)
以下是一些“有趣”的事实:
BeforeLoad是虚拟的,并且是接口方法的实现AppBaseCore是.NET 3.5,并且3个程序集无法加载AppBaseCore是.NET 4和5程序集加载失败当我使用ILSpy和ILDAsm检查程序集时,它们没有任何错误(很明显)。
在这一点上,我真的迷路了,不知道如何解决这个问题。
任何帮助表示赞赏。
谢谢
请耐心等待,我花了30多个小时试图完成这项工作 - 但没有成功.
在我的程序开始时,我在bytearray中加载一个Assembly(dll)并在之后删除它.
_myBytes = File.ReadAllBytes(@"D:\Projects\AppDomainTest\plugin.dll");
Run Code Online (Sandbox Code Playgroud)
稍后在程序中我创建一个新的Appdomain,加载字节数组并枚举类型.
var domain = AppDomain.CreateDomain("plugintest", null, null, null, false);
domain.Load(_myBytes);
foreach (var ass in domain.GetAssemblies())
{
Console.WriteLine($"ass.FullName: {ass.FullName}");
Console.WriteLine(string.Join(Environment.NewLine, ass.GetTypes().ToList()));
}
Run Code Online (Sandbox Code Playgroud)
类型得到正确列出:
ass.FullName:plugin,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null
...
Plugins.Test
...
现在我想在新的AppDomain中创建该类型的实例
domain.CreateInstance("plugin", "Plugins.Test");
Run Code Online (Sandbox Code Playgroud)
这个电话会产生,System.IO.FileNotFoundException我不知道为什么.
当我查看ProcessExplorer时,.NET Assemblies -> Appdomain: plugintest我看到程序集在新的appdomain中正确加载.
我怀疑发生异常,因为在磁盘上再次搜索程序集.但为什么该程序想再次加载它?
如何使用从字节数组加载的程序集在新的appdomain中创建实例?
appdomain ×10
c# ×9
.net ×4
assemblies ×1
c#-4.0 ×1
clr ×1
compilation ×1
marshalling ×1
reflection ×1
runtime ×1
static-class ×1
wcf ×1
windows ×1