Page view counter

RenderView ToString()

Last post 06-04-2008 4:19 AM by mikehadlow. 14 replies.

Sort Posts:

  • Geeked [8-|] RenderView ToString()

    12-13-2007, 9:07 AM
    • Loading...
    • Tom Schreck
    • Joined on 02-23-2007, 3:55 PM
    • Ft Worth Texas
    • Posts 12
    • Points 1

    Is there a way to capture the results of RenderView() to a string?

    Thanks

    Tom Schreck

    "I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
    Filed under: , ,
  • Re: RenderView ToString()

    12-13-2007, 12:30 PM
    Answer

    Yes, there are a few ways of doing that. If it's in a unit test, you probably want to set up a mock IHttpResponse and read whatever gets written to it.

     If, for some reason, you're trying to do it from a controller, you could use a hack like this:

     

    [ControllerAction]
    public void About()
    {
    StringWriter interceptingWriter = new StringWriter();
    TextWriter originalWriter = this.ControllerContext.HttpContext.Response.SwitchWriter(interceptingWriter);
    RenderView("About");

    originalWriter.Write("The text written was: " + interceptingWriter.ToString());
    }
  • Re: RenderView ToString()

    12-13-2007, 2:20 PM
    • Loading...
    • Tom Schreck
    • Joined on 02-23-2007, 3:55 PM
    • Ft Worth Texas
    • Posts 12
    • Points 1

    Thanks for the feedback, I'll have to give this a try. 

    What I'm envisioning is something like this:

    [ControllerAction]
    public void Category(int id)
    {
         Category category = GetCategoryById(id);
         string ViewResults = RenderView("Category", category);
    
         ...
    }
    Being able to capture the rendered output of a View is important because within a controller, I could call multiple views and capture those results as strings then be able to cache them or whatever else I need to do.
    I use an Ajax library called Taconite and having this capability would be of incredible value with working with Taconite.
     
     
    Thanks

    Tom Schreck

    "I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
  • Re: RenderView ToString()

    12-13-2007, 2:35 PM
    • Loading...
    • Tom Schreck
    • Joined on 02-23-2007, 3:55 PM
    • Ft Worth Texas
    • Posts 12
    • Points 1

    Steve

    Your solution allows me to accomplish my goal of capturing the View's rendered output.

    Thanks

    Tom Schreck

    "I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
  • Re: RenderView ToString()

    12-13-2007, 3:42 PM
    • Loading...
    • robconery
    • Joined on 02-23-2005, 10:16 PM
    • Posts 192
    • Points 846
    • AspNetTeam

    In the next release of the Toolkit I'm hoping to refactor RenderUserControl() down to the Toolkit core (rather than only expose it as an extension). This will allow you to do this with a control as well.

    Would it be helpful to have a ControllerExtension do this as well?

  • Re: RenderView ToString()

    12-18-2007, 6:44 PM
    • Loading...
    • Kepler
    • Joined on 05-03-2004, 11:31 PM
    • Posts 38
    • Points 70

    I need that functionality as well.  In my case, I'm writing a content management system, and I need to dynamically render multiple partial views to a single page.  A way to capture the render of a ViewUserControl to a string would help immensely.  At a very high level, I need to do the following:

    • Get a list of partial views to be displayed on the page from the database (easy, nothing new in MVC)
    • Call a controller action to render each partial view - the controller actions can be defined in the database as well or defaulted for each view (not sure how to do this)
    • Place them in the appropriate locations on the parent View (easy if I can manage/manipulate the renderings of each partial view)

    I think I've come up with a way to handle all this in an overriden RenderView() method, but I'd like to hear your insights on the above before I start a new topic on those ideas.

  • Re: RenderView ToString()

    12-18-2007, 7:00 PM
    • Loading...
    • abombss
    • Joined on 06-27-2006, 4:13 PM
    • Chicago, IL
    • Posts 164
    • Points 574

    While we are at it can we fix the issue that SwitchWriter is an internal method on HttpResponse but included on the public IHttpResponse interface?  How can I ever build my own wrapper?  The interfaces can be used for more things than just testing.

    The easiest thing would be if MS opened up their wrappers and made them public with virtual methods.  Why are they internal? 

    Adam Tybor -- abombss.com
  • Re: RenderView ToString()

    12-20-2007, 5:13 PM
    • Loading...
    • Haacked
    • Joined on 09-17-2003, 2:43 PM
    • Posts 377
    • Points 4,901
    • AspNetTeam

    You could shorten that a bit:

    [ControllerAction]
    public void About()
    {
        StringWriter builder = new StringWriter();
        TextWriter originalWriter = Response.Output;
        Response.SwitchWriter(builder);
        RenderView("About");
    
        string html = builder.ToString();
        
        originalWriter.Write(html);
    }
    
    Phil Haack (http://haacked.com/)
    Senior Program Manager, Microsoft

    What wouldn’t you do for a Klondike bar?
  • Re: RenderView ToString()

    12-20-2007, 5:34 PM

     If you are assembling multiple partial views together in a controller isn't that violating the seperation of concerns between presentation and logic?

     Personally, I think there should be something like "MasterViews" that contain references to partial views. That way the master view logic can decide how to populate the partial views based upon the data passed to it from the controller.


     

  • Re: RenderView ToString()

    12-20-2007, 6:17 PM
    • Loading...
    • Kepler
    • Joined on 05-03-2004, 11:31 PM
    • Posts 38
    • Points 70

    In most cases, I'd say "yes", but not in the case of a Content Management System.  I like your MasterView idea, but you'd still need a controller to handle the model manipulation for that.  Something's got to hit the database to determine what partial views to display on a particular page, and I think that might just be the responsibility of a specific, focused controller somewhere.  A CMS is an exception when we're talking about separation of concerns, because of exactly what it's trying to do.  If the business logic of your domain IS to map modules/views together onto pages, and you have database tables to facilitate that, then View manipulation is exactly what your controller will do.  Controllers handle whatever their domain requires them to handle.  It just so happens that a CMS will probably have at least one controller who's primary responsibility is handling the mapping of Views onto pages.  That controller might handle Views like another controller would handle Products or Employees.  I totally agree that all the partial views should be completely ignorant, however, of anything but their own piece of the pie.

    That's why my idea to encapsulate all of this into RenderView is the best I've come up with so far.  Every partial view would just call his own Render for his View, then RenderView is responsible for figuring out if the parent View has been "built" and calling out to the other partial view's controllers to have them render their pieces, then aggregating the results.  That way the page-building logic is in RenderView (might consider it the "framework") and out of any specific controller.

  • Re: RenderView ToString()

    12-20-2007, 6:28 PM

    I understand your point, and I think it is valid, though perhaps this is a situation where web forms is a better architecture instead of MVC. We have to be careful not to make everything into a nail now that we have the magic MVC hammer.

    Another thought I had is that instead of having the "MasterView" pass its own Viewdata to "dumb" partial views, instead it would be able to call other controllers, which would reach into the model to get their specific data, and pass this to a partial view.

    At this point, the master view would assemble the final page from all of the partial views.

    But this is just thinking aloud :)
     

  • Re: RenderView ToString()

    01-02-2008, 1:57 PM
    • Loading...
    • Tom Schreck
    • Joined on 02-23-2007, 3:55 PM
    • Ft Worth Texas
    • Posts 12
    • Points 1

    Johnathan

    What's a partial view?

    Thanks

    Tom Schreck

    "I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
  • Re: RenderView ToString()

    01-02-2008, 3:43 PM
    • Loading...
    • Kepler
    • Joined on 05-03-2004, 11:31 PM
    • Posts 38
    • Points 70

    A partial view is just what we're calling any View that doesn't represent a complete html page.  Anything that just renders a snippet of html.

    And, yes, Jonathan, having partial views be rendered from controller methods is absolutely necessary.  That's my methodology as well.  It's the only way to keep MVC intact.  Every view (partial or otherwise) should be rendered from a controller action, and not necessarily one big controller action in order to honor encapsulation.

    I finally got my idea working, but it's a big hack calling out to other controllers and having ViewUserControls render themselves to strings.  I'm thinking about posting my code somewhere and starting a discussion.  I'm just trying to figure out the best venue.  The closest I've seen is the code posted by shinakuma in this thread.  That's a great discussion on what we cms/portal developers are trying to accomplish.

  • Re: RenderView ToString()

    01-02-2008, 4:34 PM
    • Loading...
    • Tom Schreck
    • Joined on 02-23-2007, 3:55 PM
    • Ft Worth Texas
    • Posts 12
    • Points 1

    Ah, yes.  Partial views is what I'm trying to achieve.  We have a content management system where a page is basically a collection of controls.  All of the content for a page is stored in a database.  Each control is responsible for consuming the data and rendering XHTML.  So a page would be the coming together of multiple "partial views".  Controls are arranged on a page via zones.

    Currently, our CMS is web forms driven and I'm trying to wrap my head around how I would go about using MVC approach.  I'm new to ASP.Net, but have been using MVC for years with ColdFusion.  I do not care for post back and view state, so I'm excited about having ASP MVC.  I plan on following the thread you mentioned.

    I think I can collect all of the data via the model that a page needs which would be a collection of data organized by control.  I'm not sure how I'm going to dynamically call all of the controls for a page and pass to each control the data it needs.

    I'm glad to find others working on similar approaches.

    Thanks

    Tom Schreck

    "I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
  • Re: RenderView ToString()

    06-04-2008, 4:19 AM
    • Loading...
    • mikehadlow
    • Joined on 03-06-2008, 7:27 AM
    • Posts 17
    • Points 28

     I've just written about doing this with CTP 3 by using the MVCContrib BlockRenderer class:

    http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view.html

    Here's a snippet:

               // pass the current controller context to orderController
    orderController.ControllerContext = ControllerContext;

    // create a new BlockRenderer
    var blockRenderer = new BlockRenderer(HttpContext);

    // execute the Item action
    var viewResult = (ViewResult) orderController.Item(1);

    // change the master page name
    viewResult.MasterName = "Print";

    // we have to set the controller route value to the name of the controller we want to execute
    // because the ViewLocator class uses this to find the view
    this.RouteData.Values["controller"] = "Order";

    string result = blockRenderer.Capture(() => viewResult.ExecuteResult(ControllerContext));

     UPDATE:

    This technique has problems, Here's a better one:

    http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

Page 1 of 1 (15 items)