RoleEnvironment Changed事件未在非默认AppDomain中触发

时间:2014-02-25 12:14:43

标签: c# azure appdomain azure-role-environment

我正在运行Azure服务,该服务在单独的AppDomain中托管代码。我需要处理这些AppDomain中的服务配置更改。为此,我正在听RoleEnvironment.Changed事件。

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

我错过了什么,或者这是设计上的限制?

我需要让这个工作,所以我认为我需要开发一个解决方法,只有默认的AppDomain监听Changed事件,然后使用一些基本的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值:

Using CSRUN.EXE to update the setting

这是我在计算模拟器中看到的:

Trace output in Azure Compute Emulator

我还在Windows Azure上的实际部署中对此进行了测试,结果相同。

我真的没有看到任何理由(如果是设计),所以我认为这可能是一个错误。

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

只需执行以下操作即可通过RoleRuntimeBridge中的公开Microsoft.WindowsAzure.ServiceRuntime.Implementation.Loader课程调用此方法:

new RoleRuntimeBridge().Initialize(null);

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

原因似乎是本机基础结构函数WaRegisterCallback仅支持每个进程和回调类型的一个回调。

任何帮助或指示都会受到欢迎!

对于这个问题,我filed a bug on Microsoft Connect

0 个答案:

没有答案