Я внедряю модульную систему для моего C # IRC Bot.Модули - это сборки .dll, которые хранятся в подкаталоге «модули», и они используются для добавления функциональности боту, например, добавления дополнительных команд в 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. Это имеет катастрофический эффект,и вызывает неисправность других модулей, которые впоследствии загружаются. Как я могу обновить количество ботов (помимо прочего) в главном домене приложений после его изменения во вторичном домене приложений?