2013-12-17 3 views
4

Я выполнял шаги в документации Microsoft Enterprise Library 5.0, чтобы создать модуль HTTP для ввода ссылки на контейнер Enterprise Library на страницы ASP .NET веб-приложение.HTTP-модуль для впрыска ASP.NET (MS Enterprise Library)

Он содержит следующий код (который также появляется на сайте here):

using System; 
using System.Collections.Generic; 
using System.Web; 
using System.Web.UI; 
using Microsoft.Practices.Unity; 

namespace Unity.Web 
{ 
    public class UnityHttpModule : IHttpModule 
    { 
    public void Init(HttpApplication context) 
    { 
     context.PreRequestHandlerExecute += OnPreRequestHandlerExecute; 
    } 

    public void Dispose() { } 

    private void OnPreRequestHandlerExecute(object sender, EventArgs e) 
    { 
     IHttpHandler currentHandler = HttpContext.Current.Handler; 
     HttpContext.Current.Application.GetContainer().BuildUp(
          currentHandler.GetType(), currentHandler); 

     // User Controls are ready to be built up after page initialization is complete 
     var currentPage = HttpContext.Current.Handler as Page; 
     if (currentPage != null) 
     { 
     currentPage.InitComplete += OnPageInitComplete; 
     } 
    } 

    // Build up each control in the page's control tree 
    private void OnPageInitComplete(object sender, EventArgs e) 
    { 
     var currentPage = (Page)sender; 
     IUnityContainer container = HttpContext.Current.Application.GetContainer(); 
     foreach (Control c in GetControlTree(currentPage)) 
     { 
     container.BuildUp(c.GetType(), c); 
     } 
     context.PreRequestHandlerExecute -= OnPreRequestHandlerExecute; 
    } 

    // Get the controls in the page's control tree excluding the page itself 
    private IEnumerable<Control> GetControlTree(Control root) 
    { 
     foreach (Control child in root.Controls) 
     { 
     yield return child; 
     foreach (Control c in GetControlTree(child)) 
     { 
      yield return c; 
     } 
     } 
    } 
    } 
} 

Есть целый ряд проблем, связанных с этим кодом и инструкциями, прилагаемыми к ней.

1) В инструкциях не упоминается, где разместить этот код. Поскольку это класс, я поместил его в папку App_Code моего проекта веб-сайта ASP.NET.

На самом деле, здесь есть инструкции для этого бита кода:

Создать новый класс модуля ASP.NET HTTP (с именем, например, UnityHttpModule) в проекте, который захватывает PreRequestHandlerExecute события и выполняет код, который обрабатывает полное дерево управления текущего запроса страницы, применяя метод Unity BuildUp для каждого элемента управления.

2) HttpContext.Current.Application. Метод GetContainer() не существует для меня, хотя я использую те же DLL-ссылки (я кодирую в .NET 4.0).

3) Событие OnPageInitComplete ссылается на переменную «context» ... которая, похоже, не существует в этом контексте.

Любые идеи о том, что мне здесь не хватает?

ответ

5

Кажется, документация плохо организована.

В ответ на (2), что не было объяснено, метод HttpContext.Current.Application.GetContainer() на самом деле является методом расширения, который реализован, как показано в коде here.

Чтобы использовать этот метод расширения, вам просто нужно импортировать пространство имен Unity.Web.

Вот копия методы расширения:

using System.Web; 
using Microsoft.Practices.Unity; 

namespace Unity.Web 
{ 
    public static class HttpApplicationStateExtensions 
    { 
    private const string GlobalContainerKey = "EntLibContainer"; 

    public static IUnityContainer GetContainer(this HttpApplicationState appState) 
    { 
     appState.Lock(); 
     try 
     { 
     var myContainer = appState[GlobalContainerKey] as IUnityContainer; 
     if (myContainer == null) 
     { 
      myContainer = new UnityContainer(); 
      appState[GlobalContainerKey] = myContainer; 
     } 
     return myContainer; 
     } 
     finally 
     { 
      appState.UnLock(); 
     } 
    } 
    } 
} 

касаемо код модуля инъекции зависимостей, я на самом деле просто использовал basic method для получения экземпляра контейнера, который, насколько я» m, работает так же хорошо. В документации говорится, что код модуля HTTP для инъекций зависимостей улучшает «тестируемость» и «открытость», что немного расплывчато.

Во всяком случае, вот код для базового подхода:

protected void Application_Start(object sender, EventArgs e) 
{ 
    Application.Lock(); 
    try 
    { 
    var myContainer = Application["EntLibContainer"] as IUnityContainer; 
    if (myContainer == null) 
    { 
     myContainer = new UnityContainer(); 
     myContainer.AddExtension(new EnterpriseLibraryCoreExtension()); 
     // Add your own custom registrations and mappings here as required 
     Application["EntLibContainer"] = myContainer; 
    } 
    } 
    finally 
    { 
    Application.UnLock(); 
    } 
}   

Так с кодом расширения на месте, и код в моем файле global.asax создать экземпляр контейнера Enterprise Library, единственным осталось сделать код, чтобы получить экземпляр контейнера по мере необходимости.Поэтому, когда я хочу, чтобы получить экземпляр класса LogWriter, я бы написал так:

using Unity.Web; 

public LogWriter getLogWriter() 
{ 
    var container = HttpContext.Current.Application.GetContainer(); 
    return container.Resolve<LogWriter>(); 
} 

Пространство имен Unity.Web необходимо, чтобы позволить нам вызвать метод расширения GetContainer().

+0

Плохо организованная на самом деле не режет - код не будет компилироваться в первую очередь и дает исключения во время выполнения, если вы внесете некоторые базовые изменения, чтобы заставить его скомпилировать. Я подробно описал это в своем ответе. –

2

Код, предоставленный статьей MSDN, довольно шокирует. Во-первых, он не будет компилироваться, так как вы получите необъявленную переменную ошибку на этой линии:

context.PreRequestHandlerExecute -= OnPreRequestHandlerExecute; 

В контексте передается в метод Init и нигде не сохраняются. Если вы захватить этот параметр и сохранить его в поле, то вы получите исключение во время выполнения:

обработчики событий могут быть связаны только с HttpApplication событий во время инициализации IHttpModule.

Итак, следующее, кажется, работает:

using System; 
using System.Collections.Generic; 
using System.Web; 
using System.Web.UI; 
using Microsoft.Practices.Unity; 

namespace Unity.Web 
{ 
    /// <summary> 
    /// An <see cref="IHttpModule" /> that automatically injects dependencies into ASP.NET WebForms pages. 
    /// </summary> 
    /// <remarks> 
    /// Since the pages have already been constructed by the time the module is called, constructor injection cannot be used. However, 
    /// property injection can be used instead. 
    /// </remarks> 
    public class UnityHttpModule : IHttpModule 
    { 
     private HttpApplication _context; 
     private bool _disposed; 

     /// <summary> 
     /// Initializes a module and prepares it to handle requests. 
     /// </summary> 
     /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application </param> 
     public void Init(HttpApplication context) 
     { 
      _context = context; 
      _context.PreRequestHandlerExecute += OnPreRequestHandlerExecute; 
     } 

     /// <summary> 
     /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>. 
     /// </summary> 
     public void Dispose() 
     { 
      GC.SuppressFinalize(this); 
      Dispose(true); 
     } 

     /// <summary> 
     /// Releases unmanaged and - optionally - managed resources. 
     /// </summary> 
     /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> 
     protected virtual void Dispose(bool disposing) 
    { 
     if (_disposed) 
     { 
      return; 
     } 

     if (disposing) 
     { 
      if (_context != null) 
      { 
       _context.PreRequestHandlerExecute -= OnPreRequestHandlerExecute; 
      } 
     } 

     _disposed = true; 
    } 

    /// <summary> 
    /// Handles the <see cref="E:PreRequestHandlerExecute" /> event. 
    /// </summary> 
    /// <param name="sender">The sender.</param> 
    /// <param name="eventArgs">The <see cref="EventArgs"/> instance containing the event data.</param> 
    private void OnPreRequestHandlerExecute(object sender, EventArgs eventArgs) 
    { 
     var currentHandler = HttpContext.Current.Handler; 
     if (currentHandler != null) 
     { 
      HttpContext.Current.Application.GetContainer().BuildUp(currentHandler.GetType(), currentHandler); 
     } 

     // User Controls are ready to be built up after page initialization is complete 
     var currentPage = HttpContext.Current.Handler as Page; 
     if (currentPage != null) 
     { 
      currentPage.InitComplete += OnPageInitComplete; 
     } 
    } 

    /// <summary> 
    /// Handles the <see cref="E:PageInitComplete" /> event. 
    /// </summary> 
    /// <param name="sender">The sender.</param> 
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> 
    private void OnPageInitComplete(object sender, EventArgs e) 
    { 
     var currentPage = (Page)sender; 
     var container = HttpContext.Current.Application.GetContainer(); 
     foreach (var c in GetControlTree(currentPage)) 
     { 
      container.BuildUp(c.GetType(), c); 
     } 
    } 

    /// <summary> 
    /// Gets the controls in the page's control tree, excluding the page itself. 
    /// </summary> 
    /// <param name="root">The root control.</param> 
    /// <returns>The child controls of the <paramref name="root" /> control.</returns> 
    private static IEnumerable<Control> GetControlTree(Control root) 
    { 
     foreach (Control child in root.Controls) 
     { 
      yield return child; 
      foreach (var control in GetControlTree(child)) 
      { 
       yield return control; 
      } 
     } 
    } 
} 

Вы будете нуждаться в остальной части кода инфраструктуры, которая @CiaranGallagher ссылается в своем ответе, чтобы закончить сантехнику, хотя я предпочитаю использовать проект инжекторы, так и в его примере кода будет:

using Unity.Web; 

[Dependency] 
public LogWriter Writer { get; set; } 

Вы не можете использовать инъекции конструктора с WebForms как модуль использует налипание на уже существующие элементах управления, но инъекция свойства работает хорошо, как это делает метамфетамин впрыск.

Смежные вопросы