user2156088
user2156088

Reputation: 2420

How to call another controller Action From a controller in Mvc

I need to call a controller B action FileUploadMsgView from Controller A and need to pass a parameter for it.

Its not going to the controller B's FileUploadMsgView().

Here's the code:

ControllerA:

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

ControllerB (receiving part):

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

Upvotes: 193

Views: 470530

Answers (11)

DLeh
DLeh

Reputation: 24385

As @mxmissile says in the comments to the accepted answer, you shouldn't new up the controller because it will be missing dependencies set up for IoC and won't have the HttpContext.

Instead, you should get an instance of your controller like this:

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

in .NET Core / .NET 5+ you should inject the controller like so:

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

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

in general though, calling another controller is an antipattern and it would be better practice to do abstract the important part of your controller into a shared service and inject that where it's needed.


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

Upvotes: 259

Ogglas
Ogglas

Reputation: 69928

If you use .NET Core or .NET 5 < you can do it like this:

MVC:

services.AddMvc().AddControllersAsServices();

ApiController:

services.AddControllers().AddControllersAsServices();

Then you can simply inject your controller like any other service

Upvotes: 5

Watth
Watth

Reputation: 446

I know it's old, but you can:

  • Create a service layer
  • Move method there
  • Call method in both controllers

Upvotes: 13

Leonardo Wildt
Leonardo Wildt

Reputation: 2599

If anyone is looking at how to do this in .net core I accomplished it by adding the controller in startup

services.AddTransient<MyControllerIwantToInject>();

Then Injecting it into the other controller

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

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

Then just call it like so _myControllerIwantToInject.MyMethodINeed();

Upvotes: 12

AlexB
AlexB

Reputation: 7416

Dleh's answer is correct and explain how to get an instance of another controller without missing dependencies set up for IoC

However, we now need to call the method from this other controller.
Full answer would be :

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

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

Upvotes: 6

user5407401
user5407401

Reputation:

if the problem is to call. you can call it using this method.

yourController obj= new yourController();

obj.yourAction();

Upvotes: 5

David Castro
David Castro

Reputation: 1957

Let the resolver automatically do that.

Inside A controller:

public class AController : ApiController
{
    private readonly BController _bController;

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

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

}

Upvotes: 12

Nishanth Shaan
Nishanth Shaan

Reputation: 1472

as @DLeh says Use rather

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

But, giving the controller, a controlller context is important especially when you need to access the User object, Server object, or the HttpContext inside the 'child' controller.

I have added a line of code:

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

or else you could have used System.Web to acces the current context too, to access Server or the early metioned objects

NB: i am targetting the framework version 4.6 (Mvc5)

Upvotes: 19

cghore
cghore

Reputation: 101

This is exactly what I was looking for after finding that RedirectToAction() would not pass complex class objects.

As an example, I want to call the IndexComparison method in the LifeCycleEffectsResults controller and pass it a complex class object named model.

Here is the code that failed:

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

Worth noting is that Strings, integers, etc were surviving the trip to this controller method, but generic list objects were suffering from what was reminiscent of C memory leaks.

As recommended above, here's the code I replaced it with:

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

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

All is working as intended now. Thank you for leading the way.

Upvotes: 7

Ed Chapel
Ed Chapel

Reputation: 6932

Your sample looks like psuedo code. You need to return the result of RedirectToAction:

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

Upvotes: 66

Tieson T.
Tieson T.

Reputation: 21191

Controllers are just classes - new one up and call the action method just like you would any other class member:

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

Upvotes: 124

Related Questions