Click here to Skip to main content
14,177,305 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

10.9K views
7 bookmarked
Posted 16 Jun 2013
Licenced CPOL

Three Steps to Get Fat-Razor MVC Views on Diet

, 16 Jun 2013
Rate this:
Please Sign up or sign in to vote.
ASP.NET MVC Views give you the power of Razor View Engine with the flexibility of writing C# code. However, if you do too much C#, you will end up with Fat-Razors that need to go on a diet or you might be risking separation of concern attacks.

Fat Razor in MVC

Let me first define the terms that I will be referring to:

Presentation Code: Is the minimal code in a view that is necessary to display visual elements, but does not take any business decision. This is a fictional simple example:

// Business Logic Code. This code understands how the business works
// (don't do this)
@if (Model.IsMonthly && !Model.IsPaid && Model.Payment >= 12 && ...)
{
    <p>Some warning message</p>
}

// Presentation Code. This code is only concerned with whether to
// show or hide a UI element.
@if (Model.ShouldWarn)
{
    <p>Some warning message</p>
}

Fat-Razor: I've coined this term to define ASP.NET Razor views with a lot of Razor/C# code that is not presentation code. This is about the Razor/C# code specifically and not about HTML/CSS/JS.

Model: This is an overloaded term. However, in this context, it is an object of data representation such as a record in the database.

Viewmodel: They are data transfer objects that are meant to be view-specific and to carry exactly what the view needs, no less and no more. Generally, viewmodels are non-reusable and each vm is meant to be tightly coupled to one view, however, there are exceptions depending on what you are doing.

To give you a flavour of a model and a viewmodel:

// An example of a model
public class Person
{
    public Guid PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public short YearOfBirth { get; set; }
    public DateTime LastAuth { get; set; }
    // This might represent a one-to-many db relationship
    public Order[] Orders { get; set; }
}

// An example of a viewmodel
public class ProfileViewModel
{
    // Doesn't necessarily need an id

    // Combined first and last name
    public string Name { get; set; }
    // Calculated from YearOfBirth
    public short Age { get; set; }
    // E.g. "One day ago" and constructed from LastAuth
    public string LastSeen { get; set; }
    // Calculated by projections on Orders
    public short NumberOfAllOrders { get; set; }
    public short NumberOfUndeliveredOrders { get; set; }
}

Why Would It Hurt to Have Fat-Razor Views?

Before we discuss a solution, we need to agree that there is a problem.

Distribution (non-centralisation) of Business Logic

Fat-Razors carry similar criticism to what the old classical ASP had (and what PHP currently has), that is no separation of concerns. The concern of this piece of code is to show visuals and not to do business logic.

The business logic for your domain should be centralised, having Fat-Razor views highlights the use of business logic in your views, hence you are giving more control to what should be a dumb layer and violating “the power in the wrong hand” principle. You would be risking a fragile business logic that will break more often.

Due to the scope of this post, I will just tell you “It is bad, don’t do it” and won’t dive into this topic but don’t take my word for it, here is Uncle Bob’s Clean Architecture.

Unit Testing

You’ve heard it before, views aren’t unit testable (well, you can unit test them with some tools like Razor Generator but this is not the norm), or maybe more accurately shouldn’t be unit tested and should rely on different type of testing such as web testing like Visual Studio Testing Tools, Selenium or Capybara. So, Fat-Razor views mean more code you cannot unit test.

Refactoring

How many times did you change your code and compiled fine until you hit the page with your browser? And boom, your code refactoring did not propagate to the views, because it sees the views as text. Today, it is not that dramatic with tools like ReSharper, but it is still a problem. Having less C# code would reduce the problem size but not eliminate it.

Why Would Views Become Fat-Razor Views?

This is my experience of the symptoms from the industry, feel free to highlight more reasons in comments.

Using a Generic Model Rather Than a Specific Viewmodel

The MVC beginner tutorials try to show how simple MVC is by loading a record from the DB, transferring it into an object with an OR Mapper (Entity Framework, NHibernate and the likes) and then passing it to the view which renders it. Building a blog with MVC tutorials, I am looking at you.

Good example for beginners, gets them up to speed, but only works in trivial applications. Why? If your view is not getting exactly what it wants, then it is going to have to do some inspections on the model, hence, code and more code! If you treat the view as dumb and give it exactly what it wants, you will reduce the need for it to have any non-presentation logic.

Get your Fat-Razor into Shape

Razor Ramon

Big Boss Man is my early teenage wrestling hero (he is strong and cool), but Razor Ramon fits better in this post.

Now that I have touched some of the necessary concepts around this subject, I could highlight some steps for Thin-Razor views.

1. Use a Viewmodel for Your View

Do not take a model from the database and throw it directly into your view. This will couple your views to your entities and will probably invite business logic code.

My favourite way of doing this is by using a CQRS type query, this article does a good job in introducing CQRS: Introduction to CQRS. I query exactly what my view needs into a viewmodel, no intermediate model (or DTO), have a look at Dapper – a simple object mapper for .Net.

If you have a different architecture or legacy code, perhaps you could have a layer that would map a model into a viewmodel, have a look at AutoMapper, it may help.

2. Try to Differentiate Business from Presentation Code

When writing views, always flag the question “Is this presentation code or business logic?” This is a hard question as in some cases, it might be a fine line between the two. Sometimes, I ask for a second opinion and encourage a healthy debate.

3. Package Repeated Presentation Patterns into HTML Helpers and Partial Views

Sometimes, one repeats the same presentation code again and again in different views. I do that as well following the agile principle “Do the simplest thing that works, then refactor” then when I notice a pattern forming, I do refactor it into an HTML Helper or a Partial View.

Conclusion

As they say “More is less”, the less code you write is the less code you have to maintain and the proper code you write will keep you safe if the developer inheriting the project, knows where you live.

I did review this post multiple times to cut it shorter, however, it is a big topic and it is still not complete. If you have any points that you would like to share, then please do comment.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Adam Tibi
Architect
United Kingdom United Kingdom
Passionate about refining software practices, promoting self-motivated teams and orchestrating agile projects.
Lives in London, UK and works as a .NET architect consultant in the City.

Blog AdamTibi.net.

You may also be interested in...

Pro
Pro

Comments and Discussions

 
GeneralMy vote of 5 Pin
am.net17-Jun-13 20:31
memberam.net17-Jun-13 20:31 
GeneralMy vote of 5 Pin
MaskedDev16-Jun-13 11:29
professionalMaskedDev16-Jun-13 11:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01 | 2.8.190526.1 | Last Updated 16 Jun 2013
Article Copyright 2013 by Adam Tibi
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid