将数据从控制器传递到视图,再传递回控制器,再传递回视图

发布于 2024-08-13 01:00:58 字数 1467 浏览 3 评论 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
    }
}

I'm new to ASP.NET MVC. After working with traditional ASP.NET model for so long, it's taking some time for me to get to understand this model.

I am going through NerdDinner to understand how things work.

So, I have an object that needs to be passed through couple of views. Similar to the article NerdDinner Step 6: ViewData and ViewModel.

I retain the data from Get to Post for the first time, then I put it in TempData and pass it to another action (AnotherAction). Once I get my data on Get I cannot retain it on Post.

Here's my code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

全部不再 2024-08-20 01:00:58

要获得您期望的格式,您可能必须在从各种视图收集信息时填充一些隐藏字段。

另外,使用模型绑定可以使代码看起来更好一些,并避免在某些地方使用 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") %>

<% } %>

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

To get the format that you're expecting you may have to populate some hidden fields as you collect the information from various views.

Also, using model binding you could make your code look at bit better and avoid TempData in places:

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
}

So in the AnotherAction view you would have something like:

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

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

<% } %>

There is no user friendliness in the above example but you get the point.

春夜浅 2024-08-20 01:00:58

根据这篇博客文章 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 视图:

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

<% } %>

According to this blog post TempData is only around for 1 single request after its set.

Here is a quote from the post:

If you set TempData and your action then returns a ViewResult, then the next request, whatever it happens to be (an AJAX request, another page the user opened in a different tab, etc.), is going to see the TempData value you set, and no other request will see it.

So given the code that I'm seeing, you can get the dinner from TempData on the get from AnotherAction which is the first request after you set it on Action. However looking at the code and not seeing the code for view for AnotherAction it is unclear how you are passing the data to the post for AnotherAction. The dinner instance is not going to be in TempData for that request because it's the second request after you set it in TempData. And if you do not have the proper form tags set on the AntoherAction view the framework will not have the proper form values to instantiate a dinner object in the post.

So either you'll have to reset TempData with the dinner instance it the first AnotherAction call and then retrieve the dinner out of TempData in the post AnotherAction, or you can follow the advice of dm and use hidden fields in your view.

IMO, you should use DMs way of doing this and avoid using TempData.

Edit Added example of reseting the TempData in AnotherAction to get access to it in the post.

Model:

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

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

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

Controller:

  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 ) );
    }
  }

Action View:

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

<% } %>
一直在等你来 2024-08-20 01:00:58

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

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

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

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

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

You can't pass raw C# objects from Views to Controllers.

In ASP.NET MVC, when an action takes an object for a parameter, ASP.NET MVC looks at all the POST/GET data and looks for values which coincide with property names on the parameter object.

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

myDinner object will be populated ONLY if you post to the action with form fields that correspond to the Dinner object's properties (location, date, etc.) or if you were to place that information in a GET URL (Dinners/SomeAction?location=chicago&date=12/1/2009 etc.)

If you absolutely can't use hidden fields (As DM suggested), then Sessions is probably your only option.

眸中客 2024-08-20 01:00:58

你应该从存储库得到晚餐。您的操作应该类似于:

[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 中的数据通过请求持续存在。

You should get dinner from repository. You action should be like:

[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 actions can also take from repository, so you can pass only id.

EDIT

If you want to create wizard style page, you can store previously entered data in Session object.

Session['CurrentDinner'] = dinner;

Data stored in Session persist through requests.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文