Mike Bosch's Blog on .NET

Agile enterprise architecture in .NET, SOA, WCF, WS-*, AJAX, MVC, Sharepoint and more...

Using the ComponentController in ASP.NET MVC CTP 2

ASP.NET MVC CTP 2 shipped with a new controller class which you may have missed.  Community feedback begged for a better way to handle component pages that don't rely on the main page's view data.  A classic example might be a stock ticker.  We would want a reusable component that you can place in other pages.

The ComponentController allows you to call a controller action from within the page itself.  It's use is very similar to the regular controller.  You basically create a new class the inherits ComponentController.  Then you create public methods as the actions of the controller.  Within the action method, you can implement whatever logic you need the component to perform.  You finally call RenderView to render the view just like the regular controllers.  

It's important to note that the ComponentController doesn't look in the same places as the regular controller when finding the views.  On this CTP, all component views need to reside in the right directory for the RenderView method to find it.  The convention is Components/[ComponentControllerName]/Views/[ViewName] directory.  In this case, the name of my controller is MyComponentController and the view name is CustomerOrderView

 

I'm not a big fan of forcing convention this since I may want to put my components wherever I please, but I digress.  Let's look at the controller.


This very simple controller has a single action named ShowCustomerOrders.  This method calls my order repository and returns a list of orders for a customer.  I will be able to use this on any view where I need a quick summary of the customer orders.  It accepts a CustomerID and renders a view named CustomerOrderView.

From within the page, I'm using the lambda notion to make the call to this controller.  The Html helper has a method called "RenderComponent".  I specify my component controller and the action it should call.  In this case we are passing the customer ID "1".   This can be easily replaced with some of the view's ViewData properties.


Taking a look at the view that my component will render, we see it is a simple list using a strongly-typed CustomerOrder[] as the ViewData.


That's all there is to it.  When we run the page, our customer orders show up where I placed the call to the RenderComponent method.  

Hope this helps!

UPDATE:  I uploaded the source code for the example.  Download it here.

Posted: Mar 10 2008, 12:45 PM by MikeBosch | with 19 comment(s) |
Filed under: ,

Comments

Henry Tait said:

Could this be used in a web service to render out the html from a view?

Any ideas how I would get an instance of a ViewContext to instanciate an instance of HtmlHelper ie, using something like this?

HtmlHelper html = new HtmlHelper(viewContext);

html.RenderComponent<blah>()

# March 10, 2008 6:50 PM

Tuna Toksoz said:

Could you please send the whole code?

I am having trouble with doing data passing right,but no luck.

# March 11, 2008 4:05 PM

MikeBosch said:

Sure.  You can download it here:

weblogs.asp.net/.../component-controller-example.zip

# March 11, 2008 4:35 PM

MikeBosch said:

Henry Tait:

There's also a property named RenderedHtml which you can set custom html as a string.  You could probably do something like:

this.RenderedHtml = _webserviceProxy.GetHtml();

# March 11, 2008 4:40 PM

deerchao said:

Is there a way to use components in a master page?

# March 14, 2008 4:08 AM

Mike Bosch said:

Exactly the same.  Just add it to your master page.  Did you get an error doing this?

# March 14, 2008 4:37 PM

theyang said:

I am using the exact system but no luck. I get the following error although I put the View page in the right location.

The file '/Components/Banner/Views/Banner/Spotlight.aspx' does not exist.

The Spotlight.aspx page in under /Components/Banner/View folder, I don't understand where that second Banner came from.

# March 15, 2008 1:16 PM

dkl said:

The problem of this solution is that the ComponentController are activated after the main controler's data has been used in view. In multitier applications you need to aggregate requests to underlying remote data-providing service, so you need all the ComponentControllers to register the requests before any data is consumed in the view, so that the requests can be aggregated to single call. I would like to see solution that activates all the ComponentControllers before the main controller's action calls RenderView method.

In other words, my opinion is that all controller's logic should occur before the view is rendered, to ensure that the view takes care of presentation aspect and nothing else.

# April 9, 2008 10:44 AM

mikehadlow said:

There are a whole load of problems with the current implementation of ComponentController, it breaks many of the design goals of the MVC framework including:

Unit testing

Enabling IoC containers

Mulitple view engines

See my blog post:

mikehadlow.blogspot.com/.../problems-with-mvc-framework.html

# April 14, 2008 9:40 AM

Eric said:

Mike, do you suppose the ComponentController would be something useful for a web content management system?

# May 23, 2008 2:19 AM

Steve said:

Say the Customer Orders component included some ajax to page through recent orders, how would the component link back to itself to get the data, is this possible?

# June 15, 2008 7:35 AM

Mike Bosch said:

That's a great question.  I suppose would have a couple of options.  You could probably bring all the orders down to the client and have the paging work client side (without posting back to the server), or you could call another controller which returns JSON to display the next page.

public ActionResult PageCustomer(int page)

 Customer[] cust = _rep.GetCustomers(page);

 return Json(cust);

# June 15, 2008 11:08 PM

Kelly Harrison said:

A little late to the party here, but here goes:

I've got a site in development using MVC.  *After* development kicked off, the client decided that, at some point in the future, they'd like the site to be ported to work w/ SiteCore (a commercial asp.net-based CMS).  My understanding is that if everything is contained in *WebForms* user controls, then porting is easy.

So that begs the question - can you integrate two existing sites, one standard webforms, one mvc?  If so, might componentcontroller be the key?

Any thoughts are welcome.

Thanks!

-k

# June 28, 2008 10:56 AM