Передача даних між різними методами дії контролера


74

Я використовую ASP.NET MVC 4. Я намагаюся передавати дані від одного контролера до іншого контролера. Я не розумію цього правильно. Я не впевнений, що це можливо?

Ось мій метод дії джерела, з якого я хочу передати дані:

public class ServerController : Controller
{
     [HttpPost]
     public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
     {
          XDocument updatedResultsDocument = myService.UpdateApplicationPools();

          // Redirect to ApplicationPool controller and pass
          // updatedResultsDocument to be used in UpdateConfirmation action method
     }
}

Мені потрібно передати його цьому методу дій у цьому контролері:

public class ApplicationPoolController : Controller
{
     public ActionResult UpdateConfirmation(XDocument xDocument)
     {
          // Will add implementation code

          return View();
     }
}

Я спробував наступне в ApplicationPoolsUpdateметоді дії, але він не працює:

return RedirectToAction("UpdateConfirmation", "ApplicationPool", new { xDocument = updatedResultsDocument });

return RedirectToAction("UpdateConfirmation", new { controller = "ApplicationPool", xDocument = updatedResultsDocument });

Як би я цього досягти?


3
Це спокусило мене на віки - в основному, використовуйте TempData / Session. Див stackoverflow.com/questions/672143 / ...
glosrob

Відповіді:


74

HTTP та переспрямування

Давайте спочатку розповімо, як працює ASP.NET MVC:

  1. Коли надходить запит HTTP, він відповідає набору маршрутів. Якщо маршрут відповідає запиту, буде викликано дію контролера, що відповідає маршруту.
  2. Перш ніж викликати метод дії, ASP.NET MVC виконує прив'язку моделі. Прив'язка моделі - це процес відображення вмісту HTTP-запиту, який в основному є лише текстом, до сильно набраних аргументів вашого методу дії.

Давайте також нагадаємо собі, що таке переспрямування:

Перенаправлення HTTP - це відповідь, яку веб-сервер може надіслати клієнтові, вказуючи клієнту шукати необхідний вміст за іншою URL-адресою. Нова URL-адреса міститься в Locationзаголовку, який веб-сервер повертає клієнту. В ASP.NET MVC ви виконуєте перенаправлення HTTP, повертаючи a RedirectResultз дії.

Передача даних

Якщо ви просто передавали такі прості значення, як рядки та / або цілі числа, ви можете передати їх як параметри запиту в URL-адресі в Locationзаголовку. Ось що могло б статися, якби ви використовували щось подібне

return RedirectToAction("ActionName", "Controller", new { arg = updatedResultsDocument });

як припускали інші

Причина того, що це не спрацює, полягає в XDocumentтому, що це потенційно дуже складний об'єкт. Немає простого способу для ASP.NET MVC серіалізувати документ у щось, що вміщуватиметься у URL-адресу, а потім моделювати прив’язку зі значення URL-адреси до вашого XDocumentпараметра дії.

Загалом, передача документа клієнту для того, щоб клієнт передав його назад серверу при наступному запиті, є дуже крихкою процедурою: для цього потрібні всілякі серіалізації та десериалізації, і всілякі речі можуть піти не так. Якщо документ великий, це також може бути значною втратою пропускної здатності та може суттєво вплинути на ефективність вашої програми.

Замість цього потрібно зберегти документ на сервері та передати ідентифікатор клієнту. Потім клієнт передає ідентифікатор разом із наступним запитом, а сервер отримує документ, використовуючи цей ідентифікатор.

Зберігання даних для отримання за наступним запитом

Отже, постає питання, де тим часом сервер зберігає документ? Ну, це вирішувати вам, і найкращий вибір буде залежати від вашого конкретного сценарію. Якщо цей документ повинен бути доступним у довгостроковій перспективі, можливо, ви захочете зберегти його на диску або в базі даних. Якщо вона містить лише перехідну інформацію, збереження її в пам'яті веб-сервера, у кеші ASP.NET або Session(або TempData, що більш-менш однаково Sessionз кінцевим) може бути правильним рішенням. У будь-якому випадку ви зберігаєте документ під ключем, який дозволить вам отримати документ пізніше:

int documentId = _myDocumentRepository.Save(updatedResultsDocument);

а потім ви повертаєте цей ключ клієнту:

return RedirectToAction("UpdateConfirmation", "ApplicationPoolController ", new { id = documentId });

Коли ви хочете отримати документ, ви просто отримуєте його на основі ключа:

 public ActionResult UpdateConfirmation(int id)
 {
      XDocument doc = _myDocumentRepository.GetById(id);

      ConfirmationModel model = new ConfirmationModel(doc);

      return View(model);
 }

1
Дякую Руне. Це гуд.
Devsainii

64

Ви пробували використовувати ASP.NET MVC TempData ?

Словник ASP.NET MVC TempData використовується для обміну даними між діями контролера. Значення TempData зберігається до тих пір, поки воно не буде прочитане або до закінчення часу сеансу поточного користувача. Збереження даних у TempData корисно в таких сценаріях, як переспрямування, коли значення потрібні за одним запитом.

Код буде приблизно таким:

[HttpPost]
public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
{
    XDocument updatedResultsDocument = myService.UpdateApplicationPools();
    TempData["doc"] = updatedResultsDocument;
    return RedirectToAction("UpdateConfirmation");
}

А в ApplicationPoolController:

public ActionResult UpdateConfirmation()
{
    if (TempData["doc"] != null)
    {
        XDocument updatedResultsDocument = (XDocument) TempData["doc"];
            ...
        return View();
    }
}

1
Чи правильно я вважаю, що TempData не безпечна для використання на декількох серверах із збалансованою навантаженням, якщо я також не підклав під неї спільний кеш сеансу?
GGleGrand

Я все ще вважаю, що нам слід усіма способами уникати використання сеансу, в даному випадку ViewData. Вони не набираються, а працюють лише в In-procсесійному режимі. Для будь-якого навантаження збалансовано сервера , який використовує State Severабо Sql Serverрежим сеансу, то ViewData губляться.
Блез

11

Особисто мені не подобається використовувати TempData, але я вважаю за краще передавати сильно набраний об'єкт, як це пояснюється в розділі Передача інформації між контролерами в ASP.Net-MVC .

Ви завжди повинні знайти спосіб зробити це явним і очікуваним.


TempData спеціально створена для передачі деяких простих даних з одного контролера перегляду іншому, не виставляючи всіх даних в URL-адресі клієнта або в запиті. Це не ідеально, але ефективніше, ніж Sessions. Він чудово справляється з ViewModels (або простими моделями). І це зручна функція для використання.
Piotr Kula

2
Він не обробляє ViewData, оскільки ViewData не можна серіалізувати, що є вимогою до сеансів, які неможливо запустити в процесі (веб-ферма) ... Мені дуже не подобається TempData (це найкращий спосіб сказати).
Novox

4

Я вважаю за краще використовувати це замість TempData

public class Home1Controller : Controller 
{
    [HttpPost]
    public ActionResult CheckBox(string date)
    {
        return RedirectToAction("ActionName", "Home2", new { Date =date });
    }
}

а інший controller Actionє

public class Home2Controller : Controller 
{
    [HttpPost]
    Public ActionResult ActionName(string Date)
    {
       // do whatever with Date
       return View();
    }
}

запізно, але я сподіваюся бути корисним для когось із них у майбутньому


2
Але в багатьох випадках ми хочемо передати складну модель в RedirectToAction.
Блез

-3

Якщо вам потрібно передати дані з одного контролера на інший, ви повинні передавати дані за значеннями маршруту. Оскільки обидва вони відрізняються за запитом. Якщо ви надсилаєте дані з однієї сторінки на іншу, тоді вам потрібно ввести рядок запиту користувача (те саме, що значення маршруту).

Але ви можете зробити один фокус:

У вашій дії, що викликає, називайте викликану дію простим методом:

public class ServerController : Controller
{
 [HttpPost]
 public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
 {
      XDocument updatedResultsDocument = myService.UpdateApplicationPools();
      ApplicationPoolController pool=new ApplicationPoolController(); //make an object of ApplicationPoolController class.

      return pool.UpdateConfirmation(updatedResultsDocument); // call the ActionMethod you want as a simple method and pass the model as an argument.
      // Redirect to ApplicationPool controller and pass
      // updatedResultsDocument to be used in UpdateConfirmation action method
 }
}

4
ти вважаєш, чи варто робити так? чи це змінить значення маршруту та завантажить правильний вигляд, коли ви спробуєте повернути View () у дії UpdateConfirmation?
KD

Так зухвало. Оскільки, якщо ви викликаєте UpdateConfirmation (), тоді повернене представлення базується на дії "UpdateConfirmation", тобто "View / ApplicationPool / UpdateConfirmation". Спробуйте спробувати. Я думаю, це спрацює.
jishnu saha

1
Не буде. це не змінить значення словника значення маршруту, отже, MVC спробує завантажити подання для дії, яка виконується першою :)
KD

Але з першої дії ви повертаєте подання, яке містить адресу другого перегляду, тому воно буде працювати.
jishnu saha
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.