2016-08-09 6 views
0

(я уверен, что я отформатировал вопрос плохо, я был бы рад пересмотреть и исправить в зависимости от комментариев)Как преобразовать этот метод статического класса в инъекцию зависимостей? (Специальный код включен)

У меня есть статический класс, и я пытаюсь улучшить дизайн внедрение зависимости. Я не обязательно хочу, чтобы этот класс стал статическим, потому что я буду использовать .NET Core, который продвигает инъекцию зависимостей над ситуациями статического класса.

Упрощенный код в .NET (не основной):

public static class Utils 
    { 
    public static readonly string tokenUrl = ConfigurationManager.AppSettings["tokenUrl"]; 
    public static readonly string tokenKey = ConfigurationManager.AppSettings["tokenKey"]; 

    public async static Task<bool> SendEmail(Email email) 
     { 
      var http = new HttpClient(); 
      http.DefaultRequestHeaders.Add("subscription-key", tokenKey); 

      try 
      { 
       await http.PostAsync(tokenUrl + "email", new StringContent(JsonConvert.SerializeObject(email), Encoding.UTF8, "application/json")); 
      } 
      catch (Exception e) 
      { 
       return false; 
      } 

      return true; 
     } 
    } 

Для ConfigurationManager.AppSettings (он не существует в .NET Ядра), я планирую использовать метод в этой ссылке: http://www.danylkoweb.com/Blog/no-configurationmanager-in-aspnet-core-GC

Однако, для преобразования этого метода (SendMail) в инъекцию зависимостей, я совершенно потерян. Я прочитал много примеров и статей, и я понимаю логику инъекции зависимостей, но я не знаю, как преобразовать этот статический класс в правильную инъекцию зависимостей. Существуют другие методы в том же классе Utils, но это самый простой, и я надеюсь найти других, используя этот.

Подход, который я думал, был выключен:

public interface ISendMail 
{ 
    FormSettings ConfigSettings { get; set; } 

    Task<bool> SendEmail(IOptions<FormSettings> settings, Email email); 

} 

и:

public class SendEmail : ISendMail 
{ 
    public async static Task<bool> SendEmail(IOptions<FormSettings> settings, Email email) 
    { 
     //do same things 
    } 
} 

но я ЯСНО потерял с этим, потому что он даже не имеет смысла. Другой подход, который я думал был:

public class SendEmail 
{ 
    FormSettings ConfigSettings { get; set; } 
    protected Email email = null; 

    public SendEmail(IOptions<FormSettings> settings, Email email) 
    { 
     ConfigSettings = settings.Value; 
     this.email = email; 
    } 

    public async static Task<bool> SendEmailAction() 
    { 
     //do same things with "email" and "ConfigSettings" 
    } 
} 

Я знаю, что я даю много кода здесь, и я не был уверен, что я должен спросить об этом в «Code Review» или что-то. Моя самая большая проблема - неFormSettings часть, но реализующая функциональность SendEmail в формате инъекции зависимостей.

Вскоре, как я могу преобразовать этот класс «SendEmail» в формат, где я могу использовать его с .NET Core без статического класса? Этот конкретный метод не требует изменений в .NET Core, но мои другие методы, поэтому я пытаюсь избавиться от подхода статического класса.

Я могу исключить части tokenUrl и tokenKey и упростить проблему, если это требуется, я просто совершенно потерял, как подойти к этой ситуации.

+0

Я хотел бы упомянуть, что я не уверен, что я думал о том, чтобы включить функциональность в конструктор в первом испытании внедрения инъекций зависимостей, включая интерфейс, но я все равно оставлю это в вопросе, чтобы подчеркнуть, насколько потерян я в настоящее время , –

+1

подумайте об этом с единицы измерения. Как вы могли бы назвать SendEmailAction? Поскольку это по-прежнему статический метод, вам будет сложно называть его, используя макетный экземпляр ISendMail. Если вы создадите единичный тест с макетом для ISendMail, я думаю, что он разъяснит, насколько полезен инъекция зависимостей. – Rake36

ответ

2

Что должен делать этот класс? Отправка электронной почты, не так ли? Таким образом, интерфейс:

public interface IEmailSender 
{ 
    Task<bool> Send(Email email); 
} 

Как мы можем его реализовать? Как это:

public class MyEmailSenderOne : IEmailSender 
{ 
    public static readonly string tokenUrl = ConfigurationManager.AppSettings["tokenUrl"]; 
    public static readonly string tokenKey = ConfigurationManager.AppSettings["tokenKey"]; 

    public async Task<bool> Send(Email email) 
    { 
     var http = new HttpClient(); 
     http.DefaultRequestHeaders.Add("subscription-key", tokenKey); 

     try 
     { 
      await http.PostAsync(tokenUrl + "email", new StringContent(JsonConvert.SerializeObject(email), Encoding.UTF8, "application/json")); 
     } 
     catch (Exception e) 
     { 
      return false; 
     } 

     return true; 
    } 
} 

или

public class MyAnotherAwesomeEmailSender : IEmailSender 
{ 
    public async Task<bool> Send(Email email) 
    { 
     // send with different way 
     return true; 
    } 
} 

Как мы можем придать этому?

public class SomeClass 
{ 
    private IEmailSender _sender; 
    public SomeClass(IEmailSender sender) 
    { 
     _sender = sender; 
    } 

    public void Foo() 
    { 
     // do smth useful 
     _sender.Send(new Email()); 
    } 
} 

UPD.

Поскольку ваши настройки электронной почты устойчивы (не будут меняться в течение жизни), и поскольку эти настройки относятся ТОЛЬКО к вашей реализации IEMailSender, вы должны ввести их в свою реализацию. Подумайте о том, почему код вызывающего абонента (Controller) должен знать о том, как работает ваша реализация? Так

public class MyEmailSenderOne : IEmailSender 
{ 
    private FormSettings _settings; 

    public MyEmailSenderOne(IOptions<FormSettings> settings) 
    { 
     _settings = settings.Value; 
    } 

    public async Task<bool> Send(Email email) 
    { 
     var http = new HttpClient(); 
     http.DefaultRequestHeaders.Add("subscription-key", _settings.tokenApiKey); 

     try 
     { 
      await http.PostAsync(_settings.tokenApiUrl + "email", new StringContent(JsonConvert.SerializeObject(email), Encoding.UTF8, "application/json")); 
     } 
     catch (Exception e) 
     { 
      return false; 
     } 

     return true; 
    } 
} 

И, Теперь контроллер вмятина знает о каких-либо настроек для вашей реализации, и это выглядит как

public class CommunicationsController : Controller 
{ 
    private IEmailSender _sender; 

    public CommunicationsController(IEmailSender sender) 
    { 
     _sender = sender; 
    } 

    public async Task<ActionResult> ContactUsFormSubmit(ContactUs request) 
    { 
      ... 
        request.EmailSent = await _sender.SendEmail(new Email() { TemplateId = 3, Body = JsonConvert.SerializeObject(request) }); 
      ... 
    } 
} 

Как вы можете видеть, контроллер очень чистый и теперь вы можете легко изменить реализацию IEmailSender для любого другого без изменения кода контроллера. Это одно из преимуществ использования DI.

+0

Не могли бы вы проверить мой ответ на вопрос? Я хочу убедиться, что я правильно понял вас и смог правильно ответить на свой вопрос. –

+1

добавлен UPD, пожалуйста, проверьте его. – tym32167

+0

Это прекрасный пример моей ситуации, спасибо за UPD. В этом примере я смог реализовать другие методы в DI. –

0

Основываясь на ответе tym32167, я смог реализовать функциональность IEmailSender (наконец). Я все равно выберу его ответ как правильный ответ, но именно так я реализовал инъекцию зависимостей.

Пожалуйста, прочитайте ссылку, предоставленную мной в вопросе, если вы хотите узнать больше о классе IOptions и FormSettings, который я использую.

Вот интерфейс и класс:

public interface IEmailSender 
    { 

     Task<bool> SendEmail(Email email, FormSettings settings); 

    } 

    public class EmailSender : IEmailSender 
    { 

     FormSettings ConfigSettings { get; set; } 

     public async Task<bool> SendEmail(Email email, FormSettings settings) 
     { 

      var http = new HttpClient(); 
      http.DefaultRequestHeaders.Add("subscription-key", settings.tokenApiKey); 

      try 
      { 
       await http.PostAsync(settings.tokenApiUrl + "email", new StringContent(JsonConvert.SerializeObject(email), Encoding.UTF8, "application/json")); 
      } 
      catch (Exception e) 
      { 
       return false; 
      } 

      return true; 
     } 
    } 

В инъекции контроллера:

public class CommunicationsController : Controller 
    { 

     private IEmailSender _sender; 
     private FormSettings ConfigSettings { get; set; } 

     public CommunicationsController(IEmailSender sender, IOptions<FormSettings> settings) 
     { 
      _sender = sender; 
      ConfigSettings = settings.Value; 
     } 

public async Task<ActionResult> ContactUsFormSubmit(ContactUs request) 
     { 
      ... 
        request.EmailSent = await _sender.SendEmail(new Email() { TemplateId = 3, Body = JsonConvert.SerializeObject(request) }, ConfigSettings); 
      ... 
     } 

здесь FormSettings просто для удобства в случае, если ссылка плашки:

public class FormSettings 
{ 
    public string tokenApiUrl { get; set; } 
    public string tokenApiKey { get; set; } 
} 

Надеюсь, я не пропустил никаких подробностей, до сих пор это не давало мне никаких ошибок, но поскольку у нас нет единицы тестирование в проекте, я не смогу сразу проверить. Пожалуйста, дайте мне знать, если что-то не получилось с ответом.

 Смежные вопросы

  • Нет связанных вопросов^_^