Solved

RenderAction from Controller

Posted on 2010-09-03
1
1,064 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
Comment Utility
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

771 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now