0

(I am sure that I formatted the question badly, I would be happy to revise and fix depending on comments)

I have a static class and I am trying to improve the design with dependency injection. I don't necessarily want this class to be static anymore because I will be using .NET Core, which promotes dependency injection over static class situations.

The simplified code in .NET (not 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;
        }
    }

For ConfigurationManager.AppSettings (it does not exist in .NET Core), I am planning to use the method in this link: http://www.danylkoweb.com/Blog/no-configurationmanager-in-aspnet-core-GC

However, for converting this (SendMail) method into a dependency injection, I am quite lost. I have read many examples and articles and I understand the logic of dependency injection but I don't know how to convert this static class into a proper dependency injection. There are other methods in the same Utils class but this is the simplest one and I hope to figure out the others using this one.

An approach that I was thinking off was:

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

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

}

and:

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

but I am CLEARLY lost with this because it does not even make sense. Another approach that I was thinking of was:

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"
    }
}

I know I am giving a lot of code here and I wasn't sure if I should ask about this in "Code Review" or something. My biggest concern is not the FormSettings part but implementing the functionality of SendEmail in a dependency injection format.

Shortly, how can I convert this "SendEmail" class into a format where I can use it with .NET Core, without having a static class? This particular method does not require change with .NET Core but my other methods do, that is why I am trying to get rid of the static class approach.

I can exclude the tokenUrl and tokenKey parts and simplify the problem if requested, I am just quite lost as to how to approach this situation.

2
  • I wanted to mention that I am unsure about what I was thinking putting the functionality into the constructor in my first trial of dependency injection implementation including an interface, I will still leave it in the question just to highlight how lost I am currently. Commented Aug 9, 2016 at 15:00
  • 1
    think of it from a unit testing point of view. How would you call SendEmailAction? Since it's still a static method, you'd have a hard time calling it using a mock instance of ISendMail. If you build yourself a unit test with a mock for ISendMail, I think it will clarify how useful the dependency injection is. Commented Aug 9, 2016 at 15:07

2 Answers 2

2

What should do this class? Sending email, right? So interface:

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

How we can implement it? Like this:

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;
    }
}

or

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

How we can inject this?

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

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

UPD.

Because your email settings persistant (will not change during lifetime), and because this settings related ONLY to your implementation of IEMailSender, you should to inject them in your implementation. Just think about = why caller code (Controller) should know about how your implementation works? So

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;
    }
}

And, controller now dint know about any settings for your implementation, and it looks like

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) });
            ...
    }
}

As you can see, controller is very clean now and you can easily change your implementation of IEmailSender to any other without changing Controller code. This is one of advantages of using DI.

Sign up to request clarification or add additional context in comments.

3 Comments

Could you please check my implementation answer? I want to make sure that I understood you correctly and was able to answer my own question correctly.
added UPD, please check it.
This is a perfect example for my situation, thank you for the UPD. I was able to implement my other methods into DI using this example.
0

Based on tym32167's answer, I was able to implement the IEmailSender functionality (finally). I will still choose his answer as the correct answer but this is how I implemented dependency injection.

Please read the link I provided in the question, if you'd like to know more about the IOptions and FormSettings class that I am using.

Here is the interface and the class:

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;
        }
    }

In controller injection:

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);
            ...
        }

Here is FormSettings just for easy reference in case the link dies:

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

I hope I didn't miss any details, so far it didn't give me any errors but since we do not have unit testing in the project, I won't be able to test immediately. Please let me know if there is something missing with the answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.