Solved

RenderAction from Controller

Posted on 2010-09-03
1
1,087 Views
Last Modified: 2012-05-10
Greetings!

I've created a fancy pagination tool, and it works well, but I want to refactor/simplify it's implementation more.  

(Look at the code sample to see what's exactly going on)

1. I have a base controller with the PaginationPackage property (it's a custom class I whipped up).  
2. User drops an IQueryable object into the PaginationPackage.FilterData() method.
3. User returns List<DTO_Whatever> to GetTable View.
4. User calls RenderAction() in the GetTable View, which invokes PaginationPackage's supplemental View.  The magic happens in that supplemental view.

I want to remove the RenderAction() from the GetTable View and move it to the BaseController if the PaginationPackage has been filled in.

In other words, I have a Partial View with a table and some other data... And at the end of it, I have:
<% Html.RenderAction("Initialize", "Pagination", new { package = (DomainModel.Entities.PaginationPackage)ViewData["PaginationPackage"] }); %>

I don't want to have to call this on the User Control; it should be automatically invoked during the controller life cylce if that PaginationPackage object is set.

Any ideas?
// --------------------------------------------------------
// MyDataController.cs
// --------------------------------------------------------
public ActionResult GetTable() {

// IQueryable<DTO_Whatever>
var dtoPackage = myRepository.GetDTO();

// ...

// PaginationPackage property is in the base controller
this.PaginationPackage = new PaginationPackage(){
   PageSize = 25
};

var filteredData = this.PaginationPackage.FilterData(dtoPackage);

ViewData["PaginationPackage"] = this.PaginationPackage;

return PartialView(filteredData.ToList(););

}

// --------------------------------------------------------
// MyData > GetTable.ascx
// --------------------------------------------------------

// Table HTML code/Model stuff, etc...
<% Html.RenderAction("Initialize", "Pagination", new { package = (DomainModel.Entities.PaginationPackage)ViewData["PaginationPackage"] }); %>

Open in new window

0
Comment
Question by:Unionblitz
1 Comment
 

Accepted Solution

by:
Unionblitz earned 0 total points
ID: 33618314
For anyone who cares (or Googled a similar question/answer):

I wanted to call a RenderAction(...) dynamically, based on a flag.  

Example 1:
Solution: One option was to just set a ViewData value, and call the RenderAction based on it: see Example 1 in the code below.  
Problem: I wanted the solution to be more dynamic... I didn't want to keep copying/pasting the ViewData["..."] flag on every partial view I created.

Example 2:
(Attempted) Solution: Another option was to call the RenderAction dynamically from the Controller. See Example 2 for the logic behind that.
Problem: I couldn't find a way to call the HTML Helper RenderAction(....) from the controller end... I guess it doesn't make sense to do it anyway, seeing as it's an HTML/View concern.

Example 3 (the winner)
Solution: Create a base controller, with the PaginationPackage class as a property that can be get/set easily.  Then, in that base controller, have the "Initialize()" ActionResult, and throw the partial page into the Shared directory (so any sub controller can access it).  Then, to call "initialize()" dynamically:
1. Override the OnActionExecuted(...) method
2. In the overridden OnActionExecuted(...) method, see if paginationpackage has been filled with content.
3. If the PaginationPackage is filled with content, Render the Initialize() method dynamically by calling the ViewEngines.Engines.FindPartialView(...), rendering the ViewContext, and converting the viewResult into a string.
4. Append the string from step 3 into the Response.
Problem: None, really... I am doing a Response.Write(...) with the dynamically created View; there is probably a better way to do it.
EXAMPLE 1:
(in the ascx page)
...
<%
// if user wishes to show the pagination toolbar:
if ((bool)ViewData["ShowPagination"]){
    Html.RenderAction("Initialize", "Pagination", new { package = (DomainModel.Entities.PaginationPackage)ViewData["PaginationPackage"] });
}
%>

Example 2:
(MyTableController class)
public ActionResult ShowTableOfData(){
var dtoCollection = repository.GetData();

// Do pagination stuff
// .....

// this method would call RenderAction from the controller level.
// I couldn't find any code that could do this, so ignore it.
AppendPaginationToResult();

return View(dtoCollection);
}

Example 3:

(some where in a child controller, I am instantiating a PaginationPackage object, and filling it in with pagination-related content. At some point, I call a "FilterData" method to filter the IQueryable content.  Eventually, a PartialView() is returned as an ActionResult to the child controller.  This will trigger the OnActionExecuted(...) method in the parent controller class)

(The base controller class, called PaginationController)

public class PaginationController : Controller
    {

        public PaginationPackage PaginationPackage { get; set; }

        public PaginationController()
        {
            // this can all be overridden!
            PaginationPackage = new PaginationPackage()
            {
                PageSize = 25,
                TargetTableClassName = "tbl-draft-folder",
                IsEnabled = false
            };

        }


        // When the action has been executed, attach the pagination HTML to the result:
        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
            if (PaginationPackage.IsEnabled)
            {
                
                // load the controller/action info into the pagination package:
                PaginationPackage.LoadControllerInformation(this.ControllerContext);
                
                // load the pagination HTML/View here:
                string paginationContent = RenderPartialViewToString("Initialize", PaginationPackage);
                
                // Is there a better way to append the pagination code then 
                // to just dump to the response stream?
                
                Response.Write(paginationContent);
            }
        }


        protected string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewDataDictionary vd = new ViewDataDictionary(model);
            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, vd, TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }


        public ActionResult Initialize(PaginationPackage package)
        {
            return View(package);
        }

    }

Open in new window

0

Featured Post

Space-Age Communications Transitions to DevOps

ViaSat, a global provider of satellite and wireless communications, securely connects businesses, governments, and organizations to the Internet. Learn how ViaSat’s Network Solutions Engineer, drove the transition from a traditional network support to a DevOps-centric model.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction This article shows how to use the open source plupload control to upload multiple images. The images are resized on the client side before uploading and the upload is done in chunks. Background I had to provide a way for user…
Problem Hi all,    While many today have fast Internet connection, there are many still who do not, or are connecting through devices with a slower connect, so light web pages and fast load times are still popular.    If your ASP.NET page …
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question