Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

RenderAction from Controller

Posted on 2010-09-03
1
Medium Priority
?
1,124 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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

Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

Question has a verified solution.

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

Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…

618 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