使用网站中的反射访问 AssemblyInfo.cs 中的信息

发布于 2024-07-18 00:27:36 字数 1456 浏览 5 评论 0原文

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

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
    }
}

如果我从给定应用程序 MyApp 中的任何 DLL 调用它,那么它的用途是,假设名称始终是“MyApp”。 检索该信息不是问题,并且它在 Windows 服务和 Windows 应用程序中运行良好。 我的问题是这样的: 如何获取最顶层网站的Assembly?

我找到了几篇文章,可以通过将网站的AssemblyInfo.cs移出Global.asax.cs来获取Global.asax.cs中的信息App_Code 文件夹并进入网站的根目录。 然后,通过将 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 中的信息。 现在,我可以重载 AppInfo 类的构造函数以接受 Assembly 并以这种方式检索信息,但如果 MyWebSite 使用另一个 DLL创建一个 new AppInfo() 我将获取该 DLL 而不是父网站的程序集信息。

我知道,如果我使用网络应用程序而不是网站,我就不会遇到此问题,但由于我不会详细说明的原因,我无法使用网络应用程序。 对于如何从我正在运行的网站的 AssemblyInfo.cs 中读取信息(无论我位于什么 DLL 中)有什么建议吗?

编辑:我需要这个才能用于网站、Windows 应用程序和 Windows 服务

I have created a DLL that will gather information from the AssemblyInfo.cs. In the class constructor I am using Reflection to get the top-most application that is running.

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
    }
}

How this is intended to be used is if I call this from any DLL in a given application, MyApp, that lets say the name will always be 'MyApp'. Retrieving that information is not a problem and it works great in Windows Services and Windows Applications. My question is this:
How do I get the Assembly of the top-most Website?

I have found a few articles and I can get the information in the Global.asax.cs by moving the AssemblyInfo.cs for the Website out of the App_Code folder and into the root of the Website. Then by adding a compilerOption to the physical path of the 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">

Using that I am able to retrieve information in the AssemblyInfo.cs for the Website through System.Reflection.Assembly.GetExecutingAssembly(). Now I can overload the constructor of my AppInfo class to accept an Assembly and retrieve information that way, but if another DLL that is used by MyWebSite creates a new AppInfo() I will get the assembly information of that DLL instead of the parent Website.

I know that if I was working with Web Apps instead of Web Sites I wouldn't have this issue, but for reasons I won't go into I am not able to use Web Apps. Any suggestions on how I can read information from the AssemblyInfo.cs of the Website I'm running in no matter what DLL I'm in?

EDIT: I need this to work for Web Sites, Windows Apps and Windows Services

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

少跟Wǒ拽 2024-07-25 00:27:36

如果我正确理解你的意思,问题是 Assembly.GetEntryAssembly() 在网站中返回 null,而 Assembly.GetCallingAssembly() 返回错误的内容,因为你有一系列调用导致网站不是直接调用者。 如果是这种情况,您可以使用堆栈跟踪和查找“条目程序集”。 走回调用框架。 堆栈将充满来自 System.Web 等的引用,因为调用将源自 IIS 深处的某处,但您应该能够通过抓取您可以明确识别的最低框架来挑选出您感兴趣的程序集作为属于你的。 请注意,这是相当老套的,但我认为它会给你你想要的......

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;
   }
}

希望其他人能够想出一个不那么令人讨厌的方法......但如果你真的陷入困境,这可能有帮助。

If I understand you properly, the problem is that Assembly.GetEntryAssembly() returns null in a Website and Assembly.GetCallingAssembly() is returning the wrong thing because you've got a chain of calls resulting in the website not being the immediate caller. If that's the case, you could find the "Entry Assembly" using the stack trace & walking back up the calling frames. The stack will be full of references from System.Web, etc as the call will have originated from deep within IIS somewhere, but you should be able to pick out the assembly you're interested in by grabbing the lowest frame that you can positively identify as belonging to you. Note that this is pretty hacky, but I think it'll get you what you want...

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;
   }
}

Hopefully someone else will be able to come up with a less nasty way of doing it... but if you're really stuck, this might help.

无语# 2024-07-25 00:27:36

AppDomain 是按网站创建的,然后 bin*.dll 文件会加载到该应用程序的 AppDomain 中。 该站点没有“主大会”,至少没有任何具有特殊含义的“主大会”。

这是一个过程。 System.Web.Hosting.ProcessHost 其中通过创建 System.Web.ApplicationHost System.Web.Hosting.ApplicationManger< 的组合/a> 和 System.Web.Hosting.Environment< /a> 然后为应用程序创建一个 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 目录)并且与您的子站点驻留在同一应用程序池中您是否需要访问权限才能执行此操作?主站点是共享托管站点还是其他站点?

AppDomains are created per website and then the bin*.dll files are loaded into that Application's AppDomain. There is not a "Master Assembly" of the site, at least any that has any special meaning.

It is a process. System.Web.Hosting.ProcessHost which creates a System.Web.ApplicationHost through a combination of the System.Web.Hosting.ApplicationManger and System.Web.Hosting.Environment which then creates a System.AppDomain for the application.

AppDomain is secured pretty well so unless you know how to get into an AppDomain, you're out of luck.

If you can update your question, someone may be able to help more.

You MAY be able to do this if security is not setup properly"

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

You are assuming alot here that the Master site is not compiled (has a App_Code directory) and resides in the same Application Pool as your child site. Do you have needed access to do this? Is the master site a shared hosting site or something?

孤者何惧 2024-07-25 00:27:36

偏差是对的。 但如果可以的话,您应该使用 Assembly.Load 而不是 Assembly.LoadFile。

这里有一些很好的参考:

http://gisresearch.blogspot。 com/2007/09/ assembly-load-loadfrom-loadfile.html

Deviant is right. But if you can you should use Assembly.Load instead of Assembly.LoadFile.

Here is some nice reference:

http://gisresearch.blogspot.com/2007/09/assembly-load-loadfrom-loadfile.html

秋日私语 2024-07-25 00:27:36

使用 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);
    }
}

Using Alconja's suggestion I was checking for assembly.GlobalAssemblyCache until I found the first one being there. The last one not being there is the first of my own dlls that I consider the entry assembly.

The class below helps getting a Type object if only the assembly name and the type name is known.

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文