Як викликати інший контролер Дія Від контролера в Mvc


153

Мені потрібно викликати контролер B дії FileUploadMsgView від контролера A і мені потрібно передати його параметр.

 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 як найкращий, Тісон виглядає як хак, він все ще дійсний, але навіщо використовувати вирішення, коли ви можете використовувати його так, як це мало бути і отримайте бажаний результат
Андерс М.

1
@AndersM Відповідь Еда переспрямовує. Це не те, чого я хочу, коли знайшов це питання, шукаючи рішення.
mxmissle

@mxmissle не бути хуїм, але відповідь Еда - це те, що запитувачеві потрібно, оскільки він хоче переглянути, який повертається на основі завантаженого, я погоджуюся, що кандидат може зробити кращу роботу при формулюванні свого питання (це правильне слово? ) ми не можемо цього знати, хоча його англійська мова може бути обмеженою, навіть якщо відповідь Тієсона допомогла вам - що добре - це не змінює факту, що відповідь Еда найкраще відображає те, що потрібно запитувачу
Андерс М.

2
@AndersM Я розумію, моє формулювання коментарів було просто поганим ... :-) Я повинен був підкреслити той момент, що це був не той результат, якого я бажав.
mxmissle

@AndersM Запитуючий прийняв відповідь Тісона як найкращу, тож я не впевнений, чому ти вирішиш за нього? Відповідь, яку мені дав Тісон, більше допомогла мені, ніж відповідь Еда. ТАК не лише для допомоги одній людині, а для всіх, хто має подібні проблеми. То чому б просто не тримати відповідь Тісона зверху?
Кевін Воорн

Відповіді:


106

Контролери - це просто класи - нові та виклик методу дії так само, як і будь-який інший член класу:

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


76
Ви не пропустите ControllerContext, Request та друзів, якщо ви просто це зробите?
цир

20
Екземпляр контролера не є хорошою ідеєю, оскільки його життєвий цикл може контролюватися іншою частиною програми. Наприклад, при користуванні контейнером IoC всі залишки слід вводити тощо.
Mo Valipour

48
Якщо ви користуєтесь IoC, ви можете отримати заселений контролер черезvar controller = DependencyResolver.Current.GetService<ControllerB>();
mxmissle

3
@mxmissle Це варто додати як нову відповідь, а не коментар тут.
Тієсон Т.

2
@ilasno Ви знайомі з терміном "інверсія управління"? Справа, яку він робить, полягає в тому, що якщо у ваших контролерах є компоненти, які потрібно вводити в конструктор, моя відповідь насправді не працює, якщо ви не використовуєте щось на зразок DependencyResolver як локатор служби.
Tieson T.

202

Як говорить @mxmissle в коментарях до прийнятої відповіді, ви не повинні створювати контролер, тому що в ньому будуть відсутні залежності, встановлені для IoC, і не буде HttpContext.

Натомість вам слід отримати такий примірник вашого контролера:

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

Саме те, що я шукав. Зауважте, що тим, хто не використовує IoC, все ще не вдасться зробити HttpContextін’єкцію.
бричін

var controllerбуде призначений тип ControllerB, так.
DLeh

1
Це мене зближує, але одна з проблем, яка виникає, полягає в тому, що в моєму випадку, controller.MyAction () посилається на User.Identity, який видається невиявленим.
Роберт Х. Бурдо

1
@ilasno Я іржавий на MVC в ці дні, але я думаю, я мав на увазі, що вам потрібно створити IoC, щоб отримати повністю заселений об'єкт Controller (наприклад, асоційований HttpContext). Я вважаю, що я використовував цей підхід без будь-якого IoC, щоб отримати "неглибокий" об'єкт контролера (просто потрібен доступ до певної функціональності) і спочатку плутався з приводу того, чому частини "відсутні". [осторонь: я працював над цим, ще використовуючи цей підхід, але, ймовірно, повинен був би відновити цю функціональність до спільного класу.] Щодо налаштування та варіантів IoC, я повинен був би посилатись на інші статті / питання ТА.
бричін

3
Деякі люди захоплюються безглуздими правками ... зауважте, що хтось редагував відповідь, змінюючи змінну "контролер" на "ctrlr" ... тому він повинен читати "ctrlr.ControllerContext = новий ControllerContext (this.Request.RequestContext, ctrl) ; " якщо цей користувач відредагував його правильно
JoeSharp

62

Ваш зразок виглядає як код psuedo. Вам потрібно повернути результат RedirectToAction:

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

4
Слід зазначити, що якщо цільова дія приймає лише POST, це не буде працювати.
Марко Алвеш

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
Якщо ви спробуєте викликати дію в контролері, який використовує View (..) або PartialView (...), вам потрібно вручну змінити routeData, щоб ASP.NET знав, як знайти ваш погляд. controller.RouteData.Values["controller"] = "Home";controller.RouteData.Values["action"] = "Index";Якщо припустити, що ви намагаєтесь повернути результат від дії Index в HomeController.
Стівен

@Steven Мені довелося застосувати ці значення, thisа не controller. У кінцевому підсумку результат повертається через локальний контролер (це), тому ось що закінчується намаганням знайти вигляд.
aaaantoine

Додам також, що властивість Url не ініціалізується на DependencyResolver.Current.GetService <ControllerB> (). Тому вам доведеться скопіювати його з поточного контролера вручну.
Ральфей

У націлюванні Дія ви повинні використовувати return View("ViewName");замість цього простоreturn View();
mNejkO

9

Нехай вирішувач автоматично це робить.

Всередині контролера:

public class AController : ApiController
{
    private readonly BController _bController;

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

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

}

2
imo найчистіша відповідь, але слід встановити контекст контролера новому контролеру.
Мафія

8

Якщо хтось дивиться на те, як це зробити в ядрі .net, я це досяг, додавши контролер при запуску

services.AddTransient<MyControllerIwantToInject>();

Потім вводять його в інший контролер

public class controllerBeingInjectedInto : ControllerBase
{
    private readonly MyControllerIwantToInject _myControllerIwantToInject

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

Тоді просто називайте це так _myControllerIwantToInject.MyMethodINeed();


4

Це саме те, що я шукав після того, як виявив, що RedirectToAction()не передасть складні об’єкти класу.

Як приклад, я хочу викликати IndexComparisonметод в LifeCycleEffectsResultsконтролері і передавати йому складний об'єкт класу з назвою модель.

Ось код, який не вдався:

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

Варто зазначити, що рядки, цілі числа тощо переживали поїздку до цього методу контролера, але загальні об'єкти списку страждали від того, що нагадувало витоки пам'яті C.

Як рекомендовано вище, ось код, який я замінив на:

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

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

Всі працюють зараз, як задумано. Дякую, що ви провели шлях.


3

Відповідь Дле є правильною і поясніть, як отримати екземпляр іншого контролера без пропущених залежностей, встановлених для 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, рядковий текст)?
Patee Gutee

3

Я знаю, що це старе, але ви можете:

  • Створіть рівень обслуговування
  • Перемістіть туди метод
  • Спосіб виклику в обох контролерах

2

якщо проблема в тому, щоб зателефонувати. ви можете викликати це за допомогою цього методу.

yourController obj= new yourController();

obj.yourAction();

1
Pfft! Що робити, якщо натомість ви очікуєте результату від дії? var res = new ControllerB().SetUpTimer(new TimeSpan(23, 20, 00));
DirtyBit
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.