Home MVC Storefront

ASP.NET MVC: Using UserControls Usefully

This post is in response to a forum user, who is wondering how to properly use a ViewUserControl:

I'm sorry if this is a really silly question,  but I'm having a hard time grokking what the right usage of a ViewUserControl looks like. Does one invoke the RenderView from a controller? If so, where is the parent page that the ViewUserControl is embedded in? Or, should you put RenderView into the ASPX of a ViewPage itself?

I can make the thing  render in any number of different ways from different places, but I'm not clear on what the right MVC model is for this situation. I've read the long thread on the ".. very complex page with many MVC modules..." but I'm thinking of a simpler scenario: Let's suppose you have three or four different views that you want to compose into a page? Is this the right scenario for a ViewUserControl? If so, where would you reference the control itself?

This is an interesting issue, and as he went on to point out, there are lots of ways to use these partial UI bits to your advantage. As always, I'll offer some ideas here for you, but this is not the only way to do it.

 

The "Viewlet"
Given that a ViewPage inherits from System.Web.Page, you can still register and reference a UserControl (.ascx file) on a View and have it render. You can even pass it data in the code behind or as a property setting:

<uc1:MyUserControl ID=myControlView runat=server myProperty="Hi Mom" />


But using the WebForms model inside MVC can be a little confusing - especially for folks who will pick up your project later. In this case - the ViewUserControl will render just fine, and in many cases it's all you need. But if you're interesting in keeping things as modular as possible within MVC, read on.

Your UseControl can be one of two things:

  • A granular bit of UI that renders information passed from a Controller
  • A granular bit of UI that renders information from an application-wide data source

The idea here is reusability and maintainability.

I personally don't like the idea of putting logic into ViewUserControls, but at the same time it can serve a purpose - with portal stats for instance where you might want to serve up personalized links (using the Memebership.Profile for instance), etc.

In other MVC frameworks they make a distinction between the two. In Rails, for instance, a "Partial" is simply a View that's shared between views, and not meant to be standalone. If you've ever used Rails to create the demo scaffold, you've used the partial "_form.rhtml" which is responsible for rendering an input form for the New and Edit views.

If you need more than basic rendering of HTML in Rails, you can move to a Layout. Layouts essentially wrap UI around some logic, and are a nice modular way to reuse UI/logic elements around an application. These are like "UserControls Light".

Rails also allows for "sub apps" called "Components", which are useful when you have "sub applications" like an image gallery or rss reader. The idea here is that these components contain their own logic and can be used between many applications.

My point with all this is that if you feel lost trying to make a decision (architecturally) regarding MVC - it helps to see how other platforms do it (like Rails or Django).

 

Rendering a ViewUserControl
The MVC Toolkit has a nice method called "RenderUserControl()" that allows you to process your ViewUserControl and output it's result inline:

 
<%=Html.RenderUserControl(“~/UserControls/UserList.ascx”)%>


If the ViewUserControl is typed (say ViewUserControl<MyControllerData>), then it's ViewData object will be filled for you, and your ViewPage and rendered control will share the same data.

If you want to be explicit about it, you can do that as well, specifying the data to pass:


<%
=Html.RenderUserControl(“~/UserControls/UserList.ascx”,ViewData.Users)%>


Finally, if you need to set properties on the ViewUserControl, you can do that as well by passing in an anonymous type:


<%
=Html.RenderUserControl(“~/UserControls/UserList.ascx”,ViewData.Users, new {GroupID=2})%>

 

Using the RenderUserControl method allows you to have complete control over how your ViewUserControl is supposed to be used

 

Summary
UserControls are a great way (still) to encapsulate UI elements for your MVC app. There are many ways to use them, and if you have one I didn't mention (or dislike my approach here) - do let me know. As always - we're still CTP and there's lots of room for comments.

Vijay Santhanam avatar
Vijay Santhanam says:
Monday, January 07, 2008
Very neat. You've given us so many user control choices, it's great! Will the control instance declaration by default be passed the current view page data??

mike avatar
mike says:
Monday, January 07, 2008
I don't see why a method RenderUserControl would be member of an object HTML. It might be better as a member of ViewPage. Please consider, thanks!! What I find strange is that we are supposed to call from the ViewPage directly to a user control. We should really call a controller method and have that controller render its view which ends up at the place where we called to the controller. That controller should provide the view with all the data. It migh even return an empty string based on the data. That way, the user control is reusable.

tgmdbm avatar
tgmdbm says:
Monday, January 07, 2008
I agree that there are two types of "sub view" involved here. In one case where the sub views are part of the entity being rendered then RenderUserControl is ideal because we will have the data in the pages ViewData. However, in the case where the page is rendering "widgets" it's impractical for the main controller to know where to get all the data for all the widgets. each widget should be responsible for collecting its own data, and so would require a call to the widgets controller. In second case, the ONLY thing that is required is a call to a method on the controller, because that would in turn render the widget in-place and continue rendering the current page, however, there is some initialisation that needs doing like passing in the correct ControllerContext etc. it would be nice if there was a method on the ViewPage which allowed us to do this. ( x => x.Show() ); %> The second one is more dynamic but less type safe.

Shawn Oster avatar
Shawn Oster says:
Monday, January 07, 2008
Mike, if you prefer the concept of a 'WidgetController' there is nothing preventing you from writing your own. That is something I think a lot of WebForms developers are going to have to wrap their minds around, that MVC is a lot more malleable and not quite the rigid framework as WebForms. It's really a matter of semantics, because you could create a WidgetController, just don't descend it from the base Controller, and expose a Show() method that grabs the needed data as well as either hand generates the HTML or instead makes the call to RenderView itself. The only real downside I see to this approach though is maintainability in teams. Now you have two types of controllers and you need to let others know at a glance that it's not a main controller. I believe some people get around this by instead calling them Services :) I hope the MVC team keeps that in mind as well, that we don't need a 100 different methods to do the same thing because with extensions and 3.5 it's much easier to extend the framework on our own, keeping MVC a clean framework to build up from instead of an all encompassing beast like WebForms.

Sergey avatar
Sergey says:
Monday, January 07, 2008
Hi, sorry for wrong article to ask, but I have one question on MVC databinding (and UpdateFrom method). Suppose I have control. UpdateFrom method will unbind control's value to my object's Name property (if one exists). Does unbinding using id or name attribute for Property name and can I use different id and name values, for example id="txtName" and name="Name". If so, are you going to implement this kind of overload to HtmlHelper extension method Text()?

mike avatar
mike says:
Monday, January 07, 2008
Shawn, do you mean just instantiate WeatherController and call its Forecast() action? That seems allright to me. But then why does Ruby on Rails have this special notion of partials, layouts and components? What was the idea behind that? PS. I still really like the declarative markup:

mike avatar
mike says:
Monday, January 07, 2008
Ugh, can't post html here? Let's try again. PS. I still really like the declarative markup: [my:Weather Display="Forecast"/]

tgmdbm avatar
tgmdbm says:
Monday, January 07, 2008
@Sergy, the unbinding uses the name and not the id, and yes you can have a different id. also, I didn't see the first time but my brackets screwed up my last post. <% CallController<WidgetController>( x => x.Show() ); %> <% CallController( "Widget", "Show" ); %> The second one is obviously more dynamic, you could just return a list of strings and have it output all the different widgets.

tgmdbm avatar
tgmdbm says:
Monday, January 07, 2008
that gives me an idea!!! <mvc:Call Controller="Weather" Action="Forecast" /> that could create the WeatherController and call the Forecast action. However there's the problem of passing arguments to the action. <mvc:Call Controller="Weather" Action="Forecast" > <Arguments> <Argument Name="Date" Value="Monday" /> </Arguments> </mvc:Call> thoughts?

Rob Conery avatar
Rob Conery says:
Monday, January 07, 2008
@tgm - outstanding idea. Circulating it internally to see if the team is working on something like this right now. Will let you know....

tgmdbm avatar
tgmdbm says:
Monday, January 07, 2008
Rob, sorry to post this here. There are a few forum posts that have moved on to the 2nd page which i think could still use some input from the team. http://forums.asp.net/t/1201315.aspx - rexmorgan http://forums.asp.net/t/1196459.aspx - francois_tanguay http://forums.asp.net/t/1199824.aspx - tgmdbm http://forums.asp.net/t/1200778.aspx - tgmdbm Thanks for your time.

tgmdbm avatar
tgmdbm says:
Thursday, January 17, 2008
"Will let you know..." Have you heard anything from the team regarding this?

Rob Conery avatar
Rob Conery says:
Friday, January 18, 2008
@tgmdbm - I've created a new method (in your honor!) called "RenderAction" but it's a tad hackish. It works, but not the way I want it to. I'm looking at some other ways to do it but in general the feedback internally was (specifically from Scott) "Awesome idea!".

Rex Morgan avatar
Rex Morgan says:
Sunday, January 20, 2008
Rob, you answered my question on the ASP.NET forums, but I would like to follow up with that here, since caching is extremely important to me - can we expect to see these methods for rendering ViewUserControls respect Output Caching?

tgmdbm avatar
tgmdbm says:
Monday, January 21, 2008
I feel very honoured that yourself the big S.G. like the idea. Thank you. I have also written this code, and yes, mine too is extremely hacky. check it out here: http://forums.asp.net/t/1207994.aspx Would be nice if the framework would allow this code to be cleaner. When's the next drop of the toolkit? Are you waiting for the next drop of the framework?

Pure Krome avatar
Pure Krome says:
Monday, January 21, 2008
ZOMG! Tgmdbm ... that's my post (with your answers) that you've referenced :) So kewl! Also, your post sent me here ... and i do understand what Rob is saying, a bit easier. I suppose i'm begging for some sample c# solutions that have a simple example of a few pages with an MVC View User Control being used in each one ... AND ... the MVC VUC having a simple 'postback' ... say a linkbutton (the equiv, if we were using the asp.net webforms stuff .. which we are not). In the code i'm trying to do, i'm trying to drop a reusable control onto various Views which toggles something in the user's Session -- for example .. maybe .. times in 24hour or 12 hour. Once i've got this working, i was going to try and AJAX that MVC VUC ... but that's a whole other huge problem. Sounds like i'm going to look at JQuery or Prototype ... which is another new learning experience because i'm used to some simple MS Ajax stuff (eg. UpdatePanel). So much to learn and so little time. Would love some suggestions / help :)

cxvin avatar
cxvin says:
Wednesday, February 27, 2008
I like tgmdbm's idea lots and glad to hear it's on the way from the team. When will it be? I'm just getting going in MVC framework and when I started making user controls I felt that the way they are placed on the page didn't feel right. I've tried to get away from this before in asp.net by dynamically adding the ascx controls - but to do that here would be to treat the page as a controller, and mess up the seperation.

Addifsnefmini avatar
Addifsnefmini says:
Friday, February 29, 2008
Hello there. Just found your site. Great job! I like it much. look here http://live.com


Search Me
Subscribe

Index Of MVC Screencasts

You can watch all of the MVC Screencasts up at ASP.NET, and even leave comments if you like.

Popular Posts
 
My Tweets
  • @haacked must.... resist... assimilation...
  • Dinner at the Haacks. How did Phil get such a cute kid? Evidently Phil's in the doghouse though...
  • @shanselman dude turn off twitter and drive! that's gotta be illegal!
  • For D'Arcy and Justice... Scottgu goes Canuck! http://twitpic.com/mfz1
  • Working in ScottGu's office with @shanselman. Wearing an Orange Polo and saying "go ahead" a lot for some reason.
  About Me



Hi! My name is Rob Conery and I work at Microsoft. I am the Creator of SubSonic and was the Chief Architect of the Commerce Starter Kit (a free, Open Source eCommerce platform for .NET)

I live in Kauai, HI with my family, and when my clients aren't looking, I sometimes write things on my blog (giving away secrets of incalculable value).