Revisiting Partial View Rendering in ASP.NET MVC

For any browser-based application, it makes sense to load into the web page just the content that is immediately required and avoid whole-page refreshes whenever possible. Ajax technology and JSON makes this partial-rendering easy. It is, however, worth considering ASP.NET's own partial-rendering techniques, returning HTML. It requires less client-logic and is quicker to implement.

In the real-world, or at least in the section of the real world that I see every day, there are still plenty of classic ASP.NET Web Forms and ASP.NET MVC web sites. By ‘classic web sites’ mean web sites where the vast majority of pages are being served entirely from the web server and fully refreshed after each postback. The full refresh of the page after a postback can be significantly slow and cumbersome for users, especially when the use of graphics of these sites is quite heavy. This is the reason why at some point Ajax and partial rendering of pages became so popular.

Today, the Ajax approach is often taken to the limit when single-page applications (SPA) are built. A single-page application (or just a few-pages application) downloads from the web server as an empty DIV element. All the remaining content is inserted dynamically after placing additional HTTP requests for JSON data. In this context, posting a form is merely a JavaScript-driven request. The response of such a request is mostly JSON data that the local script will process as appropriate, updating the user interface. As you can easily appreciate, the performance problem of the full page refresh just doesn’t exist anymore.

In between SPAs and classic full page refresh solutions, there are techniques based on plain jQuery calls to HTTP endpoints returning JSON data. Technically speaking, a jQuery solution is not that much different from anything you can do in a SPA; However, it is a technique that you can use just where required and appropriate but not necessarily throughout the entire solution. You can use jQuery to make a GET request and receive JSON data. Such data is then incorporated in the current DOM via HTML templates and libraries such as Knockout or AngularJS. You can also use jQuery to place a POST request and receive back a plain ack message or some JSON data.

All this is well-known and, for the most part, it is mainstream practice today. In this article, instead, I’ll discuss a different approach for partial page refreshes that is closer to what in ASP.NET Web Forms and ASP.NET MVC is still referred to as ‘partial rendering’. The idea behind partial rendering is that of placing a jQuery call, having the endpoint perform its command or query and then returning any response as pure HTML. Some SPA purists may dislike this approach because-they may say-returning HTML is less efficient than returning plain JSON data. True, but the techniques presented in this article are a lot smoother to implement in coding scenarios where the predominant skills are server-side ASP.NET Web Forms and ASP.NET MVC. Still a bit of JavaScript is required, but it is limited to using familiar DOM properties such as innerHTML or just a few core jQuery methods.

Setting Up a Sample Project

Let’s say you have an ASP.NET MVC project with a Razor view that produces the output of Figure 1. The page contains a list of data elements that users can delete one by one by clicking a button. In classic ASP.NET, you may have a HTML form all around the list and each of the delete buttons is implemented as a submit button. When any button is clicked, the page posts back. On the server you figure out which button was clicked, and from there you get the ID of the element to delete.

2118-clip_image002.jpg

Here’s some code that illustrates the behavior of the ASP.NET MVC endpoint reached when any of the buttons in Figure 1 are clicked.

The method DeletePost proceeds with the backend operation and then redirects to the method in charge of refreshing the view. This is an instance of the Post-Redirect-Get (PRG) pattern that keeps commands distinct from queries and also avoids the nasty problem of resending POST data when the user hits F5 from the browser. Here’s some sample code for the Index method.

The Index method gets the updated list of customers (after the deletion) and refreshes the page. When the PRG pattern is used to implement a POST, the last action repeatable by the browser is always a GET. As a result, users will see the updated list of customers. Even if they press F5 or Refresh within the browser all they obtain is a plain refresh of the page; no additional deletion of data occurs.

How can this code be improved to avoid a full page refresh without rewriting the entire application, or large portions of it, as a SPA? A possible approach is based on the HTML Message pattern-one of the most popular Ajax patterns. The HTML Message pattern refers to a situation in which the request carries back ready-to-display markup instead of raw (JSON) data.

The PartialView Method

In ASP.NET MVC, a partial view is analogous to user controls in ASP.NET Web Forms. A partial view is a chunk of HTML that can be safely inserted into an existing DOM. Most commonly, partial views are used to componentize Razor views and make them easier to build and update. Partial views can also be returned directly from controller methods. In this case, the browser still receives text/html content but not necessarily HTML content that makes up an entire page. As a result, if a URL that returns a partial view is directly invoked from the address bar of a browser, an incomplete page may be displayed. This may be something like a page that misses title, script and style sheets. However, when the same URL is invoked via script, and the response is used to insert HTML within the existing DOM, then the net effect for the end user may be much better and nicer.

With an eye on Figure 1, let’s see what we could do to have users click a delete button and update the list of customers without spinning a full page refresh.

The most important point to remember is that an endpoint that returns a partial HTML view should only be called via script. The list of customers of Figure 1, therefore, might be generated from code as below. By the way, the sample code below is based on Bootstrap.

Clicking the button triggers a JavaScript function. The JavaScript function receives the ID of the customer the user intends to delete and calls the appropriate controller method. When the remote call returns the script grabs the HTML chunk and updates the DIV element container of the customer list.

On the server side, the Delete method on the controller class becomes as shown below:

To make the actual behavior of the method clear to occasional readers of the code from the beginning, you can also change the return type of the controller method from a generic ActionResult to a more specific PartialViewResult type. The actual behavior doesn’t change; but the code is inherently easier to understand.

Let’s review the new mechanics of the page. When users click to delete a record, a POST request is made to a HTTP endpoint within a controller. The controller deletes the record and returns a chunk of HTML for the script to use and update the current DOM. The request is sent over as a POST, but at the end of the day there’s no strict requirement for a POST verb; a GET would work anyway. At the same time, because the request is expected to cause a state change on the server side, it’s ideally configured to be a POST. The request is placed using JavaScript and it’s not tracked by the browser. Whether it goes as a GET or POST, it won’t be repeatable if the user hits F5. For the end user, the net effect is that changes become immediately visible without any page flickering.

Limitations of this Technique

The amount of script code used for this technique is the bare minimum. This is good and bad news at the same time. It’s good because any line of code is under your strict control: it’s all about jQuery, the DOM and you. It’s bad because dependencies between controller, Razor view and JavaScript code are explicit. If you happen to change, say, the ID of the DIV in the Razor view you may break the script. Likewise, if you modify the script or the code in the controller you may cause unexpected results in the HTML being served to the user. In a nutshell, the three elements (controller, Razor view, script code) must work together in perfect harmony.

There’s another drawback, however, in the technique discussed so far. To see what it is, have a look at Figure 2.

2118-clip_image004.jpg

The drop-down menu in the figure has one item for each customer in the list. This means that when the user clicks a button to delete a customer from the client-side, it is not enough to refresh the list. Also the contents of the drop-down should be updated. This is not an issue, instead, if the entire page is rebuilt on the server as during a classic postback and a full page refresh. Likewise, this is not an issue if you are in the context of SPA. In this case, the request brings back raw JSON data that the client-side logic knows how to handle to update all the involved segments of the user interface.

More in general, whenever you send a request via JavaScript multiple segments of the user interface may be touched by the effects of that request. And when the request is coded to return ready-to-display markup, multiple chunks of HTML should be returned. Let’s see how to do this.

Combining Multiple Partial Views Together

The idea therefore is that a controller method (say, Delete) is invoked via JavaScript and returns multiple partial views. By design, a controller method must return a type derived from ActionResult but none of the predefined action result types supports multiple HTML chunks. Hence, a new action result type is in order.

The constructor of the MultipleViewResult type accepts a list of PartialViewResult types and caches them internally in a read-only collection. An action result type must necessarily override the ExecuteResult method declared as abstract in the base class. ASP.NET MVC requires that an implementation of ExecuteResult just writes down any response to the output stream.

Because MultipleViewResult contains multiple instances of PartialViewResult, it is sufficient to loop over the collection of PartialViewResult objects and ask each to execute. Finally, a separator must be added so that on the client side the various chunks can be easily detected. In principle, you can use any character (or combination thereof) to separate HTML chunks. In practice, instead, any character, or combination of characters, that is common in the HTML body can break the script. I usually use a string like “—|||—“, but feel free to adapt it to your own purposes. With the MultipleViewResult class in place, here’s how to rewrite the controller method:

In the example, the two partial views use the same view model. This is not a limitation though. The script code in the client page receives a single string and unpacks it before display.

Look at Figure 2 again and imagine a user that clicks on the selected customer. Figure 3 shows the final effect. The customer 435 has been removed from the backend database and the view has been updated instantaneously and without full page refresh. For the user, it is definitely a great experience.

2118-clip_image006.jpg

Summary

Pages that are quick to respond to users are essential these days. This requirement is behind the huge success of single-page applications and frameworks such as AngularJS. Building a SPA, though, may be hard not so much for the technologies involved, but because of the skills required to build SPAs effectively. The approach presented in this article represents a quick-and-easy way to extend existing ASP.NET MVC applications and make them as responsive as SPAs without learning a brand new framework.

In terms of performance it’s undeniable that downloading raw JSON is faster than downloading HTML chunks. However, plain download of HTML chunks is fast enough compared to full page refresh for the vast majority of users.

Tags: , , , ,

  • 150975 views

  • Rate
    [Total: 24    Average: 4.1/5]
  • Anonymous

    Use JS to remove entry from select list?
    .done {

    removeItem($list, id);
    }

    ?

  • JoNSmith

    I Like it!
    Hi Dino,

    Excellent article. Your article ‘scratches where it itches’ for me as I would like to remove some of the ‘flashes’, especially of the menu, when clicking actions and your approach makes a lot of sense.

    I could use a Single Page Application (SPA) but having built a fairly large one for data visualisation I know how hard they are! As you say, in some situations partial views with Ajax might be enough. I like your ideas.

    I think the next stage is to see if you can make it easier to define what partial views are needed rather than having to write code for each view. Almost all the JavaScript MVC libraries, like backbone.js, angularjs etc., form a hierarchy of views to build up each page. I wonder if this could be achieved in your scheme either convention of attributes/declarative programming. Any thoughts on that?

  • JoNSmith

    RE: I Like it!
    Sorry, last two sentences on my last post should read…

    I wonder if this could be achieved in your scheme either by convention or attributes/declarative programming. Any thoughts on that?

  • Rob

    Nice Article
    I have been thinking about doïng something like this as well. But did not dare to use in a production enviroment yet. Have you?

    I would like to detect on te server if a script is calling (and then serve a partial) or a browser (and than somehow serve the hole page. What are your toughts about such a scenario?

  • Harry Vu

    I DO NOT LIKE IT
    Hi Dino Esposito,

    You are my respected author, but I do not like this specific article. Why? There are many reasons and I don’t want to repeat them here. Web Forms is the thing in the past, and/or will fading out soon. Let Web Foms developers learn Javascript and other languages/frameworks. They also should learn and apply OOP, SOLID, design patterns.

    Thanks.

    Thanks.

  • gcyoung

    Excellent
    An additional advantage of returning HTML is that all the client has to do is a single DOM insertion. I’ve seen a number of SPA-type apps where the variation in client performance (and capabilities) caused problems.

    Also, one can rely on the server (more powerful, easier to debug, and a single possible point of failure) for calculations/operations.

    Win-win, IMHO.

  • Anonymous

    ?
    if any one of the partview contains the "—|||—",what will happend?

  • Anonymous

    Excellent
    I found this article very useful. It fits bill in so many cases.

  • Thanigainathan

    Huge benefit when rendering multiple table rows
    I agree with the solution provided, because in SPA applications it takes grater time to render html tables with huge number of rows. Its pretty faster in server side and easy to place them in client side. Excellent article.

  • Dino Esosito

    Remarks
    A few replies in a single comment:
    @JoNSmith–I’ve been thinking to ways of making less script necessary or anyway simpler. Not found anything reasonable yet.
    @Rob: Idea came out of a custom CMS I’m working on. Yes.
    @Anonimous: I tried to use a weird combination of chars, but yes the problem exists 🙂
    @gcyoung: TOTALLY agree!
    @Harry Vu: not sure IMHO you really got the point of it. This is plain HTML and presentation. No need to waste time here with OOP and SOLID 🙂

  • Steve Adams

    What about two models?
    Hi Dino, Great article. I tried your code, which works great for a single shared model. If passing different models with each view, however, the code uses the first model for all views. Any ideas why? The error when run is:

    The model item passed into the dictionary is of type [first model] but this dictionary requires a model item of type [second model]

  • maddydare

    MVC special views like Partial Views
    ASP.NET MVC special views like Partial Views and Layouts.
    Rendering Partial View: We can render a partial view using one of the following 4:

    Html.Partial
    Html.RenderPartial
    Html.Action
    Html.RenderActionHere is one simple example explaining everything: http://mvc4all.com/mvc/how-to-create-partial-view-in-mvc-4-mvc-5/

  • Carlos Alberto Morales Osorio

    MVC Partial View
    Thanks very much Dinno Esposito!

  • pjdiii

    Great Article
    Do you have a revision for MVC6?

  • Wanton

    I know this post is over year old and all. But pretty please don’t use separator like —|||—
    Example if you have this @messageDraft and message draft contains —|||— it will break your page!
    Use separator that is normally escaped in HTML something like or

  • Oduma

    Hello every one here I never believed in a spell casting but After 6 years of dating my ex lover, I still imagine how Dr oduma brought my ex lover back to me in just 24 hour. No one could have ever made me believe that there is a real spell caster that really work. am Sophia by name,I want to quickly tell the world that there is a real an online spell caster that is powerful and genuine, His name is Dr oduma He helped me recently to reunite my relationship with my ex lover who left me, When i contacted Dr oduma Whats App +27638438737 he cast a love spell for me and my ex lover who said he doesn’t have anything to do with me again called me and started begging me. he is back now with so much love and caring. today i am glad to let you all know that this spell caster have the powers of bring lovers back. because i am now happy with my lover,and the most surprise,is that our love is very strong,every day is happiness and joy. and there is nothing like been with the man you love.i am so happy my love is back to me with the help of Dr oduma – Supernatural Power if you have similar problem here’s his contact WhatsApp +27638438737 and Email: pt066709@gmail.com

  • Shirajul Mamun

    Nice Article! Recently I am working with partial view and facing some problem regarding its javascript, let me explain, I have a partial view for CRUD Operation for customers I want this partial view will sometimes show as modal popup in my various page, I have written some jquery for that partial view and referenced the jquery file to that partial view.

    While I dynamically load the partialview and render inside bootstrap modal it shows perfectly, but the problem the jquery scripts are not running, further searching about it i found there are some sync problem between DOM, PartialView Html and jquery scripts(which I am not clear about). could you guide me through the issue and what would be the effective solution?