Вызов методов и получение значений в основном домене приложения из вторичного домена

Я внедряю модульную систему для своего IRC-бота С#. Модули представляют собой сборки .dll, которые хранятся в подкаталоге «modules» и используются для добавления функциональности боту, например добавления дополнительных команд в IRC. Эти модули предназначены для загрузки и выгрузки во время выполнения, поэтому я могу обновлять бота или исправлять ошибки без перезапуска всего приложения.

В настоящее время модульная система создает новый AppDomain для каждого загружаемого модуля, а прокси создается с использованием CreateInstanceFromAndUnwrap внутри класса с именем 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;
}

Этот прокси наследуется от MarshalByRefObject.

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

    internal protected virtual void OnUnload()
    {
    }
}

OnLoad и OnUnload вызываются при загрузке или выгрузке модуля. Модули также наследуют от 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, я обнаружил, что вызов IrcBot.Bots.Count после вызова Add во вторичном домене приложения возвращает 1, а повторный вызов сразу после вызова OnLoad в основном домене приложения возвращает 0. Это имеет катастрофические последствия и вызывает другие модули, которые загружаются впоследствии, выходят из строя. Как я могу обновить количество ботов (среди прочего) в основном AppDomain после его изменения в дополнительном AppDomain?


person Scott    schedule 16.07.2011    source источник
comment
Я не уверен в своем ответе, поэтому вместо этого опубликую его как комментарий :) Я не думаю, что вы сможете обновить статическое состояние с помощью MarshalByRefObject, поскольку изменения в одном AppDomain будут невидимы для других AppDomains. Возможно, было бы проще создать какой-то объект контекста, содержащий общее состояние, для передачи между вашим основным и дочерним доменами, но на этом пути много стенаний и скрежета зубов. Возможно, вам будет проще использовать именованные каналы WCF для более незаметного взаимодействия, см. 2-0" title="межпроцессное взаимодействие для окон в c net 2 0">stackoverflow.com/questions/50153/   -  person Juliet    schedule 16.07.2011


Ответы (1)


Как сказала Джульетта, домены приложений действительно изолированы, поэтому «статические» переменные не видны из других доменов приложений. Решением может быть использование синглетонов между доменами приложений, как описано в 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.

person floele    schedule 16.07.2011