簡體   English   中英

獲取進程的程序集名稱在應用程序域中啟動

[英]Getting the assembly name for a process started within an app domain

我有一個創建應用程序域並啟動它的服務:

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”記錄為源(條目程序集名稱)。

這是概述:主機 - >控制器(在app域中運行)

如何獲取在域中運行的程序集(具有控制器)的名稱?

注意:我也嘗試了這個(下面),但它給了我存在日志記錄類的框架的名稱(不是控制器在app域中運行的程序集的名稱):

assembly = Assembly.GetExecutingAssembly();

這可能是你想做的事情的一種方式。 我在這里演示的是通過SetDataGetData方法向創建的AppDomain傳遞和接收元數據,因此忽略我創建實際遠程類型的方式。

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主持人
按任意鍵繼續 ...

因此,在您的情況下,您可以將任何源元數據傳遞給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;
        }
    }
}

我遇到了一個隱藏在.net代碼中的地方,它依賴於Assembly.GetEntryAssembly()。 它將獲取返回的程序集並檢查它以獲取程序集級別屬性。 如果代碼位於應用程序域中,那將會失敗。

長話短說,我不得不解決同樣的問題。 解決方案是丑陋的,我討厭我需要這樣做,但它有效...

如果你在這里閱讀文檔 - Assembly.GetEntryAssembly()方法

它包含這一部分:

回報價值

鍵入:System.Reflection.Assembly

作為默認應用程序域中可執行的進程的程序集, 或AppDomain.ExecuteAssembly執行的第一個可執行文件 從非托管代碼調用時可以返回null。

為了解決這個問題,我在我的exe中添加了一些代碼,如果將“/ initializingappdomain”作為參數傳遞,則會使進程退出。

這是一些代碼來做到這一點......

// 1. Create your new app domain...
var newDomain = AppDomain.CreateDomain(...);

// 2. call domain.ExecuteAssembly, passing in this process and the "/initializingappdomain" argument which will cause the process to exit right away
newDomain.ExecuteAssembly(GetProcessName(), new[] { "/initializingappdomain" });

private static string GetProcessName()
{
   return System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName.Replace(".vshost", ""));
}

// 3. Use your app domain as you see fit, Assembly.GetEntryAssembly will now return this hosting .net exe.

再次,這遠非理想。 如果您可以避免這種情況,可以使用更好的解決方案,但如果您發現自己處於不依賴於Assembly.GetEntryAssembly()的代碼的情況下,這將使您處於緊張狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM