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
通过控制器操作中的操作来访问插件,例如/ reports / get /?type = spend
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?
因此,在这种情况下,操作必须将控制器放置在“插件”区域内并调用索引操作(例如,areas / plugin / expenditure / index)。如何在/ reports / get /?type = spend操作中调用此操作,并获取其输出?
3 个解决方案
#1
8
Html.RenderAction Method is used for rendering other action's output in view. Inpired from that, same in controller would be
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");
}
Actually, RenderAction can be passed all the routing data you want, not only action name
实际上,RenderAction可以传递您想要的所有路由数据,而不仅仅是动作名称
#2
3
RedirectToAction is probably the best option - that way you can use the built in routing to find the right action - something like
RedirectToAction可能是最好的选择 - 这样你就可以使用内置的路由来找到正确的动作 - 就像这样
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.
如果您不想要重定向,您可以像Nathan建议的那样直接找到并调用控制器方法,但这往往会变得不必要地复杂并干扰定位视图。
#3
3
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)
注意:这个解决方案可能看起来有点复杂,但它似乎是解决问题的唯一方法,正如提问者在他的问题中所描述的那样,更具体地说是对他的问题的评论,其中指出,“这是关于创建控制器的问题。被要求,并阅读actionresult的输出。“(强调我的)
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;
}
}
#1
8
Html.RenderAction Method is used for rendering other action's output in view. Inpired from that, same in controller would be
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");
}
Actually, RenderAction can be passed all the routing data you want, not only action name
实际上,RenderAction可以传递您想要的所有路由数据,而不仅仅是动作名称
#2
3
RedirectToAction is probably the best option - that way you can use the built in routing to find the right action - something like
RedirectToAction可能是最好的选择 - 这样你就可以使用内置的路由来找到正确的动作 - 就像这样
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.
如果您不想要重定向,您可以像Nathan建议的那样直接找到并调用控制器方法,但这往往会变得不必要地复杂并干扰定位视图。
#3
3
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)
注意:这个解决方案可能看起来有点复杂,但它似乎是解决问题的唯一方法,正如提问者在他的问题中所描述的那样,更具体地说是对他的问题的评论,其中指出,“这是关于创建控制器的问题。被要求,并阅读actionresult的输出。“(强调我的)
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;
}
}