2016-05-12 116 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"); 
} 

虽然这是不好的模式,因为这会留在应用程序的整个生命周期中,我无法找到更好的方式在控制器之外使用它。