I've been loving playing around with the CTP of the MVC framework for ASP.net. On several occasions in the past, I've rolled my own hybrid MVC implementations on top of ASP.net, so the prospect of a high-quality, "official" implementation is pretty exciting.
Note that I'm NOT on the ASP.net team. I don't have any "inside" information about the framework, other than the privilege of getting to play with early bits. But, since my previous jobs have involved alot of web development, I feel like I have some interesting insights. I've been doing alot of app-building with the framework, and I found myself missing a few things that I'm sure are in the planning phases, but they are missing nonetheless. Nikhil has some great AJAX support prototyped, so I was able to build on that, but I have some other samples I'll share that may be of some use.
First, users will no doubt be frustrated by trying to implement something simple like shared components. Think of a blogroll, or list of categories on a blog. These items don't really depend on input from the route (URL), they show the same data for every page. Currently, each controller action has to put this data into the ViewData (which makes it more difficult to dynamically add shared components, especially if you're using strongly-typed ViewData).
You could solve this in your controllers by inheriting from a common controller type that prepared that data for you, but then you likely have a controller pulling data that is totally unrelated to it.
I think a better approach is to allow Views to render actions directly. At first, this may seem like a violation of general MVC practices, but think of it this way...
So, as Nikhil adds "RenderPartial" support to views, here's my RenderAction implementation:
First are some extension methods for the different view types. These would go in an appropriate static class.
/// <summary>
/// Common logic for rendering actions as part of a view.
/// </summary>
static void RenderAction(string actionUrl, IHttpContext currentContext) {
//create a fake IHttpContext that will fool the route collection
//into creating RouteData for our action
var fakeContext = new FakeContext(actionUrl, currentContext);
var routeData = RouteTable.Routes.GetRouteData(fakeContext);
//Make a new MvcHandler that will process our fake request
var handler = new MvcHandler() {
RequestContext = new RequestContext(fakeContext, routeData)
};
((IHttpHandler)handler).ProcessRequest(HttpContext.Current);
}
/// Allows a page-based view to render actions
public static void RenderAction(this ViewPage page, object values) {
RenderAction(page.Url.Action(values), page.ViewContext.HttpContext);
/// Allows a master-based view to render actions
public static void RenderAction(this ViewMasterPage page, object values) {
/// Allows a usercontrol-based view to render actions
public static void RenderAction(this ViewUserControl control, object values) {
RenderAction(control.Url.Action(values), control.ViewContext.HttpContext);
You could imagine adding a similar extension to enable this for any kind of view.
Now, the "FakeContext" type is an implementation of IHttpContext that does the trickiness we need to get the routes to work, and the MvcHandler to execute the request. Here's the relevant parts, the rest of the implementation just throws so that it is clear when something breaks that we haven't really thought through.
class FakeContext : IHttpContext {
//This is a similar fake object to help
class FakeRequest : IHttpRequest {
FakeContext _FakeContext;
public FakeRequest(FakeContext context) {
_FakeContext = context;
public string AppRelativeCurrentExecutionFilePath {
get { return VirtualPathUtility.ToAppRelative(_FakeContext._ActionUrl); }
public string PathInfo {
get { return string.Empty; }
/// This is here to allow Nikhil's IsAjaxRequest method to continue to work
public System.Collections.Specialized.NameValueCollection Headers {
get { return new System.Collections.Specialized.NameValueCollection(); }
//the rest of the implementation just throws.
//that way, we know if something needs to be implemented later.
string _ActionUrl;
IHttpContext _Context;
public FakeContext(string actionUrl, IHttpContext context) {
_ActionUrl = actionUrl;
_Context = context;
public IHttpRequest Request {
get { return new FakeRequest(this); }
public IHttpSessionState Session {
get { return _Context.Session; }
This is a testament to the flexibility of the interface-based approach. This would be MUCH more difficult if we had to deal with the concrete HttpContext type.
So, if we want to inject the results of an action in part of a view, you would just do something similar to the following in your view, and you can pass other data, just as if you were creating an Action.Link:
<% this.RenderAction(new { Controller = "Tags", Action = "Cloud" }); %>
Bingo, the system processes the request (almost) as if it were an isolated request. There are obviously some limitations here, as well as some dependency on using Controller-based controllers and the MvcHandler, but that's certainly the common scenario.
Next time, I'll show you how to add support for ".ashx"-based views.
Remember Me
Page rendered at Friday, March 12, 2010 5:45:51 AM (Pacific Standard Time, UTC-08:00)
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.