(我确信我严重格式化了这个问题,我很乐意根据评论进行修改和修改)
我有一个静态类,我正在尝试使用依赖注入来改进设计。我不一定希望这个类是静态的,因为我将使用.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 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部分并在需要时简化问题,我对如何处理这种情况感到很遗憾。
答案 0 :(得分: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的优势之一。
答案 1 :(得分: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; }
}
我希望我没有错过任何细节,到目前为止它没有给我任何错误,但由于我们没有在项目中进行单元测试,我将无法立即测试。如果答案遗漏了,请告诉我。