![](/img/trans.png)
[英]Injecting different dependencies with Simple Injector depending on assembly
[英]Injecting IUrlHelper with Simple Injector
我正在使用Simple Injector開發一個ASP.NET Core應用程序,用於依賴注入任務。 我正在尋找一種方法將IUrlHelper
注入控制器。 我知道IUrlHelperFactory
,但更喜歡直接注入IUrlHelper
來保持模擬更簡單和更簡單。
以下問題為通過標准ASP.Net依賴注入注入IUrlHelper
提供了有用的答案:
根據這些答案,我想出了一個類似的SimpleInjector注冊:
container.Register<IUrlHelper>(
() => container.GetInstance<IUrlHelperFactory>().GetUrlHelper(
container.GetInstance<IActionContextAccessor>().ActionContext));
它確實有效,但由於IActionContextAccessor.ActionContext
在沒有活動的HTTP請求時返回null
,因此在app啟動期間調用此綁定會導致container.Verify()
失敗。
(值得注意的是,來自鏈接問題的ASP.Net DI注冊也可以通過交叉布線工作,但遇到同樣的問題。)
作為一種解決方法,我設計了一個代理類......
class UrlHelperProxy : IUrlHelper
{
// Lazy-load because an IUrlHelper can only be created within an HTTP request scope,
// and will fail during container validation.
private readonly Lazy<IUrlHelper> realUrlHelper;
public UrlHelperProxy(IActionContextAccessor accessor, IUrlHelperFactory factory)
{
realUrlHelper = new Lazy<IUrlHelper>(
() => factory.GetUrlHelper(accessor.ActionContext));
}
public ActionContext ActionContext => UrlHelper.ActionContext;
public string Action(UrlActionContext context) => UrlHelper.Action(context);
public string Content(string contentPath) => UrlHelper.Content(contentPath);
public bool IsLocalUrl(string url) => UrlHelper.IsLocalUrl(url);
public string Link(string name, object values) => UrlHelper.Link(name, values);
public string RouteUrl(UrlRouteContext context) => UrlHelper.RouteUrl(context);
private IUrlHelper UrlHelper => realUrlHelper.Value;
}
然后有標准注冊...
container.Register<IUrlHelper, UrlHelperProxy>(Lifestyle.Scoped);
這有效,但讓我有以下問題:
第二點:MVC架構師顯然希望我們注入IUrlHelperFactory
,而不是IUrlHelper
。 這是因為在創建URL Helper時需要HTTP請求(請參閱此處和此處 )。 我提出的注冊確實掩蓋了這種依賴關系,但是沒有從根本上改變它 - 如果無法創建一個幫助器,我們可能只會拋出異常。 我錯過了一些比我意識到的更危險的東西嗎?
根據這些答案,我想出了一個類似的SimpleInjector注冊:
container.Register<IUrlHelper>( () => container.GetInstance<IUrlHelperFactory>().GetUrlHelper( container.GetInstance<IActionContextAccessor>().ActionContext));
它確實有效,但由於
IActionContextAccessor.ActionContext
在沒有活動的HTTP請求時返回null,因此在app啟動期間調用此綁定會導致container.Verify()
失敗。
這里的根本問題是IUrlHelper
的構造需要運行時數據,並且在構造對象圖時不應使用運行時數據。 這與將運行時數據注入組件的代碼氣味非常相似。
作為一種解決方法,我設計了一個代理類......
我不考慮代理是一個解決辦法都沒有 。 就像我看到的那樣,你幾乎把它釘了起來。 代理(或適配器)是推遲創建運行時數據的方法。 我通常會使用適配器並定義特定於應用程序的抽象,但在這種情況下這會適得其反,因為ASP.NET Core在IUrlHelper
上定義了許多擴展方法。 定義自己的抽象可能意味着必須創建許多新方法,因為您可能需要其中的幾個。
有更好/更簡單的方法嗎?
我不認為有,雖然您的代理實現可以在不使用Lazy<T>
:
class UrlHelperProxy : IUrlHelper
{
private readonly IActionContextAccessor accessor;
private readonly IUrlHelperFactory factory;
public UrlHelperProxy(IActionContextAccessor accessor, IUrlHelperFactory factory)
{
this.accessor = accessor;
this.factory = factory;
}
public ActionContext ActionContext => UrlHelper.ActionContext;
public string Action(UrlActionContext context) => UrlHelper.Action(context);
public string Content(string contentPath) => UrlHelper.Content(contentPath);
public bool IsLocalUrl(string url) => UrlHelper.IsLocalUrl(url);
public string Link(string name, object values) => UrlHelper.Link(name, values);
public string RouteUrl(UrlRouteContext context) => UrlHelper.RouteUrl(context);
private IUrlHelper UrlHelper => factory.GetUrlHelper(accessor.ActionContext);
}
IActionContextAccessor
和IUrlHelperFactory
都是單例(或者至少,它們的實現可以注冊為singleton),因此您也可以將UrlHelperProxy
注冊為singleton:
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelper, UrlHelperProxy>();
ActionContextAccessor
使用AsyncLocal
存儲在請求期間存儲ActionContext
。 IUrlHelperFactory
使用ActionContext
的HttpContext
在該請求期間緩存創建的IUrlHelper
。 因此,對同一請求多次調用factory.GetUrlHelper
會導致在該請求期間返回相同的IUrlHelper
。 這就是您不需要在代理中緩存IUrlHelper
的原因。
另請注意,我現在在IActionContextAccessor
注冊了IActionContextAccessor
和IUrlHelper
,而不是Simple Injector。 這表明當使用內置容器或任何其他DI容器時,此解決方案也可以正常工作 - 而不僅僅是使用Simple Injector。
這只是一個壞主意嗎?
絕對不。 我甚至想知道為什么這樣的代理實現沒有被ASP.NET核心團隊開箱即用。
MVC架構師顯然希望我們注入IUrlHelperFactory,而不是IUrlHelper。
這是因為那些架構師意識到不應該使用運行時數據構建對象圖。 這實際上也是我過去與他們討論過的事情。
我在這里看到的唯一風險是你可以在沒有web請求的上下文中注入IUrlHelper
,這將導致使用代理拋出異常。 但是,當你注入一個IActionContextAccessor
時,這個問題也存在,所以我覺得這沒什么大不了的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.