Параметры DI для библиотеки классов без контроллера - PullRequest
0 голосов
/ 17 января 2019

Так что я не уверен, что я что-то упускаю, но в основном каждый пример DI, который я вижу с ядром asp.net, показывает передачу параметров из файла appSettings.json через конструктор в контроллере, а затем во что-нибудь еще.

Можно ли обойти контроллер и просто ввести библиотеку классов напрямую?

Для примера того, что я пытаюсь сделать, скажем, у меня есть appSettings.json с

"EmailSettings":{"smtpServer":"mail.example.com", "port":123, "sendErrorsTo":"errors@example.com"}

Затем библиотека классов для EmailServices

EmailSettings.cs

public class EmailSettings{
   public string smtpServer {get;set;}
   public int port {get;set;}
   public string sendErrorsTo {get;set;}
}

IEmailService.cs

public interface IEmailService
{
   void SendErrorEmail(string method, Exception ex);
}

и EmailService.cs

public class EmailService :IEmailService
{
   private readonly EmailSettings _emailSettings;
   public EmailService(EmailSettings emailSettings)
   {
      _emailSettings = emailSettings;
   }
   public void SendErrorEmail(string method, Exception ex)
   {
      ....
   }
}

Startup.cs в основном приложении ядра asp.net

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
   services.AddScoped<IEmailService, EmailService>(p => {
      return new EmailService(p.GetService<EmailSettings>());
   });
   ...
}

Без загрузки параметров EmailServices или appsetting.json через контроллер, а затем в библиотеку классов BusinessLayer, я хочу иметь возможность вызывать SendErrorEmail из BusinessLayer (или любого другого места).

DoWork.cs

public MakeItWork()
{
   try
   {...}
   catch (exception ex)
   {
      IEmailService.SendErrorEmail("BAL - MakeItWork",ex)
   }
}

Но это просто не с нулевым исключением. DI при запуске не создает EmailService вместо IEmailService, и я собираюсь предположить, что параметров там тоже нет.

Спасибо за любую помощь, которую вы можете оказать.

---- EDIT ----

В итоге я просто переключился на использование AutoFac для DI. Он способен выполнить то, что я искал. Принял ответ ниже, чтобы дать Фантому очки за попытку помочь.

1 Ответ

0 голосов
/ 17 января 2019

Пара вещей:

  • В вашем методе MakeItWork() есть код, который "вызывает" метод с использованием имени интерфейса - даже не уверен, как он будет компилироваться. Вам нужно использовать объект класса, который реализует этот интерфейс, чтобы фактически выполнять вызовы методов во время выполнения. Например, в вашем классе DoWork вы можете иметь конструктор, запрашивающий экземпляр класса, который реализует интерфейс IEmailService, и сохранять его для будущего использования в других методах.

  • Во-вторых, в коллекцию Services вы добавляете зависимость «Scoped» (в методе ConfigureServices). Зависимость "scoped" создается только по запросу (http), обычно через обращения к контроллерам. Исходя из вашего кода и вашего объяснения, похоже, что вы хотите добавить объект Singleton для интерфейса IEmailService. Таким образом, вместо добавления зависимости Scoped используйте AddSingleton - как вы уже сделали, вы также можете создать конкретный объект в вызове AddSingleton - это означает, что этот объект будет предоставляться каждый раз, когда вы его запрашиваете (через конструкторы классов, например). Если вы используете его как синглтон, вы также должны убедиться, что он является потокобезопасным. Кроме того, вы также можете добавить зависимость, используя AddTransient - если вы используете это, каждый раз при запросе будет создаваться новый объект.

Обновление: Пример кода

Измените ваши ConfigureServices, чтобы сделать EmailService как временный (это означает новый объект каждый раз, когда запрашивается эта служба):

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
   services.AddTransient<IEmailService, EmailService>();
   ...
}

Ваш класс "DoWork" должен запросить службу EMail в конструкторе:

public class DoWork()
{

private IEmailService _emailService;

//Dependency should be injected here
public DoWork(IEmailService emailService)
{
    _emailService = emailService;
}


public MakeItWork()
{
   try
   {...}
   catch (exception ex)
   {
      //Use the saved email service object to do your work
      _emailService.SendErrorEmail("BAL - MakeItWork", ex)
   }
}

}

Это не заканчивается здесь. Остается вопрос, как вы собираетесь создать объект класса DoWork. Для этого одной из идей является создание интерфейса для самого класса DoWork, а затем настройка контейнера для этого интерфейса. Затем, где бы вы ни захотели использовать реализацию DoWork, вы можете «запросить» интерфейс для DoWork. Или используйте контейнер напрямую для создания экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...