Asp.net

為什麼在 PageHandlerFactory 和 IHttpHandlerFactory 存在的情況下,每個人都說 ASP.NET webforms 中的依賴注入很難?

  • June 28, 2011

所以我有一個舊的網路表單站點,並且正在努力使其更易於維護。把它扔掉並重寫它不是一種選擇。

IoC 顯然是它首先得到的東西之一,但這給我留下了服務定位器模式和糟糕的品味,並且想知道它是否可以做得更好。

我線上和離線交談過的各種人告訴我,我可以使用 HttpModule 進行屬性注入,該模組會掃描 Page 類以查找用 Inject 屬性或類似屬性裝飾的屬性,但這聽起來像是反射命中(記憶體,但仍然)在每一個請求。不吸引人。

所以我在尋找其他選項,並遇到了System.Web.IHttpHandlerFactory,它顯然從 v2 開始就在框架中。可以在 httpHandlers web.config 部分刪除預設的 *.aspx 處理程序並將其替換為使用自定義實現的處理程序。

所以,我與之交談過的人並不愚蠢。我想我會在這裡問。 用基於 IoC 的實現替換 webforms PageHandlerFactory 是否有任何問題……?

看起來它同時具有 CreateHandler 和 ReleaseHandler 方法,因此來自容器的與生活方式相關的記憶體洩漏保持對已創建組件的引用應該不是問題……

由於 ASP.NET 的設計方式,Page類需要有一個預設建構子。當您想使用建構子注入時,有一種方法可以解決這個問題。您可以使預設建構子受保護並添加一個公共建構子,該建構子採用如下依賴項:

public partial class _Default : System.Web.UI.Page
{
   private IUserService service;

   protected _Default()
   {
   }

   public _Default(IUserService service)
   {
       this.service = service;
   }
}

這允許您在建構子中創建自定義PageHandlerFactory並註入依賴項。

所以這行得通,但有一個問題。您定義的_Default類不是 ASP.NET 使用的實際類。ASP.NET 創建一個繼承自_Default. 這個新類基於 .aspx 文件中的標記建構控制項層次結構。這個類看起來有點像這樣:

public class ASPGeneratedDefault : _Default
{
   public ASPGeneratedDefault() : base()
   {
   }

    protected override void OnPreInit(object s, EventArgs e)
    {
         // Building up control hierarchy.
    }
}

如您所見,自定義建構子尚未在ASPGeneratedDefault ASP.NET 中被覆蓋。因此,沒有辦法讓 DI 框架為我們創建這種類型。_Default解決這個問題的方法是讓 ASP.NET 為我們創建此類型,並在該現有實例上呼叫基類的非預設建構子。因為這個實例已經存在,我們必須通過反射來做這件事,當在部分信任下執行時,這將失敗。

除此之外,這適用於頁麵類,但不適用於頁面上的使用者控制項。ASP.NET 的程式碼生成器在控制項層次結構建構過程中使用它們的預設建構子更新這些控制項。當您希望這適用於他們時,您需要自定義PageHandlerFactory掛鉤到PreInit這些控制項的事件,因為在構造頁麵類期間,尚未創建相關控制項和使用者控制項。但是,要PreInit在它們上註冊事件,您需要在頁麵類中找到這些控制項,並且我們需要再次反映頁麵類。因為控制項儲存在非公共實例欄位中,所以這在部分信任下也不起作用。

您的應用程序無法在部分信任下執行是否是一個問題取決於您,但由於 .NET 4 的安全模型已大大簡化,因此在部分信任下執行 Web 應用程序非常容易,這是我努力去做。

TLDR ; 所以總而言之,這樣做是可能的(例如,參見這個例子),但是由於 ASP.NET Web 窗體框架的限制,您需要完全信任地執行才能使其工作。

更新Microsoft 已從 NET 4.0 開始取消對 ASP.NET 的部分信任(請閱讀此處)。所以從這個角度來看,遠離完全信任可能沒有那麼有用(無論如何你都需要它)。

引用自:https://stackoverflow.com/questions/6504150