开发者

How to call and return the output of another controller's action inside an action?

We are开发者_运维问答 working on a 'plugin' architecture for our project where to extend the software's functionality, client can write their own controllers and include it with the project. (The plugins are to generate different outputs based on tables which the client will add into the schema).

The plugins are accessed through an action in a controller's action, say like /reports/get/?type=spending

So in this case, the action will have to location a controller inside the 'plugin' area and invoke the index action (eg. areas/plugin/spending/index). How do I invoke this action while inside the /reports/get/?type=spending action, and get its output?


Html.RenderAction Method is used for rendering other action's output in view. Inpired from that, same in controller would be

using System.Web.Mvc.Html;
public void Index()
        {
            StringBuilder resultContainer = new StringBuilder();
            StringWriter sw = new StringWriter(resultContainer);

            ViewContext viewContext = new ViewContext(ControllerContext, new WebFormView(ControllerContext, "fakePath"), ViewData, TempData, sw);

            HtmlHelper helper = new HtmlHelper(viewContext, new ViewPage());

            helper.RenderAction("create");

            sw.Flush();
            sw.Close();
            resultContainer.ToString(); //"This is output from Create action"
        }
public ActionResult Create()
        {
            return Content("This is output from Create action");
        }

Actually, RenderAction can be passed all the routing data you want, not only action name


RedirectToAction is probably the best option - that way you can use the built in routing to find the right action - something like

return RedirectToAction("Index", "SpendingPlugin");

If you don't want a redirect you can find and call the controller method directly as Nathan suggested, but that tends to get unnecessarily complex and interfere with locating views.


NOTE: This solution may seem kind of complex but it does seem to be the only way to solve the problem as described by the questioner in both his question and more specifically the comment on his question which states, "It's about creating the controller that is being requested, and reading the output from the actionresult. " (emphasis mine)

Controllers and actions are just fancy names for classes and methods. Why not just instantiate the controller like you would any other class and then call the index action on the controller? The hardest part would be instantiating the controller since you're going for the 'plugin' architecture and all the information you have about the controller is it's name as a string. Nothing a little reflection wouldn't solve though:

// GET: /reports/get/?type=spending

public Controller Reports
{
    public ActionResult Get(string typeName)
    {
        Type typeOfController;
        object instanceOfController;

        try
        {
            typeOfController = System.Reflection.Assembly.GetExecutingAssembly().GetType(name: typeName, throwOnError: true, ignoreCase: true)
            instanceOfController = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(typeName: typeName, ignoreCase: true);
        }
        catch(Exception ex)
        {
            // Controller not found
            return View("InvalidTypeName");
        }

        ActionResult result = null;

        try
        {
            result = typeOfController.InvokeMember("Index", System.Reflection.BindingFlags.InvokeMethod, null, instanceOfController, null)as ActionResult;
        }
        catch(Exception ex)
        {
            // Perhaps there was no parametersless Index ActionMethod
            // TODO: Handle exception
        }

          return result;
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜