2009-11-28 2 views
0

Я новичок в ASP.NET MVC. После долгой работы с традиционной моделью ASP.NET мне понадобилось время, чтобы понять эту модель.Передача данных с контроллера для просмотра, обратно к контроллеру, назад к просмотру

Я иду через NerdDinner, чтобы понять, как все работает.

Итак, у меня есть объект, который необходимо передать через пару видов. Как и в статье NerdDinner Step 6: ViewData and ViewModel.

Я сохраняю данные из Get to Post в первый раз, затем помещаю его в TempData и передаю его другому действию (AnotherAction). Как только я получу свои данные в Get, я не могу сохранить его в Post.

Вот мой код:

public class DinnerFormViewModel 
{ 
    public Dinner Dinner { get; private set; } 

    public DinnerFormViewModel(Dinner dinner) 
    { 
     Dinner = dinner; 
    } 
} 

public class DinnersController : Controller 
{ 
    public ActionResult Action() 
    { 
     Dinner dinner = new Dinner(); 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Action(Dinner dinner, FormCollection collection) 
    { 
     try 
     { 
      // Some code 
      TempData["Dinner"] = dinner; 
      return RedirectToAction("AnotherAction"); 
     } 
     catch 
     { 
      return View(); 
     } 
    } 

    public ActionResult AnotherAction() 
    { 
     Dinner dinner = (Dinner)TempData["Dinner"]; // Got my dinner object 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult AnotherAction(Dinner dinner, FormCollection collection) 
    { 
     // Lost my dinner object, dinner comes in as null 
    } 
} 

ответ

1

В соответствии с этим blog post TempData предназначен только для одного запроса после его набора.

Вот цитата из поста:

Если вы установите TempData и ваше действие затем возвращает ViewResult, то следующий запрос, все, что случается (запрос AJAX, другая страница открыл пользователь на другой вкладке и т. д.), вы увидите установленное значение TempData, и никакой другой запрос не увидит его.

Так дали код, который я вижу, что вы можете получить обед из TempData на Достаньте из AnotherAction, который первый запрос после того, как вы установили его на Action. Однако, глядя на код и не видя код для просмотра для AnotherAction, неясно, как вы передаете данные на сообщение для AnotherAction. Этот экземпляр не будет в TempData для этого запроса, потому что это второй запрос после его установки в TempData.И если у вас нет правильных тегов формы, установленных в представлении AntoherAction, структура фреймворка не будет иметь правильных значений формы для создания экземпляра объекта ужина в сообщении.

Так что либо вам придется сбросить TempData с экземпляром обеда его первым AnotherAction вызовом, а затем получить обед из TempData в посте AnotherAction, или вы можете следовать советам дх и использовать скрытые поля с вашей точкой зрения ,

IMO, вы должны использовать DM-способ этого и избегать использования TempData.

Редактировать Добавлен пример перезапуска TempData в AnotherAction, чтобы получить доступ к нему в сообщении.

Модель:

public class Dinner 
    { 
    public string Name{get;set;} 
    } 

    public class DinnerFormViewModel 
    { 
    public Dinner Dinner {get;private set;} 

    public DinnerFormViewModel(Dinner dinner) 
    { 
     Dinner = dinner; 
    } 
    } 

Контроллер:

public class DinnersController : Controller 
    { 
    public ActionResult Action() 
    { 
     Dinner dinner = new Dinner(); 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Action(Dinner dinner, FormCollection collection) 
    { 
     try 
     { 
     // Some code 
     TempData[ "Dinner" ] = dinner; 
     return RedirectToAction("AnotherAction"); 
     } 
     catch 
     { 
     return View(); 
     } 
    } 

    public ActionResult AnotherAction() 
    { 
     Dinner dinner = (Dinner)TempData[ "Dinner" ]; // Got my dinner object 
     TempData[ "Dinner" ] = dinner; // Reset the dinner object in temp data 
     return View(new DinnerFormViewModel(dinner)); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult AnotherAction(Dinner dinnerFromPostedFormValues, FormCollection collection) 
    { 
     //dinnerFromPostedFormValues is null 
     var dinnerFromTempData = TempData[ "Dinner" ] as Dinner; // Got my dinner object 

     return View("Action", new DinnerFormViewModel(dinnerFromTempData)); 
    } 
    } 

Действие Вид:

<h2>Action</h2> 

<% using (Html.BeginForm()) {%> 

    <fieldset> 
     <legend>Fields</legend> 
     <p> 
      Name: <%= Html.TextBox("Name", Model.Dinner.Name) %> 
     </p> 
     <p> 
      <input type="submit" value="Save" /> 
     </p> 
    </fieldset> 

<% } %> 

AnotherAction Вид:

<h2>AnotherAction</h2> 

<% using (Html.BeginForm()) {%> 

    <fieldset> 
     <legend>Fields</legend> 
     <p> 
      Name: 
      <%= Html.Encode(Model.Dinner.Name) %> 
     </p> 

     <p> 
      <input type="submit" value="Do Something" /> 
     </p> 
    </fieldset> 

<% } %> 
+0

Сброс TempData на AnotherAction не помогает. Я понимаю, что TempData хорош только после RedirectToAction. Во всяком случае, я тоже пробовал этот метод с и без RedirectToAction. Конечно, RedirectToAction вводит бесконечный цикл, вызывающий версию GetAccess, и установка TempData без RedirectToAction ничего мне не дает. Поэтому я использую DinnerFormViewModel. Если вы посмотрите на код, то в моем первом действии (Get) я сделаю то же самое.Здесь я могу изменить объект Dinner, но я хочу, и я верну тот же объект Dinner на Action (Post). – Sai

+0

Jon, я добавил пример для переопределения TempData в другом действии, чтобы он был доступен для сообщения обратно другому действию. Я могу получить объект обеда из TempData успешно. Тем не менее, поскольку мое представление не публикует правильные переменные формы в AnotherAction, экземпляр унаследователя, переданный в действие, имеет значение null. FYI, у меня нет проекта ужина ботаника, поэтому я создал свой собственный класс Ужин с единственным свойством Name. –

+0

Это волшебство работает Аарон, потрясающе! Знаешь, я думал, что раньше пытался это сделать, поэтому я выполнил свои шаги с моим текущим проектом, и это не сработало. Затем я начал новый проект только с вашим кодом, и он работал там, поэтому я знал, что у меня были некоторые незначительные ошибки где-то. Поэтому я стал идиотом. Спасибо! – Sai

0

Вы должны получить обед из репозитория. Вы должны действовать следующим образом:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult AnotherAction(int dinnerId, FormCollection collection) 
{ 
    var dinner = dinnerRepository.Get(dinnerId); 
    ... do something with dinner ... 
    dinnerRepository.Save(dinner); 
    return RedirectToAction("AnotherAction", ... pass dinner id ...); 
} 

Действия GET также могут быть взяты из хранилища, поэтому вы можете передавать только идентификатор.

EDIT

Если вы хотите создать страницу мастера стиля, вы можете хранить ранее введенные данные в объекте Session.

Session['CurrentDinner'] = dinner; 

Данные, хранящиеся в сеансе, сохраняются через запросы.

+0

Я не передаю идентификатор, я передаю весь объект. И объект еще не сохранен в базе данных, поэтому я не могу волшебно сделать «поиск» из репозитория. – Sai

+0

Затем вы должны прочитать о связующих устройствах. Вы должны создать объект Dinner из значений формы. Почему вы хотите ужинать несколько раз, не сохраняя его в БД? – LukLed

+0

Я буду читать на модельных вяжущих. Спасибо за предложение. Я хочу собирать информацию у пользователя из нескольких разных представлений, и когда у меня есть информация, которая мне нужна, я собираюсь ее сохранить. Вместо того, чтобы делать ненужные множественные вызовы базы данных. Что меня беспокоит, это то, что оно работает для одного экземпляра и не работает для другого. Это та же самая чертовская концепция. – Sai

2

Чтобы получить формат, который вы ожидаете, возможно, вам придется заполнять некоторые скрытые поля при сборе информации из разных видов.

Кроме того, с помощью модели привязки вы могли бы сделать свой код смотреть на немного лучше и избегать TempData в местах:

public ActionResult Action() 
{ 
    Dinner dinner = new Dinner(); 
    return View(new DinnerFormViewModel(dinner)); 
} 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Action(Dinner dinner) 
{ 
    try 
    { 
     return RedirectToAction("AnotherAction", dinner); 
    } 
    catch 
    { 
     return View(); 
    } 
} 

public ActionResult AnotherAction(Dinner dinner) 
{ 
    return View(new DinnerFormViewModel(dinner)); 

    //In this view is where you may want to populate some hidden fields with the Dinner properties that have already been entered... so when the Post action picks up the dinner object it will be fully populated 
} 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult AnotherAction(Dinner dinner) 
{ 
    //work with fully populated Dinner object 
} 

Таким образом, в AnotherAction просмотра у Вас было бы что-то вроде:

<% using(Html.BeginForm()) { %> 

    <%= Html.Hidden("dinnerProperty1") %> 
    <%= Html.Hidden("dinnerProperty2") %> 
    <%= Html.Hidden("dinnerProperty3") %> 
    <%= Html.TextBox("dinnerProperty4") %> 
    <%= Html.TextBox("dinnerProperty5") %> 
    <%= Html.TextBox("dinnerProperty6") %> 

<% } %> 

Там в приведенном выше примере не является удобством для пользователя, но вы понимаете это.

+0

Благодарим вас за предложение. К сожалению, скрытые поля не являются опцией. Существует одно значение, которое я не хочу, чтобы пользователь нюхал исходный код и видел. Я могу, возможно, зашифровать это, но это было бы моим последним средством. Спасибо! – Sai

1

Вы не можете передавать необработанные объекты C# из представлений в контроллеры.

В ASP.NET MVC, когда действие принимает объект для параметра, ASP.NET MVC просматривает все данные POST/GET и ищет значения, которые совпадают с именами свойств объекта параметра.

public ActionResult SomeAction(Dinner myDinner) 
{ 
     // do stuff 
} 

объект myDinner будет заполняться ТОЛЬКО если вы размещаете в действие с полями формы, которые соответствуют свойствам объекта Ужин (место, дата и т.д.), или если вы должны были разместить эту информацию в GET URL (Dinners/SomeAction? Location = chicago & date = 12/1/2009 и т. Д.)

Если вы абсолютно не можете использовать скрытые поля (как предложено DM), то сеансы, вероятно, являются вашим единственным вариантом.

+0

Я согласен с Бадди. TempData использует состояние сеанса за занавесом для вас любыми способами. Я бы прекратил использование TempData и просто сохранил объект в состоянии сеанса напрямую. Конечно, только если вы не можете использовать скрытые поля. –

Смежные вопросы