Avoiding duplicity in Razor with helpers

Imagine that you are developing an ASP.NET MVC application and you find yourself writing the same code in the same view multiple times. I’ve been in this situation couple days ago while coding new features to Bonobo Git Server.

I was working on the diff view for files and had code that looked like this.

<div class="changes">
    <h3>@model.GetType().GetDisplayValue("Changes")</h3>
    @foreach (var item in Model.Changes)
    {
        <div class="item">
          <!-- Lots of code for displaying an item -->
        </div>
    }
    <div class="details">
        <h3>@Resources.Repository_Commit_Details</h3>
        @foreach (var item in Model.Changes.Where(...))
        {
            <div class="item">
              <!-- Lots of code for displaying an item -->
            </div>
            <pre class="brush: diff; gutter: false;">@item.Patch</pre>
        }
    </div>
</div>

My code smell alarm started beeping immediately. I had a HTML definition for an item twice in the code. Oh no, it can’t be good.

So, I started to think how to solve this situation. Firstly, I though about some sacrifices to GOF gods, but then I realized that I can create a custom HTML helper.

After a while I started to question this approach, because my item template isn’t something general. It’s just a small local duplicity. Therefore, custom HTML helper would be an overkill and a small lamb was still in danger again.

Fortunately for me (and the lamb), there is a way to write a helper method directly in a Razor view template . You can define it with the @helper keyword. After refactoring, the code is much cleaner.

@helper HeaderForDiff(RepositoryCommitChangeModel item)
{
    <div class="item">
        <!-- Lots of code for displaying an item -->
    </div>
}

<div class="changes">
    <h3>@model.GetType().GetDisplayValue("Changes")</h3>
    @foreach (var item in Model.Changes)
    {
        @HeaderForDiff(item)
    }
    <div class="details">
        <h3>@Resources.Repository_Commit_Details</h3>
        @foreach (var item in Model.Changes.Where(...))
        {
            @HeaderForDiff(item)
            <pre class="brush: diff; gutter: false;">@item.Patch</pre>
        }
    </div>
</div>

Helper markup is very useful for avoiding local duplicities and this is exactly the case where it should be used. For the more general controles, there is a custom HTML helper.

Disclaimer: No animals were harmed when finding this solution.


Would you like to get the most interesting content about C# every Monday?
Sign up to C# Digest and stay up to date!