C# IRC ボットのモジュール システムを実装しています。モジュールは、サブディレクトリ "modules" に格納されている .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();
}
...
...
...
問題は、メイン appdomain に属するものを変更すると (具体的には、新しいボットを IrcBot.Bots コレクションに追加するとIrcBot.Bots.Add(_configuration.Id, bot);
) IrcBot.Bots
、セカンダリ appdomain 内でのみカウントが増加し、必要なメイン appdomain では増加しないことです。 .
Console.WriteLining を少し実行したIrcBot.Bots.Count
後Add
、セカンダリ appdomain での呼び出しが 1 を返した後にOnLoad
呼び出し、メイン appdomain での呼び出しが 0 を返した直後にもう一度呼び出すことがわかりました。これは悲惨な結果をもたらし、他のモジュールを引き起こします後でロードされて誤動作します。セカンダリ AppDomain で変更した後、メイン AppDomain のボット数を (とりわけ) 更新するにはどうすればよいですか?