2010-11-25 40 views
36

Assembly.GetEntryAssembly()不適用於Web應用程序。用於Web應用程序的GetEntryAssembly

但是...我真的需要這樣的東西。 我使用一些在web和非web應用程序中使用的深嵌套代碼。

我目前的解決方案是瀏覽StackTrace以查找第一個調用程序集。

/// <summary> 
/// Version of 'GetEntryAssembly' that works with web applications 
/// </summary> 
/// <returns>The entry assembly, or the first called assembly in a web application</returns> 
public static Assembly GetEntyAssembly() 
{ 
    // get the entry assembly 
    var result = Assembly.GetEntryAssembly(); 

    // if none (ex: web application) 
    if (result == null) 
    { 
     // current method 
     MethodBase methodCurrent = null; 
     // number of frames to skip 
     int framestoSkip = 1; 


     // loop until we cannot got further in the stacktrace 
     do 
     { 
      // get the stack frame, skipping the given number of frames 
      StackFrame stackFrame = new StackFrame(framestoSkip); 
      // get the method 
      methodCurrent = stackFrame.GetMethod(); 
      // if found 
      if ((methodCurrent != null) 
       // and if that method is not excluded from the stack trace 
       && (methodCurrent.GetAttribute<ExcludeFromStackTraceAttribute>(false) == null)) 
      { 
       // get its type 
       var typeCurrent = methodCurrent.DeclaringType; 
       // if valid 
       if (typeCurrent != typeof (RuntimeMethodHandle)) 
       { 
        // get its assembly 
        var assembly = typeCurrent.Assembly; 

        // if valid 
        if (!assembly.GlobalAssemblyCache 
         && !assembly.IsDynamic 
         && (assembly.GetAttribute<System.CodeDom.Compiler.GeneratedCodeAttribute>() == null)) 
        { 
         // then we found a valid assembly, get it as a candidate 
         result = assembly; 
        } 
       } 
      } 

      // increase number of frames to skip 
      framestoSkip++; 
     } // while we have a working method 
     while (methodCurrent != null); 
    } 
    return result; 
} 

確保大會是我們想要的,我們有3個條件:

  • 大會是不是在GAC
  • 大會沒有動態
  • 不產生裝配(以避免臨時asp.net文件

我遇到的最後一個問題是當基本頁面被定義爲單獨的sembly。 (我使用ASP.Net MVC,但它將與ASP.Net一樣)。 在這種特殊情況下,返回的是單獨的程序集,而不是包含頁面的程序集。

我正在尋找的是:

1)我的程序集驗證條件是否足夠? (我可能已經忘記了案例)

2)有沒有一種方法,從ASP.Net臨時文件夾中給定的代碼生成的程序集中獲取有關包含Page/View的項目的信息? (我想不會,但誰知道...)

+1

「入口程序集」在ASP.NET應用程序中並沒有任何意義,因爲許多ASP.NET應用程序都是在適當的時間串聯執行代碼的大量程序集。你究竟在做什麼? – Levi 2010-11-27 10:42:05

+0

我完全同意你,一個Web應用程序作爲「入門程序集」。實際上,我們可以認爲他們有多個切入點。我最終需要的是在入口程序集中獲取AssemblyInfo.cs文件中的內容。爲什麼我想要這樣做,這不是重點。 – Mose 2010-12-01 13:00:21

+1

我需要做一個類似的任務,並且通常找不到比這更好的方法。 ExcludeFromStackTraceAttribute是你的一類嗎?我似乎無法在BCL中找到它。 `GetAttribute <>`同樣的問題是,你爲了方便而創建了一個方法嗎? – 2011-07-19 19:38:48

回答

43

這似乎是一個可靠,簡單的方法來獲取Web應用程序的「入口」或主要程序集。

如果您將控制器放在單獨的項目中,您可能會發現ApplicationInstance的基類與包含視圖的MVC項目不在同一個程序集中 - 但是,此設置似乎非常罕見(我提到它是因爲我我曾嘗試過這種設置,並且一段時間以前有一些博客支持這個想法)。

static private Assembly GetWebEntryAssembly() 
    { 
     if (System.Web.HttpContext.Current == null || 
      System.Web.HttpContext.Current.ApplicationInstance == null) 
     { 
      return null; 
     } 

     var type = System.Web.HttpContext.Current.ApplicationInstance.GetType(); 
     while (type != null && type.Namespace == "ASP") { 
      type = type.BaseType; 
     } 

     return type == null ? null : type.Assembly; 
    } 
4

的回答爲我自己的問題(這裏有些人是公認的速度真的敏感) =>我沒有找到比中給出的代碼更好的方法這個問題。

這意味着te解決方案並不完美,但只要您的基本頁面是在前端裝配體中定義的,就可以工作。

2

在這個問題對我來說確實工作提出的算法,而使用System.Web.HttpContext.Current.ApplicationInstance方法沒有。我認爲我的問題是,我需要解決方案的舊式ASP.Net應用程序缺少global.asax處理程序。

這短的解決方案也爲我工作,我想一般會在該頁面的處理程序是在前端集中定義的條件下工作:

private static Assembly GetMyEntryAssembly() 
    { 
     if ((System.Web.HttpContext.Current == null) || (System.Web.HttpContext.Current.Handler == null)) 
     return Assembly.GetEntryAssembly(); // Not a web application 
     return System.Web.HttpContext.Current.Handler.GetType().BaseType.Assembly; 
    } 

我的應用程序是一個ASP.Net 4.x版Web表單應用程序。對於此應用程序類型,HttpContext.Current。處理程序是包含當前請求處理程序入口點的代碼模塊。 Handler.GetType()。Assembly是一個臨時的ASP.Net程序集,但Handler.GetType()。BaseType.Assembly是我的應用程序真正的「入口程序集」。我很好奇,如果同樣適用於各種其他ASP.Net應用程序類型。

-1

我能夠一致地爲Web應用程序工作(至少在.NET 4.5.1中)的唯一方法是在Web應用程序項目本身中執行Assembly.GetExecutingAssembly()。

如果您嘗試使用靜態方法創建實用程序項目並在那裏執行調用,您將從該程序集中獲取程序集信息 - 對於GetExecutingAssembly()和GetCallingAssembly()。

GetExecutingAssembly()是一個返回Assembly類型實例的靜態方法。該方法不存在於Assembly類本身的一個實例中。

因此,我所做的創建了一個接受構造函數中的Assembly類型的類,並創建了此類的一個實例,從Assembly.GetExecutingAssembly()傳遞結果。

public class WebAssemblyInfo 
    { 
     Assembly assy; 

     public WebAssemblyInfo(Assembly assy) 
     { 
      this.assy = assy; 
     } 

     public string Description { get { return GetWebAssemblyAttribute<AssemblyDescriptionAttribute>(a => a.Description); } } 


     // I'm using someone else's idea below, but I can't remember who it was 
     private string GetWebAssemblyAttribute<T>(Func<T, string> value) where T : Attribute 
     { 
      T attribute = null; 

      attribute = (T)Attribute.GetCustomAttribute(this.assy, typeof(T)); 

      if (attribute != null) 
       return value.Invoke(attribute); 
      else 
       return string.Empty; 
     } 
    } 
} 

,並使用它

string Description = new WebAssemblyInfo(Assembly.GetExecutingAssembly()).Description; 
5

就我而言,我需要得到「條目集結號」的web應用程序System.Web.HttpContext.Current.ApplicationInstance初始化之前。此外,我的代碼需要適用於各種應用程序類型(窗口服務,桌面應用程序等),我不喜歡用Web關注來污染我的通用代碼。

我創建了一個自定義的程序集級屬性,該屬性可以在要指定爲入口點程序集的程序集的AssembyInfo.cs文件中聲明。然後,您只需調用該屬性的靜態GetEntryAssembly方法即可獲取條目組件。如果Assembly.GetEntryAssembly返回非空值,則使用該值,否則它將搜索加載的程序集中的自定義屬性。結果緩存在一個懶惰的<T>中。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 

namespace EntryAssemblyAttributeDemo 
{ 
    /// <summary> 
    /// For certain types of apps, such as web apps, <see cref="Assembly.GetEntryAssembly"/> 
    /// returns null. With the <see cref="EntryAssemblyAttribute"/>, we can designate 
    /// an assembly as the entry assembly by creating an instance of this attribute, 
    /// typically in the AssemblyInfo.cs file. 
    /// <example> 
    /// [assembly: EntryAssembly] 
    /// </example> 
    /// </summary> 
    [AttributeUsage(AttributeTargets.Assembly)] 
    public sealed class EntryAssemblyAttribute : Attribute 
    { 
     /// <summary> 
     /// Lazily find the entry assembly. 
     /// </summary> 
     private static readonly Lazy<Assembly> EntryAssemblyLazy = new Lazy<Assembly>(GetEntryAssemblyLazily); 

     /// <summary> 
     /// Gets the entry assembly. 
     /// </summary> 
     /// <returns>The entry assembly.</returns> 
     public static Assembly GetEntryAssembly() 
     { 
      return EntryAssemblyLazy.Value; 
     } 

     /// <summary> 
     /// Invoked lazily to find the entry assembly. We want to cache this value as it may 
     /// be expensive to find. 
     /// </summary> 
     /// <returns>The entry assembly.</returns> 
     private static Assembly GetEntryAssemblyLazily() 
     { 
      return Assembly.GetEntryAssembly() ?? FindEntryAssemblyInCurrentAppDomain(); 
     } 

     /// <summary> 
     /// Finds the entry assembly in the current app domain. 
     /// </summary> 
     /// <returns>The entry assembly.</returns> 
     private static Assembly FindEntryAssemblyInCurrentAppDomain() 
     { 
      var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 
      var entryAssemblies = new List<Assembly>(); 
      foreach (var assembly in assemblies) 
      { 
       // Note the usage of LINQ SingleOrDefault. The EntryAssemblyAttribute's AttrinuteUsage 
       // only allows it to occur once per assembly; declaring it more than once results in 
       // a compiler error. 
       var attribute = 
        assembly.GetCustomAttributes().OfType<EntryAssemblyAttribute>().SingleOrDefault(); 
       if (attribute != null) 
       { 
        entryAssemblies.Add(assembly); 
       } 
      } 

      // Note that we use LINQ Single to ensure we found one and only one assembly with the 
      // EntryAssemblyAttribute. The EntryAssemblyAttribute should only be put on one assembly 
      // per application. 
      return entryAssemblies.Single(); 
     } 
    } 
}