I’ve been working a lot with ASP.NET 5 and Visual Studio 2015, creating many new projects for samples for blog articles and content on the official documentation site (docs.asp.net). There are a couple of things that continue to irk me about the built-in templates, causing friction with each new sample (or production) project I create. My hope is that by sharing them here, others in the community will either confirm to Microsoft that these are legitimate concerns, or let me know that I’m just being a curmudgeon and I should deal with it. Time will tell.
Create a new ASP.NET 5 web project in Visual Studio 2015 and select the Web Application template from the ASP.NET 5 Preview Templates, as shown:
Next, open the Models folder, in Solution Explorer:
The first thing you’ll notice here is that there are several kinds of models in the folder. There are two files containing ViewModels, and there is one file containing (in theory) IdentityModels. These two kinds of models have nothing to do with one another in an MVC architecture, and so right away there’s a problem with Separation of Concerns in this folder. The M in MVC stands for the Model, which is a model of the application. Controllers interact with the Model, delegating decisions to classes contained in the Model. Controllers should make very few decisions, and the decisions they do make should be related to their level of abstraction, which is the user interface. Controllers return a View, and need to pass into the view any state that is required for the view to be rendered correctly. Some views require no state, others can render with a string literal or two passed in a ViewData collection. However, more complex views can benefit from having a strongly typed ViewModel passed into them. A ViewModel in this context is separate from the Model that was used by the controller, and should contain little or no behavior, just a collection of properties to be displayed by the View. It should be clear now that the ViewModel and Model types in the application should not be located together.
Recommendation 1: Move ViewModels to their own folder.
Ideally, each View that requires a ViewModel should have its own ViewModel tailored specifically to what it needs to display, rather than trying to have a one-viewmodel-fits-all approach. As such, the application may have quite a few ViewModels, and it may make sense to group them together by controller, to match the structure of the Views folder. Some developers prefer to group classes in their MVC projects by feature, which also works. In any case, I generally prefer to have one file per class, rather than many classes within a file, and this matches StyleCop’s recommendation and most .NET coding style guides I have worked with. If this means you end up with a lot of files, so be it. That’s a solved problem and the reason why folders and namespaces exist.
Recommendation 2: Use folders, not files, to group related classes.
Following the recommendations so far, the project structure would look like this – still very clean:
Returning to the Models folder, we still have the IdentityModels.cs file to contend with. Following the same one class per file rule, the first thing to do is to split up the ApplicationUser and ApplicationDbContext classes.
Recommendation 3: Put ApplicationUser and ApplicationDbContext in separate files.
Visual Studio 2015 has some great code visualization and clean up features. It will show whether a given namespace is needed, and with a single key combination (ctrl-., enter), it will remove unnecessary using statements. The default template has a ton of unnecessary using statements cluttering up its files, and these files would be smaller and easier to read if these were removed. Here’s what the ApplicationDbContext class looks like currently (click to enlarge):
And here it is after:
Recommendation 4: Remove unnecessary using statements from all classes in the project.
At this point, things are looking pretty good. The last thing I would do, though, is move the ApplicationDbContext class out of the Models folder. Generally, I’m going to use separate projects for any real application I build, following N-Tier and DDD best practices (which you can learn more about from my Pluralsight courses on these subjects). However, even if I’m only going to be using a single project, I would still want to put my data access logic into a separate location than my domain model. So, the last thing I would do is move ApplicationDbContext into another folder, in this case one called simply Data. The final project structure is shown here:
If you agree with these changes, please share this article and add your comments. You can also comment on this GitHub issue to rename IdentityModels. The final version of the template after making the above recommended changes is available on GitHub as well. Note that there are still some tweaks to be made, such as adding an Interfaces folder and pulling the interfaces out of MessageServices.cs, but I figured I’d covered enough ground for one article.