在Web站点中使用反射访问AssemblyInfo.cs文件中的信息

3

我已经创建了一个DLL,它将从AssemblyInfo.cs中收集信息。在类构造函数中,我使用反射来获取正在运行的最顶层应用程序。

public class AppInfo()
{
    public AppInfo()
    {
        System.Reflection.Assembly assembly =
            System.Reflection.Assembly.GetEntryAssembly();
        if (assembly == null)
            assembly = System.Reflection.Assembly.GetCallingAssembly();


        //code to gather needed information
    }
}

这个功能是设计成从任何给定应用程序中的 DLL 调用的,假设该应用程序名字总是 'MyApp'。在 Windows 服务和 Windows 应用程序中获取这些信息不是问题,而我的问题是: 我如何获取顶层网站(top-most Website)的程序集? 我发现了一些文章,在 Global.asax.cs 中移动 Website 的 AssemblyInfo.cs 到网站根目录中,然后通过将 compilerOption 添加到 AssemblyInfo.cs 的物理路径来获取信息。
<compiler
language="c#;cs;csharp"
extension=".cs"
compilerOptions="C:\Sandbox\MyWebSite\AssemblyInfo.cs"
type="Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4">

使用System.Reflection.Assembly.GetExecutingAssembly(),我可以检索网站的AssemblyInfo.cs中的信息。现在,我可以重载我的类的构造函数来接受一个并以这种方式检索信息,但是如果被使用的另一个DLL创建了一个,那么我将得到该DLL的程序集信息而不是父Website的信息。
我知道,如果我使用Web应用程序而不是Web站点,我就不会有这个问题,但出于某些原因,我不能使用Web应用程序。您有什么建议,无论我在哪个DLL中,都能从正在运行的网站的AssemblyInfo.cs中读取信息?
编辑:我需要这适用于Web站点、Windows应用程序和Windows服务。

你如何自己区分“最顶层”的应用程序? - Mehrdad Afshari
对于使用Assembly.GetEntryAssembly()的应用程序,它返回“最顶层”的应用程序。在网站中,Assembly.GetEntryAssembly()的值为null,如果从网站本身调用,则Assembly.GetCallingAssembly()是AppInfo的DLL,而不是我需要的网站。 - Alexander Kahoun
你有预编译的dll文件的访问权限吗? - Yordan Georgiev
4个回答

2

如果我理解你的问题正确,那么问题是在网站中Assembly.GetEntryAssembly()返回null,而Assembly.GetCallingAssembly()返回错误的东西,因为你有一连串的调用导致网站不是直接调用者。如果是这种情况,你可以通过堆栈跟踪并向上遍历调用帧来找到“入口程序集”。由于调用将始于IIS的深处,所以堆栈中将充满来自System.Web等的引用,但你应该能够通过获取最低的帧并明确标识它属于你的程序集来选择你感兴趣的程序集。请注意,这种方法相当hacky,但我认为它会得到你想要的结果...

var trace = new StackTrace();
Assembly entryAssembly = null;
foreach (var frame in trace.GetFrames())
{
   var assembly = frame.GetMethod().DeclaringType.Assembly;
   //check if the assembly is one you own & therefore could be your logical
   //"entry assembly". You could do this by checking the prefix of the
   //Assembly Name if you use some standardised naming convention, or perhaps
   //looking at the AssemblyCompanyAttribute, etc
   if ("assembly is one of mine")
   {
      entryAssembly = assembly;
   }
}

希望有其他人能够想出一种更少冒犯性的方法...但如果你真的卡住了,这可能会有所帮助。


这是最好的答案,因为它不仅适用于网站,还适用于Web应用程序、Win应用程序和Win服务。我所做的一件事是,我没有使用"assembly is one of mine",而是使用了if (!company.ToUpper().Contains("MICROSOFT")) entryAssembly = assembly。由于您建议使用堆栈跟踪,因此堆栈中的第一个条目和最后一个非Microsoft的条目将始终是调用应用程序。干得好,谢谢! - Alexander Kahoun

1

每个网站都会创建一个AppDomain,然后将bin*.dll文件加载到该应用程序的AppDomain中。至少没有任何具有特殊意义的“主要程序集”。

这是一个过程。System.Web.Hosting.ProcessHost通过System.Web.Hosting.ApplicationMangerSystem.Web.Hosting.Environment的组合创建System.Web.ApplicationHost,然后为应用程序创建System.AppDomain。

AppDomain非常安全,所以除非您知道如何进入AppDomain,否则您就没有机会了。

如果您可以更新您的问题,可能会有人能够提供更多帮助。

如果安全设置不正确,则可能可以执行此操作。

String binDir = Server.MapPath("/bin/");
Response.Write(String.Format("Bin dir:{0}<br/><br/>",binDir));

foreach (string file in Directory.GetFiles(binDir, "*.dll"))
{
    Response.Write(String.Format("File:{0}<br/>", file));
    try
    {
        Assembly assembly = Assembly.LoadFile(file);
        object[] attrinutes = assembly.GetCustomAttributes(true);
        foreach (var o in attrinutes)
        {
            //AssemblyCompanyAttribute is set in the AssemblyInfo.cs
            if (o is AssemblyCompanyAttribute)
            {
                Response.Write(String.Format("Company Attribute: Company = {0}<br/>", ((AssemblyCompanyAttribute)o).Company));
                continue;   
            }
            Response.Write(String.Format("Attribute: {0}<br/>", o));
        }
    }
    catch(Exception ex)
    {
        Response.Write(String.Format("Exception Reading File: {0} Exception: {1}",file,ex));
    }
}

你在这里做了很多假设,比如主站点没有编译(有一个App_Code目录),并且与你的子站点驻留在同一个应用程序池中。你有必要的访问权限吗?主站点是共享托管站点还是其他类型的站点?


这适用于网站,但不适用于Windows应用程序或Windows服务。我需要它能够适用于所有这些。 - Alexander Kahoun

1

0

使用Alconja的建议,我一直在检查assembly.GlobalAssemblyCache,直到找到第一个存在的。最后一个不存在的是我自己的dll中的第一个,我认为它是入口程序集。

下面的类有助于获取Type对象,如果只知道程序集名称和类型名称。

public static class AssemblyHandler {

    private static Dictionary<String, Assembly> Assemblies;

    public static Assembly GetAssembly(String Name) {

        if (Assemblies == null) {
            Assemblies = new Dictionary<string, Assembly>();
            var mainAsm = Assembly.GetEntryAssembly();

            if (mainAsm == null) {
                var trace = new StackTrace();
                foreach (var frame in trace.GetFrames()) {
                    var assembly = frame.GetMethod().DeclaringType.Assembly;
                    if (assembly.GlobalAssemblyCache) {
                        break;
                    }
                    mainAsm = assembly;
                }
            }

            Assemblies.Add(mainAsm.FullName, mainAsm);
            ScanReferencedAssemblies(mainAsm);
        }

        if (!Assemblies.ContainsKey(Name)) {
            return null;
        }
        return Assemblies[Name];
    }

    private static void ScanReferencedAssemblies(Assembly Asm) {

        foreach (var refAsmName in Asm.GetReferencedAssemblies()) {
            Assembly a = Assembly.Load(refAsmName);
            if (a.GlobalAssemblyCache) {
                continue;
            }
            if (!Assemblies.ContainsKey(a.FullName)) {
                Assemblies.Add(a.FullName, a);
                ScanReferencedAssemblies(a);
            }
        }
    }

    public static Type GetType(string AssemblyName, string TypeName) {

        return GetAssembly(AssemblyName).GetType(TypeName);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接