Search code examples
asp.net-coreasp.net-identityrazor-pages

ASP.NET Core 3.0 - Identity UI Manage folder not receiving layout


I have Identity scaffolded out in accordance with the documentation, and everything works properly except for the layout of the /Manage folder. The directory setup is exactly as it gets scaffolded.

Directory setup with all misc. files removed

For clarity's sake: /Areas/Identity/Pages/Account/Manage is the problem folder.

/Pages Contains the _ViewStart file which sets the Layout from my Views/Shared folder.
/Pages/Account Receives the layout from _Viewstart and works properly.
/Pages/Account/Manage Everything in here only receives the _ViewStart layout. The _Layout file in here isn't automatically found by the pages inside of it.

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

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Manage your account</h1>

<div>
    <h4>Change your account settings</h4>
    <hr />
    <div class="row">
        <div class="col-md-3">
            <partial name="_ManageNav" />
        </div>
        <div class="col-md-9">
            @RenderBody()
        </div>
    </div>
</div>

@section Scripts {
    @RenderSection("Scripts", required: false)
}

This is exactly as it gets scaffolded in and the layout only breaks when you change AddDefaultIdentity() to AddIdentity(). I work with a reference I scaffolded and it just leads me to believe I'm not accounting for something when removing the default UI. The only workaround I found was manually setting the layout of each .cshtml file within /Manage

@{
    Layout = "_Layout";
}

This fixes everything and causes the layout to work properly for the pages inside of /Manage. I read the documentation and it states that each Razor Page controller should search its own folder for a _Layout file before searching elsewhere. Is there a reason it isn't detecting the file?


Solution

    1. "The only workaround I found was manually setting the layout of each .cshtml file within /Manage":

      You don't have to do that. Simply create a _ViewStart.cshtml under your Manage/ foler:

      @* file: Manage/_ViewStart.cshtml *@
      @{
          Layout = "_Layout";    // Use a partial layout name instead of absolute name
      }
      

      Also be careful that the default Manage/Layout.cshtml uses a parent layout of /Areas/Identity/Pages/_Layout.cshtml which might not exist in your scaffolded files :

      @* file: Manage/Layout.cshtml *@
      @{
          Layout = "/Areas/Identity/Pages/_Layout.cshtml";  // you might want to change this to `/Views/Shared/_Layout.cshtml`
      }
      
    2. "it states that each Razor Page controller should search its own folder for a _Layout file before searching elsewhere"

      That's true only when you're using a partial _Layout name. However, if you're using an absolute name that starts with a slash, it will use that layout directly. See official docs :

      When a partial name is provided, the Razor view engine searches for the layout file using its standard discovery process. The folder where the handler method (or controller) exists is searched first, followed by the Shared folder. This discovery process is identical to the process used to discover partial views.

      In your case, the layout name /Areas/Identity/Pages/_Layout.cshtml, which starts with a /, is not a partial name. That's the reason why your pages cannot discover the layout. In order to fix this issue, using a partial name _Layout instead. (This can be done by a single _ViewStart.cshtml file as I do above, don't add it for every page)

    3. Finally, you might wonder why it renders normally when using AddDefaultIdentity(). As you find out, the AddDefaultIdentity() will add the default UI, which eventually invokes the AddRelatedParts() method. This allows that it fallbacks to the default UI when there's no such a layout or page. e.g., when you scaffold Identity with Visual Studio, it offers a list which you can use to override the default pages. The above /Areas/Identity/Pages/_Layout.cshtml comes from the default UI.