ViewComponent returns but model is null in view when using route value

2.4k Views Asked by At

I'm still new to Razor pages and view components, but have been around the block a few times with ASP.NET.

I'm not sure why my view component doesn't have its model populated. One thing I noticed I had done incorrectly is putting a route parameter at the top; e.g.,

@page "{handler?}"

I know (now at least) that View Components are not intended to be routed to directly as endpoints, but now I'm curious what does using a @page with a route attribute do to prevent the model binding from happening? I only discovered by trial/error that removing this lets my model get populated within the View Component.

Here is the code

ViewComponent

public class TestViewComponent : ViewComponent
{

    public async Task<IViewComponentResult> InvokeAsync(Data.CustomerListModel cust)
    {
        List<Data.CustomerListModel> clist = new List<Data.CustomerListModel>();
        clist.Add(new Data.CustomerListModel() { Customer = "fred" });
        clist.Add(new Data.CustomerListModel() { Customer = "wilma" });

        var dlist = clist.AsEnumerable();

        return View(dlist);
    }
}

View for ViewComponent, Default.html

@page "{handler?}"
@using System.Collections.Generic
@addTagHelper *, TelerikAspnetCoreApp1
@model IEnumerable<Data.CustomerListModel>

<h1>Default</h1>

<h3>Machine name @Environment.MachineName</h3>
<ul>
    @foreach (Data.CustomerListModel c in Model)
    {
        <li>@c.Customer</li>
    }
</ul>

CustomerListModel

namespace TelerikAspNetCoreApp1.Data
{
    public class CustomerListModel
    {
        public string Customer { get; set; }
    }
}

Parent view, Index.cshtml

<div>
    @await Component.InvokeAsync("Test",new { Name = "tester123" })
</div>
3

There are 3 best solutions below

1
On BEST ANSWER

The view of ViewComponent looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. Then @page directive is used in Razor page and it makes the file into an MVC action - which means that it handles requests directly, without going through a controller. @page affects the behavior of other Razor constructs.

You could take aside time to read the MS documentations on the View Component and Razor Pages :

https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.0

https://learn.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-3.0&tabs=visual-studio

0
On

I just had a similar problem. I'm ashamed because it was a brutal rookie mistake. My mistake was that the objects I sent and received respectively were different. I my cshtml I had:

@if (Model is IHasBanner {HasMessage: true } model)
{
    @await Component.InvokeAsync("MessageArea", model)
}

Then in my ViewComponent I had:

public async Task<IViewComponentResult> InvokeAsync(Banner banner)
    => this.View("Default", banner);

And in my View I had:

@if (Model is IHasBanner {HasMessage: true} model)
{
    message = model.Banner.Text;
}

So the mess was perfect!

That's why you have to pay attention to which objects you work with during implementation! What is given, what is received. I was surprised that my Model was null within the View, but it was just a result of my own confusion.

1
On

Don't use @page in the page that you want to be executed by return View(<page_name>, <model>) and the Model property won't be null anymore.