I am writing a Web API project and for one of my end points (the HandleAsync
method is the implementation) I am unable to use the discard syntax (_
) and I can't figure out why.
I have other places that do this same pattern: call CheckoutFileAsync
and in the processNotifications
delegate I am able to use _
fine when calling SendEmailAsync
.
The only difference is a different entry of IfContentManagementAuthorizedAsync
instead of IfFileActionAuthorizedAsync
, but each has the 'same' concept of an async callback if everything is good in the authorization logic.
The compile error I receive is on this line
_ = emailService.SendEmailAsync(
and this is the error:
Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'bool'
And if I hover over the _
, intellisense says (parameter) bool _
. If I hover over _
where this works, it says (discard) Task<bool> _
.
I basically want a 'fire and forget' mechanism to send out a notification email. I don't want to process the results or wait for any delays that might occur and as I understood it, the discard syntax is the pattern I should be doing. Given the code below, do you see any reason why I couldn't use the discard syntax?
Note, I have two overloads of If*AuthorizedAsync
methods, one returning Task<IActionResult>
and the other returning Task<ActionResult<T>>
because they are used in all my end points which vary their return type and I couldn't figure out how to make one signature work for all end points.
public async Task<IActionResult> HandleAsync( [FromQuery] FileIdParameters parameters )
{
var fileInfo = await GetFilePropertiesAsync<DataLockerFile>( parameters.Id, null );
if ( fileInfo == null )
{
return NotFound();
}
return await IfFileActionAuthorizedAsync(
"Write",
fileInfo.FolderName,
async ( user, userEmail, canCreateFolder ) =>
await CheckoutFileAsync(
userEmail,
fileInfo,
dateTimeService.UtcNow,
fileInfo =>
{
_ = emailService.SendEmailAsync(
string.Join( ";", notificationEmails ),
emailService.DefaultFrom,
$"KAT Management Secure File Checkout: {fileInfo.FolderName}:{fileInfo.Name}",
$"{user} has checked out {fileInfo.FolderName}:{fileInfo.Name}."
);
}
)
);
}
protected async Task<ActionResult<T>> IfFileActionAuthorizedAsync<T>(
string requiredClaim, string folder,
Func<string, string, bool, Task<ActionResult<T>>> validResult )
{
var claimResult = Foo(); // .. logic
return await validResult( claimResult.User, claimResult.UserEmail, claimResult.CanCreateFolder );
}
protected async Task<IActionResult> IfFileActionAuthorizedAsync(
string requiredClaim, string folder,
Func<string, string, bool, Task<IActionResult>> validResult )
{
var claimResult = Foo(); // .. logic
return await validResult( claimResult.User, claimResult.UserEmail, claimResult.CanCreateFolder );
}
protected async Task<IActionResult> CheckoutFileAsync(
string userEmail,
DataLockerBaseFile fileInfo,
DateTime checkoutTime,
Action<DataLockerBaseFile> processNotifications
)
{
var fileInfo = await DoSomethingAsync(); // logic
processNotifications( fileInfo );
return Ok();
}
// This method is part of another class, the smtp configuration object is inject with DI
public async Task<bool> SendEmailAsync( string to, string from, string subject, string body )
{
var message = CreateMailMessage( to, from, subject body );
var mailClient = new SmtpClient( smtp.Server );
mailClient.Credentials = new System.Net.NetworkCredential( smtp.UserName, smtp.Password );
await mailClient.SendMailAsync( message );
return true;
}