programing

Controller 클래스 이외의 클래스를 사용한 종속성 주입

projobs 2021. 1. 16. 09:11
반응형

Controller 클래스 이외의 클래스를 사용한 종속성 주입


이 시점에서 어떤 경우에는 내 자신의 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
    }
}

내가 이것을 추적하는 문제는 실제로 DI에 대해 말하는 모든 것이 컨트롤러 수준에서 말하는 것입니다. 나는 그것이 Controller개체 소스 코드 에서 발생하는 곳에서 사냥을 시도했지만 거기에서는 다소 미쳤습니다.

IOptions의 인스턴스를 수동으로 생성하고 MyHelper생성자에 전달할 수 있다는 것을 알고 있지만 .NET에서 작동하기 때문에 프레임 워크가이를 수행 할 수 있어야하는 것 같습니다 Controllers.

귀하의 도움에 감사드립니다.


다음은 MVC 컨트롤러를 포함하지 않고 DI를 사용하는 작업 예입니다. 이것이 제가 그 과정을 이해하기 위해해야 ​​할 일입니다. 그래서 아마도 다른 사람에게 도움이 될 것입니다.

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();
        }
    }
}

Let's say MyHelper is used by MyService which in turn is used by your controller.

The way to resolve this situation is:

  • Register both MyService and MyHelper in Startup.ConfigureServices.

    services.AddTransient<MyService>();
    services.AddTransient<MyHelper>();
    
  • The controller receives an instance of MyService in its constructor.

    public HomeController(MyService service) { ... }
    
  • MyService constructor will in turn receive an instance of MyHelper.

    public MyService(MyHelper helper) { ... }
    

The DI framework will be able resolve the whole object graph without problems. If you are worried about new instances being created every time an object is resolved, you can read about the different lifetime and registration options like the singleton or request lifetimes.

You should be really suspicious when you think you have to manually create an instance of some service, as you might end up in the service locator anti-pattern. Better leave creating the objects to the DI Container. If you really find yourself in that situation (let's say you create an abstract factory), then you could use the IServiceProvider directly (Either request an IServiceProvider in your constructor or use the one exposed in the httpContext).

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

I would recommend reading the specific documentation about the ASP.Net 5 DI framework and about dependency injection in general.


Unfortunately there is no direct way. The only way I managed to make it work is by creating a static class and using that everywhere else as below:

public static class SiteUtils
{

 public static string AppName { get; set; }

    public static string strConnection { get; set; }

}

Then in your startup class, fill it in as below:

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");
}

Although this is bad pattern, as this will stay for the whole life cycle of the application and I couldn't find better way to use it outside controller.


Here's a more complete example to directly answer the OP's question, based on the current .NET Core 2.2 DI documentation here. Adding this answer since it may help someone that's new to .NET Core DI, and because this question is Google's top search result.

First, add an interface for MyHelper:

public interface IMyHelper
{
    bool CheckIt();
}

Second, update the MyHelper class to implement the interface (in Visual Studio, press ctrl-. to implement the interface):

public class MyHelper : IMyHelper
{
    private readonly ProfileOptions _options;

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

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

Third, register the interface as a framework-provided service in the DI service container. Do this by registering the IMyHelper service with the concrete type MyHelper in the ConfigureServices method in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddScoped<IMyHelper, MyHelper>();
    ...
}

Fourth, create a private variable to reference an instance of the service. Pass the service as an argument in the constructor (via constructor injection) then initialize the variable with the service instance. Reference any properties or call methods on this instance of the custom class via the private variable.

public class MessageCenterController : Controller
{
    private readonly MyOptions _options;
    private readonly IMyHelper _myHelper;

    public MessageCenterController(
        IOptions<MyOptions> options,
        IMyHelper myHelper
    )
    {
        _options = options.value;
        _myHelper = myHelper;
    }

    public void DoSomething()
    {
        if (_myHelper.CheckIt())
        {
            // Do Something
        }
    }
}

ReferenceURL : https://stackoverflow.com/questions/37189984/dependency-injection-with-classes-other-than-a-controller-class

반응형

'programing' 카테고리의 다른 글

Swagger로 정적 문서 생성  (0) 2021.01.16
jQuery .data ()는 어떻게 작동합니까?  (0) 2021.01.16
Powershell을 사용한 Vim  (0) 2021.01.16
MOQ 문서는 어디에 있습니까?  (0) 2021.01.16
ASP.NET MVC 3 Razor 설명서  (0) 2021.01.16