2016-05-12 160 views
26

其他類在這一點上,我的東西注射到我的控制器自如,在某些情況下建設自己的ResolverServices類。 生活不錯依賴注入比控制器類

我想不出怎麼做的就是框架自動注入到非控制器類。什麼工作是有框架自動注入到我的控制器IOptions,這實際上是爲我的項目配置:我想我可以有相同的發生爲我自己的類的我以爲我

public class MessageCenterController : Controller 
{ 
    private readonly MyOptions _options; 

    public MessageCenterController(IOptions<MyOptions> options) 
    { 
     _options = options.Value; 
    } 
} 

關閉時,我模仿的控制器,就像這樣:

public class MyHelper 
{ 
    private readonly ProfileOptions _options; 

    public MyHelper(IOptions<ProfileOptions> options) 
    { 
     _options = options.Value; 
    } 

    public bool CheckIt() 
    { 
     return _options.SomeBoolValue; 
    } 
} 

我想在那裏我失敗的是,當我這樣稱呼它:

public void DoSomething() 
{ 
    var helper = new MyHelper(??????); 

    if (helper.CheckIt()) 
    { 
     // Do Something 
    } 
} 

的proble我已經跟蹤了這個實際上是關於DI在控制器層面談論它的所有事情。我試圖在Controller對象源代碼中尋找它發生的位置,但它在那裏變得有點瘋狂。

我知道我可以手動創建一個IOptions實例並將它傳遞給MyHelper的構造函數,但似乎我應該可以使框架做到這一點,因爲它適用於Controllers

您的幫助表示讚賞。

+3

當您使用依賴注入你不叫'new'。從來沒有爲應該解決的對象 – Tseng

+0

當我試圖創建一個MyHelper的實例,我不叫新? (1)聽起來太容易了,(2)這是一個語法錯誤。 :-) –

+0

是的,這就是依賴注入的全部要點(特別是如果使用控制容器的反轉來管理和實例化)。將服務/類之外的瞬時推送到ioc容器在內部執行的時間點。在無法通過構造函數注入的情況下,您將創建一個工廠並將工廠界面傳遞給您的服務。它的實現使用容器來解決它,在ASP.NET核心案例注入'IServiceProvider'在你的工廠和調用'IMyHelper helper = services.RequestService ()' – Tseng

回答

7

下面是使用DI而沒有任何涉及MVC控制器的工作示例。這是我理解這個過程所需要做的,所以也許它會幫助其他人。

的ShoppingCart對象獲得,通過DI,INotifier的一個實例(通知他們訂單的客戶。)

using Microsoft.Extensions.DependencyInjection; 
using System; 

namespace DiSample 
{ 
    // STEP 1: Define an interface. 
    /// <summary> 
    /// Defines how a user is notified. 
    /// </summary> 
    public interface INotifier 
    { 
     void Send(string from, string to, string subject, string body); 
    } 

    // STEP 2: Implement the interface 
    /// <summary> 
    /// Implementation of INotifier that notifies users by email. 
    /// </summary> 
    public class EmailNotifier : INotifier 
    { 
     public void Send(string from, string to, string subject, string body) 
     { 
      // TODO: Connect to something that will send an email. 
     } 
    } 

    // STEP 3: Create a class that requires an implementation of the interface. 
    public class ShoppingCart 
    { 
     INotifier _notifier; 

     public ShoppingCart(INotifier notifier) 
     { 
      _notifier = notifier; 
     } 

     public void PlaceOrder(string customerEmail, string orderInfo) 
     { 
      _notifier.Send("[email protected]", customerEmail, $"Order Placed", $"Thank you for your order of {orderInfo}"); 
     } 

    } 

    public class Program 
    { 
     // STEP 4: Create console app to setup DI 
     static void Main(string[] args) 
     { 
      // create service collection 
      var serviceCollection = new ServiceCollection(); 

      // ConfigureServices(serviceCollection) 
      serviceCollection.AddTransient<INotifier, EmailNotifier>(); 

      // create service provider 
      var serviceProvider = serviceCollection.BuildServiceProvider(); 

      // This is where DI magic happens: 
      var myCart = ActivatorUtilities.CreateInstance<ShoppingCart>(serviceProvider); 

      myCart.PlaceOrder("[email protected]", "2 Widgets"); 

      System.Console.Write("Press any key to end."); 
      System.Console.ReadLine(); 
     } 
    } 
} 
+4

如果我想在另一個類或方法中實例化'ShoppingCart',那麼我們不訪問'serviceProvider'對象? – rejnev

+0

在這裏有相同的問題 – Casey

+0

謝謝,我不得不搜索太多的ActivatorUtilities.CreateInstance。 –

13

假設MyHelper所使用的MyService這又是使用的控制器。

來解決這種情況的方法是:

  • RegisterMyServiceStartup.ConfigureServicesMyHelper

    services.AddTransient<MyService>(); 
    services.AddTransient<MyHelper>(); 
    
  • 控制器在其構造接收的MyService一個實例。

    public HomeController(MyService service) { ... } 
    
  • MyService構造將依次收到的MyHelper一個實例。

    public MyService(MyHelper helper) { ... } 
    

的DI框架將能解決整個對象圖沒有問題。如果你擔心新的實例被創建的每個對象得到解決的時候,你可以看到不同lifetime and registration options像單或要求壽命。

你應該真的懷疑,當你認爲你必須手動創建一些服務的一個實例,你可能在service locator anti-pattern結束。最好留下創建對象到DI容器。如果你真的發現自己在這種情況下(假設您創建一個抽象工廠),那麼你可以直接使用IServiceProvider(無論是在你的構造請求IServiceProvider或使用一個exposed in the httpContext)。

var foo = serviceProvider.GetRequiredService<MyHelper>(); 

我建議閱讀有關ASP.Net 5 DI框架,對一般依賴注入的具體documentation

+0

我有這個問題是,我使用後臺服務與數據庫交互,所以使用dbcontext的作用域生命週期不起作用,對吧?如何正確使用DI與EF核心和後臺服務? – zuckerthoben

+0

thanx,這對我的場景完全適用 –

3

不幸的是沒有直接的辦法。我設法使它工作的唯一方法是通過創建一個靜態類和使用其他任何地方,如下:

public static class SiteUtils 
{ 

public static string AppName { get; set; } 

    public static string strConnection { get; set; } 

} 

然後在你的啓動類,填充在如下圖所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{ 
    //normal as detauls , removed for space 
    // set my variables all over the site 

    SiteUtils.strConnection = Configuration.GetConnectionString("DefaultConnection"); 
    SiteUtils.AppName = Configuration.GetValue<string>("AppName"); 
} 

雖然這是不好的模式,因爲這會留在應用程序的整個生命週期中,我無法找到更好的方式在控制器之外使用它。