如何将此静态类方法转换为依赖注入?(包含特定代码)



(我确信我的问题格式很糟糕,我很乐意根据评论修改和修复)

我有一个静态类,我正试图用依赖注入来改进设计。我不希望这个类是静态的,因为我将使用。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;  }
}

我希望我没有错过任何细节,到目前为止它没有给我任何错误,但由于我们没有在项目中进行单元测试,我将无法立即进行测试。请让我知道,如果有什么东西与答案缺失。

最新更新