views:

594

answers:

3

Hello,

I am new to MVC, and so am working through the NerdDinner tutorial, here. In particular, I'm running into problems with the use of the UpdateModel method, which is explained in the part five of that tutorial. The problem is, when I try to edit the value of a dinner object using the UpdateModel method, the values do not get updated, and no exceptions are thrown.

Oddly, I am not having any trouble with the Create or Delete features that are illustrated in the tutorial. Only the update feature isn't working.

Below, I have included the Controller code that I am using, as well as the view markup, which is contained in both an aspx View file and an ascx Partial View file.

Here is the code inside my Controller, called DinnerController.cs:

    //
    // GET: /Dinners/Edit/2
    [Authorize]
    public ActionResult Edit(int id)
    {

        Dinner dinner = dinnerRepository.GetDinner(id);

        return View(new DinnerFormViewModel(dinner)); 
    }

    //
    // POST: /Dinners/Edit/2
    [AcceptVerbs(HttpVerbs.Post), Authorize]
    public ActionResult Edit(int id, FormCollection formValues)
    {

        Dinner dinner = dinnerRepository.GetDinner(id);

        try
        {
            UpdateModel(dinner);
            var x = ViewData.GetModelStateErrors(); // <-- to catch other ModelState errors

            dinnerRepository.Save();

            return RedirectToAction("Details", new { id = dinner.DinnerID });
        }
        catch
        {

            ModelState.AddRuleViolations(dinner.GetRuleViolations());

            return View(new DinnerFormViewModel(dinner)); 
        }
    }

The line with the comment "to catch other ModelState errors" was added after reading a possible solution from another StackOverflow thread, here:

http://stackoverflow.com/questions/1461283/asp-net-mvc-updatemodel-not-updating-but-not-throwing-error

Unfortunately, that solution didn't help me.

Here is the corresponding markup in my Dinners/Edit.aspx View:

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Edit Dinner</h2>

    <% Html.RenderPartial("DinnerForm"); %>

</asp:Content>

Here is the corresponding markup in my DinnerForm.ascx Partial View. This Partial View file is also used by the Create feature, which is working fine:

<%=Html.ValidationSummary("Please correct the errors and try again.") %>  

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

    <fieldset>
        <p>
            <label for="Title">Dinner Title:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.Title)%>
            <%=Html.ValidationMessage("Title", "*") %>
        </p>
        <p>
            <label for="EventDate">EventDate:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.EventDate, new { value = String.Format("{0:g}", Model.Dinner.EventDate) })%>
            <%=Html.ValidationMessage("EventDate", "*") %>
        </p>
        <p>
            <label for="Description">Description:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.Description)%>
            <%=Html.ValidationMessage("Description", "*")%>
        </p>
        <p>
            <label for="Address">Address:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.Address)%>
            <%=Html.ValidationMessage("Address", "*") %>
        </p>
        <p>
            <label for="Country">Country:</label>
            <%=Html.DropDownListFor(model => Model.Dinner.Country, Model.Countries)%>
            <%=Html.ValidationMessage("Country", "*") %>
        </p>
        <p>
            <label for="ContactPhone">ContactPhone #:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.ContactPhone)%>
            <%=Html.ValidationMessage("ContactPhone", "*") %>
        </p>
        <p>
            <label for="Latitude">Latitude:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.Latitude)%>
            <%=Html.ValidationMessage("Latitude", "*") %>
        </p>
        <p>
            <label for="Longitude">Longitude:</label>
            <%=Html.TextBoxFor(model => Model.Dinner.Longitude)%>
            <%=Html.ValidationMessage("Longitude", "*") %>
        </p>
        <p>
            <input type="submit" value="Save"/>
        </p>
    </fieldset>

<% } %>

In any case, I've been hitting away at this for hours, and I'm out of ideas. So, I'm hoping someone here can help nudge me in the right direction, in order to figure out what I'm doing wrong.

+2  A: 

dinnerRepository.Save() is the code the actually updates the database. What UpdateModel(dinner) does is extract the values from the form collection and put them in your dinner object.

Keltex
Thank you for your response. You are correct regarding the intearction between the dinnerRepository.Save() method and the UpdateModel(dinner) method. I knew that, I just didn't know it well enough to clarify that distinction in my post above :)
campbelt
+1  A: 

You got something mixed up. You are sending DinnerFormViewModel to View but trying to receive Dinner.Change your post method like this:

[AcceptVerbs(HttpVerbs.Post), Authorize]
    public ActionResult Edit(int id, FormCollection formValues)
    {

        var dinner=new DinnerFormViewModel(dinnerRepository.GetDinner(id));

        try
        {
            UpdateModel(dinner);
            var x = ViewData.GetModelStateErrors(); // <-- to catch other ModelState errors

            dinnerRepository.Save();

            return RedirectToAction("Details", new { id = dinner.Dinner.DinnerID });
        }
        catch
        {

            ModelState.AddRuleViolations(dinner.GetRuleViolations());

            return View(new DinnerFormViewModel(dinner)); 
        }
    }

There may be something I missed here, don't remember DinnerFormViewModel right now. Please check those

edit: Actually I realized this post doesn't solve the problem really. The code posted in the question works for me. There is a problem but but not here.

Ufuk Hacıoğulları
You're right, it does have something to do with my use of the DinnerFormViewModel class. I verified this by getting rid of the use of that class and just using the Model.Dinner object instead. When I rolled the code back in this way, the update worked fine. I would really like to use the ViewModel here though, so I wish I knew what about my use of it was wrong. Do you happen to have any more insight into how I could have implemented it better? Or, do you have thoughts as to how I might have been misusing it?
campbelt
I am not sure. I think something is wrong with what's strongly typed with views. What is strongly typed with partial view, Edit view and Create view?
Ufuk Hacıoğulları
The only thing that is strongly typed in the Partial View, I think, is the Model, which was a DinnerFormViewModel object, and is now a Dinner object. In any case, thanks again for your help. If I stumble upon more information regarding this, I'll pop back in and update this thread with more details. Thanks!
campbelt
+1  A: 

Just in case it helps someone else in the future, the problem here was not necessarily due to the use of a DinnerFormViewModel, as I suspected. Rather, the problem was with the use of strongly-typed helper methods, such as Html.TextBoxFor and the way I was invoking the UpdateModel method.

This problem and it's solution is explained in detail in another thread in StackOverflow, here.

campbelt