Search code examples
c#asp.netasp.net-mvcasp.net-corerazor-pages

ViewData is not passed to layout in ASP.NET Core 2.1


Edited

I have an ASP.NET Core 2.1 website which I've scaffolded all of its Identity items. The scaffolding process created a layout file in this location:

/Areas/Identity/Pages/Account/Manage/_Layout.cshtml

As I wanted to use the layout globally, I have moved the layout file (with cut-paste) to this new location:

/Views/Shared/AdminLayout/_Layout.cshtml

Then created a _ViewStart.cshtml file in the first location to use the layout in the 2nd location. The content of _ViewStart file is this:

@{
    Layout = "/Views/Shared/AdminLayout/_Layout.cshtml";
    ViewData["ThisOneWorks"] = "some value";
}

Now the problem is, ViewDatas that I set from scaffolded pages (e.g. SetPassword.cshtml, ExtenalLogins.cshtml, ...) are not working in the layout file. For example ViewData["Title"] is always empty, but the ViewData that I've set in the _ViewStart is working.

The question is, How can I use ViewData from scaffolded identity files when I'm using a layout from the shared view folder?

Edit 1:

It seems the problem is with this line:

ViewData["ThisOneWorks"] = "some value";

When I remove it from the _ViewStart, all other ViewDatas work correctly, but why?


Solution

  • Well , it take me quite a lot of time to reproduce the same issue and debug . And finally , I find out it's a known bug .

    1. In which case will the bug occur ?

    If you try to render a page that has an associated _ViewStart.cshtml , and if you set the ViewData within the ViewStart at the same time , the _Layout.cshtml will not render its ViewData correctly .

    1. The reason why it cannot work .

    In short , the reason is that the ViewData within the Layout is the ViewContext.ViewData , instead of the this.ViewData that you set in your page . See the detailed explanation here

    1. Walkaround

    The bug has been fixed in 2.2.0-preview1, and unfortunately there's no plan to fix it in 2.1.x. If you don't want to update your sdk , you can use the HttpContext.Items . Set Items in your RazorPage :

    @{
        ViewData["Title"] = "Profile";                   // not working
        HttpContext.Items["Title"]="Workaround - Title"; // workaround
    }
    

    render Items in your _Layout:

    <h1>@Context.Items["Title"]----render in layout</h1>