質問

I am trying to get a HTTPPost working for a comment section of a video page but am having some difficulty on postback. The save is being recorded to the database but on reload of the page I am not able to find the @Model.SelectedMediaItem.Name variable that was found the first time. My html is as follows:

@{
ViewBag.Title = "Screencast";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@model Project.ViewModels.MediaViewModel
<body onload="initialize()">

<div class="container region3wrap_screencast">
  <div class="row content_top_contact">
    <div class="nine columns">
      <ul class="breadcrumbs">
        <li><a href="@Url.Action("Index","Home")">Home</a></li>
        <li><a href="@Url.Action("Index","Media")">Media</a></li>
        <li><a href="@Url.Action("Screencast","Media")">Screencast</a></li>
        <li class="current"><a href="#">@Model.SelectedMediaItem.Name</a></li>
      </ul>
    </div>
  </div>
</div>

<div class="twelve columns leave-comment">
  <h3>Leave a Comment</h3>
  @using(Html.BeginForm("Screencast","Media", FormMethod.Post, Model))
  {              
    <div class="row">
      <div class="six columns">
        <div class="row">
          <div class="six columns">
            @Html.LabelFor(c => c.FeedbackComment.UserID)
            @Html.TextBoxFor(c => c.FeedbackComment.UserID)
          </div>
          <div class="six columns">
            @Html.LabelFor(c => c.FeedbackComment.ContentID)
            @Html.TextBoxFor(c => c.FeedbackComment.ContentID)
          </div>   
          <div class="row">
            <div class="twelve columns">
              @Html.LabelFor(c => c.FeedbackComment.FeedbackString)
              @Html.TextAreaFor(c => c.FeedbackComment.FeedbackString)
            </div>
          </div>        
        </div>
      </div>
    </div>          
    <input type="submit" value="Submit button" class="medium button bottom20"/>
  }
</div>
</body>

My controller actions are as follows:

  //GET
  public ActionResult Screencast(int ID)
  {                        
    mvm = new ViewModels.MediaViewModel(ID);
    return View(mvm);
  }

  //POST
  [HttpPost]
  public ActionResult Screencast(MediaViewModel mvm)
  {
    Feedback newFeedback= new Feedback();
    newFeedback.UserID = mvm.FeedbackComment.UserID;
    newFeedback.ContentID = mvm.FeedbackComment.ContentID;
    newFeedback.CourseID = null;
    newFeedback.Timestamp = DateTime.Now;
    newFeedback.FeedbackString = mvm.FeedbackComment.FeedbackString;

    //Initialize the Feedback Repository and save changes
    feedbackRepository = new Repository<Feedback>(dbcontext);
    feedbackRepository.Add(newFeedback);
    feedbackRepository.SaveChanges();

    return View(mvm);
  }

When I call the page to begin with at the URL /Media/Screencast/1 it loads with a viewmodel populated with details of the SelectedMediaItem and all appears as is expected.

When I try to post back to this my viewmodel detail is being lost although the comment is actually saved as expected I need to visit another page and revisit before I am able to see.

How can I pass my view model in the @Html.BeginFor as an additional parameter?

My ViewModel is as follows:

public class MediaViewModel
{
    private Repository<Content> contentRepository;
    private Repository<Feedback> feedbackRepository;
    private MetaLearningContext dbcontext;

    public int screencastID { get; set; }

    public IEnumerable<Content> Screencasts { get; set; }
    public IEnumerable<Content> Podcasts { get; set; }
    public IEnumerable<Content> Documents { get; set; }
    public IEnumerable<Feedback> FeedbackComments { get; set; }
    public Content SelectedMediaItem { get; set; }
    public MetaLearningUser User { get; set; }
    public MetaLearningUser FeedbackAuthor { get; set; }
    public Feedback FeedbackComment { get; set; }

    public MediaViewModel()
    {
        this.dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
        this.contentRepository = new Repository<Content>(dbcontext);
        this.feedbackRepository = new Repository<Feedback>(dbcontext);
        this.dbcontext.Configuration.LazyLoadingEnabled = true;

        //Retrieve a list of Screencasts
        Screencasts = contentRepository
            .Get(c => c.ContentTypeID == 1);

        //Retrieve a list of Podcasts
        Podcasts = contentRepository
            .Get(c => c.ContentTypeID == 2);

        //Retrieve a list of Documents
        Documents = contentRepository
            .Get(c => c.ContentTypeID == 3);

    }

    public MediaViewModel(int id)
    {
        this.dbcontext = new MyContext(System.Configuration.ConfigurationManager.ConnectionStrings["MyContext"].ConnectionString);
        this.contentRepository = new Repository<Content>(dbcontext);
        this.feedbackRepository = new Repository<Feedback>(dbcontext);
        this.dbcontext.Configuration.LazyLoadingEnabled = true;

        //Retrieve a list of Screencasts
        Screencasts = contentRepository
            .Get(c => c.ContentTypeID == 1);

        //Retrieve a list of Podcasts
        Podcasts = contentRepository
            .Get(c => c.ContentTypeID == 2);

        //Retrieve a list of Documents
        Documents = contentRepository
            .Get(c => c.ContentTypeID == 3);                       

        //Retrieve selected screencast
        SelectedMediaItem = contentRepository
            .Get(c => c.ContentID == id)
            .FirstOrDefault();              

    }

}
役に立ちましたか?

解決

Just to add something to the answer from Mattias:

1) he's right - if you want some information where to redirect place it in a hidden field or add it as parameter to the Form-Method.

2) The pattern, which is common in MVC is PRG (Post/Redirect/Get) so essentially your POST should answer with a RedirectToAction("Screencast") instead of view. (http://en.wikipedia.org/wiki/Post/Redirect/Get)

To use this you should refactor your functions a little bit:

public ActionResult Screencast(int ID)
{                        
    mvm = new ViewModels.MediaViewModel(ID); //The id is in the viewmodel i think
    return View(mvm);
}


[HttpPost] 
//Even if unused include the formcollection for cases where the GET has the same signature
public ActionResult Screencast(int ID, MediaViewModel mvm, FormCollection collection)
{
    //Do something
    return RedirectToAction("Screencast", new { id = ID });
}

And inside your view:

@using(Html.BeginForm("Screencast", new { id = Model.SelectedMediaItem })) 
{ ... }
  • It might be that the suggested overload needs more parameters, but you will see that ...

他のヒント

This is probably because SelectedMediaItem wasn't posted along with the rest of the values in the form. So when the form is serialized to a model the SelectedMediaItem property is null. What you could do is just add this inside the posting form:

@Html.HiddenFor(c => c.SelectedMediaItem)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top