获取进程的程序集名称在应用程序域中启动

时间:2013-06-11 14:17:51

标签: c# appdomain

我有一项服务可以创建应用域并启动它:

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

2 个答案:

答案 0 :(得分:3)

这可能是你想做的事情的一种方式。我在这里演示的是通过AppDomainSetData方法向创建的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主持人
  按任意键继续......

因此,在您的情况下,您可以将任何源元数据传递给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;
        }
    }
}

答案 1 :(得分:0)

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

长话短说,我不得不解决同样的问题。解决方案是丑陋的,我讨厌我需要这样做,但它有效...

如果你在这里阅读文档 - Assembly.GetEntryAssembly() Method

它包含此部分:

  

返回值

     

类型:System.Reflection.Assembly

     

默认应用程序域中可执行的流程的程序集,或   由AppDomain.ExecuteAssembly 执行的第一个可执行文件。能够   从非托管代码调用时返回null。

为了解决这个问题,我在我的exe中添加了一些代码,如果将“/ initializingappdomain”作为参数传递,则会使进程退出。

以下是一些代码来执行此操作...

var predicate = PredicateBuilder.True<Data.AccountAllocation>();
var initString = predicate.ToString();

if (startDate.HasValue)
   predicate = predicate.And(p => p.DateEntered >= startDate);

...

if (predicate.ToString() == initString)
    predicate = predicate.And(p => false);

同样,这远非理想。如果您可以避免这种情况,可以使用更好的解决方案,但如果您发现自己处于不依赖于Assembly.GetEntryAssembly()的代码的情况下,这将使您处于紧要关头。

相关问题