如何从Mvc中的控制器调用另一个控制器操作


153

我需要从控制器A调用控制器B动作FileUploadMsgView,并需要为其传递参数。

 Code---its not going to the controller B's FileUploadMsgView().
    In ControllerA
  private void Test()
    {

        try
        {//some codes here
            ViewBag.FileUploadMsg = "File uploaded successfully.";
            ViewBag.FileUploadFlag = "2";

            RedirectToAction("B", "FileUploadMsgView", new { FileUploadMsg = "File   uploaded successfully" });
        }

     In ControllerB receiving part
  public ActionResult FileUploadMsgView(string FileUploadMsg)
    {
         return View();
    }

3
我知道这个问题很旧,但我认为您应该将ed chapel的答案标记为最佳答案,tieson看起来像是一个hack,它仍然有效,但是为什么要按原本打算的方式使用替代方法并获得理想的结果
Anders M.

1
@AndersM。Ed的答案进行了重定向。当我发现这个问题寻找解决方案时,这不是我想要的。
mxmissile

@mxmissile不是鸡巴,但Ed的回答是asker的需求,因为他希望基于上传的内容返回视图,我同意asker在提出问题方面可以做得更好(这是正确的词吗? )尽管Tiesons的回答对您有所帮助,但我们仍不知道这一点,尽管Tiesons的回答对您有所帮助-很好-它并不能改变Ed的回答最能反映申请者的需求的事实
Anders M.

2
@AndersM。我知道,我的评论措词很不好……:-)我应该强调一点,这不是想要的结果。
mxmissile 2014年

@AndersM。询问者最好地接受了Tieson的答案,所以我不确定您为什么会为他决定?铁森给我的答案比爱德的答案对我的帮助更大。SO不仅是为了帮助一个人,而且是每个有类似问题的人。那么,为什么不仅仅把铁森的答案放在首位呢?
凯文·沃恩

Answers:


106

控制器只是类-新的类并像其他任何类成员一样调用action方法:

var result = new ControllerB().FileUploadMsgView("some string");


76
如果您只是这样做,就不会错过ControllerContext,Request和朋友吗?
卷云

20
控制器的实例化不是一个好主意,因为它的生命周期可能由应用程序的另一部分控制。在使用IoC容器所有depdencies应注射等EG
莫Valipour

48
如果您使用的是IoC,则可以通过var controller = DependencyResolver.Current.GetService<ControllerB>();
mxmissile 2014年

3
@mxmissile值得添加为新答案,而不是在此处发表评论。
Tieson T. 2014年

2
@ilasno您熟悉术语“控制反转”吗?他的意思是,如果控制器中有需要注入到构造函数中的组件,除非您使用诸如DependencyResolver之类的东西作为服务定位符,否则我的答案实际上是行不通的。
Tieson T.

202

正如@mxmissile在接受的答案的注释中所说,您不应该新建控制器,因为它将丢失为IoC设置的依赖项,并且没有HttpContext

相反,您应该像这样获得控制器的实例:

var controller = DependencyResolver.Current.GetService<ControllerB>();
controller.ControllerContext = new ControllerContext(this.Request.RequestContext, controller);

正是我想要的。请注意,那些不使用IoC的人仍然不会被HttpContext注入。
brichins

var controller将被分配类型ControllerB,是的。
DLeh '16

1
这使我很接近,但是出现的一个问题是,在我的情况下,controller.MyAction()引用了User.Identity,这似乎是实例化的。
罗伯特·H·布尔多

1
@ilasno我对MVC是生锈的这些天,但我想我的意思是你必须真正具有国际奥委会成立得到一个完全填充的控制器对象(例如相关的HttpContext)。我相信我在没有任何IoC的情况下使用了这种方法来获取“浅”控制器对象(只是需要访问某些功能),并且最初对为什么零件“缺失”感到困惑。[此外:我仍在使用这种方法,但仍在解决该问题,但可能应该将该功能重构为共享类。]至于IoC的设置和选择,我将不得不向您介绍其他文章/ SO问题。
brichins 2016年

3
有些人无意义地进行编辑...请注意,有人编辑了答案,将变量“ controller”更改为“ ctrlr” ...因此它应显示为“ ctrlr.ControllerContext = new ControllerContext(this.Request.RequestContext,ctrl)” ;“ 如果该用户正确编辑了它
JoeSharp

62

您的示例看起来像伪代码。您需要返回以下结果RedirectToAction

return RedirectToAction("B", 
                        "FileUploadMsgView",
                        new { FileUploadMsg = "File uploaded successfully" });

4
必须指出的是,如果目标操作仅接受POST,则此操作将无效。
Marco Alves 2014年

13
这将返回302,这将导致服务器再次命中,这不是问题要问的。
rboarman

16

就像@DLeh所说的那样使用

var controller = DependencyResolver.Current.GetService<ControllerB>();

但是,为控制器提供控制器上下文非常重要,尤其是当您需要访问User对象,Server对象或HttpContext“子”控制器内部时。

我添加了一行代码:

controller.ControllerContext = new ControllerContext(Request.RequestContext, controller);

否则,您可能也曾使用System.Web访问当前上下文,访问Server或早期提及的对象

注意:我的目标是框架版本4.6(Mvc5)


4
如果尝试在使用V​​iew(..)或PartialView(...)的控制器中调用动作,则需要手动更改routeData,以便ASP.NET知道如何查找视图。controller.RouteData.Values["controller"] = "Home";controller.RouteData.Values["action"] = "Index";假设您尝试从HomeController中的Index操作返回结果。
史蒂文·

@Steven我必须将这些值应用于this而不是controller。最终,结果通过本地控制器(this)返回,因此最终试图找到视图。
aaaantoine

我还要补充一点,Url属性未在DependencyResolver.Current.GetService <ControllerB>()上初始化。因此,您必须手动从当前控制器复制它。
Ralfeus

在瞄准动作,你应该使用return View("ViewName");刚刚代替return View();
mNejkO

9

让解析器自动执行此操作。

在A控制器内部:

public class AController : ApiController
{
    private readonly BController _bController;

    public AController(
    BController bController)
    {
        _bController = bController;
    }

    public httpMethod{
    var result =  _bController.OtherMethodBController(parameters);
    ....
    }

}

2
imo最干净的答案,但是您应该将控制器上下文设置为新控制器。
Mafii

8

如果有人正在寻找如何在.net核心中执行此操作,则可以通过在启动时添加控制器来完成此操作

services.AddTransient<MyControllerIwantToInject>();

然后将其注入另一个控制器

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

     public controllerBeingInjectedInto(MyControllerIwantToInject myControllerIwantToInject)
{
       _myControllerIwantToInject = myControllerIwantToInject;
      }

然后像这样称呼它 _myControllerIwantToInject.MyMethodINeed();


4

这正是我发现RedirectToAction()不会传递复杂的类对象之后一直在寻找的东西。

例如,我想IndexComparisonLifeCycleEffectsResults控制器中调用该方法,并将其传递给名为model的复杂类对象。

这是失败的代码:

return RedirectToAction("IndexComparison", "LifeCycleEffectsResults", model);

值得一提的是,字符串,整数等幸存于使用此控制器方法的过程中,但是通用列表对象正遭受C内存泄漏的困扰。

按照上面的建议,这是我替换为的代码:

var controller = DependencyResolver.Current.GetService<LifeCycleEffectsResultsController>();

var result = controller.IndexComparison(model);
return result;

现在一切都按预期工作。感谢您的指导。


3

Dleh的答案是正确的,并解释了如何在不丢失为IoC设置依赖项的情况下获取另一个控制器的实例

但是,我们现在需要从另一个控制器调用该方法。
完整答案将是:

var controller = DependencyResolver.Current.GetService<ControllerB>();
controller.ControllerContext = new ControllerContext(this.Request.RequestContext, controller);

//Call your method
ActionInvoker.InvokeAction(controller.ControllerContext, "MethodNameFromControllerB_ToCall");

如果需要参数,如何调用动作“ MethodNameFromControllerB_ToCall”?例如MethodNameFromControllerB_ToCall(int somenum,string sometext)?
Patee Gutee

3

我知道它很旧,但是您可以:

  • 创建一个服务层
  • 在那里移动方法
  • 两个控制器中的调用方法

2

如果问题是打电话给。您可以使用此方法调用它。

yourController obj= new yourController();

obj.yourAction();

1
ff!如果您期望操作会产生结果怎么办? var res = new ControllerB().SetUpTimer(new TimeSpan(23, 20, 00));
DirtyBit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.