0

I ran up against this error and I'm wondering if anyone can help explain why this is happening.
I'm displaying a list of books in a view and everything is displaying properly from the model. However, this code below isn't working:

@foreach (var item in Model.Books)
{
  .. (other unrelevant code is here)...
@{
<!-- Display icon based on the recommendation status -->     
if (item.Recommendation.recName == "Highly Recommended" || item.Recommendation.recName == "Recommended")
{
    <img src="~/Content/Images/check.png" alt="Recommended" title="This book is recommended."/>      
}

if (item.Recommendation.recName == "Parental Judgement")
{
    <img src="~/Content/Images/warning.png" alt="Parental Judgement" title="Parental Judgement required for this book."/>
}

if (item.Recommendation.recName == "NOT Recommended")
{
    <img src="~/Content/Images/stop.png" alt="Not Recommended" title="This book is NOT Recommended!"/>
}
}
.. (other unrelevant code is here)...
}

It should be pretty obvious from the code, but what I'm trying to do is display a different icon based on the recommendation status of each book. When I run that code, it gives me an error saying Object reference not set to an instance of an object.

This is a pretty standard type of error, but I'm confused because the object reference seems to be set, based on the fact that this code works properly and displays the proper value (such as Highly Recommended or Not recommended) for each book:
@Html.DisplayFor(modelItem => item.Recommendation.recName)

So to sum up my specific question: Why is the lambda expression in modelItem => item... working, while the other code for the same exact model isn't working?

And since I'm clearly missing an understanding of something here, let me ask the more general question for this: When is it "legal" to use the @item.property syntax, and when will it result in an error (like I have above)?

S.S.
  • 506
  • 2
  • 15
  • Where is `item` defined? Can you show that code? Also that lambda seems wrong, it'd expect `item = > item.Recommedation.recName`. – juharr May 30 '17 at 02:11
  • Have you sure `item.Recommendation.recName` exists? NRE means that each `item` or `Recommendation` part contains null value which can't be dereferenced (see NRE explanation here: https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it). – Tetsuya Yamamoto May 30 '17 at 02:16
  • @juharr I added in the beginning of the foreach loop. – S.S. May 30 '17 at 02:19
  • Why was the question marked down? And @TetsuyaYamamoto I understand what a NRE is, but `@Html.DisplayFor(modelItem => item.Recommendation.recName) ` works. Doesn't that mean that the `item` or `Recommendation` both truly exists properly? – S.S. May 30 '17 at 02:19
  • Indeed, NRE in `foreach` loop maybe originated from `Model.Books` which trying to dereference null value, common way to avoid NRE is null-checking `Model` in first place, e.g. `@if (Model != null) { foreach (var item in Model.Books) { ... }}` and ensure action method returns collection which already initialized (https://stackoverflow.com/questions/10359319/how-does-one-avoid-a-nullreferenceexception-in-a-foreach-loop-within-a-view-when). – Tetsuya Yamamoto May 30 '17 at 02:29
  • @TetsuyaYamamoto I checked `@if (Model != null) { foreach (var item in Model.Books) { ... }}` and it's not null. It definitely returns the collection, which I knew already because I have plenty of other code which returns the collection from the model. All the code blocks work if they use Html.Helper methods, but this one uses straight @item.property and won't work. – S.S. May 30 '17 at 02:38
  • I suspect it is because of your `@{`that you have immediately after your `@foreach()` statement. Eitherway, I don't suggest you do mix-and-matching, **go for one coding-style and keep it consistent**. – Svek May 30 '17 at 02:42
  • @Svek well there's actually HTML code in between there (which I removed for the sake of this post). If I take out that `@{ ... }`, then it displays the if-loop as plain text without evaluating it. – S.S. May 30 '17 at 02:45
  • Well, even more so a reason not to enclose your HTML in a `@{}` block. My comment means to use `@if()` instead. – Svek May 30 '17 at 02:46
  • @Svek Let me clarify: The HTML is after the @foreach, in standard Razor syntax. I didn't put HTML inside my `@{}` block. But either way, I tried switching to `@if()` like you said, but it didn't make a difference. I appreciate everyone's trying to help though! – S.S. May 30 '17 at 02:51
  • @Sh306 I updated my answer. I meant to go for the `item.Recommendation` type... I'm not with it today – Svek May 30 '17 at 03:10
  • 1
    I don't know the controller method looks like, but often `Model` returns null due to not passing strongly-typed collection with `return View(modelName)`. Note that `ViewBag.Model` is dynamic property, and potentially contains null value if model collection not returned properly. `Model.Books.Recommendation` probably uninitialized at this point and throwing NRE when dereferencing `recName`. – Tetsuya Yamamoto May 30 '17 at 03:12

1 Answers1

4

Null Reference Exception

Based on your description, the evidence points to your item.Recommendation type causing the null reference exception. It appears (without providing us with more information) that it is likely not initialized. Which may explain why your @Html.DisplayFor() is working.

You should consider checking if it is null first.

if(item.Recommendation == null) throw new Exception(" Whoops! :) ");

or on the alternative you could do a Safe Navigational / Null-conditional Operator

item.Recommendation?.recName // which does the work for you inline.

Side Note

I'm not a big fan of nesting / combining the use of @{ } razor code blocks inside other blocks. It can be difficult to read and usually a headache to debug.

@foreach ( ... )
{
    @{
        if( ... )
        {
            <html></html>
        }
    }
}

Versus

@{ var foo = null; } // appropriate for declaring variables, and clean blocks of code.

@foreach ( ... )
{
    @if( ... )
    {
        <html></html>
    }
}
Svek
  • 10,726
  • 4
  • 32
  • 63
  • The type is a string, so it didn't solve the issue. But I appreciate the tip about not the nesting the razor block. What you were saying makes a lot more sense now that it's written out with an example. – S.S. May 30 '17 at 03:02
  • Yup, that did the trick! I got a Whoops :( but at least I know where to work from now. thank you Svek – S.S. May 30 '17 at 03:14