0

Note: To the moderator that incorrectly closed this question, it's completely different from the generic nullref question. This is specific to SendGrid.

I believe I'm following pretty close to documented SendGrid usage:

public async Task<string> SendEmailSendGrid(string emailTo, string subject, string body) {
  var apiKey = SafeTrim(ConfigurationManager.AppSettings["SendGridAPIKey"]);
  var client = new SendGridClient(apiKey);
  var from = new EmailAddress(SafeTrim(ConfigurationManager.AppSettings["SendGridEmail"]));
  var to = new EmailAddress(emailTo);
  var msg = MailHelper.CreateSingleEmail(from, to, subject, string.Empty, body);

  try {
    var response = await client.SendEmailAsync(msg);
    //return response;
    return "SUCCESS";
  } catch (Exception ex) {
    return "ERROR in SendEmailSendGrid(): " + ex.Message;
  }
}

And the caller:

var result = utils.SendEmailSendGrid(decodedEmail, "email test", "This is a test email using SendGrid.");

And the error I get every time EVEN THOUGH IT WORKS and the email actually sends and arrives in my inbox:

Object reference not set to an instance of an object.

That error occurs on this line:

var response = await client.SendEmailAsync(msg);

I verified that all my variables are populated as expected - none are null or empty. I am passing an empty string to the plain text param (because I always want HTML contents), but I also tried passing that some content and it made no difference; same error.

A strange thing: this blows up so hard that my catch block is never entered. Instead, as soon as the exception is thrown, this full-screen window comes up in my VS2022:

enter image description here

So it is working and sending the email, but why the heavy crash? What am I doing wrong?

HerrimanCoder
  • 6,835
  • 24
  • 78
  • 158
  • If the email is sent, then the NRE is probably from deserializing the response. Try disabling Just My Code, enabling source server and sourcelink support, and then observing the exception. If it doesn't break in the SendGrid source code, you should at least have a stack trace. – Stephen Cleary Jan 15 '22 at 22:53
  • If the info in the duplicate is not enough to help you diagnose the mishap then you'll have to ask for help from the people that wrote the code. Click the [new issue button](https://github.com/sendgrid/sendgrid-csharp/issues). – Hans Passant Jan 15 '22 at 23:04
  • I see you do not await the call: `var result = utils.SendEmailSendGrid(decodedEmail, "email test", "This is a test email using SendGrid.");` should be `var result = await utils.SendEmailSendGrid(decodedEmail, "email test", "This is a test email using SendGrid.");`. What are you doing with `result` in your current code? – Peter Bons Jan 16 '22 at 08:35
  • Also, at what line do you get the `Object reference not set to an instance of an object.` exception. What is the call stack? – Peter Bons Jan 16 '22 at 08:36
  • Stephen: Tried those steps, didn't really change anything. Peter: Great catch, but I don't think I can do that because the caller is inside a .net handler's `ProcessRequest()` method. Any ideas? The object reference error occurs on the line that calls `client.SendEmailAsync(msg)`. – HerrimanCoder Jan 16 '22 at 15:08
  • In an event handler you need to change the method signature to `async void`. Then `await` the method call. – Peter Bons Jan 16 '22 at 15:38
  • A workaround: `var response = await client.SendEmailAsync(msg).Result;` ? – Rahul Sharma Jan 16 '22 at 18:29
  • @RahulSharma - No! Never just call `.Result` on an awaitable method. I'm not going to rehash why that's a terrible idea, but would encourage you to do some of your own research so you can understand why that's a terrible recommendation. – Metro Smurf Jan 16 '22 at 18:59
  • @MetroSmurf I looked this up here: https://github.com/sendgrid/sendgrid-csharp/blob/main/TROUBLESHOOTING.md#ui-requests-are-failing--deadlocks and https://github.com/sendgrid/sendgrid-csharp/issues/879 so maybe the recommendation was not correct as it seems – Rahul Sharma Jan 16 '22 at 19:18

1 Answers1

4

The method is awaitable:

public async Task<string> SendEmailSendGrid(...

Yet, the caller is not awaiting the result:

var result = utils.SendEmailSendGrid(decodedEmail, ...

Either await the result:

var result = await utils.SendEmailSendGrid(decodedEmail, ...

Or, if the invoking method is not an async method:

var result = utils.SendEmailSendGrid(decodedEmail, ...).GetAwaiter().GetResult();

Visual Studio is not breaking inside of your try/catch b/c the exception is in the .NET framework by not awaiting the result. You should be able to resolve that by enabling "just my code" in the visual studio debugger settings (IIRC).

Metro Smurf
  • 37,266
  • 20
  • 108
  • 140
  • Metro, you are right, that solved it. Thank you. Though it's disturbing that .net would crash so hard that it can't even enter the catch block. Seems preferable that the .net compiler would simply refuse to compile given that situation. – HerrimanCoder Jan 16 '22 at 23:11
  • 1
    The code compiles. There's nothing preventing one from using the .net framework in a manner that causes a runtime exception, like in your example. There's only so much a compiler can verify. With regards to your specific issue of directly accessing the `.Result` property, there are many methods that will successfully complete without correctly awaiting, it just depends on how fast the method returns the value. – Metro Smurf Jan 16 '22 at 23:41