{"id":1928,"date":"2015-01-15T00:00:00","date_gmt":"2015-01-06T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/revisiting-partial-view-rendering-in-asp-net-mvc\/"},"modified":"2021-05-17T18:34:49","modified_gmt":"2021-05-17T18:34:49","slug":"revisiting-partial-view-rendering-in-asp-net-mvc","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/revisiting-partial-view-rendering-in-asp-net-mvc\/","title":{"rendered":"Revisiting Partial View Rendering in ASP.NET MVC"},"content":{"rendered":"<div id=\"pretty\">\n<p class=\"start\">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 &#8216;classic web sites&#8217;  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.  <\/p>\n<p>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&#8217;t exist anymore. <\/p>\n<p>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.<\/p>\n<p>All this is well-known and, for the most part, it is mainstream practice today.  In this article, instead, I&#8217;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 &#8216;partial rendering&#8217;. 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 <code>innerHTML<\/code> or just a few  core jQuery methods.<\/p>\n<h2>Setting Up a Sample Project <\/h2>\n<p>Let&#8217;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. <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" height=\"196\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2118-clip_image002.jpg\" width=\"307\" alt=\"2118-clip_image002.jpg\" \/><\/p>\n<p>Here&#8217;s some code that illustrates the behavior of the ASP.NET MVC endpoint  reached when any of the buttons in Figure 1 are clicked.<\/p>\n<pre class=\"lang:c# theme:vs2012\">[HttpPost]\n[ActionName(\"delete\")]\npublic ActionResult DeletePost(int id)\n{\n&#160;&#160;&#160; _repository.Delete(id);\n&#160;\n&#160;&#160;&#160; \/\/ Redirect to generate the subsequent view\n&#160;&#160;&#160; RedirectToAction(\"index\");\n}\n<\/pre>\n<p>The method <code>DeletePost<\/code> 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&#8217;s some sample code for the Index method.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public ActionResult Index()\n{\n&#160;&#160; var customers = _repository.FindAll();\n&#160;&#160; var model = new IndexViewModel(customers);\n&#160;&#160; return View(model);\n}\n&#160;\n<\/pre>\n<p>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.<\/p>\n<p>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.<\/p>\n<h2>The PartialView Method<\/h2>\n<p>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.<\/p>\n<p>With an eye on Figure 1, let&#8217;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. <\/p>\n<p>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.<\/p>\n<pre class=\"lang:xhtml theme:github\">&lt;div class=\"col-md-6\" id=\"listOfCustomers\"&gt; \n&lt;table class=\"table table-condensed\"&gt;\n&#160;&#160;&#160; @foreach (var c in Model.Customers)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;tr&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;td&gt;@c.Id&lt;\/td&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;td&gt;@c.Name&lt;\/td&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;td&gt;@c.Address&lt;\/td&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;td&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;button class=\"btn btn-xs btn-danger\" onclick=\"d(@c.Id)\"&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;span class=\"glyphicon glyphicon-trash\"&gt;&lt;\/span&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;\/button&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;\/td&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; &lt;\/tr&gt;\n&#160;&#160;&#160; }\n&lt;\/table&gt;\n&lt;\/div&gt;\n<\/pre>\n<p>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 <code>DIV<\/code> element  container of the customer list.<\/p>\n<pre class=\"lang:c# theme:vs2012\">function d(id) {\n&#160;&#160;&#160; var url = \"\/home\/delete\/\";\n&#160;&#160;&#160; $.post(url, { id: id })\n&#160;&#160;&#160;&#160; .done(function (response) {\n&#160; &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;$(\"#listOfCustomers\").html(response);\n&#160;&#160;&#160; });\n&#160;\n<\/pre>\n<p>On the server side, the Delete method on the controller class becomes as shown  below:<\/p>\n<pre class=\"lang:c# theme:vs2012\">[HttpPost]\n[ActionName(\"delete\")]\npublic ActionResult DeletePost(int id)\n{\n&#160;&#160;&#160; \/\/ Executes the command\n&#160;&#160;&#160; _repository.Delete(id);\n&#160;\n&#160;&#160;&#160; \/\/ Return HTML to update the view\n&#160;&#160;&#160; return PartialView(Common.Views.ListOfCustomers);\n}\n&#160;\n<\/pre>\n<p>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 <code>ActionResult<\/code> to a more specific <code> PartialViewResult <\/code>type. The actual behavior doesn&#8217;t change; but the code is inherently easier to understand.<\/p>\n<p>Let&#8217;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&#8217;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&#8217;s ideally configured to be a POST. The request is placed using  JavaScript and it&#8217;s not tracked by the browser. Whether it goes as a GET or POST, it won&#8217;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.  <\/p>\n<h2>Limitations of this Technique<\/h2>\n<p>The amount of script code used for this technique is the bare minimum. This is  good and bad news at the same time. It&#8217;s good because any line of code is under your strict control: it&#8217;s all about  jQuery, the DOM and you. It&#8217;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.<\/p>\n<p>There&#8217;s another drawback, however, in the technique discussed so far. To see  what it is, have a look at Figure 2. <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" height=\"206\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2118-clip_image004.jpg\" width=\"301\" alt=\"2118-clip_image004.jpg\" \/><\/p>\n<p>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. <\/p>\n<p>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&#8217;s see how to do this.<\/p>\n<h2>Combining Multiple Partial Views Together<\/h2>\n<p>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.<\/p>\n<pre class=\"lang:c# theme:vs2012\">public class MultipleViewResult : ActionResult\n{\n&#160;&#160;&#160; public const string ChunkSeparator = \"---|||---\";\n&#160;&#160;&#160; public IList&lt;PartialViewResult&gt; PartialViewResults { get; private set; }\n&#160;\n&#160;&#160;&#160; public MultipleViewResult(params PartialViewResult[] views)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (PartialViewResults == null)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; PartialViewResults = new List&lt;PartialViewResult&gt;();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; foreach(var v in views)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; PartialViewResults.Add(v);\n&#160;&#160;&#160; }\n&#160;\n&#160;&#160;&#160; public override void ExecuteResult(ControllerContext context)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (context == null)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new ArgumentNullException(\"context\");\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; var total = PartialViewResults.Count;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; for (var index = 0; index &lt; total; index++)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; var pv = PartialViewResults[index];\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; pv.ExecuteResult(context);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (index &lt; total - 1)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; context.HttpContext.Response.Output.Write(ChunkSeparator);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160; }\n}\n<\/pre>\n<p>The constructor of the <code> MultipleViewResult<\/code> type accepts a list of <code>PartialViewResult<\/code> types and  caches them internally in a read-only collection. An action result type must necessarily override the <code>ExecuteResult <\/code>method declared as abstract in the base class. ASP.NET MVC  requires that an implementation of <code>ExecuteResult<\/code> just writes down any  response to the output stream. <\/p>\n<p>Because <code>MultipleViewResult<\/code> contains  multiple instances of <code>PartialViewResult<\/code>, it is sufficient to loop over the  collection of <code>PartialViewResult<\/code> 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 &#8220;&#8212;|||&#8212;&#8220;, but feel free  to adapt it to your own purposes. With the<code> MultipleViewResult<\/code> class in  place, here&#8217;s how to rewrite the controller method:<\/p>\n<pre class=\"lang:c# theme:vs2012\">public ActionResult DeleteCustomer(int id)\n{\n&#160;&#160;&#160; _repository.Delete(id);\n&#160;&#160;&#160; var customers = _repository.FindAll();\n&#160;\n&#160;&#160;&#160; \/\/ Combine multiple partial views \n&#160;&#160;&#160; var model = new IndexViewModel(customers);\n&#160;&#160;&#160; return new MultipleViewResult(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; PartialView(Common.Views.ListOfCustomers, model),\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; PartialView(Common.Views.OnBehalfOfCustomers, model));\n}\n<\/pre>\n<p>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.<\/p>\n<pre class=\"lang:c# theme:vs2012\">function d(id) {\n&#160;&#160;&#160; var url = \"\/home\/d\/\";\n&#160;&#160;&#160; $.post(url, { id: id })\n&#160;&#160;&#160;&#160; .done(function (response) {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; var chunkSeparator = \"---|||---\";\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; var chunks = response.split(chunkSeparator);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; $(\"#listOfCustomers\").html(chunks[0]);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; $(\"#onBehalfMenu\").html(chunks[1]);\n&#160;&#160;&#160; });\n}\n<\/pre>\n<p>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.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" height=\"190\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2118-clip_image006.jpg\" width=\"277\" alt=\"2118-clip_image006.jpg\" \/><\/p>\n<h2>Summary<\/h2>\n<p>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. <\/p>\n<p>In terms of performance it&#8217;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. <\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>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&#8217;s own partial-rendering techniques, returning HTML. It requires less client-logic and is quicker to implement.&hellip;<\/p>\n","protected":false},"author":221911,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4156,4157,4880,5166],"coauthors":[],"class_list":["post-1928","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-asp","tag-asp-net","tag-json","tag-mvc"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1928","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221911"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1928"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1928\/revisions"}],"predecessor-version":[{"id":91050,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1928\/revisions\/91050"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1928"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1928"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1928"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1928"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}