5

アプリ ドメインを作成して開始するサービスがあります。

this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.Evidence, appDomainSetup);
this._startStopControllerToRun = (IStartStop)this._appDomain.CreateInstanceFromAndUnwrap(assemblyName, this._fullyQualifiedClassName);
this._startStopControllerToRun.Start();

それは長い間うまくいっています。問題は、このアプリ ドメイン内で開始されたコントローラーが、フレームワークのログ クラスを呼び出すときです。ロガーはエントリ アセンブリ名を取得し、それをソースとしてイベント ログに記録します。これは、ロガーがソース (呼び出し元) 名を取得する方法です。

private static string GetSource()
{
    try
    {
        var assembly = Assembly.GetEntryAssembly();

        // GetEntryAssembly() can return null when called in the context of a unit test project.
        // That can also happen when called from an app hosted in IIS, or even a windows service.
        if (assembly == null)
        {
            // From http://stackoverflow.com/a/14165787/279516:
            assembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;
        }

        return assembly.GetName().Name;
    }
    catch
    {
        return "Unknown";
    }
}

そのチェックを追加する前ifに、ロガーはソースに対して「不明」を記録します。いくつかの調査の後、その試みをifブロックに追加しました。これで、ロガーは "mscorlib" をソース (エントリ アセンブリ名) として記録します。

これは概要です: ホスト -> コントローラー (アプリ ドメイン内で実行)

ドメイン内で実行されているアセンブリ (コントローラーを含む) の名前を取得するにはどうすればよいですか?

注:これも試しました(以下)が、ロギングクラスが存在するフレームワークの名前が表示されます(アプリドメイン内でコントローラーが実行されているアセンブリの名前ではありません):

assembly = Assembly.GetExecutingAssembly();
4

2 に答える 2

3

これはおそらく、あなたが望むことを行う1つの方法です。ここでデモンストレーションしているのは、作成されたAppDomainviaSetDataおよびGetDataメソッドにメタデータを渡したり受け取ったりしているため、実際のリモート タイプを作成する方法は無視してください。

using System;
using System.Reflection;

namespace ConsoleApplication13
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain appDomain = AppDomain.CreateDomain("foo");

            appDomain.SetData(FooUtility.SourceKey, FooUtility.SourceValue);

            IFoo foo = (IFoo)appDomain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, typeof(Foo).FullName);

            foo.DoSomething();
        }
    }

    public static class FooUtility
    {
        public const string SourceKey = "Source";
        public const string SourceValue = "Foo Host";
    }

    public interface IFoo
    {
        void DoSomething();
    }

    public class Foo : MarshalByRefObject, IFoo
    {
        public void DoSomething()
        {
            string source = AppDomain.CurrentDomain.GetData(FooUtility.SourceKey) as string;

            if (String.IsNullOrWhiteSpace(source))
                source = "some default";

            Console.WriteLine(source);
        }
    }
}

どの出力:

Foo Host
続行するには何かキーを押してください...

したがって、あなたの場合、ソース メタデータを AppDomain に渡すことができます。

this._appDomain = AppDomain.CreateDomain(this._appName, AppDomain.CurrentDomain.Evidence, appDomainSetup);

this._appDomain.SetData("Source", "MyController");

this._startStopControllerToRun = (IStartStop)this._appDomain.CreateInstanceFromAndUnwrap(assemblyName, this._fullyQualifiedClassName);
this._startStopControllerToRun.Start();

そしてあなたのGetSourceメソッドでその存在をチェックしてください。

private static string GetSource()
{
    try
    {
        string source = AppDomain.CurrentDomain.GetData("Source") as string;

        if (!String.IsNullOrWhiteSpace(source))
            return source;

        var assembly = Assembly.GetEntryAssembly();

        // GetEntryAssembly() can return null when called in the context of a unit test project.
        // That can also happen when called from an app hosted in IIS, or even a windows service.
        if (assembly == null)
        {
            // From http://stackoverflow.com/a/14165787/279516:
            assembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;
        }

        return assembly.GetName().Name;
    }
    catch
    {
        return "Unknown";
    }
}

代替案を更新

ターゲット ドメインの静的な場所にソースを設定するためのパブリック インターフェイス メソッドを宣言することもできます。

using System;
using System.Reflection;

namespace ConsoleApplication13
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain appDomain = AppDomain.CreateDomain("foo");

            IFoo foo = (IFoo)appDomain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, typeof(Foo).FullName);

            foo.SetSource("Foo Host");

            foo.DoSomething();
        }
    }

    public interface IFoo
    {
        void DoSomething();
        void SetSource(string source);
    }

    public class Foo : MarshalByRefObject, IFoo
    {
        public void DoSomething()
        {
            string source = Foo.Source;

            if (String.IsNullOrWhiteSpace(source))
                source = "some default";

            Console.WriteLine(source);
        }

        public static string Source{get; private set;}

        public void SetSource(string source)
        {
            Foo.Source = source;
        }
    }
}
于 2013-06-12T15:38:24.167 に答える