2

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();
}
5
  • I think you're after FirstOrDefault? Commented Sep 24, 2017 at 14:18
  • How did you defined Payments? Commented Sep 24, 2017 at 14:20
  • Hey, don't use Async - check the type of your paymentMate variable. Use sync version or await. Commented Sep 24, 2017 at 14:20
  • Same thing with FirstOrDefault @user12345 Commented Sep 24, 2017 at 14:22
  • you're using the asynchronous version and not awaiting it. Commented Sep 24, 2017 at 14:33

4 Answers 4

8

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();
}
Sign up to request clarification or add additional context in comments.

Comments

0

This is because SingleOrDefaultAsync actually return task. You should do it like this.

public async Task<IActionResult> Success(string token)
{

    var paymentMade = await _context.Payments
        .SingleOrDefaultAsync(m => m.StripeToken == token);

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

    return View();
}

Comments

0

Try FirstOrDefault, instead of SingleOrDefault, if you don't want a list, and depend of the data type of the object paymentMade.

In case you want a list, use .Where(m => m.StripeToken == token).ToList(), and in your if verify paymentMade.Count==0.

Look at this LINQ: When to use SingleOrDefault vs. FirstOrDefault() with filtering criteria.

Comments

0

You're using the async version of SingleOrDefault(): SingleOrDefaultAsync(), and are not "awaiting" it, so what you actually have on your paymentMade variable is an awaitable object, which won't be null no matter what.

There are several ways to go about it:

1- You make your action async and use await, like this:

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

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

    return View();
}

2- You can call the non-async (standard) version of the SingleOrDefault() method and your code would be like this:

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

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

    return View();
}

use the one that fits you best

2 Comments

Your last example is the same as the other one
You still need to remove that await

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.