- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我已经阅读了与 Stack Overflow 上一样多的这个问题的不同版本,以及 3 个不同的 Google 搜索教程首页上的每个蓝色链接,以及 MSDN(有点浅执行程序集)。我只能想到我为让 Tao 成为一个好的测试用例所做的努力,但相信我,我已经尝试过一个简单的字符串返回、一个 double 、一个带参数的函数。无论我的问题是什么,都不是道。
基本上,我想在 GLPlugin 命名空间中创建我的 Draw 类的 testLibraryDomain.CreateInstance()
。
if( usePlugin )
{
AppDomain testLibraryDomain = AppDomain.CreateDomain( "TestGLDomain2" );
//What the heck goes here so that I can simply call
//the default constructor and maybe a function or two?
AppDomain.Unload( testLibraryDomain );
}
Gl.glBegin( Gl.GL_TRIANGLES );
我知道一个事实:
namespace GLPlugin
{
public class DrawingControl : MarshalByRefObject
{
public DrawingControl()
{
Gl.glColor3f( 1.0f , 0.0f , 0.0f );
//this is a test to make sure it passes
//to the GL Rendering context... success
}
}
}
确实改变了笔的颜色。当我给它一个 static void Main( string args[] )
入口点并且我调用 testLibraryDomain.ExecuteAssembly( thePluginFilePath )
时它起作用我很担心,因为我不确定 GL 调用是否会进入“顶级”AppDomain 的 OpenGL 上下文。它甚至让我可以覆盖程序集并再次更改笔颜色。不幸的是,给它一个可执行的入口点意味着弹出式控制台会打断我然后消失。当我在项目中简单地给它一个引用并创建一个常规的 GLPlugin.DrawingTool tool = new GLPlugin.DrawingControl()
,甚至创建一个 someAssembly = Assembly.LoadFrom( thePluginFilePath )
(当然不幸的是,这会锁定程序集,防止替换/重新编译)。
当使用我尝试过的各种方法中的任何一种时,我总是得到“给定的程序集名称或其代码库无效”。我保证,它是有效的。我尝试加载它的方式不是。
我知道我缺少的一件事是 testLibraryDomain.CreateInstance( string assemblyName , string typeName);
据我所知,assemblyName 参数不是程序集文件的文件路径。它是命名空间,还是只是程序集名称,即:GLPlugin
?如果是这样,我在哪里引用实际文件?没有 someAppDomain.LoadFrom( someFilename ),但如果有的话会很方便。此外,Type 和 string typeName 到底是什么?我不想在这里输入 "Object"
,因为除了对象的实例之外没有创建类型吗?我也尝试过 CreateInstanceAndUnwrap( ... , ... )
,但同样缺乏对 AppDomain 的基本了解。通常我可以通过教程蒙混过关并让事情正常进行,即使我经常不明白“为什么?”......这里不是这样。通常,查找六个不同的教程对我很有帮助……这里不再如此,但因为每个教程都采用了一种基本的(或看起来如此)方法。
所以请 ELI5... 我想从一个单独的 AppDomain 中的 dll 加载一个类的实例,也许运行一些函数,然后卸载它。最终将这些函数的列表创建为 List,根据需要删除/更新......我也希望能够将参数传递给它们,但这将是第 2 步。根据 StackOverflow,我必须了解 serializable
我将推迟到另一天。 (我想您将能够从我的示例中看出我正在尝试做什么。)
最佳答案
好的,我们必须澄清几件事。首先,如果您希望能够在不锁定文件 iteslf 的情况下将 dll 加载和卸载到不同的 AppDomain,也许您可以使用这样的方法:
AppDomain apd = AppDomain.CreateDomain("newdomain");
using(var fs = new FileStream("myDll.dll", FileMode.Open))
{
var bytes = new byte[fs.Length];
fs.Read(bytes, 0, bytes .Length);
Assembly loadedAssembly = apd.Load(bytes);
}
这样,您就不会锁定文件,您应该能够稍后卸载域,重新编译文件并稍后加载更新版本。但我不能 100% 确定这是否会破坏您的应用程序。
那是因为第二件事。如果您将使用 CreateInstanceAndUnwrap
方法,根据 MSDN,您必须在两个应用程序域中加载程序集 - 调用的应用程序域和调用的应用程序域。当您在 AppDomains 中加载了两个不同的 dll 时,这可能会结束。
我现在不记得了,但我认为当您调用 CreateInstanceAndUnwrap
时,两个应用程序域中的对象创建行为会有所不同,但我不记得细节了。
对于您的插件架构,您可能需要阅读这篇博文。 About how to handle Dynamic Plugins using the AppDomain Class to Load and Unload Code
编辑
我忘记了这个 AppDomains 是如何工作的,我可能会引起一些困惑。我准备了一个简短的例子,说明“插件”架构是如何工作的。它与我之前在博客中描述的内容非常相似,这是我使用卷影复制的示例。如果出于某些原因您不想使用它,可以很容易地将其更改为使用 AppDomain.Load(byte[] bytes)
我们有 3 个程序集,第一个是基础插件程序集,它将作为代理工作,并将加载到所有 AppDomains(在我们的例子中 - 在主应用程序域和插件应用程序域中)。
namespace PluginBaseLib
{
//Base class for plugins. It has to be delivered from MarshalByRefObject,
//cause we will want to get it's proxy in our main domain.
public abstract class MyPluginBase : MarshalByRefObject
{
protected MyPluginBase ()
{ }
public abstract void DrawingControl();
}
//Helper class which instance will exist in destination AppDomain, and which
//TransparentProxy object will be used in home AppDomain
public class MyPluginFactory : MarshalByRefObject
{
//This method will be executed in destination AppDomain and proxy object
//will be returned to home AppDomain.
public MyPluginBase CreatePlugin(string assembly, string typeName)
{
Console.WriteLine("Current domain: {0}", AppDomain.CurrentDomain.FriendlyName);
return (MyPluginBase) Activator.CreateInstance(assembly, typeName).Unwrap();
}
}
//Small helper class which will show how to call method in another AppDomain.
//But it can be easly deleted.
public class MyPluginsHelper
{
public static void LoadMyPlugins()
{
Console.WriteLine("----------------------");
Console.WriteLine("Loading plugins in following app domain: {0}", AppDomain.CurrentDomain.FriendlyName);
AppDomain.CurrentDomain.Load("SamplePlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
Console.WriteLine("----------------------");
}
}
}
这里我们将有另一个带有虚拟插件的程序集,名为 SamplePlugin.dll 并存储在“Plugins”文件夹下。它引用了 PluginBaseLib.dll
namespace SamplePlugin
{
public class MySamplePlugin : MyPluginBase
{
public MySamplePlugin()
{ }
public override void DrawingControl()
{
var color = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("----------------------");
Console.WriteLine("This was called from app domian {0}", AppDomain.CurrentDomain.FriendlyName );
Console.WriteLine("I have following assamblies loaded:");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Console.WriteLine("\t{0}", assembly.GetName().Name);
}
Console.WriteLine("----------------------");
Console.ForegroundColor = color;
}
}
}
最后一个程序集(简单的控制台应用程序)将仅引用 PluginBaseLib.dll 和
namespace ConsoleApplication1
{
//'Default implementation' which doesn't use any plugins. In this sample
//it just lists the assemblies loaded in AppDomain and AppDomain name itself.
public static void DrawControlsDefault()
{
Console.WriteLine("----------------------");
Console.WriteLine("No custom plugin, default app domain {0}", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine("I have following assamblies loaded:");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Console.WriteLine("\t{0}", assembly.GetName().Name);
}
Console.WriteLine("----------------------");
}
class Program
{
static void Main(string[] args)
{
//Showing that we don't have any additional plugins loaded in app domain.
DrawControlsDefault();
var appDir = AppDomain.CurrentDomain.BaseDirectory;
//We have to create AppDomain setup for shadow copying
var appDomainSetup = new AppDomainSetup
{
ApplicationName = "", //with MSDN: If the ApplicationName property is not set, the CachePath property is ignored and the download cache is used. No exception is thrown.
ShadowCopyFiles = "true",//Enabling ShadowCopy - yes, it's string value
ApplicationBase = Path.Combine(appDir,"Plugins"),//Base path for new app domain - our plugins folder
CachePath = "VSSCache"//Path, where we want to have our copied dlls store.
};
var apd = AppDomain.CreateDomain("My new app domain", null, appDomainSetup);
//Loading dlls in new appdomain - when using shadow copying it can be skipped,
//in CreatePlugin method all required assemblies will be loaded internaly,
//Im using this just to show how method can be called in another app domain.
//but it has it limits - method cannot return any values and take any parameters.
//apd.DoCallBack(new CrossAppDomainDelegate(MyPluginsHelper.LoadMyPlugins));
//We are creating our plugin proxy/factory which will exist in another app domain
//and will create for us objects and return their remote 'copies'.
var proxy = (MyPluginFactory) apd.CreateInstance("PluginBaseLib", "PluginBaseLib.MyPluginFactory").Unwrap();
//if we would use here method (MyPluginBase) apd.CreateInstance("SamplePlugin", "SamplePlugin.MySamplePlugin").Unwrap();
//we would have to load "SamplePlugin.dll" into our app domain. We may not want that, to not waste memory for example
//with loading endless number of types.
var instance = proxy.CreatePlugin("SamplePlugin", "SamplePlugin.MySamplePlugin");
instance.DrawingControl();
Console.WriteLine("Now we can recompile our SamplePlugin dll, replace it in Plugin directory and load in another AppDomain. Click Enter when you ready");
Console.ReadKey();
var apd2 = AppDomain.CreateDomain("My second domain", null, appDomainSetup);
var proxy2 = (MyPluginFactory)apd2.CreateInstance("PluginBaseLib", "PluginBaseLib.MyPluginFactory").Unwrap();
var instance2 = proxy2.CreatePlugin("SamplePlugin", "SamplePlugin.MySamplePlugin");
instance2.DrawingControl();
//Now we want to prove, that this additional assembly was not loaded to prmiary app domain.
DrawControlsDefault();
//And that we still have the old assembly loaded in previous AppDomain.
instance.DrawingControl();
//App domain is unloaded so, we will get exception if we try to call any of this object method.
AppDomain.Unload(apd);
try
{
instance.DrawingControl();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
}
影子复制似乎很方便。
关于C# 动态加载/卸载 DLL Redux(当然使用 AppDomain),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13462525/
我为 ReSharper 编写了 xunit.net 测试运行程序,但在 8.0 版本中遇到了一个问题 - 我看到程序集无法加载到影子复制的 AppDomain 中。相同的代码和测试项目在 7.1 版
我无法弄清楚有关我的 AppDomain.Unload(...) 调用的问题。我有来自 my earlier question 的代码的详细解释.事实证明,我执行了几个显然不需要的步骤。但是,我相当确
我想在应用程序域内运行第三方库(在本例中为 XSP),这样我就可以关闭它或以其他方式控制它的行为。 基本流程: var child = AppDomain.CreateDomain(...) ...
我正在尝试将一个 dll 加载到控制台应用程序中,然后将其卸载并完全删除该文件。我遇到的问题是,在其自己的 AppDomain 中加载 dll 的行为会在父 AppDomain 中创建一个引用,因此除
我的印象是 AppDomains 彼此隔离。似乎在 StackOverException 的情况下,情况并非如此。 为了演示这个问题,我创建了一个简单的控制台应用程序,其唯一目的是生成一个新的 App
我有一个带有服务器“AppDomain”的应用程序,它接受来自单独的 AppDomain 的调用(其中托管插件,由其他人开发且不值得信赖)。 从服务器 AppDomain 中,我需要知道哪个“插件”(
坐: 我正在从我的进程中创建子应用程序域以加载程序集。 我可以调用此 AppDomain。 我想将一个对象从我的默认进程 AppDomain 传递到这个新创建的 AppDomain,以接收从加载到新
可能是以下副本:Can I prevent an uncaught exception in another AppDomain from shutting down the application?
我已经在 Specflow 2.0、nUnit 3.X、TeamCity 和 Visual Studio 2013 中编写了自动化测试。我试图并行运行这些测试,但它们失败了,因为代码使用静态类/对象。
我有一个 Bootstrapper,它查看 ASP.NET MVC 应用程序中的所有程序集以查找实现 IBootstrapperTask 接口(interface)的类型,然后将它们注册到 IOC C
我有一个 .NET 应用程序,它创建多个单独的 AppDomain 来运行一些可插入代码,每个 AppDomain 都设置自己的 WCF 命名管道服务来与中央应用程序进行通信。 但是我想为每个应用程序
对于我的项目,我需要从其他 .Net 程序集访问资源,但我不想让它们加载,因为我可能会加载同一程序集的不同版本。 为此,我创建了另一个 AppDomain,我使用 CreateInstanceAndU
我正在使用 AppDomain 来加载程序集然后卸载它们。 但是,我遇到了一个非常奇怪的问题。卸载 AppDomain 后 - 我仍然可以在进程资源管理器中看到某些程序集被多次加载! 为什么有加载的程
假设我有 AppDomainA,它启动 AppDomainB。 AppDomainB 然后启动 AppDomainC。 如果在 AppDomainA 中卸载 AppDomainB,AppDomainC
是否可以通过它的“友好名称”或 ID 来引用现有的 AppDomain(不是由我的代码创建)?还是以其他方式? 最佳答案 List AppDomains in Process 关于.net - 如何通
我在同一个虚拟目录下有一个网站和一个 web 服务,一些网页调用了 web 服务。 调用 Web 服务时,IIS 是创建新的 AppDomain 还是在同一个 AppDomain 中运行 Web 服务
在 ASP.NET 3.5(带有 IIS6)中,是否为每个请求创建了 AppDomains?我知道所有应用程序在 w3wp.exe 下都有自己的 AppDomain,但是整个 AppDomain 究竟
我一直无法找到关于使用 AppDomains 时发生的事情的非常清楚的描述,所以希望有人能够启发我。我有一个简单的测试程序(基本上是扯掉了 MSDN example ): using System;
我仍在尝试了解持续存在的问题,但它几乎可以概括为无法卸载 AppDomain。 它发生在将 ASP.NET WebAPI 部署到 Azure 应用服务期间,我们观察到以下情况: 进程 ID 不会更改,
我已经编写了在所有专用服务器上运行的软件(C#.NET控制台应用程序),这些服务器将管理各个Java进程(启动/停止/重新启动它们)。我遇到的问题是,当我的应用程序崩溃时,它不会关闭它启动的Java子
我是一名优秀的程序员,十分优秀!