How about a very complex page which need many "MVC modules/parts" ?

Rate It (4)

Last post 01-13-2008 6:38 PM by mave99a. 29 replies.

Sort Posts:

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-20-2007, 9:35 AM
    Answer

    I think there are a couple valid MVC methodologies being debated here:

    1. 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.
       
    2. 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.

    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:

    • 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.
    • 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.

    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

     

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-20-2007, 10:00 AM
    • Loading...
    • mave99a
    • Joined on 12-19-2007, 6:28 AM
    • Posts 8

     Ian, great summary of above discussion!


     

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-20-2007, 8:02 PM
    • Loading...
    • abombss
    • Joined on 06-27-2006, 4:13 PM
    • Chicago, IL
    • Posts 164

     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.

    Adam Tybor -- abombss.com
  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-20-2007, 9:06 PM
    • Loading...
    • convit
    • Joined on 09-10-2002, 8:46 AM
    • Posts 5

    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.
     
    Todd Huss

    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.  

     

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-20-2007, 10:40 PM
    • Loading...
    • shinakuma
    • Joined on 03-01-2003, 4:09 PM
    • Posts 92

    abombss:
    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.

    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();
    }

    }

    Filed under:
  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-20-2007, 11:11 PM
    • Loading...
    • convit
    • Joined on 09-10-2002, 8:46 AM
    • Posts 5

    shinakuma: Thank you very much. I've tried to implement my self  but not success. Thanks again :)

    DTK 

    I've just tested, it runs smoothly :)). Now I could use MVC modules in my project :)

     

     

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-21-2007, 1:49 PM
    • Loading...
    • shinakuma
    • Joined on 03-01-2003, 4:09 PM
    • Posts 92

    It just occured to me that I effectively implemented Server.Execute for MVC (and in case if you are wondering, the regular Server.Execute is tied to the webform model it appears).

    I would like to hear some opinions from the dev team on whether "render_component" has any place in the mvc framework. Seems to me that this is really no different from ajax calls as far as the amount of work the server has to do.

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    12-21-2007, 5:03 PM
    • Loading...
    • mave99a
    • Joined on 12-19-2007, 6:28 AM
    • Posts 8

    shinakuma:
    t just occured to me that I effectively implemented Server.Execute for MVC (and in case if you are wondering, the regular Server.Execute is tied to the webform model it appears).
     

    I believe Execute() will work well. however I am wondering if  Execute() is not that lightweight enough? ( I mean it may have too many overhead from inside of Execute, and it would be better to have a light weight one) 

     

    shinakuma:
    I would like to hear some opinions from the dev team on whether "render_component" has any place in the mvc framework. Seems to me that this is really no different from ajax calls as far as the amount of work the server has to do.

    Me too.

    I believe the problem we discuss here is quite common in a "real" web application. 

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    01-02-2008, 4:35 PM
    • Loading...
    • Kepler
    • Joined on 05-03-2004, 11:31 PM
    • Posts 38

    I was able to finally hack up a conversion of the core of my old content management system into the new MVC framework.  All the issues you guys discussed here were real problems for me.  The biggest issues I'd like to see some framework help from was the execution of Controller methods and Rendering of partial views.  

    I like your solution shinakuma, in that you call ProcessRequest.  That seems a bit heavy though, to just call a controller method and output a snippet of html.  I managed to use IController's Execute method, but I think that's too heavy as well, plus it was very hackish to get it to work. 

    In my cms, you can either navigate to a particular page, or render a module directly.  The former is old school portal stuff where the engine determines all the views to throw on the page and renders them in the right places.  The latter is just like a normal MVC route, with the exception that the rendered html then goes in the main content area of the site template.  The cms engine then figures out the home page for that module (basically all the views in a controller share a home page), then draws all the modules/portlets/webparts/partialviews in all the areas outside the main content area.  Any POSTs will be handled via AJAX or will be interactions solely with the module represented in the main content area, so all the Route stuff should work just fine.  Here's the basic workflow relevant to the discussion you guys have been having:

    1. Created custom Controller class that overrides RenderView
    2. RenderView checks a context variable "isPageBuildingInProgress"
    3. If not, take the view being rendered (remember, a controller action has already been executed) and capture it in a string - to be placed in the main content area
    4. If page building is in progress, just render to a string and store it in the right place (number 6 below)
    5. Interact with the model to get all the partial views that belong in all the other areas of the page (a controller and an action will come back for each)
    6. Execute the appropriate actions on each of the controllers, capturing the rendered html and placing it in StringBuilders on a PageData object (ViewData for the page)
    7. Render "THE" aspx view (there is only one in the whole app, everything else is a ViewUserControl) - it binds to the PageData object which just contains html for each of the content areas within the MasterPage

    The benefit of this implementation is that all my controllers just call RenderView and know nothing about the cms view manipulation that is going on.  The exact same code is executed whether the partial view is the main attraction (directly accessed in the url to show up in the main content area) or if it's just been selected to show up in a particular location by the user for that particular page (rendered due to configuration of the portal).  All of the logic is in the base Controller class's Render method, leaving all the controllers and their views for all the modules very clean and nicely encapsulated.

    The drawback is the hackish nature of the code I had to mangle to get this to work.  Messing with the ControllerContext and RouteData made me feel particularly dirty.  Here are some code snippets (Disclaimer - I'm certain there are better ways to do this, but this is as far as I got):

    protected void Execute(System.Web.IHttpContext httpContextInterface, RouteData routeData, string controllerName, string action) {
    	routeData.Values.Clear();
    	routeData.Values.Add("controller", controllerName);
    	routeData.Values.Add("action", action);
    	routeData.Values.Add("id", null);
    	ControllerContext controllerContext = new ControllerContext(new RequestContext(httpContextInterface, routeData), (IController)this);
    			
    	base.Execute(controllerContext);
    }
    
     

    When executing the final Render for the page (all partial views rendered with their html strings securely fastened to my PageData object), I had to do the following: 

    // Now, render the containing page, passing in the pageData object, which contains all the html for each of the SiteTemplate locations
    RouteData routeData = this.RouteData;
    routeData.Values.Clear();
    routeData.Values.Add("controller", "Nav");
    routeData.Values.Add("action", "Show");
    routeData.Values.Add("id", null);
    ControllerContext controllerContext = new ControllerContext(new RequestContext(this.HttpContext, routeData), (IController)this);
    this.ControllerContext = controllerContext;
    base.RenderView("~/Views/Nav/Show.aspx", masterName, pageData);

    Oh, and I used home grown reflection code to create all my partial view controllers to call Execute on. I think I've got some more work ahead of me to handle all the data that can be passed into the url route in my Execute method, but calling ProcessRequest seems like a bit much to accomplish a partial view render.

     

    Filed under: , ,
  • Re: How about a very complex page which need many "MVC modules/parts" ?

    01-02-2008, 6:20 PM
    • Loading...
    • Momcilo
    • Joined on 07-21-2004, 2:06 AM
    • Brookfield, WI
    • Posts 114

    convit:
    I've got the same problem with master page which include M-V-C modules. I search on the net, ROR or PHP MVC have method: render_component which will render a view to solve this problem
    <html>
    <body
    <div id="leftCol">
       render_component(Controller="Category", Action = "List", {param1=value1, param2=value2}) 
    </div> 
    <div id="mainCol">
       render_component(Controller="Product", Action = "List", {param1=value1, param2=value2, param3=value3})
    </div> 
    </body> 
    </html> 

    Can we have any same solutions for asp.net mvc ?

    Sounds reasonable while we have M-V-V-C, but if we get to M-V-C-V-C then it all was in vain... Smile

    In other words, while we keep SoC and keep these "components" to be in fact "subviews" (and not what the term "component" may suggest...) all is fine.

    Writing software would be a lot easier if it weren't for customers
  • Re: How about a very complex page which need many "MVC modules/parts" ?

    01-03-2008, 3:20 PM
    • Loading...
    • shinakuma
    • Joined on 03-01-2003, 4:09 PM
    • Posts 92

    Kepler:
    I like your solution shinakuma, in that you call ProcessRequest.  That seems a bit heavy though, to just call a controller method and output a snippet of html.  I managed to use IController's Execute method, but I think that's too heavy as well, plus it was very hackish to get it to work.

    The goal wasn't to just call a controller method, but to invoke a full MVC cycle, going through a typical execution pipeline like any other request, thus preserving all custom hooks along the way. That is not to say this is a efficient way of doing things however.

    I'm now thinking that MVC by itself is not going to address this need sufficiently. You would need another architecture layer on top of the basic MVC that will give you a flexible and configurable plugin framework usually demanded by CMS. Think of it as the difference between WebForms, PHP and DotNetNuke, Joomla.

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    01-04-2008, 10:54 AM
    • Loading...
    • abombss
    • Joined on 06-27-2006, 4:13 PM
    • Chicago, IL
    • Posts 164

     RenderView calls a process request anyway to kick off the asp.net pipeline which is needed to render the view.  It would be nice to somehow inject the secondary calls to renderview into the current executing pipeline, not sure how easy that would be.

    Adam Tybor -- abombss.com
  • Re: How about a very complex page which need many "MVC modules/parts" ?

    01-04-2008, 11:25 AM
    • Loading...
    • shinakuma
    • Joined on 03-01-2003, 4:09 PM
    • Posts 92

    abombss:
    RenderView calls a process request anyway to kick off the asp.net pipeline which is needed to render the view.

    No, RenderView will call the ProcessRequest on the aspx page handler to render the view page. That only goes through the page life cycle on the apsx. It's very different from the ProcessRequest on the MvcHandler.

  • Re: How about a very complex page which need many "MVC modules/parts" ?

    01-04-2008, 11:31 AM