ASP.NET MVC Razor View Best Practices – Keep logic out of your Razor views

Last year I wrote a blog post about how you could keep logic out of your ASP.NET MVC views.

Now with the introduction of the Razor view engine for ASP.NET MVC, I thought it would be a good idea to do a ‘Razor’ version.

The code used in this post can be downloaded here.

If you recall the reasons you should not have logic in your views are because they will become difficult to read, maintain and test at the very least.

How to decide what CSS class to use for the stock level in a Razor view

The screenshot below shows the three possible messages displayed to the user depending on the number of units in stock.

Output For Logic Out Of Views Blog Post

An example of a Razor view with conditional logic

We could select the CSS class for the corresponding number of units in stock using multiple if statements like this

@inherits System.Web.Mvc.WebViewPage<KeepLogicOutOfYourRazorViews.Models.Product>
@using KeepLogicOutOfYourRazorViews.Helpers

@{
	View.Title = "Index";
	LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<div class="example">
@if(Model.UnitsInStock == 0){
								<div class="stockLevel stockLevelNone">
									<span>Number Of Units In Stock: @Model.UnitsInStock</span>
								</div>
							}
@if(Model.UnitsInStock > 0 && Model.UnitsInStock <= 20)
							{
								<div class="stockLevel stockLevelLow">
									<span>Number Of Units In Stock:	@Model.UnitsInStock</span>
								</div>
							}
@if(Model.UnitsInStock > 20){
								<div class="stockLevel stockLevelHigh">
									<span>Number Of Units In Stock: @Model.UnitsInStock</span>
								</div>
							}
</div>

but there are better ways to achieve our goal.

So what are the alternatives?

We could:

  • Move the logic for choosing the CSS class into a helper method
  • Create a method to build the HTML for displaying the number of units in stock
  • Use a Product data transfer object with a CSS class name property
  • Pass all the CSS classes to a method which will return the CSS class to use

As I want to concentrate on showing code for Razor view engine, if you want to see the methods, unit tests and discussion about the advantages and disadvantages of each option please refer to the original post.

What the view would look like if we used a method to get the CSS class in a Razor view

The code below shows how we could achieve the same result by calling a method which returns the CSS class for the number of units in stock.

@inherits System.Web.Mvc.WebViewPage<KeepLogicOutOfYourRazorViews.Models.Product>
@using KeepLogicOutOfYourRazorViews.Helpers

@{
	View.Title = "Index";
	LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<div class="example">
	<div class="stockLevel @ProductCssHelper.GetCssClassForUnitsInStock(Model.UnitsInStock)">
		<span>Number Of Units In Stock: @Model.UnitsInStock</span>
	</div>
</div>

What the view would look like if we passed the CSS classes to a method in a Razor view

Alternatively, a more designer friendly way would be to pass the CSS classes to a method which returns the appropriate CSS class to use for the stock level.

@inherits System.Web.Mvc.WebViewPage<KeepLogicOutOfYourRazorViews.Models.Product>
@using KeepLogicOutOfYourRazorViews.Helpers

@{
	View.Title = "Index";
	LayoutPage = "~/Views/Shared/_Layout.cshtml";
}

<div class="example">
	<div class="stockLevel
		@ProductCssHelper.SelectCssClassForUnitsInStock(
														 Model.UnitsInStock,
														 "stockLevelNone",
														 "stockLevelLow",
														 "stockLevelHigh"
													   )">
		<span>Number Of Units In Stock: @Model.UnitsInStock</span>
	</div>
</div>

Jag Reehal’s Final Thought on ‘ASP.NET MVC Razor View Best Practices – Keep logic out of your Razor views’

Razor does a fantastic job of cleaning up your views, but to keep them even cleaner the best practice to keep logic out of yours view still applies.

Comments

  • Ryan

    I’d prefer putting the class on the view model itself.

    div class=”stockLevel @Model.StockLevelClass” …

  • http://www.arrangeactassert.com Jag Reehal

    Ryan providing your design allows you to have properties for CSS classes in the ViewModel that’s definitely an option

  • http://www.logmytime.de Adrian Grigore

    I too am in favor of keeping logic out of views. But IMO there is also a minimum amount of of complexity which would be required to make this worthwhile. The logic above could be expressed as 0?”stockLevelNone”:Model.UnitsInStock < 20?"stockLevelLow":stockLevelHigh . In fact the view gets cleaner if put this code directly in the view because you can instantly see what is going on instead of having to browse an outside method. Putting this in the view does not mess up the syntax. It's not testable, but for trivial logic I am willing to take that risk in exchange for more readability, less code bloat and faster development.

  • Jorge Ortega

    @Adrian for faster development I would do the same, but I seen many projects where this makes sites harder to maintain as they grow.

    I guess the answer is to whatever is right for your situation.

  • Nikolas

    @Jag

    Isn’t the entire concept of having view models for these exact reasons. So you CAN add all kind of properties to it in order not to have to assert these kind of things on a view level?
    Especially in larger projects where you ideally will end up have a view model for each view this makes absolute sense.
    I know many people think its over the top to have separate view models, first to create them and then to keep the data in sync with the acrual model, but once you have worked with it you will understand how valuable it is to not have to worry to break something else when you change something in the viewmodel. Additionally a lot of the property mapping between view model and actual model can be done via automapper which is a beautiful tool that made my life so much easier. So the mapping task becomes very simple an quick to solve.

    So in my perfect world (being a dev long enough to know it does not exsit ;) ) the only logic on the page will be asserting show/no show flags.

  • faagira

    Hello, i’m a junior programmer! Can you explain, why the third way is better than the second?
    And I can’t understand how it works :-(
    Thank you!

  • http://www.arrangeactassert.com Jag Reehal

    Hi Faagira,

    If you mean using a product transfer object vs writing HTML in code then I would say the major advantage is you have a clean separation in the layers of your because all HTML generation is done in a view. This means it’s easier to see what HTML is being generated to render the page.

    For an idea of how the different options work download the code from the post about keeping logic out of ASP.NET MVC web form views.

    Cheers,

    Jag

  • Anonymous
  • ItalianCousin

    In old style, I used to write <% String.Format("Something {0} here”, “bold”) %>
    I tried to migrate to @String.Format(“Something {0} here”, “bold”)
    but rendering is wrong. How can I fix it?

  • Anonymous

    Using Razor you don’t use String.Format just add @ where you want it to be displayed