简体   繁体   中英

Accessing information in the AssemblyInfo.cs using Reflection in a Web Site

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

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.

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?

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM