Home > Blockchain >  How can I properly send email (with error) from catch ()?
How can I properly send email (with error) from catch ()?

Time:04-13

I consume an API and now I want to handle possible errors in catch section. What I want to do now is to send email to given user when error is catched. My Email method works fine and sends mails properly. CallAPI method also works fine but when I add Email method to catch section then CallAPI method get highlighted with info that 'not all code paths return a value'. I can't return anything in catch except for sending an email. So how should I properly send email from catch?

CallAPI

private static async Task<T> CallAPI<T>(string endpoint, string accessToken)
{
    try
    {
        var request = new HttpRequestMessage(HttpMethod.Get,
        new Uri(ApiUri, endpoint));

        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        var _httpClient = new HttpClient();

        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();

        var responseStream = await response.Content.ReadAsStreamAsync();
        var responseObject = await JsonSerializer.DeserializeAsync<T>(responseStream);

        return responseObject;
    }
    catch (Exception e)
    {
        await Email(e);

    }
}

Email

private static async Task Email(Exception e)
{
    try
    {
        MailMessage message = new MailMessage();
        SmtpClient smtp = new SmtpClient();
        message.From = new MailAddress("[email protected]");
        message.To.Add(new MailAddress("[email protected]"));
        message.Subject = "Test test";
        message.IsBodyHtml = true;
        message.Body = e.ToString();
        smtp.Port = 25;
        smtp.Host = "mail.yyy.com";
        await smtp.SendMailAsync(message);
    }
    catch (Exception ex) {
        Console.WriteLine(ex.Message);
    }
}

CodePudding user response:

The above answer might work for reference types but I don't suggest it for value types.
Say, if T is an int, default(T) results in 0, which might actually be an acceptable response.
Also, the caller must have a more explicit way to distinguish if the call went in error or not.

With a custom object, such as ResponseBase<T>, you can easily detect that by a simple response.IsSuccess call.

public class ResponseBase<T> {
    public bool IsSuccess { get; set; } = true;
    public T Output { get; set; }
}

private static async Task<ResponseBase<T>> CallAPI<T>(string endpoint, string accessToken) {
    var result = new ResponseBase<T>(); // Added this
    try {
        var request = new HttpRequestMessage(HttpMethod.Get,
        new Uri(ApiUri, endpoint));

        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        var _httpClient = new HttpClient();

        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode(); // Added this

        var responseStream = await response.Content.ReadAsStreamAsync();
        var responseObject = await JsonSerializer.DeserializeAsync<T>(responseStream);

        result.Output = responseObject;
    }
    catch (Exception e) {
        await Email(e);
        result.IsSuccess = false; // Added this
    }

    return result; // Added this
}

CodePudding user response:

You didn't set the return result from your catch scope that you might return generics type from Task<T>

One way you can try to return default(T)

catch (Exception e)
{
    await Email(e);
    return default(T);
}
  •  Tags:  
  • c#
  • Related