【问题标题】:How to call another controller Action From a controller in Mvc如何从 Mvc 中的控制器调用另一个控制器动作
【发布时间】:2013-05-28 01:11:54
【问题描述】:

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

它不会发送到控制器 B 的 FileUploadMsgView()

代码如下:

控制器A:

private void Test()
{
    try
    {   //some codes here
        ViewBag.FileUploadMsg = "File uploaded successfully.";
        ViewBag.FileUploadFlag = "2";
        RedirectToAction("B", "FileUploadMsgView", new { FileUploadMsg = "File   uploaded successfully" });
    }
}

ControllerB(接收部分):

public ActionResult FileUploadMsgView(string FileUploadMsg)
{
    return View();
}

【问题讨论】:

  • 我知道这个问题很老,但在我看来,你应该将 ed chapel 的答案标记为最好的,tieson 看起来像一个 hack,它仍然有效,但是为什么在你可以使用的时候使用解决方法它是它的本意并获得预期的结果
  • @AndersM。 Ed 的回答做了重定向。当我发现这个问题正在寻找解决方案时,这不是我想要的。
  • @mxmissile 不是一个家伙,但 Ed 的回答是提问者需要的,因为他想要一个根据上传的内容返回的视图,我同意提问者在制定他的问题(这是正确的词吗?)尽管他的英语可能有限,但我们无法知道这一点,尽管 Tiesons 的回答对您有所帮助 - 这很好 - 这并没有改变 Ed 的回答最能反映提问者需要什么的事实
  • @AndersM。我明白,我的评论措辞很糟糕...... :-) 我应该强调一点不是想要的结果。
  • @AndersM。提问者接受了Tieson的回答为最好,所以我不知道你为什么会为他做决定? Tieson 给我的答案比 Ed 的答案更能帮助我。 SO 不只是帮助一个人,而是帮助每个有类似问题的人。那么为什么不把 Tieson 的答案放在首位呢?

标签: c# asp.net-mvc asp.net-mvc-4 controller


【解决方案1】:

正如@mxmissile 在 cmets 中对接受的答案所说,您不应该新建控制器,因为它将缺少为 IoC 设置的依赖项,并且不会有 HttpContext

相反,您应该得到一个控制器实例,如下所示:

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

【讨论】:

  • 正是我想要的。请注意,那些不使用 IoC 的人仍然不会得到HttpContext 注入。
  • var controller 将被分配类型 ControllerB,是的。
  • 这让我很接近,但出现的一个问题是,在我的情况下,controller.MyAction() 引用了似乎未实例化的 User.Identity。
  • @ilasno 这些天我对 MVC 生疏了,但我想我的意思是你必须真正 IoC 设置以获得完全填充的控制器对象(例如关联HttpContext)。我相信我使用这种方法没有任何 IoC 来获取“浅”控制器对象(只需要访问某些功能),并且最初对部件“丢失”的原因感到困惑。 [旁白:我在仍然使用这种方法的同时解决了这个问题,但可能应该将该功能重构为共享类。]至于 IoC 设置和选择,我必须向您推荐其他文章/SO 问题。跨度>
  • 有些人被毫无意义的编辑冲昏了头脑……请注意,有人编辑了答案,将变量“controller”更改为“ctrlr”……所以它应该是“ctrlr.ControllerContext = new ControllerContext( this.Request.RequestContext, ctrl);"如果该用户正确编辑了它
【解决方案2】:

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

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

【讨论】:

  • 如果你这样做,你不会错过ControllerContext、Request和朋友吗?
  • 控制器的实例化不是一个好主意,因为它的生命周期可能由应用程序的另一部分控制。例如。使用 IoC 容器时,应注入所有依赖项,等等。
  • 如果你使用 IoC,你可以通过var controller = DependencyResolver.Current.GetService&lt;ControllerB&gt;();得到一个填充控制器
  • @mxmissile 这值得作为新答案添加,而不是在这里发表评论。
  • @ilasno 你熟悉“控制反转”这个术语吗?他的意思是,如果您的控制器中有组件需要注入到构造函数中,那么我的回答就不起作用,除非您使用 DependencyResolver 之类的东西作为服务定位器。
【解决方案3】:

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

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

【讨论】:

  • 必须指出,如果目标动作只接受POST,这是行不通的。
  • 这会返回一个 302,这会导致服务器再次受到攻击,这不是问题所要求的。
【解决方案4】:

正如@DLeh 所说 宁可使用

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

但是,给控制器一个控制器上下文很重要,尤其是当您需要访问“子”控制器内的User 对象、Server 对象或HttpContext 时。

我已经添加了一行代码:

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

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

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

【讨论】:

  • 如果您尝试在使用 View(..) 或 PartialView(...) 的控制器中调用操作,您需要手动更改 routeData,以便 ASP.NET 知道如何找到您的看法。 controller.RouteData.Values["controller"] = "Home";controller.RouteData.Values["action"] = "Index"; 假设您正在尝试从 HomeController 中的 Index 操作返回结果。
  • @Steven 我必须将这些值应用于this 而不是controller。最终结果会通过本地控制器 (this) 返回,这就是最终试图找到视图的原因。
  • 我还要补充一点,Url 属性没有在 DependencyResolver.Current.GetService() 上初始化。所以你必须手动从当前控制器复制它。
  • 在定位操作中你应该使用return View("ViewName"); 而不是return View();
【解决方案5】:

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

在控制器内部:

public class AController : ApiController
{
    private readonly BController _bController;

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

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

}

【讨论】:

  • imo 是最干净的答案,但您应该将控制器上下文设置为新控制器。
  • 别忘了 services.AddMvc().AddControllersAsServices();在 Startup.cs 中
【解决方案6】:

如果有人正在研究如何在 .net 核心中执行此操作,我通过在启动时添加控制器来完成它

services.AddTransient<MyControllerIwantToInject>();

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

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

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

那就这样称呼吧_myControllerIwantToInject.MyMethodINeed();

【讨论】:

  • 对于 .NET Core 2.1 似乎没问题,但对于添加了 AddControllers 的控制器的 .NET Core 3.1(可能还有即将推出的 .NET 5)不太适合我仍在寻找.NET 3.1 最干净的解决方案...
【解决方案7】:

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

例如,我想在LifeCycleEffectsResults 控制器中调用IndexComparison 方法并传递给它一个名为model 的复杂类对象。

这是失败的代码:

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

值得注意的是,字符串、整数等在使用此控制器方法的过程中幸存下来,但通用列表对象却遭受了类似于 C 内存泄漏的困扰。

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

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

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

现在一切都按预期工作。谢谢你带路。

【讨论】:

    【解决方案8】:

    我知道它很旧,但你可以:

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

    【讨论】:

      【解决方案9】:

      Dleh's answer 是正确的,并解释了如何获取另一个控制器的实例而不会丢失为 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)?
      【解决方案10】:

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

      yourController obj= new yourController();
      
      obj.yourAction();
      

      【讨论】:

      • 噗!如果您希望从某个操作获得结果怎么办? var res = new ControllerB().SetUpTimer(new TimeSpan(23, 20, 00));
      • 仅仅因为他们没有解析返回值并不意味着它不是一个有效的答案。
      【解决方案11】:

      如果你使用 .NET Core 或 .NET 5

      MVC:

      services.AddMvc().AddControllersAsServices();
      

      ApiController:

      services.AddControllers().AddControllersAsServices();
      

      然后你可以像任何其他服务一样简单地注入你的控制器

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-29
        • 2011-08-11
        • 1970-01-01
        • 2011-09-30
        • 1970-01-01
        • 1970-01-01
        • 2015-09-07
        相关资源
        最近更新 更多