Home > Net >  Asp.Net Core create a controller to send emails using SendGrid
Asp.Net Core create a controller to send emails using SendGrid

Time:06-01

I'm trying to create a controller following this https://www.ryadel.com/en/asp-net-core-send-email-messages-sendgrid-api/ tutorial

I've added everything apart from the controller. What I have as a code in the controller is this

public class SendGridController : BaseApiController
{
    private readonly IEmailSender _emailSender;
    public SendGridController(IEmailSender emailSender)
    {
        _emailSender = emailSender;
        
    }

    [HttpPost]
    [ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
    [ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.Unauthorized)]
    [ProducesResponseType(typeof(string), (int)HttpStatusCode.InternalServerError)]
    public async Task<ActionResult> SendEmail() {
        await _emailSender.SendEmailAsync("[email protected]", "subject", "something");
        return Ok(await _emailSender.SendEmailAsync("[email protected]", "subject", "something"));
    }
}

But I'm getting the following error

Argument 1: cannot convert from 'void' to 'object'

I would like to be able to see the response from send grid if it has sent it or not.

Here is the SendGridEmailSender class:

public class SendGridEmailSender : IEmailSender
{
    public SendGridEmailSender(
        IOptions<SendGridEmailSenderOptions> options
        )
    {
        this.Options = options.Value;
    }

    public SendGridEmailSenderOptions Options { get; set; }

    public async Task SendEmailAsync(
        string email, 
        string subject, 
        string message)
    {
        await Execute(Options.ApiKey, subject, message, email);
    }

    private async Task<Response> Execute(
        string apiKey, 
        string subject, 
        string message, 
        string email)
    {
        var client = new SendGridClient(apiKey);
        var msg = new SendGridMessage()
        {
            From = new EmailAddress(Options.SenderEmail, Options.SenderName),
            Subject = subject,
            PlainTextContent = message,
            HtmlContent = message
        };
        msg.AddTo(new EmailAddress(email));

        // disable tracking settings
        // ref.: https://sendgrid.com/docs/User_Guide/Settings/tracking.html
        msg.SetClickTracking(false, false);
        msg.SetOpenTracking(false);
        msg.SetGoogleAnalytics(false);
        msg.SetSubscriptionTracking(false);

        return await client.SendEmailAsync(msg);
    }
}

CodePudding user response:

You aren't returning the result of the private method you have:

await Execute(Options.ApiKey, subject, message, email);

So, you need to return the result

public async Task SendEmailAsync(
    string email, 
    string subject, 
    string message)
{
    result = await Execute(Options.ApiKey, subject, message, email);
    // do some checks with result
}

If you need to examine the result in your controller code, it would be more tricky, as the signature of the IEmailSender doesn't provide the generic task object, and you need to do it manually (which isn't recommended). You can simply assume that the sending was successful after the method finishes (because in other case you'll get the exception):

public async Task<ActionResult> SendEmail() {
    await _emailSender.SendEmailAsync("[email protected]", "subject", "something");
    // email was sent, no exception
    return Ok();
}

In case you need the response from the method, you can do something like this answer with _emailSender.SendEmailAsync("[email protected]", "subject", "something"), without using await construct (still can't recommend this approach):

/// <summary> 
/// Casts a <see cref="Task"/> to a <see cref="Task{TResult}"/>. 
/// This method will throw an <see cref="InvalidCastException"/> if the specified task 
/// returns a value which is not identity-convertible to <typeparamref name="T"/>. 
/// </summary>
public static async Task<T> Cast<T>(this Task task)
{
    if (task == null)
        throw new ArgumentNullException(nameof(task));
    if (!task.GetType().IsGenericType || task.GetType().GetGenericTypeDefinition() != typeof(Task<>))
        throw new ArgumentException("An argument of type 'System.Threading.Tasks.Task`1' was expected");

    await task.ConfigureAwait(false);

    object result = task.GetType().GetProperty(nameof(Task<object>.Result)).GetValue(task);
    return (T)result;
}
  • Related