« xUnit.net 1.0.2 Released | Main | Html.RenderPartial & Compiler Error CS1502 »

August 29, 2008

Partial Rendering & View Engines in ASP.NET MVC

Background

The ASP.NET MVC team just dropped CodePlex Preview 5. It contains a whole raft of new stuff, but there are two highly related features that I worked on. Since I have one foot in the "Dynamic Data" space and one foot into the "MVC" space (being the guy working on "Dynamic Data for MVC"), it means I get to have conversations like this:

Me: I need partial rendering for Dynamic Data for MVC.
Phil Haack: Yeah, okay, I'll put it on a list somewhere.

(...time passes...)

Me: I need partial rendering, like, soon!
Phil: I know! Go away.

(...time passes...)

Me: Okay, seriously? I need partial rendering tomorrow.
Phil: Sounds like you'll be doing it yourself then, right? ... Right?
Me: ...

I totally walked into that.

The team went through a few iterations of design discussions with me spiking a variety of ways to implement the feature. One thing we wanted to be sure to enable was the idea that the partial view you render can be done with a different view engine if necessary.

In the process, we uncovered several issues with the current implementation of view engines.

  • Controllers choose the view engine. Since the base Controller class chooses the WebForms view engine by default, many MVC users might not even realize this. Does the decision about view engines really belong with the controllers? They are otherwise divorced from view details, so this felt wrong.
  • Installing View Engines was awkward. Since controllers make the decision about view engines, how do you install a view engine? The "least intrusive" method turned out to be overriding the controller factory, yet another smell that things that shouldn't know about each other, did.
  • The View Engine decision was basically "one at a time". Since controllers make the decision about view engines, and most non-WebForms view engines get injected via the controller factory, you're more or less stuck using just a single view engine in your application (unless you want to perform a bunch of view engine overrides in your controllers).
  • Partial views don't have controllers. When a partial view is rendered, there is no associated controller, so who makes the decision about which view engine to use?

Given those limitations, and our desire to support multiple simultaneous view engines, we decided to revamp the view engine system at the same time we implemented partial rendering.

Partial views and Html.RenderPartial

There are four versions of Html.RenderPartial, and they all take a partial view name as their first parameter.

// Renders the partial view using the view data and model from the parent view.
public void RenderPartial(string partialViewName);

// Renders the partial view with an empty view data and the given model.
public void RenderPartial(string partialViewName, object model);

// Renders the partial view with the given view data.
public void RenderPartial(string partialViewName, ViewDataDictionary viewData);

// Renders the partial view with a copy of the given view data and the provided model.
public void RenderPartial(string partialViewName, object model, ViewDataDictionary viewData);

The purpose of partial views are to be small, reusable pieces of view. Ideally, they will be able to get the data to display from the ViewData of the parent, or through the use of the model that was passed specifically into them. Since partial views are intended to be a partial rendering, there is no concept of a "master view" for partial views.

In the WebForms view engine, both views and partial views can be either .aspx or .ascx files. In practice, we expect that most views will be .aspx files (pages) and most partial views will be .ascx files (user controls).

Individual view engines can set their own rules for how they process views vs. partial views.

One of the best features of this new system is that your partial views can use a different view engine than your views, and it doesn’t require any coding gymnastics to make it happen. It all comes down to how the new view system resolves which view engine renders which views.

Implementing views: the IView interface

That's right: we brought back IView! You'll notice that RenderPartial returns void, not string. This means you use the inline code syntax (no equal sign):

<% Html.RenderPartial("viewName"); %>

When views and partial views render themselves, they are not turned into strings. We did this primarily for reasons of memory consumption and scalability, but also because it was more natural with the way WebForms already work.

There is a single interface which represents both views and partial views:

public interface IView
{
    void Render(ViewContext viewContext, TextWriter writer);
}

Views are asked to render themselves into a text writer. In production usage, the provided text writer will be HttpContext.Current.Response.Output.

By providing the text writer to the Render method, it means those who are interested in testing the rendering of their views can do so without needing to mock the HttpResponse object. In your tests, you can pass a StringWriter, which wraps around StringBuilder, and inspect the resulting string when you’re done rendering.

The rules of rendering (or, what's that TextWriter there for?)

Consider the following view:

<p>Paragraph 1</p>
<% Html.RenderView("partialView"); %>
<p>Paragraph 3</p>

And the following partial view:

<p>Paragraph 2</p>

Let's assume that our view engine renders by putting everything in a string and then doing one big write at the end (there is at least one view engine today which does this, but I don't want to out anybody :-p). Our hypothetical view ends up resulting in the following code:

public void Render(ViewContext viewContext, TextWriter writer) {
    string result = "";
    result += "<p>Paragraph 1</p>";
    Html.RenderPartial("partialView");
    result += "<p>Paragraph 3</p>";
    viewContext.HttpContext.Response.Write(result);
}

And our partial view's code ends up being:

public void Render(ViewContext viewContext, TextWriter writer) {
    string result = "";
    result += "<p>Paragraph 2</p>";
    viewContext.HttpContext.Response.Write(result);
}

What's the actual output result?

<p>Paragraph 2</p>
<p>Paragraph 1</p>
<p>Paragraph 3</p>

I'm pretty sure that's not what we wanted. :)

Let's consider an implementation that uses the text writer:

public void Render(ViewContext viewContext, TextWriter writer) {
    writer.Write("<p>Paragraph 1</p>");
    Html.RenderPartial("partialView");
    writer.Write("<p>Paragraph 3</p>");
}

and:

public void Render(ViewContext viewContext, TextWriter writer) {
    writer.Write("<p>Paragraph 2</p>");
}

And the new result?

<p>Paragraph 1</p>
<p>Paragraph 2</p>
<p>Paragraph 3</p>

That's much better.

This is why views are given the text writer. Even if we could ignore memory consumption and scalability (I can hear Thomas groaning at such a suggestion), we needed to choose this implementation for another reason: WebForms already exists. :)

There's a whole bunch of infrastructure already set into place with .aspx/.ascx which means these things will be using Response.Write to put content out into the response stream. We need everything to play together in the same way, so passing Response.Output as the text writer encourages the correct implementation from view engine authors. As a bonus, it also gives us that extra test point. You know how much we love testing. :)

Implementing view engines: the IViewEngine interface

We split the behavior of rendering (IView) from the behavior of locating (IViewEngine):

public interface IViewEngine
{
    ViewEngineResult FindPartialView(ControllerContext controllerContext,
                                     string partialViewName);
    ViewEngineResult FindView(ControllerContext controllerContext,
                              string viewName, string masterName);
}

View engines are about finding views (and partial views). The ViewEngineResult that is returned offers two different constructors:

// Use this constructor when you didn't find an appropriate view
public ViewEngineResult(IEnumerable<string> searchedLocations);

// Use this constructor when you did find a view
public ViewEngineResult(IView view);

The system will run through the list of registered view engines (in order of registration) until it finds one that returns a view that can be rendered. If it never finds an appropriate view, then it throws an exception which lists all the locations that were searched.

For example, the WebForms view engine searches the following virtual paths looking for views and partial views:

~/Views/<controllerName>/<viewName>.aspx
~/Views/<controllerName>/<viewName>.ascx
~/Views/Shared/<viewName>.aspx
~/Views/Shared/<viewName>.ascx

Additionally, when you provide a non-null, non-empty master view name for FindView, it looks in the following locations:

~/Views/<controllerName>/<masterName>.master
~/Views/Shared/<masterName>.master

We anticipate that most of the view engines will be based on files in the file system, so we provided a base class which does almost all the hard work: VirtualPathProviderViewEngine. Implementing a view engine to derive from this class is very simple:

  1. In the constructor, set MasterLocationFormats, ViewLocationFormats, and PartialViewLocationFormats.
  2. Override CreateView() and CreatePartialView() to create the views when they've been found.

That's it. In fact, here's the whole source to WebFormsViewEngine:

public class WebFormViewEngine : VirtualPathProviderViewEngine {
    public WebFormViewEngine() {
        MasterLocationFormats = new[] {
            "~/Views/{1}/{0}.master",
            "~/Views/Shared/{0}.master"
        };
        ViewLocationFormats = new[] {
            "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/Shared/{0}.aspx",
            "~/Views/Shared/{0}.ascx"
        };
        PartialViewLocationFormats = ViewLocationFormats;
    }

    protected override IView CreatePartialView(ControllerContext controllerContext,
                                               string partialPath) {
        return new WebFormView(partialPath, null);
    }

    protected override IView CreateView(ControllerContext controllerContext,
                                        string viewPath,
                                        string masterPath) {
        return new WebFormView(viewPath, masterPath);
    }
}

The VirtualPathProviderViewEngine not only does the work of looking up the view through all the provided locations, it also takes care of caching the results of those lookups. When you're running ASP.NET in debug mode, it does not cache the lookup, so that you can add and remove view files without restarting your development web server; when you're running ASP.NET in production mode, it will cache the lookup results with a sliding timeout of 15 minutes.

Changes to Controller/ViewResult

We removed the ViewEngine property from the Controller base class.

On ViewResult, we added the ability for you to set an IView object directly if you need to directly create the view (rather than letting the view engines get a crack at it). We also added an overload to Controller.View() which takes an IView.

We also added a PartialViewResult class, and Controller.PartialView() methods which return it. You might find this useful to return partial views in response to AJAX partial HTML requests.

Registering the view engine

Once the view engine has been written, you register it with the system during Application_Start in your global.asax:

ViewEngines.Engines.Add(new MyViewEngine());

When attempting to render a view or partial view, the system will walk the list of view engines in order until one says "I can render this view". By default, the WebForms view engine is registered for you. As you register additional engines, you'll be able to interleave views that use any of the registered engines.

As mentioned earlier, you can render partials that use a different view engine from the parent view. This should help the case where you want to transition from one view engine to another, to be able to keep both running simultaneously, moving views over one at a time. Hopefully we can poke Phil into re-releasing his IronRuby sample, this time using both view engines to mix Ruby RHTML views with WebForms views. :)

ViewEngines.Engines is not thread-safe, so you should only register new view engines during Application_Start. If you need to be able to register view engines dynamically at runtime, you can create an instance of CompositeViewEngine, initialized with a thread safe collection, and then add and remove your view engines with that thread safe collection. Remember to register your instance of CompositeViewEngine into ViewEngine.Engines (in Application_Start, of course).

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00e54fbd8c49883400e554b3ab738833

Listed below are links to weblogs that reference Partial Rendering & View Engines in ASP.NET MVC:

» ASP.NET MVC Preview 5 Released from Johan Danforth's Blog
Hey, I'm just helping to spread the word! A sampled a few links and quotes that has already been posted [Read More]

» The MVC platform – action result views from LA.NET [EN]
In the last post we’ve seen how ActionResult derived classes will encapsulate the return values of action [Read More]

Comments

Feed You can follow this conversation by subscribing to the comment feed for this post.

Great info, thanks. It's always nice to know the why as well as the what.

Any thoughts given to renaming ViewEngine to something more indicative (ViewLocator, ViewFactory, ...)? It seems like the name doesn't really fit anymore.

@Kevindente Meh. It's still the engine of getting a view rendered. ;) It's funny, I suggested the idea of calling it a ViewFactory again, but then we're all the way back to our December CTP naming! Ha!

In any case, the way you use it is like a view engine. I think the name is appropriate enough, no?

>>can do so without needing to mock the HttpResponse object

Excellent... Have been thinking lately how LoD == clean mocking.

This does make me wonder why HttpContext appears in ViewContext? Guess I'll have to download the source and figure that out for myself :)

@Nicholas,

Yeah, the core classes in ASP.NET (HttpContext, HttpRequest, HttpResponse, etc.) are not very TDD-friendly. Even introducing the base versions that can be mocked is little comfort.

It would be an interesting intellectual exercise to see what you could come up with to replace all those things (and their LoD-violating knowledge of one another).

@Brad - an interesting exercise indeed, but not one to fit between reading the paper and washing the car on a Saturday morning.

I think to improve on the current design some kind of DI container :) would need to be employed in order to decouple the components - but... that relies on clients of the framework themselves being instantiated by the container in order to retrieve references to the composed bits and pieces...

To make such a thing generally usable, some kind of facade like HttpContext is inevitable.

That HttpContext does provide an instance-based means to get to so much information is far preferable to the copious statics that could otherwise have eventuated.

My query was really restricted to the role that HttpContext plays in rendering a view or partial - in which use cases *should* a view require information beyond its model and parameters? I've answered that for myself in the last 10 minutes - pretty much anything real-world will fall into this category.

Cheers

@haacked - "It's still the engine of getting a view rendered" - Is it? Based on Brad's code, I'd say WebFormView is actually what I would think of as the "View Engine" - the thing that renders the view. The ViewEngine just finds one.

I assume this is the last chance to change it for all eternity, which is why I'm raising the question. :)

@haacked, since it's choosing which view engine to use, shouldn't it be ViewEngineFactory?

@ceilidhboy,

I think during one of the iterations we actually had ViewEngineFactory and ViewEngine, and decided that we liked the names ViewEngine and View better.

To be semi-pedantic, if you think the "engine" is the thing that does the heavy lifting, then the engine for WebForms exists inside of classic ASP.NET then. :)

A naming conundrum to be sure.

Great stuff... I hope now this is final solution for rendering sub-views after the RenderContoller and RenderComponent (or whichever where the name before) of the previous releases.
Thanks for sharing
Simo

So given three pages (home, products, services) how am I supposed to provide data for the 'latest news' partial view in the sidebar? I can't put that into three controllers at the same time (I can, but I don't want to).

What is so awful about calling back to a controller that will render/return the partial view? I must be missing something obvious here, because to me that seems vital.

Thanks!

@Mike,

I don't recall using the word "awful" anywhere. :)

The solution that we like best in this scenario is to write an action filter which places the data into ViewData, and then decorate the appropriate action methods and/or controller classes with the action filter. This is pretty much the identical scenario to having a view with a master, but the master never has a controller either. If this view is pretty much everywhere, then you could make your own controller base class to ensure that the sidebar data is always present in ViewData.

The thing about the MVC pattern is the controller is in charge. Views should never know any details about controllers or how they work. A view says "My data is here, and I will render it". The kind of pattern you're suggesting, where each sub-piece of a view has it's own "controller", is actually the MVP pattern. There's nothing wrong with that pattern, but I think you'll find that mixing the two patterns is going to lead to a lot of confusion and complexity.

I think that this is a similar question to "3 pages" posted by Mike but I am still confused so I will ask it in a different way.

I have a Site.Master for the whole site. On that Site.Master are 2 partials, one for the header and the other for the footer. The navigation of the site is a classic tab type structure. So while I am in the controller I need to tell prepare the data that will tell the partial that renders the Header which tab should be highlighted. Do I need to create a ModelBase kind of class that has a property called "ActiveTab" so that no matter what model is being passed to what view the "ActiveTab" property is always available to the header?

Or is there a better place for this information... ModelStateDictionary?

While I have a basic understanding of the MVC pattern I have only been using the ASP.NET for few days. If I am just out in left field someplace please don't hesitate to let me know.

@Ryan,

I think the "best" solution depends a lot on what kind of information can be inferred at runtime.

One way you might attempt to solve this problem is with an action filter. In the action filter callbacks, the ActionExecutingContext and ActionExecutedContext derive from ControllerContext. If your site map directly maps onto controllers, then the action filter could not only fill in the site map, but also say 'this is the selected tab, because this is the active controller'.

You could get progressively more sophisticated as you attempt to determine the active tab. Maybe the combination of controller and action tells you what the active tab is, either by name or by some form of convention or configuration. Maybe you can make an educated guess, but allow the action itself to override the choice, either with code or some custom attribute. Or maybe it's simply not deterministic, so actions always have to set the active tab.

Whatever the choice you make, you should be able to write a solution that serves you.

As for ModelState, the purpose of that is to hold information about data models that are currently being edited, so it wouldn't be the appropriate place to put the information. The kind of information we're talking about here belongs in ViewState.

By the way, I do want to say that I personally (which means this is my opinion, not the team's) think that the fact that the view has access to the controller is a violation of the spirit of the MVC pattern. I would consider any view which accessed its controller to be a strong indication of a bad design.

That's also one of the reasons I don't like the HtmlHelpers which allow route rendering based on LINQ expressions of controller methods. I am a strong proponent of refactoring and good refactoring tools, but this is one place where controller method does not necessarily == action, even if that seems to be the suggested default/conventional behavior.

I asked for an explanation, and I got one. But I still don't get it. Let me try to explain how I see it.

Given a NewsController, it might have the following actions:
Index (get's latest news, view shows the headlines and small excerpts)
Show (get's one news article and max 5 related articles, view shows the headline and body, and shows the 5 related articles' headlines)
Archive (get's all news articles paged, the view shows 10 and paging)

That's a neat controller, it handles the news, and it does it well. However, somewhere in my project there's another class that handles news. It's not in the folder controllers and it's not clear from looking at just the NewsController that it even exists. It's called LatestNewsActionFilterAttribute or something even more convoluted and it gets the latest 5 news articles. It places them in the ViewData and has no associated view. It's not clear how or when the data is rendered. Then there is a partial view that can render news articles in just an HTML list. This is pretty clear, its intent and the way it handles data.
Isn't this counter intuitive? I would expect to find news related code in the NewsController, not in an ActionFilterAttribute, which are logical places for authentication, caching and logging for instance.

In my view, given the right method, you could say that to get the latest news into my sidebar, I have to 'call' the Latest action on the NewsController, and the result is exactly what I want there. I think it's similar to saying that a form on a view has an action attribute that points to the Register action on the UsersControllers or a link that goes to the List action on the ProductsController.

Maybe I'm totally not getting it, it is kind of strange coming from WebForms. Basically, I don't view ActionFilterAttribute as a great way to do it, and I am not convinced my proposal is that bad.

Monday I will start my first project in ASP.NET MVC so I will get it, I have to! I waited especially for partial views to be solved because I need it, I will be aggregating data from different sources in multiple loosely coupled web applications.

Given that the next version is beta, this is what we have for now, no more changing right?

Thanks for listening!

@Mike,

Yes, the confusion is probably at least based somewhat on the way WebForms works vs. the way MVC works.

In the WebForms world, the typical "Presentation Separation" pattern that you choose is Model-View-Presenter. The reason this is a commonly chosen pattern is because in MVP, the Presenter is an implementation detail of the View. The outside world calls into Views first, not Presenters. You see this pattern reflected in the way WebForms uses URLs: to point directly to Views (.aspx files).

In MVC, the outside world calls into Controllers first, and Controllers make the decision about which Views to render. The Views in MVC don't really know anything about which Controller asked them to render or why, nor do they care. They take the data -- through whatever data passing system is appropriate -- and display it.

So that means it's the Controllers responsibility to gather ALL the data that will be displayed on the view, and give it to the view. The choice of using sub-views/partial views is one that the view makes, not one that the controller makes. Partial views are an implementation detail of the views in MVC, and controllers are non-the-wiser about whether the data is rendered directly or through a partial view.

So the attributes can act as an AOP-ish way of doing method interception to say "the fact that this view data is required to the path is somewhat orthogonal to the core purpose of this action, so isolating it off here in a reusable bit of logic makes the core behavior cleaner and easier to read and write".

Or, if you don't like the attributes and want a "different" method to get the data, then it's still the controller's responsibility to call that method, because views are supposed to be stupid. They don't care where the data comes from; they just expect it to be there.

I have an article on "composite views" in MVP, which probably describes the thought processes you're going through right now. If you were doing MVP rather than MVC, that's what you would do. I agree that it's going to take some time to train our brains away from the "view-in-command" mentality of WebForms over to the "controller-in-command" mentality of MVC.

http://bradwilson.typepad.com/blog/2008/06/composite-views.html

I'll add my (useless) 2 cents to the superfluous view engine naming debate. I think the view engine is something that is directly bound to the IView instance returned by FindView or FindPartialView). In that sense, the IViewEngine interface feels like a misnomer because all this time we have been using the "view engine" terminology to refer to things like NHaml, NVelocity, WebForms, etc, which are responsible for the actual rendering of the view contents, not for producing the IView object.
I tend to agree with @KevinDente on this one. Even ViewEngineFactory wouldn't sound right. Unless I completely misunderstood the meaning of view engine or it was decided to change its meaning recently.

"So that means it's the Controllers responsibility to gather ALL the data that will be displayed on the view, and give it to the view. The choice of using sub-views/partial views is one that the view makes, not one that the controller makes. Partial views are an implementation detail of the views in MVC, and controllers are non-the-wiser about whether the data is rendered directly or through a partial view."

This seems to contradict itself. When programming, the controller needs to get the latest news BECAUSE the view uses a subview of the latest news. It's more coupled instead of less! I you have a design with a big sidebar full of data gathered from around the site, the controller is huge and fetching ALL the data, just because the DESIGN wants that data.

In my proposal, there would be no such problem. Each controller would be in charge of providing several views with data, be they full pages or pieces of HTML. I think my proposal is way better. Also in my proposal views are still none the wiser of their controllers. They just use helper methods. In fact, I compared specifically to other helper methods that also point to controllers and actions (to make links for example).

Now I'm going to go out on a limb here, and I really don't mean to offend but... is it possible that you guys are making a mistake here? It took three iterations, perhaps because even you are not really sure about how to best do it. I notice you did not answer my concerns about the fact that somewhere in my application there are several ActionFilterAttribute classes that are fetching data and putting them in ViewData, just the thing you'd expect from a Controller class, and NOT from an Attribute class.

I'm afraid the blog is not the best venue to go deep into these subjects so I guess time will tell. I'll be back on the forums for this too. But to be really honest, I am not at all convinced and slightly worried that it will be revisited again post beta.

I hope RenderPartial can be used in any view using the MVC versions of the Dynamic Data Field Templates. As this will allow a clear place in Shared to put reusable field/label/validation combined templates.

@Mike,

I guess we just have to agree to disagree here.

@Andy,

Yes, RenderPartial will pay into the MVC implementation of Dynamic Data. That's why I bugged them for it. :)

I suggest you use Spark.. or anything else that has partial views.. but forget about WebForms.

@Mihai,

Now all view engines have partial rendering, and the view-engine-specific partial rendering systems can (and should probably) be removed or deprecated.

@Brad,

That was one of my first thoughts also, but I think there's enough of a difference between them to keep both internal and external partials distinct.

In Spark the generated code from a partial appears inline, so all of the locals in scope and other view class members are available. The syntax of internal partials is also very clean and terse, a core part of the view engine's goal.

If anything the internal partials should be called something else to avoid confusion.

@Louis,

I think the problem with that is that the systems work differently, so leaving both systems in place can cause a lot of confusion when people move from one view engine to another.

@Brad,

(read { } as lt gt)

Agreed, which is why I'm thinking of replacing the term render partial with something like import or include. Beyond that confusion hopefully won't be an issue - the {% Html.RenderPartial("Menu") %} notation looks and acts exactly the same in either spark or aspx.

But they work differently enough to serve different purposes. The inclusion support in spark is one where you can draw in any file that starts with an underscore by using it's name as an element. _footer.spark can be used as {footer/}. You can also pass information in context as attributes and as content of the element.

After all the syntactic sugar and other conveniences is what it's all about. Take that away and there's no reason to use spark at all. :)

Love the changes to the IViewEngine/IView by the way - registering a view by replacing the controller factory was awkward. Say - do you think the IViewEngine would have a DisposeView method at some point? (Similar to IControllerFactory) I ask because if a view is created from an IoC container, like Windsor, it's best to release the object with the container when it's done being used.

Also please consider overloading RenderView with a TextWriter parameter. I agree with your points about performance, but there are many situations where a mandatory one-pass top-down output can be problematic.

Ah wait! I see RenderPartialInternal is virtual... Nope. internal virtual. Aww...

That is to say, please consider overloading HtmlHelper.RenderPartial with a TextWriter parameter.

@Louis,

Would simply supporting IDisposable be good enough?

The internal virtual of RenderPartialInternal is for testing. There really wouldn't be a convenient way for someone to be able to get in there and override that behavior.

Whether you do a one-pass top-down system or not, the idea that you can avoid the TextWriter is a flawed one for the reasons I outlined in this post. I guarantee you will cause problems if you don't follow the guidance here. Existing view engines that used strings or StringBuilder were already broken, but they hadn't yet discovered it; we're just highlighting that they were broken, and offering TextWriter as a reminder (and a testability point). If you'd prefer to use Response.Write to the TextWriter, than you'll lose the testability hook, but at least you won't be broken in the mixed-view scenario.

@Louis,

We can consider overloading RenderPartial with a TextWriter, but under what circumstances do you think users would actually call it? What TextWriter would they have in hand that they would be passing to it?

@Brad,

Unfortunately no, IDisposable alone wouldn't work in a few cases. For example if a component implements IStartable or IDisposable, Windsor will track the instance to know which lifecycle concerns need to run when it's ultimately released/decommissioned. Worst case this can result in components, or the components they use, that are never disposed because the container's still referencing them.

I think this is part of what Hamilton calls the component burden.

http://hammett.castleproject.org/?p=252

----

Spark does indeed use a TextWriter for it's output, one of the few properties of the abstract base view is a TextWriter Output {get;} and before Preview 5 at the outermost level used the ViewContext.Response.Output. It's using the writer argument from Render now, of course, so if anything the new IViewEngine/IView interfaces are an even better fit for it's internal rendering model.

However one of the things spark can do is shift scopes of output into named content regions. For example if you want to add js/css to the head, you could:

in the view (tags mangled to pass comment validation)
{content name="head"}
{script sr=~/content/yaddajs}
{link hrf=~/content/yaddacss}
{/content}
{p}hello world{/p}

in the layout/master
{html}
{head}
{title}...{/title}
{script sr=~/content/alwaystherejs}
{link hrf=~/content/alwaystherecss}
{use content="head"/}
{/head}
{body}
etc.
{use content="view"/}
etc.
{/body}
{/html}

It's quite flexible... You can use several named content areas in a layout and fill them in with specific information on a per-view level. left-rail, right-rail, etc. Adding end-of-page js to "foot" content with {use content="foot"/}{/body}.

But to make it work with external engine rendering you would either need to use {% Html.RenderPartial("partialView", Output) %} in the template, or more universally the view engine would need some way of directing the response output in the view context.

Which, thanks to the magic of the wonderful HttpContextBase, is probably do-able... And more convenient and reliable for the developer too...


"there is at least one view engine today which does this"

Well, it's not NHaml :-)

Correct me if I'm wrong, but isn't the whole API distinction between view and partial view here purely to support the idea of views rendering partials from a different view engine?

If you were to drop support for that scenario, and assume that view engines are capable of sorting out their own mechanism for partials, then you'd avoid several problems:

[1] You could allow view engines to do single-pass top-down string building style rendering if they wanted (as well as WebForms-style Response.Write() rendering if they wanted)

[2] You could allow different view engines to implement different partial view semantics. For example, Spark would be allowed to define its own unique semantics about which local variables remain in scope.

[3] You could simplify the whole IViewEngine API, avoiding the unnecessary confusion between partials and actual views (in in WebFormViewEngine, there's actually no difference in behavior between views and partials, so users will be confused about why there's different IViewEngine methods for them)

So what I'm saying is, do you really think that having one view engine render partials from a different engine is really going to be an important scenario? I can't think of a good reason why I'd ever do this. What's your cost-benefit assessment?

@Steven,

The decision was made to support different view engines for views vs. partials to support both mixing as well as migration stories. If you can imagine that third party "control" systems might become reliant on partial rendering, then supporting multiple view engines becomes critical, since the third party vendors can render their own views in a way that's independent of the view engine selected by the application developer.

Specifically, on your three points:

The problem with #1 is it places an unnecessary burden on both HTML helper authors (they must always output strings, whether they want to or not), and it also places undue memory pressure on the web server when the view output is large. It's just not good practice.

For #2, we're not stopping view engines from making their own partial systems, but they do so at the risk of alienating people by suggesting people do non-standard things. That's their decision to make, though.

For #3, there is a difference between views and partials: the presence of masters.

@Brad - Thanks for doing this work and writing it up. I have been waiting for a solid partial rendering story and am excited it is here.

@Brad & Haacked - I'm with Keven Dente on the naming. It feels wrong. Given that IViewEngine has two Find methods (that both find IViews), and that the ViewEngineResult has two properties that relate to the search (the IView and the SearchedLocations), surely it is an IViewFinder?

I ViewEngine does not seem intention revealing to me. Or, rather it does, but I would guess it was something that had properties like Name (e.g. NHaml), Version (e.g. 1.0) and Author (e.g. Andrew Peters).

I've only recently been trying to pick up the .Net MVC framework so I've been reading as much as I can about it and trying to get myself up to speed. Hopefully I'm beginning to get a decent understanding of things but bear with me if my questions/thoughts wind up being dumb.

I think I understand the purpose of Partial Views which are there essentially to allow for re-use of code in views independent of the View Engine, which I agree with Ben above that it sounds more like it should be called IViewFinder but I digress.

The problem I have is that in allowing for code re-use in the view you seem to have guaranteed a certain amount of code duplication in your controllers. Because as far as I can tell the Controller that handles any view that makes use of a Partial View also has to have code to load the data that is necessary for a Partial View into the appropriate Model.

That seems like you've pushed a lot of extra code into your controllers or forced yourself to do the leg work of re-using code to populate that partial view. I may have missed something in terms of how you actually handle this in practice so I apologize if I'm sort of missing the point.

I guess Partial Views almost imply the possibility for a Partial Controller but I'm not sure whether that makes sense or not. It seems like you could implement a partial controller along with actions that pertain to Partial Views and then in your controller you could have a method that would let you invoke them somehow.

Possibly something like "RegisterSubAction("{partialController}/{action}/{id}") with the same overloads as the existing RenderPartial method.

So your main action method would run and populate the model/viewdata and then your partial controllers action methods would run based on your url routing scheme and what you passed in with "RegisterSubAction" which should load all the data necessary for the partial views you have defined and then the view would be returned. You'd only have to define code necessary to display your partial views in one spot and then you could reference it in the actions that would have had to implement it before.

Of course I have no clue if that would violate the spirit of MVC in the first place. So those are just the two cents of an MVC novice and thanks for any comments back in advance.

@Sean,

You can obviously solve the "duplicated code" problem by refactoring it into some place that's easy to reuse. As I suggested earlier, helper classes and/or action filters would be my first choice for this.

There is a RenderAction helper in the futures project (Microsoft.Web.Mvc.dll). I personally believe that it does violate the spirit of MVC, but some people don't necessarily want strict MVC from their MVC framework (obviously). The partial action/partial controller system is more in line with the MVP/Presentation Model class of Separated Presentation.

@Brad,

Thanks for the quick reply, I guess I'm just thinking about this in terms of what would make the code the easiest if you were working in an environment that uses a lot of AJAX. It's just easier to think of your AJAX calls as implementing partial views. Which is one way to do it right now anyway but it'd just be nice if the way you implement the AJAX based call, using jQuery or whatever, worked in a similar way to the way you'd use a Partial View in a View. And of course bringing AJAX into it makes it pseudo-MVC anyway, it's just too bad the two get shoved together so much.

@Sean,

You can go either way: one action with conditional view choice, or two separate actions with two separate views. Either way, you can still reuse the partial view, since the AJAX action (or the AJAX fork of the single action) only renders the partial view, whereas the full version renders the full view with the partial view inside.

Hopefully developers using wouldn't be alienated, since the Html.RenderPartial() is available and it's behavior as documented is not affected in any way. You can even use the angle-bracket-percent notation around it. If anything there may be a greater chance of alienating the developers who worked so hard to bring us the partial support in the Mvc framework. ;)

I agree with the comments about preferring to have partials ajax or link to controller actions, rather than introduce partial controllers with actions. With the server web controls there was the entire life-cycle, and the command handling could occur at the control level without the pages's involvement or knowledge. It could get pretty crazy. If you have a Widget partial you will use from views on many controllers I think it's much cleaner to have all of it's ajax calls come back to a full WidgetController.

I see where you're coming from with concerns about memory pressure, though in practice that hasn't been a problem yet and we've tested under load over 350 req/sec of "home page" views. There may have been some inefficient use of memory but the numbers exceeded our requirements significantly. Doesn't BufferOutput default to true in any case? Unless I'm mistaken wouldn't most aspnet sites would be spooling their html in memory before responding already?

The previous RenderUserControl allowed ViewUserControl properties to be set via an extra overload which used an anonymous type.

This scenario agreed with the idea of separating dependencies while retaining some of the advantages of control development.

It would make sense that a ViewUserControl behaves like a control, and have the ability to have control properties set when instantiated by the ViewEngine; like it was.

So I'm left with two choices, I can extend the WebFormViewEngine to provide the ability to set control properties, like before.
Or I muddy the water, and use the ViewDataDictionary to pass properties to my ViewUserControls....

@Simon, I think user controls should now be thought of as user templates hence the name "partial view". With MVC, there is no good reason for a user control to have properties as it doesn't "fit" the new design approach.

@Simon,

There's nothing stopping you from using user controls in the traditional way, but RenderPartial cannot make assumptions about a user control as the underlying implementation. As such, RenderPartial allows you to pass a model as well as a view data dictionary. This should be sufficient for passing data to the user control.

I am trying to upgrade from Preview 3, and all I did was swap my "RenderUserControl" call with "RenderPartial"... Now, when I try to load the containing page, I get:

The best overloaded method match for 'System.IO.TextWriter.Write(char)' has some invalid arguments

I'm not sure how others were able to gleam this from your post, but I can't seem to make heads or tails of what I need to do? I would implement IView in my control, but I would really like to not have to build the output string in the codebehind. Can anyone point out what I'm missing here??

What about renaming IViewEngine interface to IViewLocator? All it does is looking for the view that needs to be rendered, and the view engine is the "collective" name for that feature.

To be honest, there is so much here to digest I would rather pose a question than to rant about my MVC philosophy. So here it goes:

1. Can I have a single page architecture (ex. ExtJs border layouts) where I can replace a portion of the page (without re-rendering the entire page)? I may have 100 different partial views that could replace the existing content area in my single page with their view html. This is similar to using an iframe to display another page.

2. If so does anyone have any idea where an example might exist?

3. If not, why?

Thanks.

@Chris,

If Javascript is acceptable, then in my experience the best solution here is controller methods that render partial views instead of full views, which are retrieved via AJAX (erm, AJAH) calls. The MVC AJAX support that was added very specifically can be used for this scenario. I don't know where the examples are for that, though.

Thanks Brad I'll keep my eye out for partial view rendering. In the meantime, if anyone finds an example please post a link to it here.

@Chris

I have an example of this in my PDC talk: http://channel9.msdn.com/pdc2008/PC21/

If you go to that URL, you can download the source code for my demo.

For anyone who wants to see how you can implement a custom view engine, I wrote an article showing how to write a view engine which enables skinning of an ASP.NET MVC application

http://thecodejunkie.blogspot.com/2008/11/adding-support-for-skins-in-aspnet-mvc.html

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment