The Model-View-Controller pattern is so common that every technology stack has an implementation of it. ASP.NET developers have been working with the pattern since 2009. Here are a few other things popular in 2009 to remind you of your rapid decay: The Hannah Montana Movie, FarmVille, Black Eyed Peas, and Avatar the Movie. But like everything, there’s a moment to reflect on our decisions and choose a different approach. For ASP.NET Core developers, that introspection might lead them to move away from the MVC style towards the pattern of Feature Folders.

In this post, we’ll quickly discuss the Feature Folders pattern and how you can get your JetBrains tooling of JetBrains Rider or ReSharper to play nicely with your newly adopted approach.

What Are Feature Folders?

In an MVC controller, you’ll typically have a folder structure style that spreads the three parts of the MVC pattern across similarly labeled folders. When working with ASP.NET Core, you have a Views and Controllers folder, and developers typically choose a “Models” folder or might even create a Core project to hold implementations. While this approach is popular, it can lead to solution sprawl, where it takes the developer looking in multiple locations to create a single feature.

Feature Folders states that it makes more sense to include all the MVC elements in a clearly labeled folder for each unique feature of a web application. For example, a “login” feature would include the controller, the model and view models, and the Razor views for that feature. Having everything organized in a single folder helps developers reduce sprawl, makes it easier to manage features, and ultimately helps teams organize around a feature mindset.

Like all styles, it’s up to you and your team whether these benefits materialize and whether you think they work.

The one drawback to this style change is that it’s typically not understood by .NET tooling by default. Have no fear. We’re about to fix that.

JetBrains Annotations and Views

So, you’ve decided to start using Feature Folders. Great! The first step is to start moving your files around in your solution. From the root of your web application, the Features folder will likely look something like this

- Features
  - _ViewStart.cshtml
  - Home
    - HomeController.cs
    - Index.cshtml
    - Privacy.cshtml

We have a Home feature responsible for showing the homepage and associated content.

The next step is to tell ASP.NET Core MVC how to find the new location of the relocated views. We can do that by configuring the RazorViewEngineOptions instance.

// feature folders  
builder.Services.Configure<RazorViewEngineOptions>(rvo =>  
{  
    rvo.ViewLocationFormats.Add("~/Features/{1}/{0}.cshtml");  
});

Note you may need more entries than a single one, depending on your implementation of Feature Folders.

That’s it! JetBrains Rider and ReSharper should start finding your new views. You might be asking yourself, well, how?

If we look at the documentation within JetBrains Rider, you’ll see an External Annotation of AspMvcViewLocationFormat added to the ViewLocationFormats collection.

[AspMvcViewLocationFormat(...)] 
public IList<string> ViewLocationFormats { get; }

This tells JetBrains Rider that this collection and any item added to it contains view locations. Registering a new location tells ASP.NET Core MVC and our JetBrains tools where to find the new Feature Folder views.

What do you do if you use a NuGet library for Feature Folders? You can do one of two things:

  1. Use External Annotations if possible
  2. Use JetBrains Annotations in your web project

I recommend using the JetBrains.Annotations package, as it’s much more straightforward. As seen previously, JetBrains Rider and ReSharper use these annotations to get more information about your codebase to enable features. You can also apply these attributes at the assembly level. In this case, we’ll tell the ReSharper engine where to find views. Once the JetBrains package is installed, add the following line anywhere in your solution.

[assembly: AspMvcViewLocationFormat("~/Features/{1}/{0}.cshtml")]

This string matches the same ViewLocationFormat we added in our registration. Add as many of these attributes as it takes to match the library you’re using. JetBrains tooling should now show no errors and let you navigate directly to matching views from a controller.

Conclusion

JetBrains tooling is world-class, and the developers have ingeniously created flexibility to give you the power to develop apps how you want to. By using methods or assemblies decorated with the AspMvcViewLocationFormat attribute, you can guide the tools to the views your application uses.

As always, thanks for reading and I hope this post helped you make your development experience that much better.