使用Controller类以外的类的依赖注入

Rob*_*sen 56 c# asp.net-core-mvc .net-core asp.net-core

此时我正在轻松地将内容注入到我的控制器中,在某些情况下构建我自己的ResolverServices类.生活很美好.

我无法弄清楚如何做的是让框架自动注入到非控制器类中.框架自动注入我的控制器的工作是什么IOptions,这实际上是我的项目的配置:

public class MessageCenterController : Controller
{
    private readonly MyOptions _options;

    public MessageCenterController(IOptions<MyOptions> options)
    {
        _options = options.Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为我可以在我自己的类中发生同样的情况,我认为当我模仿控制器时我会接近,就像这样:

public class MyHelper
{
    private readonly ProfileOptions _options;

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

    public bool CheckIt()
    {
        return _options.SomeBoolValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想我失败的地方就是我这样称呼它:

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

    if (helper.CheckIt())
    {
        // Do Something
    }
}
Run Code Online (Sandbox Code Playgroud)

我跟踪它的问题实际上是关于DI的所有内容都是在控制器级别讨论它.我试图找到它在Controller对象源代码中发生的位置,但它在那里变得有点疯狂.

我知道我可以手动创建一个IOptions实例并将其传递给MyHelper构造函数,但似乎我应该能够让框架做到这一点,因为它适用于Controllers.

非常感谢您的帮助.

Rob*_*sen 26

下面是一个使用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("admin@store.com", 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("customer@home.com", "2 Widgets");

            System.Console.Write("Press any key to end.");
            System.Console.ReadLine();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我想在另一个我们不访问`serviceProvider`对象的类或方法中实例化`ShoppingCart`,该怎么办? (12认同)
  • @GonzaloBustamante 请随意以我的名字命名一个孩子。(最好是你的一份) (3认同)
  • Thank you, I had to search far too wide to get to ActivatorUtilities.CreateInstance. (2认同)
  • 如果我没有 serviceProvider 怎么办?!! (2认同)
  • 谢谢!我将它与 Microsoft.AspNetCore.TestHost 一起使用,创建一个 TestServer 并调用 ActivatorUtilities.CreateInstance&lt;MyCustomerController&gt;(_server.Host.Services); (2认同)

Dan*_*.G. 22

假设您的控制器MyHelper使用了MyService它.

解决这种情况的方法是:

DI框架将能够毫无问题地解析整个对象图.如果您担心每次解析对象时都会创建新实例,您可以阅读不同的生命周期和注册选项,如单例或请求生命周期.

当您认为必须手动创建某个服务的实例时,您应该非常怀疑,因为您最终可能会在服务定位器反模式中.最好将对象创建到DI容器.如果您确实发现自己处于这种情况(假设您创建了一个抽象工厂),那么您可以IServiceProvider直接使用(IServiceProvider在构造函数中请求一个或使用在httpContext中公开的那个).

var foo = serviceProvider.GetRequiredService<MyHelper>();
Run Code Online (Sandbox Code Playgroud)

我建议阅读有关ASP.Net 5 DI框架的特定文档以及一般的依赖注入.


Ali*_*Ali 5

不幸的是没有直接的方法.我设法使其工作的唯一方法是创建一个静态类并在其他地方使用它,如下所示:

public static class SiteUtils
{

 public static string AppName { get; set; }

    public static string strConnection { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

然后在您的启动类中,填写如下:

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");
}
Run Code Online (Sandbox Code Playgroud)

虽然这是糟糕的模式,因为这将保持应用程序的整个生命周期,我找不到更好的方法在控制器外使用它.