从辅助域调用主应用程序域中的方法并获取值

发布于 2024-11-24 05:55:56 字数 2779 浏览 2 评论 0原文

我正在为我的 C# IRC 机器人实现一个模块系统。这些模块是 .dll 程序集,存储在子目录“modules”中,它们用于向机器人添加功能,例如在 IRC 上添加额外的命令。这些模块设计为在运行时加载和卸载,因此我可以更新机器人或修复错误,而无需重新启动整个应用程序。

目前,模块系统为每个要加载的模块创建一个新的AppDomain,并在名为ModuleHelper 的类中使用CreateInstanceFromAndUnwrap 创建代理。

AppDomain domain = AppDomain.CreateDomain(name, null, new AppDomainSetup 
{ 
    ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
    ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
    DisallowApplicationBaseProbing = true,
    PrivateBinPathProbe = ModuleDirectory,
    PrivateBinPath = ModuleDirectory,
    ShadowCopyDirectories = ModuleDirectory,
    CachePath = Path.Combine(ModuleDirectory, "cache"),
    ShadowCopyFiles = bool.TrueString 
});
ModuleProxy proxy = null;
try
{
    proxy = (ModuleProxy)domain.CreateInstanceFromAndUnwrap(location, AssemblyName.GetAssemblyName(location).Name + ".Module");
    proxy.OnLoad();
}
catch
{
    AppDomain.Unload(domain);
    throw;
}

该代理继承自MarshalByRefObject

public abstract class ModuleProxy : MarshalByRefObject
{
    internal protected virtual void OnLoad()
    {
    }

    internal protected virtual void OnUnload()
    {
    }
}

OnLoadOnUnload 在模块加载或卸载时被调用。 模块还继承自外部程序集中的 MarshalByRefObject,例如模块 ConfigurationReader.dll 中的此类。

public class Module : ModuleProxy
{
    private Configuration _configuration = new Configuration();

    protected override void OnLoad()
    {
        string fileName = Path.Combine(ModuleHelper.ModuleDirectory, AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Name + ".conf");
        _configuration.ReadAndLoadConfiguration(fileName);
        IrcBot bot = new IrcBot(_configuration);
        if (_configuration.Perform != null)
        {
            bot.EventManager.OnRegister += PerformOnRegister;
        }
        if (!string.IsNullOrWhiteSpace(_configuration.IdentifyMatchPeer + _configuration.IdentifyMatchText + _configuration.IdentifyPassword))
        {
            bot.EventManager.OnNotice += IdentifyOnNotice;
        }
        IrcBot.Bots.Add(_configuration.Id, bot);
        IrcBot.Bots[_configuration.Id].Start();
    }
...
...
...

问题是,当我修改属于主应用程序域的内容时(具体来说,将新机器人添加到 IrcBot.Bots 集合中,IrcBot.Bots.Add(_configuration.Id, bot);IrcBot.Bots 计数仅在辅助应用程序域内增加,而不是像我希望的那样在主应用程序域内增加。

做了一些 Console.WriteLining 后,我发现在辅助应用程序域中的 Add 调用之后调用 IrcBot.Bots.Count 返回 1,并在之后立即再次调用它主应用程序域中的 OnLoad 调用返回 0。这会产生灾难性的影响,并导致随后加载的其他模块出现故障。 在辅助 AppDomain 中更改后,如何更新主 AppDomain 中的机器人计数(以及其他内容)?

I am implementing a module system for my C# IRC Bot. The modules are .dll assemblies which are stored in a subdirectory, "modules", and they are used to add functionality to the bot, such as adding extra commands on IRC. These modules are designed to be loaded and unloaded at runtime so I can update the bot or fix bugs, without having to restart the entire application.

Currently the module system creates a new AppDomain for each module to be loaded, and a proxy to be created using CreateInstanceFromAndUnwrap inside a class called ModuleHelper.

AppDomain domain = AppDomain.CreateDomain(name, null, new AppDomainSetup 
{ 
    ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
    ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
    DisallowApplicationBaseProbing = true,
    PrivateBinPathProbe = ModuleDirectory,
    PrivateBinPath = ModuleDirectory,
    ShadowCopyDirectories = ModuleDirectory,
    CachePath = Path.Combine(ModuleDirectory, "cache"),
    ShadowCopyFiles = bool.TrueString 
});
ModuleProxy proxy = null;
try
{
    proxy = (ModuleProxy)domain.CreateInstanceFromAndUnwrap(location, AssemblyName.GetAssemblyName(location).Name + ".Module");
    proxy.OnLoad();
}
catch
{
    AppDomain.Unload(domain);
    throw;
}

This proxy inherits from MarshalByRefObject.

public abstract class ModuleProxy : MarshalByRefObject
{
    internal protected virtual void OnLoad()
    {
    }

    internal protected virtual void OnUnload()
    {
    }
}

OnLoad and OnUnload are called when the module is loaded or unloaded.
Modules also inherit from MarshalByRefObject in the external assembly, such as this class in a module, ConfigurationReader.dll.

public class Module : ModuleProxy
{
    private Configuration _configuration = new Configuration();

    protected override void OnLoad()
    {
        string fileName = Path.Combine(ModuleHelper.ModuleDirectory, AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).Name + ".conf");
        _configuration.ReadAndLoadConfiguration(fileName);
        IrcBot bot = new IrcBot(_configuration);
        if (_configuration.Perform != null)
        {
            bot.EventManager.OnRegister += PerformOnRegister;
        }
        if (!string.IsNullOrWhiteSpace(_configuration.IdentifyMatchPeer + _configuration.IdentifyMatchText + _configuration.IdentifyPassword))
        {
            bot.EventManager.OnNotice += IdentifyOnNotice;
        }
        IrcBot.Bots.Add(_configuration.Id, bot);
        IrcBot.Bots[_configuration.Id].Start();
    }
...
...
...

The problem is, when I modify something that belongs in the main appdomain (specifically, adding a new bot to the IrcBot.Bots collection, IrcBot.Bots.Add(_configuration.Id, bot);) the IrcBot.Bots count is increased inside the secondary appdomain only, and not the main appdomain as I want it to be.

After doing a bit of Console.WriteLining, I have found that calling IrcBot.Bots.Count after the Add call in the secondary appdomain returns 1, and calling it again straight after the OnLoad call in the main appdomain returns 0. This has a disastrous effect, and causes the other modules that are loaded afterwards to malfunction. How can I update the bot count (among other things) in the main AppDomain after changing it in the secondary AppDomain?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

末蓝 2024-12-01 05:55:58

正如 Juliet 所说,AppDomain 确实是隔离的,因此“静态”变量对于其他 AppDomain 是不可见的。解决方案可能是使用跨 AppDomain 单例,如 http://jonathan.dickinsons.co.za/blog/2010/11/cross-domain-singleton-in-c/http://www.dolittle.com/blogs /einar/archive/2007/05/18/cross-appdomain-singleton.aspx

As Juliet said, AppDomains are indeed isolated so that "static" variables are not visible from other AppDomains. A solution might be using cross-AppDomain singletons, as explained at http://jonathan.dickinsons.co.za/blog/2010/11/cross-domain-singleton-in-c/ and http://www.dolittle.com/blogs/einar/archive/2007/05/18/cross-appdomain-singleton.aspx.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文