(我确信我的问题格式很糟糕,我很乐意根据评论修改和修复)
我有一个静态类,我正试图用依赖注入来改进设计。我不希望这个类是静态的,因为我将使用。net Core,它在静态类情况下促进依赖注入。
.NET中的简化代码(不是Core):
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 Core中),我计划在此链接中使用该方法: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"
}
}
我知道我在这里给出了很多代码,我不确定我是否应该在"代码审查"或其他地方询问这个问题。我最关心的是不是FormSettings部分,而是以依赖注入格式实现SendEmail的功能。
简单地说,我如何将这个"SendEmail"类转换成一种格式,在没有静态类的情况下,我可以在。net Core中使用它?这个特殊的方法不需要改变与。net Core,但我的其他方法做,这就是为什么我试图摆脱静态类方法。
我可以排除tokenUrl和tokenKey部分,并简化问题,如果要求,我只是很失落,如何处理这种情况。
这个类应该怎么做?发邮件,对吧?所以接口:
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());
}
}
乌利希期刊指南。
因为你的电子邮件设置是持久的(在生命周期内不会改变),并且因为这些设置只与你的IEMailSender实现相关,所以你应该将它们注入到你的实现中。想想为什么调用者代码(控制器)应该知道你的实现是如何工作的?所以
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的优点之一。
基于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; }
}
我希望我没有错过任何细节,到目前为止它没有给我任何错误,但由于我们没有在项目中进行单元测试,我将无法立即进行测试。请让我知道,如果有什么东西与答案缺失。