Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Reusing Views in ASP.NET MVC for Ajax Updates

The other day I came across this post in Marteen Balliauw's blog where he demonstrates and interesting way to make the same ASP.NET MVC view render correctly from both a regular request and an Ajax request.

In Marteen's post he uses a custom ActionFilterAttribute to detect the Ajax call and replace the standard master page with an unadorned Empty master page.

I liked the idea that you can add that behavior to any action simply by bolting that attribute to it.

What I'm going to illustrate here is a variation of that idea that can be used when you have your own base class to all your controllers, which is something I always do.

SIDE NOTE: I have the habit of creating base classes for all the important things in my ASP.NET applications right after I create the project. I carried this habit from the ASP.NET Webforms-style to the MVC projects. So I typically have ApplicationController, ApplicationView<T>, PartialView<T>, ApplicationMaster, etc. These classes start off empty but code starts finding its way to them rather quickly.

What I'm going to do is override the Controller.View() method to detect the Ajax calls and replace the master page right there.

public abstract class ApplicationController: Controller
{
  protected override ViewResult View(
            string viewName, string masterName, object model)
  {
    if(IsAjaxRequest)
      return base.View(viewName, "Empty", model);

    return base.View(viewName, masterName, model);
  }

  protected virtual bool IsAjaxRequest
  {
    //Both Prototype.js and jQuery send 
    // the X-Requested-With header in Ajax calls
    get
    {
      var request = ControllerContext.HttpContext.Request;
      return (request.Headers["X-Requested-With"] == "XMLHttpRequest");
    }
  }
}

With that in place I don't need to change anything in my action code to start supporting the Ajax calls (as long as the controller inherits from the above base class)

public class SampleController : ApplicationController
{
  public ActionResult Index()
  {
    return View();
  }

  public ActionResult Details(int id)
  {
    var user = new UserInfo {Name = "user" + id, Age = 30};
    return View(user);
  }
}

My Index action calls the Details action using both a regular request and an Ajax call, for the sake of the example.

<%@ Page Title="" Language="C#" 
  MasterPageFile="~/Views/Shared/Site.Master" 
  AutoEventWireup="true" 
  CodeBehind="Index.aspx.cs" 
  Inherits="MvcBeta1.Views.Sample.Index" %>
<asp:Content ID="Content1" 
        ContentPlaceHolderID="MainContent" runat="server">
<h2>Sample View Index</h2>
<%= Html.ActionLink("Go to Details", "Details", new { id = 123 })%>
<hr />
<input type="button"  id="loadDetails" value="Load with Ajax" />
<div id="detailsDiv" style="background-color:#aaa;">
[details should load here]
</div>

<script>
  $(function() {
    $('#loadDetails').click(function() {
      $('#detailsDiv').
        load('<%= Url.Action("Details", new {id = 123}) %>');
    });
  });
</script>
</asp:Content>

The Details view is trivial. It's just a table.

<%@ Page Title="" Language="C#" 
  MasterPageFile="~/Views/Shared/Site.Master"
  AutoEventWireup="true" 
  CodeBehind="Details.aspx.cs" 
  Inherits="MvcBeta1.Views.Sample.Details" %>
<asp:Content ID="Content1" 
        ContentPlaceHolderID="MainContent" runat="server">
  <h2>Details for <%= ViewData.Model.Name %></h2>
  <table border="1">
    <tr><th>Col 1</th><th>Col 2</th><th>Col 3</th></tr>
    <% for(int i=1; i<= 5; i++) { %>
      <tr>
        <td>cell (<%= i %>, 1)</td>
        <td>cell (<%= i %>, 2)</td>
        <td>cell (<%= i %>, 3)</td>
      </tr>
    <%} %>
  </table>
</asp:Content>

When at the Index page we can click on the "Go to Details" link and see the full rendering of the Details view.

If we had instead clicked the "Load with Ajax" button we would cause a simpler version of that page to be inserted in the detailsDiv element (note that the tabs and the blue background that surrounds the table did not come in the rendered content.)

Of course, ASPX files are not the indicated place for placing content that can be used in partial updates, ASCX files would be a better choice for that. That said, sometimes it can be really convenient to have this ability.


Posted 12-05-2008 8:25 PM by sergiopereira
Filed under: ,

[Advertisement]

Comments

Dew Drop - Weekend Edition - December 6&7, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - Weekend Edition - December 6&amp;7, 2008 | Alvin Ashcraft's Morning Dew
on 12-06-2008 9:26 PM

Pingback from  Dew Drop - Weekend Edition - December 6&amp;7, 2008 | Alvin Ashcraft's Morning Dew

Pages tagged "ajax" wrote Pages tagged "ajax"
on 12-08-2008 4:48 AM

Pingback from  Pages tagged "ajax"

cypher wrote re: Reusing Views in ASP.NET MVC for Ajax Updates
on 12-08-2008 11:36 AM

Don't forget, as I did, to provide a masterpage called  "Empty".

Otherwise, it would not work.

Also for some reason, I add to use

$get() instead of load(), as show below, for this to work.

           $.get($(this).attr("href"), function(data) {

               $('#detailsDiv').html(data);

           });

sergiopereira wrote re: Reusing Views in ASP.NET MVC for Ajax Updates
on 12-08-2008 12:12 PM

I did not mention the Empty master page because it's discussed in the original post that I referenced.

jQuery's load() works just fine, you must have some syntax or reference problem.

ASP.NET MVC Archived Buzz, Page 1 wrote ASP.NET MVC Archived Buzz, Page 1
on 01-23-2009 12:35 PM

Pingback from  ASP.NET MVC Archived Buzz, Page 1

EJR wrote re: Reusing Views in ASP.NET MVC for Ajax Updates
on 02-04-2009 3:43 PM

one thing to note is that you might get in trouble with ContentPlaceHolder name mismatches from the non-ajax master and the empty master

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)