C# RoleEnvironment已更改事件未在非默认AppDomain中触发

C# RoleEnvironment已更改事件未在非默认AppDomain中触发,c#,azure,appdomain,azure-role-environment,C#,Azure,Appdomain,Azure Role Environment,我正在运行一个Azure服务,它在不同的AppDomains中托管代码。我需要处理这些AppDomain中的服务配置更改。为了这个目的,我正在收听这个活动 但是,此事件仅在默认AppDomain中激发,而不在任何其他AppDomain中激发。但是,我可以通过调用所有AppDomains来获取最新的值 我是否遗漏了什么,或者这是设计的限制? 我需要让它工作,所以我想我需要开发一个解决方案,只有默认的AppDomain侦听事件,然后使用一些基本IPC将任何更改传达给其他AppDomain有人有更好的

我正在运行一个Azure服务,它在不同的AppDomains中托管代码。我需要处理这些AppDomain中的服务配置更改。为了这个目的,我正在收听这个活动

但是,此事件仅在默认AppDomain中激发,而不在任何其他AppDomain中激发。但是,我可以通过调用所有AppDomains来获取最新的值

我是否遗漏了什么,或者这是设计的限制?

我需要让它工作,所以我想我需要开发一个解决方案,只有默认的AppDomain侦听事件,然后使用一些基本IPC将任何更改传达给其他AppDomain有人有更好的解决方法吗?

我创建了一个示例服务来说明我的问题:

public class WorkerRole : RoleEntryPoint
{
    public override void Run()
    {
        AppDomain.CreateDomain("MySubdomain", null,
             AppDomain.CurrentDomain.SetupInformation).DoCallBack(() =>
        {
            WorkerRole.EnableDevFabricTraceListener();
            new Thread(WorkerRole.WorkerThreadProc).Start("CHILD");
        });

        WorkerRole.WorkerThreadProc("MAIN");
    }

    private static void WorkerThreadProc(object id)
    {
        Trace.TraceInformation(string.Format(
            "[{0}] Starting", id), "Information");

        RoleEnvironment.Changed += (sender, args) =>
        {
            Trace.TraceInformation(string.Format(
                "[{0}] Role environment changed!", id), "Information");
        };

        string prevValue = null;

        while (true)
        {
            string currValue = RoleEnvironment.GetConfigurationSettingValue(
                 "MySetting");

            if (prevValue != currValue)
            {
                Trace.TraceInformation(string.Format(
                    "[{0}] MySetting={1}", id, currValue), "Information");
                prevValue = currValue;
            }

            Thread.Sleep(1000);
        }
    }

    // This is just a hack to enable tracing to the Azure Compute Emulator in
    // other app domains.
    private static void EnableDevFabricTraceListener()
    {
        try
        {
            const string className = "Microsoft.ServiceHosting.Tools.DevelopmentFabric.Runtime.DevelopmentFabricTraceListener";
            const string assemblyName = "Microsoft.ServiceHosting.Tools.DevelopmentFabric.Runtime, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";

            var assembly = Assembly.Load(assemblyName);
            var computeEmulatorTraceListenerType = assembly.GetType(className);
            var computeEmulatorTraceListener = (TraceListener)Activator.CreateInstance(computeEmulatorTraceListenerType);

            Trace.Listeners.Add(computeEmulatorTraceListener);
        }
        catch
        {
            // suppressed
        }
    }
}
我正在Azure Compute Emulator中运行此服务,并使用
csrun.exe
更新
MySetting
值:

这是我在compute emulator中看到的:

我也在WindowsAzure上的实际部署中对此进行了测试,得到了相同的结果

我真的看不出有什么原因(如果是设计的话),所以我认为这可能是一个bug

我发现内部方法
RoleEnvironment.InitializeCallbacks
,用于注册
Changed
事件的回调,每个进程只调用一次,而不是每个AppDomain调用一次

可以通过Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader中的public
RoleRuntimeBridge
类调用此方法,只需执行以下操作:

new RoleRuntimeBridge().Initialize(null);
但是,只有最后一个执行此操作的AppDomain才会触发事件。因此,虽然这使我能够在“子”AppDomain中激发事件,但它们不再在默认AppDomain中激发

这似乎是因为本机基础结构函数
WaRegisterCallback
只支持每个进程和回调类型一次回调

任何帮助或指点都将被感谢


我对这个问题很感兴趣。

这不是对你问题的回答,但模拟器可能只是有缺陷,在这方面无法模仿真正的云。只有在真实云中重现的问题才值得浪费时间。@sharptooth,这个问题在真实云中也存在,所以它不是针对模拟器的。