Nick Nick - 24 days ago 8
C# Question

Linq query NOT returning null when empty

I am using .NetCore 1.1.2. When I use the generated action for the

GET
action, it should return null when it does not find anything on the DB, but the Null validation does not work.

I tried using
Single()
instead of
SingleOrDefault
and using a try catch for the exception thrown but it does not seem an elegant solution.

Maybe it's the .net version?

public IActionResult Success(string token)
{
var paymentMade = _context.Payments
.SingleOrDefaultAsync(m => m.StripeToken == token);

if (paymentMade == null)
{
return NotFound(); //this never gets fired when empty
}

return View();
}

Answer Source

There are two problems with your current approach. One is your choice of method, and the other is that you're trying to use it in a synchronous context even though it is async.

First of all, SingleOrDefaultAsync, like other async methods, does not return any useful value, but rather Task, which is an object that represents the asynchronous operation. To get the result of said operation, you must await it.

To do that, you should either make your method asynchronous or run the task synchronously (not recommended, as it will block the thread until it is done). Alternatively, you can also simply use the synchronous version of the method, SingleOrDefault.

Your method modified to be asynchronous would look something like this:

public async Task<IActionResult> Success(string token)
{
    var paymentMade = await _context.Payments.SingleOrDefaultAsync(m => m.StripeToken == token);

    if (paymentMade == null)
    {
        return NotFound();
    }

    return View();
}

Running the task synchronously looks like this:

public IActionResult Success(string token)
{
    var paymentMade = _context.Payments.SingleOrDefaultAsync(m => m.StripeToken == token).Result;

    if (paymentMade == null)
    {
        return NotFound();
    }

    return View();
}

However, there is another issue you might run into. Depending on the data type, SingleOrDefault and other such methods like FirstOrDefault may never return null. This is the case for all the non-nullable built-in types such as booleans, integers, etc. If you want an alternative that works for all cases, the try-catch is your best bet:

try
{
    var paymentMade =  _context.Payments.First(m => m.StripeToken == token);
}
catch (InvalidOperationException)
{
    return NotFound();
}

If you don't want to do that, then consider splitting things up like so:

var temp = _context.Payments.Where(m => m.StripeToken == token);
if (!temp.Count == 0)
{
    return NotFound();
}