But in complex View scene, khi have to instance many controller, each controller mush have data to process it selt.
The flow will look something like this. Take a portal type page with multiple components, most likely you hit the home controler/action first, inside the action you read the db and load up some profile settings for each individual component on your portal
page, pass that to the view, inside the view, appropriate component is rendered with the setting you read from the db. preserves mvc. Basically, you either pass it through the original url when appropriate, or count on the first action to figure it out. Think
of it as a parent action with a bunch of child actions, parent will tell the children what to do.
If we use <uc:MyUserControl> : we will breaking the MVC pattern because of view is direct accessed not throught its controller,
Where does it say a view cannot call another view in MVC? We get our MVC separation because the model does not depend on the view.
convit
How to pass data cross modules ? With classic asp.net mode, I use query string to pass data.
Through parameters, everything has access to the RequestContext and if using UserControls you can use parameters.
convit
But in complex View scene, khi have to instance many controller, each controller mush have data to process itself.
This is why this is a weird idea. Why would you call an action on a 2nd controller just to render output? You call a controller to take action. Outputing a component will have no side effects. Only if the component needs to modify or presist state in
some way does it need a controller to call into an action. I only want one action happening per request, otherwise it will turn into a bloody nightmare.
How is that any different than <uc:MyUserControl />?
Unlike user controls that will break the mvc pattern, render component will not.
Take implementing this forum for example, there's a top 10 poster list on the right panel. The obvious solution is we will make a master page that contains a Top10UserControl. now let's say we hit
how do we load the data into this Top10UserControl, one option is have the user control do it, but that is not mvc. option 2 is have ForumsController.Index load up the data and pass it on, but there's a problem, what if we hit other pages
all these actions ForumsController.Show(forumId), PostsController.Index(forumId), CommentsController.New(postId) etc all have to know to load up the Top10 data for the master page. What if we decided to add something else to the master page? Code has to
be changed in lots of places. We can refactor and make an utility function called GetMasterPageData(), but every action still have to remember to invoke that, not very clean. Maybe we use the template pattern so you will never forget to call GetMasterPageData(),
but that's an extra class on the inheritance hierarchy.
With the render component approach, you don't have to worry about any of that, the master page will call render component with { controller = "top10", action = "index", forumId = forumId }. Just like you could alternatively have an ajax call on the master
page that invokes http://asp.net/top10/index/1 and retreve a html fragment, except render component is done in the same request.
When you think about it, it's a pretty simple and neat solution.
url: we will build a url string to simulate a call to action, defaults: we will provide some other information for action isAjaxRender: true if we want content will be render on client side, false if we want to execute action and render html in server side
I think there are a couple valid MVC methodologies being debated here:
<div mce_keep="true">The Primary-Controller Method, where one main Controller is essentially responsible for the start-to-finish processing of the Request/Response
This is the method that the ASP.Net MVC CTP is currently geared towards, and understandably so. It resembles classic ASP.Net page processing while adding on basic MVC concepts and architecture. In this scenario the primary controller is responsible for loading
all data and passing it to the view(s) for rendering. The main view in this instance is the .aspx Page (and optional Master Page templating). Subcomponent rendering can be delegated to partial views (i.e. .ascx User Controls) but the problem becomes how these
partial views get the data they need for rendering. One way is to have the Primary Controller load the necessary data and pass it to the User Control for rendering. Another is to have the User Control call a "Service" to generate the data itself. Another is
to simply break the MVC boundaries and load the data directly in the User Control itself.
</div>
<div mce_keep="true">The Multiple-MVC Method, where processing is handled initially by an MVC set, which can, in turn, call other MVC sets to handle sub-component processing
This is the methodology that I believe (correct me if I am wrong) shinakuma and others are describing. In this scenario page processing starts at an initial Controller just as with methodology #1. However, views can optionally delegate subcomponent rendering to
an entire sub-MVC set which is responsible for its own available actions and output. In fact, this sub-MVC set could also call other MVC sets to do nested rendering.</div>
I think the main difference between the two lies in the definition of the "MVC" concept. #1 has a more rigid scope: MVC is a Page-specific rendering concept. #2 defines it more generally. I tend to lean towards #2 because I agree that it allows for a more
natural separation of responsibilities. I feel some changes to the ASP.NET MVC framework would make developing in that way easier to manage:
<div mce_keep="true">As others have suggested, implement a way to delegate processing to a separate MVC set. The current MVC Toolkit is close to this with its Html.RenderUserControl() method. What is needed is the ability to specify a MVC resource by URI
and to have that URI processed by the same Route engine as other MVC routes. Something like:
Html.RenderComponent(String uri, object postData). The second parameter would be optional, allowing for data to be passed directly to the destination URI that would normally have been sent via a form.post.</div>
<div mce_keep="true">When working with this method, there is no tangible difference between .ascx and .aspx controls. I would recommend getting rid of this distinction by creating a new extension to define "Views" such as .view. This extension should also
have no code-behind page requirement (although it could be optional). Instead of adding an @Page or @Control directive, we could have an @View directive instead... with a potential MasterView property to allow for nested View templates.</div>
I think a compounding factor in this discussion is the concept of Master Pages. As currently structured, Master Page templates are essentially partial Pages themselves. The problem is that this relationship is backwards from an MVC standpoint (at least in
my mind). The Page refers to its Master... and thus has to pass data up the chain in order to get data to the Master Page for rendering. As others have noticed, this presents an odd problem in the MVC world as the Master has no Controller for itself, and thus
any data it needs must ultimately come from the Page Controller. Note that this problem remains with both #1 and #2 so long as Master Pages are involved in the way they are currently architected. The best solution I have come up with for this is to have a
base Controller class that handles data generation required for a particular Master template. Any Views that reference this Master would require a Controller that inherits from the MasterController base class. This allows one central data-loading point for
all data required by the Master view. Not ideal... but workable for now.
Thinking more about #2 it almost seems like the entire Master concept isn't needed at all. If you can define a parent MVC set, and then dynamically call sub-MVC sets then you essentially have a templating framework already. The only catch is that you are
forcing the relationship to go the other way (instead of View referencing Master, Master dynamically references View). In order to do that it seems like another level of Controller (similar to the Route controller) would be needed to handle the linkage. I
guess that would be the third thing I would like to see added to the MVC framework at some point in time.
-Ian
ASP.NET MVCMVCMVC PatternMVCToolkitmvc view
Marked as answer by mave99a on Jan 13, 2008 09:42 PM
By the way Render_Component was
deprecated in RoR in favor of partials which are simply UserControls in MS MVC. Apparently they never belonged there and caused
problems.
I've read the arcticle, so many people replied that they want to use component for reuse purpose,
I think the issue of using render component is performance only. But render component will help us alot in seperate business, view into smallcomponents and reuse it.
Urbanus:
Components != partials
Partials are view-related: they render information within the context of the current controller.
Components are controllers + views that you can put into a view that belong to some other controller (or controllers). They are different from partials in that they are designed to gather and present their own data separately from the controller that’s actually
preparing the current page.
Partials don’t replace components. Partials are not a “better” sort of component.
If components ever get deprecated, the DRY implications for applications that genuinely need them will be disastrous. All that controller + view code will have to be copied across multiple different controllers.
With respect kev, if you don’t see the importance of components then you just haven’t personally found a legitimate use for them yet. But that doesn’t mean they’re not a powerful and important part of Rails.
Great article, it helps to have it summarized in one place!
However, I agree with the aforementioned comments that components are extremely useful. They make developing portal like functionality where you want an area of dynamic content repeated on different pages very simple and DRY.
I have been unable to find a similar approach to combining business logic and view in a reusable component in an equally DRY manner without using components. It would be helpful if someone could provide an example of how to effectively rewrite a reusable component
(such as a web poll) without using components.
By the way Render_Component was deprecated
in RoR in favor of partials which are simply UserControls in MS MVC.
Explains why Monorail didn't have this concept either. That's very unfortunate. I understand that the problem overusing it will cause. And I also agree with the sentiment that probably 95% of the time, partials are a better way for view partitioning. But
I still think that there is definitely a place for components. I like this controller-action seperation over before filters.
convit
Could you please help me to implement a helper function with prototype like this:
At first, I wasn't planning on doing this. I briefly played around with the routing features of the drop. Other than that, I haven't had the chance to really dig into this ctp. But curiosity got the best of me and I decided to give it a shot. Gave me a chance
to understand the internals of ms-mvc a little better. Bewarned, it's just a proof of concept. There might be a better way of doing it.
In your ViewPage or ViewMasterPage, just do something like <%= this.RenderComponent( new { Controller="Top10", Action="Index", ForumId = 1 } ) %>, that will jump out, invoke Top10Controller.Index(1) and spit out the fragments. Inside the action, you should
have access to everything in the context.
shinakuma
Member
378 Points
92 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 03:16 AM|LINK
The flow will look something like this. Take a portal type page with multiple components, most likely you hit the home controler/action first, inside the action you read the db and load up some profile settings for each individual component on your portal page, pass that to the view, inside the view, appropriate component is rendered with the setting you read from the db. preserves mvc. Basically, you either pass it through the original url when appropriate, or count on the first action to figure it out. Think of it as a parent action with a bunch of child actions, parent will tell the children what to do.
abombss
Member
575 Points
164 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 03:58 AM|LINK
Where does it say a view cannot call another view in MVC? We get our MVC separation because the model does not depend on the view.
Through parameters, everything has access to the RequestContext and if using UserControls you can use parameters.
This is why this is a weird idea. Why would you call an action on a 2nd controller just to render output? You call a controller to take action. Outputing a component will have no side effects. Only if the component needs to modify or presist state in some way does it need a controller to call into an action. I only want one action happening per request, otherwise it will turn into a bloody nightmare.
shinakuma
Member
378 Points
92 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 04:04 AM|LINK
Unlike user controls that will break the mvc pattern, render component will not.
Take implementing this forum for example, there's a top 10 poster list on the right panel. The obvious solution is we will make a master page that contains a Top10UserControl. now let's say we hit
http://asp.net/forums/index
how do we load the data into this Top10UserControl, one option is have the user control do it, but that is not mvc. option 2 is have ForumsController.Index load up the data and pass it on, but there's a problem, what if we hit other pages
http://asp.net/forums/1
http://asp.net/forums/1/posts/index
http://asp.net/forums/1/posts/1000/comments/new
...
all these actions ForumsController.Show(forumId), PostsController.Index(forumId), CommentsController.New(postId) etc all have to know to load up the Top10 data for the master page. What if we decided to add something else to the master page? Code has to be changed in lots of places. We can refactor and make an utility function called GetMasterPageData(), but every action still have to remember to invoke that, not very clean. Maybe we use the template pattern so you will never forget to call GetMasterPageData(), but that's an extra class on the inheritance hierarchy.
With the render component approach, you don't have to worry about any of that, the master page will call render component with { controller = "top10", action = "index", forumId = forumId }. Just like you could alternatively have an ajax call on the master page that invokes http://asp.net/top10/index/1 and retreve a html fragment, except render component is done in the same request.
When you think about it, it's a pretty simple and neat solution.
convit
Member
10 Points
5 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 08:33 AM|LINK
Thanks shinakuma for the reply.
Could you please help me to implement a helper function with prototype like this:
ControllerHelper.ExecuteAction(string url, object defaults, bool isAjaxRender) ;
url: we will build a url string to simulate a call to action,
defaults: we will provide some other information for action
isAjaxRender: true if we want content will be render on client side, false if we want to execute action and render html in server side
Example:
<div>
<% ControllerHelper.ExecuteAction("Post/Top10", {Controller=Post}, false);%>
</div>
or a control like this
<div id="leftCol">
<mvc:ExecuteAction runat="server" Url="..." Defaults="..." id="mvcCategory" />
</div>
<div id="mainCol">
<mvc:ExecuteAction runat="server" Url="..." Defaults="..." id="mvcListProduct" />
</div>
DTK
mave99a
Member
2 Points
8 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 08:39 AM|LINK
Yes, I also love this idea.
This is exactly like what I said, use a container page to separate a whole page into many small M-V-C components.
We can use user controls to archive that, since we can put whatever parameter inside Request, Response, or even session objects, but that is not neat.
I wish asp.net could bring us something looks neat, simple, easy to understand.
I don't think rendercomponent() will break the M-V-C, it's more straight forward.
ian_a_anders...
Member
20 Points
17 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 01:35 PM|LINK
I think there are a couple valid MVC methodologies being debated here:
This is the method that the ASP.Net MVC CTP is currently geared towards, and understandably so. It resembles classic ASP.Net page processing while adding on basic MVC concepts and architecture. In this scenario the primary controller is responsible for loading all data and passing it to the view(s) for rendering. The main view in this instance is the .aspx Page (and optional Master Page templating). Subcomponent rendering can be delegated to partial views (i.e. .ascx User Controls) but the problem becomes how these partial views get the data they need for rendering. One way is to have the Primary Controller load the necessary data and pass it to the User Control for rendering. Another is to have the User Control call a "Service" to generate the data itself. Another is to simply break the MVC boundaries and load the data directly in the User Control itself.
</div>
This is the methodology that I believe (correct me if I am wrong) shinakuma and others are describing. In this scenario page processing starts at an initial Controller just as with methodology #1. However, views can optionally delegate subcomponent rendering to an entire sub-MVC set which is responsible for its own available actions and output. In fact, this sub-MVC set could also call other MVC sets to do nested rendering.</div>
I think the main difference between the two lies in the definition of the "MVC" concept. #1 has a more rigid scope: MVC is a Page-specific rendering concept. #2 defines it more generally. I tend to lean towards #2 because I agree that it allows for a more natural separation of responsibilities. I feel some changes to the ASP.NET MVC framework would make developing in that way easier to manage:
Html.RenderComponent(String uri, object postData). The second parameter would be optional, allowing for data to be passed directly to the destination URI that would normally have been sent via a form.post.</div>
I think a compounding factor in this discussion is the concept of Master Pages. As currently structured, Master Page templates are essentially partial Pages themselves. The problem is that this relationship is backwards from an MVC standpoint (at least in my mind). The Page refers to its Master... and thus has to pass data up the chain in order to get data to the Master Page for rendering. As others have noticed, this presents an odd problem in the MVC world as the Master has no Controller for itself, and thus any data it needs must ultimately come from the Page Controller. Note that this problem remains with both #1 and #2 so long as Master Pages are involved in the way they are currently architected. The best solution I have come up with for this is to have a base Controller class that handles data generation required for a particular Master template. Any Views that reference this Master would require a Controller that inherits from the MasterController base class. This allows one central data-loading point for all data required by the Master view. Not ideal... but workable for now.
Thinking more about #2 it almost seems like the entire Master concept isn't needed at all. If you can define a parent MVC set, and then dynamically call sub-MVC sets then you essentially have a templating framework already. The only catch is that you are forcing the relationship to go the other way (instead of View referencing Master, Master dynamically references View). In order to do that it seems like another level of Controller (similar to the Route controller) would be needed to handle the linkage. I guess that would be the third thing I would like to see added to the MVC framework at some point in time.
-Ian
ASP.NET MVC MVC MVC Pattern MVCToolkit mvc view
mave99a
Member
2 Points
8 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 20, 2007 02:00 PM|LINK
Ian, great summary of above discussion!
abombss
Member
575 Points
164 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 21, 2007 12:02 AM|LINK
By the way Render_Component was deprecated in RoR in favor of partials which are simply UserControls in MS MVC. Apparently they never belonged there and caused problems.
convit
Member
10 Points
5 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 21, 2007 01:06 AM|LINK
I've read the arcticle, so many people replied that they want to use component for reuse purpose,
I think the issue of using render component is performance only. But render component will help us alot in seperate business, view into smallcomponents and reuse it.
shinakuma
Member
378 Points
92 Posts
Re: How about a very complex page which need many "MVC modules/parts" ?
Dec 21, 2007 02:40 AM|LINK
Explains why Monorail didn't have this concept either. That's very unfortunate. I understand that the problem overusing it will cause. And I also agree with the sentiment that probably 95% of the time, partials are a better way for view partitioning. But I still think that there is definitely a place for components. I like this controller-action seperation over before filters.
At first, I wasn't planning on doing this. I briefly played around with the routing features of the drop. Other than that, I haven't had the chance to really dig into this ctp. But curiosity got the best of me and I decided to give it a shot. Gave me a chance to understand the internals of ms-mvc a little better. Bewarned, it's just a proof of concept. There might be a better way of doing it.
In your ViewPage or ViewMasterPage, just do something like <%= this.RenderComponent( new { Controller="Top10", Action="Index", ForumId = 1 } ) %>, that will jump out, invoke Top10Controller.Index(1) and spit out the fragments. Inside the action, you should have access to everything in the context.
public static class RenderComponentExtension{
public static string RenderComponent(this ViewPage viewPage, object values)
{
string path = viewPage.Url.Action(values);
IHttpContext context = viewPage.ViewContext.HttpContext;
return RenderComponent(path, context);
} public static string RenderComponent(this ViewMasterPage masterPage, object values)
{
string path = masterPage.Url.Action(values);
IHttpContext context = masterPage.ViewContext.HttpContext;
return RenderComponent(path, context);
} private static string RenderComponent(string path, IHttpContext context)
{
string oldPath = context.Request.Path;
context.RewritePath(path);
RouteData routeData = RouteTable.Routes.GetRouteData(context);
Type handlerType = routeData.Route.RouteHandler;
IRouteHandler routehandler = (IRouteHandler)Activator.CreateInstance(handlerType);
RequestContext requestContext = new RequestContext(context, routeData);
IHttpHandler httpHandler = (MvcHandler)routehandler.GetHttpHandler(requestContext);
TextWriter oldWriter = context.Response.Output;
StringWriter newWriter = new StringWriter();
context.Response.SwitchWriter(newWriter);
httpHandler.ProcessRequest(HttpContext.Current);
context.RewritePath(oldPath);
context.Response.SwitchWriter(oldWriter);
return newWriter.ToString();
}
}
render_component