Search code examples
c#asp.net-corerazorasp.net-core-mvc

Bizarre behavior when receiving a Model (with a IEnumerable property) from controller


I'm facing an odd behavior. Keeping it simple, I've got this method within a controller

public async Task<IActionResult> IndexAsync()
{
   var user = await userManager.GetUserAsync(this.User);

   var userEvents = context.Events
       .Where(e => e.AppIdentityUserId == user.Id)
       .AsEnumerable();

   return View(userEvents);
}

and this model:

public class Event
{
    //other properties
    public IEnumerable<Participant> ParticipantsList { get; set; }
}

When my View receives that model, ParticipantsList is null. So I write a test query, to observe what is happening.

foreach (var event in userEvents)
    test = context.Participants.Where(p => p.EventId == event.Id).AsEnumerable();

The query successfully retrieves that info

test successful results

And this happens

list now filled

So, this time, I add a breakpoint to each iteration of foreach loop, expanding test results in each break, except last

only the lists which the corresponding test I expanded have results now

As you can see, it only fills when I expand the corresponding test. And if I expand the event results before test, the list remains null.

I'd like to understand why is it happening, so that I can fix this and any related problem in the future.

I hope I managed to clarify what's going on. It proved to be a challenge to do so properly.


Solution

  • IEnumerable<T> is lazily evaluated. If nothing iterates it, the implementation of IEnumerable<T> does not execute.

    By evaluating the value in your debugger, you cause that code to run.

    If you wish to always materialize your database query, regardless of whether the result is actually used, replace .AsEnumerable() with .ToArray() or .ToList().

    As for why it seems to be null in your view, this answer may provide guidance.