我正在嘗試解決使用ASP.NET Web窗體控件的依賴注入的方法。如何在ASP.NET Web窗體中使用依賴注入
我有許多的直接創建存儲庫,並使用它們來訪問和綁定到我要尋找一個圖形數據等
在那裏我可以通過倉庫的外部控制(IOC)的控制,所以我的控件仍然不知道存儲庫是如何構造的,以及它們來自哪裏等。
我不希望從控件中獲得對IoC容器的依賴性,因此我只是希望能夠使用構造函數構造控件或財產注入。
(而就的事情,這些控件正在建設中,並通過CMS在運行時放置在頁面上!複雜)
有什麼想法?
我正在嘗試解決使用ASP.NET Web窗體控件的依賴注入的方法。如何在ASP.NET Web窗體中使用依賴注入
我有許多的直接創建存儲庫,並使用它們來訪問和綁定到我要尋找一個圖形數據等
在那裏我可以通過倉庫的外部控制(IOC)的控制,所以我的控件仍然不知道存儲庫是如何構造的,以及它們來自哪裏等。
我不希望從控件中獲得對IoC容器的依賴性,因此我只是希望能夠使用構造函數構造控件或財產注入。
(而就的事情,這些控件正在建設中,並通過CMS在運行時放置在頁面上!複雜)
有什麼想法?
您可以使用自動構造函數注入,方法是使用自定義函數替換默認的PageHandlerFactory
。這樣你可以使用重載的構造函數來加載依賴關係。您的頁面可能是這樣的:
public partial class HomePage : System.Web.UI.Page
{
private readonly IDependency dependency;
public HomePage(IDependency dependency)
{
this.dependency = dependency;
}
// Do note this protected ctor. You need it for this to work.
protected HomePage() { }
}
配置的自定義PageHandlerFactory
可以在web.config進行如下:
<?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*.aspx"
type="YourApp.CustomPageHandlerFactory, YourApp"/>
</httpHandlers>
</system.web>
</configuration>
你CustomPageHandlerFactory
可以是這樣的:
public class CustomPageHandlerFactory : PageHandlerFactory
{
private static object GetInstance(Type type)
{
// TODO: Get instance using your favorite DI library.
// for instance using the Common Service Locator:
return Microsoft.Practices.ServiceLocation
.ServiceLocator.Current.GetInstance(type);
}
public override IHttpHandler GetHandler(HttpContext cxt,
string type, string vPath, string path)
{
var page = base.GetHandler(cxt, type, vPath, path);
if (page != null)
{
// Magic happens here ;-)
InjectDependencies(page);
}
return page;
}
private static void InjectDependencies(object page)
{
Type pageType = page.GetType().BaseType;
var ctor = GetInjectableCtor(pageType);
if (ctor != null)
{
object[] arguments = (
from parameter in ctor.GetParameters()
select GetInstance(parameter.ParameterType)
.ToArray();
ctor.Invoke(page, arguments);
}
}
private static ConstructorInfo GetInjectableCtor(
Type type)
{
var overloadedPublicConstructors = (
from constructor in type.GetConstructors()
where constructor.GetParameters().Length > 0
select constructor).ToArray();
if (overloadedPublicConstructors.Length == 0)
{
return null;
}
if (overloadedPublicConstructors.Length == 1)
{
return overloadedPublicConstructors[0];
}
throw new Exception(string.Format(
"The type {0} has multiple public " +
"ctors and can't be initialized.", type));
}
}
缺點是,這隻有在完全信任的情況下運行你的身邊時纔有效。您可以閱讀更多關於它here。但請注意,開發部分信任的ASP.NET應用程序seems a lost cause。
的最好方法是有像用於控制基類:
public class PartialView : UserControl
{
protected override void OnInit(System.EventArgs e)
{
ObjectFactory.BuildUp(this);
base.OnInit(e);
}
}
這將注入來自該基類繼承的任何控制(使用structuremap)。結合與一個基於屬性的配置,你就可以有這樣的控制:
public partial class AdminHeader : PartialView
{
IMyRepository Repository{get;set;}
}
更新1:如果你不能擁有控制繼承,也許CMS有一個鉤創建的控制權後, ,在那裏你可以打電話給BuildUp。同樣,如果CMS允許你鉤住某些東西來獲取實例,你可以使用基於構造函數的注入,但是我更喜歡BuildUp,因爲asp.net沒有這個鉤子。
您還可以在Application_Start global.asax事件中創建一些單例實例,並使它們可用作公共靜態只讀屬性。
Autofac supports在ASP.NET WebForms中相當不顯眼的依賴注入。我的理解是,它只是使用http模塊掛鉤到ASP.NET頁面生命週期中,並執行屬性注入。唯一的問題是,對於控件,我不認爲這發生在之後, Init事件。
這是我最近使用,以免鉤住管道解決方案(我發現混淆大家看我在以後的代碼,但是,是的,我看到它的好處,以及):
public static class TemplateControlExtensions
{
static readonly PerRequestObjectManager perRequestObjectManager = new PerRequestObjectManager();
private static WIIIPDataContext GetDataContext(this TemplateControl templateControl)
{
var dataContext = (WIIIPDataContext) perRequestObjectManager.GetValue("DataContext");
if (dataContext == null)
{
dataContext = new WIIIPDataContext();
perRequestObjectManager.SetValue("DataContext", dataContext);
}
return dataContext;
}
public static IMailer GetMailer(this TemplateControl templateControl)
{
return (IMailer)IoC.Container.Resolve(typeof(IMailer));
}
public static T Query<T>(this TemplateControl templateControl, Query<T> query)
{
query.DataContext = GetDataContext(templateControl);
return query.GetQuery();
}
public static void ExecuteCommand(this TemplateControl templateControl, Command command)
{
command.DataContext = GetDataContext(templateControl);
command.Execute();
}
private class PerRequestObjectManager
{
public object GetValue(string key)
{
if (HttpContext.Current != null && HttpContext.Current.Items.Contains(key))
return HttpContext.Current.Items[key];
else
return null;
}
public void SetValue(string key, object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[key] = newValue;
}
}
}
這顯示瞭如何很容易地創建自己的生活時間管理器,以及如果您願意,也可以掛鉤到IoC容器中。哦,我還使用查詢/命令結構是有點風馬牛不相及,但更多的是背後的推理可以在這裏找到:
Limit your abstractions: Refactoring toward reduced abstractions
感謝您的答覆。我的完美主義者希望控件不要依賴於ObjectFactory框架,即純依賴注入。顯然這暗示着一些外部的東西,創造了控制。 – Schneider 2009-02-26 09:07:50
回覆:更新1.我將在CMS中捅一捅,看看我能否找到任何東西。我想在ASP.NET中基於構造函數的注入有一個問題,那就是控件在那個時候變得「不可信」。除非設計師知道如何構建它們。 – Schneider 2009-02-26 09:09:48