0

我是 ASP.NET MVC 的新手。在使用传统的 ASP.NET 模型这么久之后,我需要一些时间来理解这个模型。

我正在通过 NerdDinner 了解事情是如何运作的。

所以,我有一个需要通过几个视图的对象。与文章NerdDinner 第 6 步:ViewData 和 ViewModel类似。

我第一次保留从 Get 到 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
    }
}
4

4 回答 4

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") %>

<% } %>

上面的示例中没有用户友好性,但您明白了。

于 2009-11-29T05:05:22.093 回答
1

根据这篇文, TempData 在设置后仅适用于 1 个单个请求。

这是该帖子的引述:

如果您设置 TempData 并且您的操作然后返回 ViewResult,那么下一个请求,无论它碰巧是什么(AJAX 请求,用户在不同选项卡中打开的另一个页面等),都会看到您设置的 TempData 值,并且没有其他请求会看到它。

因此,鉴于我看到的代码,您可以从 TempData 获取晚餐,AnotherAction这是您设置后的第一个请求Action。但是,查看代码并没有看到代码以供查看,AnotherAction尚不清楚您如何将数据传递给AnotherAction. 晚餐实例不会出现在该请求的 TempData 中,因为这是在 TempData 中设置它之后的第二个请求。如果您没有在AntoherAction视图上设置正确的表单标签,则框架将没有正确的表单值来实例化帖子中的晚餐对象。

因此,要么您必须使用第一次AnotherAction调用的晚餐实例重置 TempData,然后在 post 中从 TempData 中检索晚餐AnotherAction,或者您可以遵循 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>

<% } %>

另一个动作视图:

<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>

<% } %>
于 2009-11-29T05:54:17.780 回答
1

您不能将原始 C# 对象从视图传递到控制器。

在 ASP.NET MVC 中,当操作将对象作为参数时,ASP.NET MVC 会查看所有 POST/GET 数据并查找与参数对象上的属性名称一致的值。

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

仅当您使用与晚餐对象的属性(位置、日期等)相对应的表单字段发布到操作或将该信息放在 GET URL 中(Dinners/SomeAction?location=chicago&date)时,才会填充 myDinner 对象=12/1/2009 等)

如果您绝对不能使用隐藏字段(正如 DM 建议的那样),那么 Sessions 可能是您唯一的选择。

于 2009-11-29T22:36:08.413 回答
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 中的数据通过请求持续存在。

于 2009-11-28T23:34:13.777 回答