我是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
}
}
答案 0 :(得分: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") %>
<% } %>
上面的示例中没有用户友好性,但您明白了这一点。
答案 1 :(得分:1)
根据这个blog post TempData仅在设置后的1个单个请求附近。
以下是帖子的引用:
如果您设置TempData并且您的操作然后返回ViewResult,那么下一个请求,无论它是什么(AJAX请求,用户在另一个选项卡中打开的另一个页面等),都会看到TempData您设置的值,没有其他请求会看到它。
因此,鉴于我所看到的代码,您可以在AnotherAction
获取来自TempData的晚餐,这是您在Action
上设置后的第一个请求。但是,如果查看代码而没有看到AnotherAction
的查看代码,则不清楚如何将数据传递到AnotherAction
的帖子。晚餐实例不会在TempData中用于该请求,因为它是您在TempData中设置后的第二个请求。如果您在AntoherAction
视图上没有设置正确的表单标签,则框架将没有正确的表单值来实例化帖子中的晚餐对象。
所以要么你必须在第一次AnotherAction
调用时用晚餐实例重置TempData,然后在帖子AnotherAction
中从TempData中检索晚餐,或者你可以按照dm的建议并在视图中使用隐藏字段。
IMO,您应该使用DM方式来避免使用TempData。
编辑添加了在AnotherAction中重置TempData以在帖子中访问它的示例。
型号:
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 View:
<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>
<% } %>
答案 2 :(得分:1)
您无法将原始C#对象从视图传递给控制器。
在ASP.NET MVC中,当一个操作获取参数的对象时,ASP.NET MVC会查看所有POST / GET数据并查找与参数对象上的属性名称一致的值。
public ActionResult SomeAction(Dinner myDinner)
{
// do stuff
}
只有当您使用与Dinner对象的属性(位置,日期等)对应的表单字段或者您要将该信息放入GET URL(Dinners / SomeAction?)时,才会填充myDinner对象。 location = chicago&amp; date = 12/1/2009 etc。)
如果你绝对不能使用隐藏字段(如建议的那样),那么Sessions可能是你唯一的选择。
答案 3 :(得分: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操作也可以从存储库中获取,因此您只能传递id。
编辑
如果要创建向导样式页面,可以将先前输入的数据存储在Session对象中。
Session['CurrentDinner'] = dinner;
存储在Session中的数据会通过请求持续存在。