如何调用并返回另一个控制器的输出';动作中的动作

本文关键字:输出 控制器 另一个 何调用 调用 返回 | 更新日期: 2023-09-27 17:59:11

我们正在为我们的项目开发一个"插件"架构,为了扩展软件的功能,客户端可以编写自己的控制器,并将其包含在项目中。(插件根据客户端将添加到架构中的表生成不同的输出)。

插件是通过控制器操作中的一个操作访问的,比如/reports/get/?type=spending

因此,在这种情况下,操作必须将控制器定位在"插件"区域内,并调用索引操作(例如areas/plugin/spending/index)。如何在/reports/get/?type=spending操作内部调用此操作并获得其输出?

如何调用并返回另一个控制器的输出';动作中的动作

Html.RenderAction方法用于在视图中呈现其他操作的输出。除此之外,控制器中的也将相同

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");
        }

实际上,RenderAction可以传递所有您想要的路由数据,而不仅仅是动作名称

RedirectToAction可能是最好的选择-这样你就可以使用内置的路由来找到正确的操作-类似

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

如果你不想重定向,你可以按照Nathan的建议直接找到并调用控制器方法,但这往往会变得不必要的复杂,并干扰定位视图。

注意:这个解决方案可能看起来有点复杂,但它似乎是解决问题的唯一方法,正如提问者在他的问题中所描述的,更具体地说,在对他的问题的评论中,"这是关于创建被请求的控制器,并读取actionresult的输出。"(emphasis mine)

控制器和操作只是类和方法的奇特名称。为什么不像实例化任何其他类一样实例化控制器,然后在控制器上调用索引操作呢?最困难的部分是实例化控制器,因为你要使用"插件"架构,而你所拥有的关于控制器的所有信息都是它作为字符串的名称。不过,没有什么是一点点反思无法解决的:

// 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;
    }
}