'ASP.NET Core 2 - ReSharper "Create Razor View" adds new view to Pages folder

I've started trying out new ASP.NET Core 2 for building an MVC Web App, and it looks good so far...

Except that when I create Views from my controller actions, ReSharper creates them in a Pages folder, rather than the Views folder (where I generally like to keep my Views ;-) )

resharper create razor view view in pages folder

ReSharper doesn't behave this way for regular ASP.NET Web Apps (not core), it puts the views in the correct view folder, so this looks to be to do with Core / Core 2.

What is resharper using to decide where to create the view?

How can I change this behavior so that it creates the views in the traditional location?



Solution 1:[1]

This still applies to the ASP.NET Core Web App (Model-View-Controller) .NET 6 template installed with VS 2022. R# generates views in \Pages by default, which is the wrong location anyway.

With the ResharperConfig.cs (as described above) now R# creates the views in the right place, assuming the View's parent folder exists.

My entity centered Clean Architecture configuration:

using JetBrains.Annotations;

[assembly: AspMvcMasterLocationFormat("~/Views/{1}/{0}.cshtml")]
[assembly: AspMvcViewLocationFormat("~/{1}/Views/{0}.cshtml")]
[assembly: AspMvcPartialViewLocationFormat("~/Views/Shared/{0}.cshtml")]
[assembly: AspMvcAreaMasterLocationFormat("~/Areas/{2}/Views/{1}/{0}.cshtml")]
[assembly: AspMvcAreaViewLocationFormat("~/Areas/{2}/Views/{1}/{0}.cshtml")]
[assembly: AspMvcAreaPartialViewLocationFormat("~/Areas/{2}/Views/Shared/{0}.cshtml")]

This [assembly: AspMvcViewLocationFormat("~/{1}/Views/{0}.cshtml")] makes sure R# generates views in this location: \<Controller>\Views\<Action>.cshtml

You should combine that with a IViewLocationExpander to instruct .NET to also look in the same location to find the views while rendering them:

using Microsoft.AspNetCore.Mvc.Razor;

public class CleanArchViewLocationExpander : IViewLocationExpander
{
    public void PopulateValues(ViewLocationExpanderContext context)
    {
    }

    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        return viewLocations.Select(l => l.Replace("/Views/{1}/", "/{1}/Views/"));
    }
}

Which you then register in Program.cs like this:

builder.Services.Configure<RazorViewEngineOptions>(
    options =>
    {
        options.ViewLocationExpanders.Add(new CleanArchViewLocationExpander());
    });

Happy coding!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1