NoMVC

In the past couple of years I’ve rewritten several ASP.NET WebForms, MVC and even some Classic ASP sites. On this post I explain why I decided to use Razor pages instead of MVC, which turned out to be a great experience.

The whole point of MVC is the idea of Separation of concerns. Dividing a single function into three components (Model, View and Controller) enables many methodologies and practices that are not as easily achievable in script-based or control-based applications. The question is, are this methodologies and practices really needed? Does MVC create more problems than it solves?

Modularity

The MVC framework should be called RCMV (Route-Controller-Model-View), because nothing happens without a route. Using routing introduces a whole set of problems and challenges, it’s no freebie. And the modularity in MVC, with or without areas, simply sucks. I like how blueric puts it:

You have no idea how long I’ve felt as though I was swimming upstream when working on MVC projects, all because I just can’t buy into the default folder structure of an MVC project. It drives me batty having to constantly navigate the file tree structure to open files that I usually work on together. For $#!@% sakes, can’t I just have AccountController, LoginViewModel, and Login.cshtml all in the same place?

With pages everything is simpler, just files and folders which you can freely organize any way you want.

Complexity

Models, view models, controllers, views, routes, areas, etc. An MVC codebase is a lot larger and more complex than a page-based codebase. A Razor page is simply a script you can read from top to bottom to fully understand what’s going on. A general recommendation in MVC is to have thin controllers and fat models. If your controller (action) is just a few lines, you can move it to the top of your view and you’d created a page, and saved yourself a lot of trouble.

Having a model that is separate from the controller and view is generally a good practice, which you don’t need an MVC framework to implement. You can have a page that calls a model from a separate layer.

Sometimes less is more.

@{
   if (IsPost) {
      <div class="alert alert-info">YES!!!</div>
   }
}

<h1>Is Razor simpler?</h1>
<form method="post">
   <button type="submit">Click for answer</button>
</form>

Reusability

Routing does enable a level of composability not possible with pages. An MVC application can be composed of various modules from different assemblies with embedded views. By stacking routes you can override and even extend controllers.

I’ve done a lot of work implementing these ideas, but I’ve come to the realization that it’s not worth it. The main feature of OOP is encapsulation, which means hiding things, not compose and extend things. If an application is organized in scripts (pages) then it’s easier to reuse its source code, as opposed to having functions split into several components.

URLs

Razor has great support for clean URLs. First, the file extension can be omitted. Then, you can append zero or more segments that become available using the UrlData property. What you can’t do are multi-level hierarchical URLs, like this one:

book/1/chapter/2

You’d have to do it like this:

book/chapter/1/2

…where book is a directory and chapter a page. Now, is the first URL better than the second one? Do users really care? URL design is overrated. I’m not saying it has no importance, but not as much. Contrary to popular belief, there’s no such thing as a RESTful URL. If a certain URL style greatly simplifies your codebase, why not embrace it.

By the way, you can still do the first URL using Routing (handled by a page instead of a controller).

Cross-cutting concerns

This is one of the things I missed the most. Attribute-based action filters is a clean declarative solution for cross-cutting concerns. For instance, in MVC, this action:

[Authorize]
public ActionResult Foo() {
   ...
}

becomes:

@{
   if (!User.Identity.IsAuthenticated) {
      FormsAuthentication.RedirectToLoginPage();
      return;
   }

   // logic goes here
}

You can also use Web.config or _PageStart, but the level of control available in MVC is simply not there.

Easier collaboration with designers

I’ve never believed in this one. I wouldn’t give a designer access to modify views. Views have code (e.g. Html.EditorFor()) and HTML markup has semantics, I don’t want designers touching that. Designers should work on CSS, not views.

Dependency injection

In pages you can use service location, and in ASP.NET 5 Razor will include an @inject directive.

RAD (Rapid application development)

Pages are definitely faster to write.

Testability

I’ve never tested a controller or view.

Portability

It’s rare to port an application to a different language/platform, but it would be easier to do if using the MVC pattern, specially if the view language is cross-platform.

Bottom line

I’m not sure if I’d consider this if it wasn’t for Razor. One of the advantages of using XSLT is that it shares the same syntax as HTML, which allows you to mix server code and client code without the need for delimiters (e.g. <? ?> or <% %>). Without sharing the same syntax as HTML, Razor is smart enough to work without delimiters, which to me makes the possibility of extending its role from view language to primary server language irresistible.

I don’t have anything against the MVC pattern, but life’s too short. Dumb views? Smart pages!

Posted by at
Tags: asp.net mvc, razor
comments powered by Disqus