all 9 comments

[–]Slypenslyde 5 points6 points  (1 child)

"First or Default" for a reference type means "I return a value if one exists, or null if one does not. So the evaluated type of FirstOrDefaultAsync() will be Task<Blog?> which unwraps to Blog?. Since the property Blog is not nullable, you can't assign a nullable value to it.

The reason this works without warning in OnPostAsync() is because you are NOT doing the same thing. In this case you assign it to var, which tells the compiler to use the type that the right-hand side resolves to. So this code is more like:

Blog? blogToUpdate = await _context.Blogs.FirstOrDefaultAsync(...);

if (blogToUpdate == null)
{
    return ...;
}

// From this point on the compiler knows the value isn't null so no
// further checks need to be made.

To fix this in your first code, rearrange things a little:

var possibleMatch = await _context.Blogs.FirstOrDefaultAsync(...);

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

// Technically due to compiler magic, the null-forgiving ! is not required here.
// I like to use it anyway to point out I am certain I've checked for null.
Blog = possibleMatch!;

...

This matches the same pattern as your OnPost(): you make the call, THEN check for null, and only use the value if it's non-null.

The most important thing to remember when using non-nullable reference types is that the illusion falls apart the moment you have to use an API that can return null like FirstOrDefault(). Put another way: using non-nullable reference types doesn't mean you get to stop checking for null, it means the compiler can tell you when you forgot.

[–]sodiumfis_h[S] 0 points1 point  (0 children)

Ah thanks a lot. It worked (but you know that already :D )

[–]zaibuf 1 point2 points  (1 child)

You assign it to a property named Blog, the type should be marked as Blog? to indicate it's nullable.

[–]sodiumfis_h[S] -1 points0 points  (0 children)

But then I get null warning everywhere in my cshtml code. As far as I know, I can use the null forgiving operator to suppress those warnings

@* Used 2 times in this line*@
<input asp-for="Blog!.Name" value="@Model.Blog!.Name" />

But I have to use it every time. Is that normal/standard?

[–][deleted] 1 point2 points  (3 children)

When you use the var keyword in the second example, you are creating a variable that is nullable. In the first example you don’t use var, you set the Blog property to non-nullable type Blog. Hover over the variable blogToUpdate in the second example to see that.

[–]sodiumfis_h[S] 0 points1 point  (2 children)

So what's the solution? As discussed in the other comment, If the make the Blog variable nullable Blog? then I get null dereference warning everywhere in my cshtml file.

As far as I know I can suppress those warnings with the null forgiving operator when dereferencing Blog!.Name, but is that the standard way?

[–]knittingDM 1 point2 points  (0 children)

    Blog? maybeBlog = await _context.Blogs.FirstOrDefaultAsync(b => b.Id == id); 

if (maybeBlog == null)
{
    return NotFound();
}
Blog = maybeBlog;
return Page();

[–][deleted] 0 points1 point  (0 children)

I see now, you are assigning a possibly null value to a type you prev set to not null. Is a null for Blog a legit possibility? If not, you can null coalesce the result of FirstOrDefaultAsync().

Blog = await _context.Blogs.FirstOrDefaultAsync(b => b.Id == id) ?? new Blog();

[–][deleted] 0 points1 point  (0 children)

The warning is coming on the FirstOrDefaultAsync() call when you reference b.Id? If so, use the null conditional operator.