Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does async await throw a NullReferenceException?

My code looks something like this

var userStartTask = LroMdmApiService.AddUser(user);
 // .... do some stuff
await userStartTask;

When AddUser() throws an exception, it bubbles up as a NullReferenceException. It doesn't wait for await.

But if I structure the code like this...

var result = await LroMdmApiService.AddUser(user);

Then exceptions get caught properly. Can someone tell me what's going on here?

Here is complete code that shows the issue. What is the best practice for such a scenario?

class Program
{
    private static void Main(string[] args)
    {
        CallAsync();
        Console.ReadKey();
    }

    public static async void CallAsync()
    {
        var task = CallExceptionAsync();
        ThrowException("Outside");
        await task;
    }

    public static Task CallExceptionAsync()
    {
        return Task.Run(() =>
        {
            ThrowException("Inside");
        });

    }

    public static void ThrowException(string msg)
    {
        throw new Exception(msg);
    }        
}
like image 394
Anish Avatar asked Sep 01 '15 16:09

Anish


People also ask

Why am I getting a NullReferenceException?

This error is caused when an object is trying to be used by a script but does not refer to an instance of an object. To fix this example we can acquire a reference to an instance of the script using GameObject.

How do I stop NullReferenceException?

The Null Reference Exception is not a major error, but one of the common ones and one of the basic and simple way to avoid the Null Reference Exception is to check the variable or property before moving ahead and accessing it. And a very basic way to do this is to check the variable within an if statement.

How do I fix NullReferenceException in C#?

Solutions to fix the NullReferenceException To prevent the NullReferenceException exception, check whether the reference type parameters are null or not before accessing them. In the above example, if(cities == null) checks whether the cities object is null or not.

What is a NullReferenceException?

A NullReferenceException exception is thrown when you try to access a member on a type whose value is null . A NullReferenceException exception typically reflects developer error and is thrown in the following scenarios: You've forgotten to instantiate a reference type.


2 Answers

This code

var result = await LroMdmApiService.AddUser(user);

is practically identical to this code:

var task = LroMdmApiService.AddUser(user);
var result = await task;

When AddUser() throws an exception, it bubbles up as a NullReferenceException. It doesn't wait for await.

AddUser probably looks like this (where _service is null):

public static Task AddUser(User user)
{
  return _service.AddUser(user);
}

This will cause a NullReferenceException to be thrown directly, not placed on the returned task.

If you always want your exceptions to be placed on the returned tasks, then make every task-returning method async:

public static async Task AddUser(User user)
{
  return await _service.AddUser(user);
}

However, you should consider whether you really want to do that. NullReferenceException in particular is a code bug; it's not an exception you should ever catch or care about in production. To use Eric Lippert's term, it's a boneheaded exception.

In my opinion, it doesn't matter where boneheaded exceptions are thrown - whether they're thrown directly or placed on a task - because these exceptions are only for the developer, not runtime.

like image 100
Stephen Cleary Avatar answered Sep 21 '22 11:09

Stephen Cleary


I found the cause. Two exceptions were getting called. Before await and inside the task. The first ended the thread and returned execution back to the caller. So when the 2nd exception (from the task) was raised, it had no parent thread.

var userStartTask = LroMdmApiService.AddUser(user); //1) An exception was being thrown inside AddUser()
 // .... do some stuff 2) And another exception was being thrown here
await userStartTask;

Exception thrown inside killed my app with the NullReferenceException bec/ the method it was called from no longer existed.

Since everybody is asking for examples, here is a simple example which shows the same issue.

class Program
{
    private static void Main(string[] args)
    {
        CallAsync();
        Console.ReadKey();
    }

    public static async void CallAsync()
    {
        var task = CallExceptionAsync();
        ThrowException("Outside");
        await task;
    }

    public static Task CallExceptionAsync()
    {
        return Task.Run(() =>
        {
            ThrowException("Inside");
        });

    }

    public static void ThrowException(string msg)
    {
        throw new Exception(msg);
    }        
}
like image 44
Anish Avatar answered Sep 20 '22 11:09

Anish