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