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

问题描述 投票:0回答:11

我需要从控制器 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" });
    }
}

控制器B(接收部分):

public ActionResult FileUploadMsgView(string FileUploadMsg)
{
    return View();
}
c# asp.net-mvc asp.net-mvc-4 controller
11个回答
256
投票

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

HttpContext

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

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

在 .NET Core / .NET 5+ 中,您应该像这样注入控制器:

public class ControllerA : ControllerBase
{
    public ControllerA(ControllerB other) { _other = other; }

    public ActionResult MyMethod() { other.SomeMethod(); }
}  

一般来说,调用另一个控制器是一种反模式,最好的做法是将控制器的重要部分抽象到共享服务中并将其注入到需要的地方。


//interface optional. register as AddSingleton<IMyService, MyService>(); or scoped or w/e
public interface IMyService
{
    string GetValue();
}
public class MyService : IMyService
{
    public string GetValue()
    {
        return "Query some database or anything else";
    }
}

public class ControllerA(IMyService _service)
{
    public ActionResult GetValueA()
    {
        var somethingDifferentFromB = _service.GetValue() + "_controllera";
        return Ok(somethingDifferentFromB);
    }
}

public class ControllerB(IMyService _service)
{
    public ActionResult GetValueB()
    {
        return Ok(_service.GetValue());
    }
}

123
投票

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

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


64
投票

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

RedirectToAction
的结果:

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

18
投票

正如@DLeh 所说 不如使用

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

但是,对于控制器来说,控制器上下文非常重要,尤其是当您需要访问

User
对象、
Server
对象或“子”控制器内的
HttpContext
时。

我添加了一行代码:

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

否则你也可以使用 System.Web 来访问当前上下文,访问

Server
或早期提到的对象

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


13
投票

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

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

12
投票

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

控制器内部:

public class AController : ApiController
{
    private readonly BController _bController;

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

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

}

12
投票

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

services.AddTransient<MyControllerIwantToInject>();

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

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

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

那就这样称呼吧

_myControllerIwantToInject.MyMethodINeed();


7
投票

这正是我在发现

RedirectToAction()
不会传递复杂的类对象后所寻找的。

举个例子,我想在

IndexComparison
控制器中调用
LifeCycleEffectsResults
方法,并向其传递一个名为 model 的复杂类对象。

这是失败的代码:

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

值得注意的是,字符串、整数等在访问此控制器方法的过程中幸存下来,但通用列表对象却遭受了让人想起 C 内存泄漏的问题。

正如上面推荐的,这是我将其替换为的代码:

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

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

现在一切都按预期进行。谢谢你带路。


6
投票

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

6
投票

如果您使用 .NET Core 或 .NET 5 < you can do it like this:

MVC:

services.AddMvc().AddControllersAsServices();

ApiController

services.AddControllers().AddControllersAsServices();

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


5
投票

如果有问题请致电。 你可以使用这个方法来调用它。

yourController obj= new yourController();

obj.yourAction();
© www.soinside.com 2019 - 2024. All rights reserved.