【问题标题】:Getting the assembly name for a process started within an app domain获取在应用程序域中启动的进程的程序集名称
【发布时间】:2013-06-07 10:29:57
【问题描述】:

我有一个创建应用程序域并启动它的服务:

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();

【问题讨论】:

  • 避免寻找后门来获取您的代码提供的琐碎而准确的信息。添加属性。
  • 那么基本上是给log方法传一个字符串? Logger.Log("MyApp", message);
  • 当日志记录在业务逻辑层完成并且可以从多个消费者调用时,该方法不起作用。消费者知道他们的名字,但随后每个人都必须将此信息传递给逻辑方法。与其传递这样的信息,我真的很想把它放在一个地方。

标签: c# appdomain


【解决方案1】:

这也许是做你想做的事情的一种方式。我在这里演示的是通过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;
        }
    }
}

【讨论】:

    【解决方案2】:

    我遇到了一种情况,它隐藏在 .net 代码中的某个地方,它依赖于 Assembly.GetEntryAssembly()。它将获取返回的程序集并检查它的程序集级别属性。如果代码在应用程序域中,这将失败。

    长话短说,我不得不解决同样的问题。解决方案很难看,我讨厌我需要这样做,但它确实有效......

    如果您阅读此处的文档 - Assembly.GetEntryAssembly() Method

    它包含这个部分:

    返回值

    类型: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() 的代码,这将让您在紧要关头度过难关。

    【讨论】:

      猜你喜欢
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-15
      • 1970-01-01
      相关资源
      最近更新 更多