Search code examples
razorasp.net-corerazor-pagesasp.net-core-viewcomponent

Can you use ViewComponents with Razor pages?


I have come across what appears to be a limitation with using ViewComponent's in ASP.NET Core 2.0.

We have a ViewComponent that works absolutely perfectly when invoked from a layout page. When we invoke the same ViewComponent from a Razor page we get the following error.

The model item passed into the ViewDataDictionary is of type <viewcomponenttype> but this ViewDataDictionary instance requires a model item of type <parentpagetype>

The ViewComponent seems to expect the model type of the parent Razor page to be passed, rather than the model type defined for the ViewComponent.

I haven't come across any examples of a ViewComponent being used from a Razor page, they only seem to be used from layout pages (which don't have models).

Can someone give me a definitive yes or no to the question: can you use ViewComponent's within a Razor page, and if so, how?


Solution

  • Yes you can, I made a quick example with a hilarious naming.

    View component class - SampleViewViewComponent :)

    namespace NetCoreUI.ViewComponents
    {
        using Microsoft.AspNetCore.Mvc;
        using System.Threading.Tasks;
    
        public class SampleViewViewComponent : ViewComponent
        {
            public async Task<IViewComponentResult> InvokeAsync(Models.TestVm testVm)
            {
                testVm.TestName = "Changing name from ViewComponent.";
    
                return View(testVm);
            }
        }
    }
    

    Default view for this View component:

    @model NetCoreUI.Models.TestVm
    
    <h1>This is viewcomponent.</h1>
    
    <p>@Model.TestId</p>
    <p>@Model.TestName</p>
    

    My Razor page code with not much going on:

    namespace NetCoreUI.Pages.Motorcycle
    {
        using Microsoft.AspNetCore.Mvc.RazorPages;
    
        public class SampleModel : PageModel
        {
            public void OnGet()
            {
    
            }
        }
    }
    

    And finally a Razor page view where I invoke my ViewComponent:

    @page
    @model NetCoreUI.Pages.Motorcycle.SampleModel
    @{
        ViewData["Title"] = "Sample";
    }
    
    <h2>Sample</h2>
    
    <div>
        @await Component.InvokeAsync("SampleView", new { testVm = new Models.TestVm() })
    </div>
    

    I chose to invoke my ViewComponent with a simple new TestVm() class, but this class could be subset inside SampleModel and you could invoke your View Component with that instance of the correct class - the correct class be the one your ViewComponent is referencing.

    This is a really simple example, I'm not sure how your app is structured or perhaps there's a different issue.