0

Can someone explain why the model object is null. I checked the post values coming across the wire and all of them are populated.

Using VS2010 Beta 2,WinXp SP2,however this works in VS2008 ??!!

Yellow screen of death message

Server Error in '/' Application. Object reference not set to an instance of an object. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error:

Line 17:             <p>
Line 18:                 <label for="id">id:</label>
Line 19:                 <%= Html.TextBox("id", Model.id) %> <--Error 
Line 20:                 <%= Html.ValidationMessage("id", "*") %>
Line 21:             </p>

Controller Code

 [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Contact contactToEdit)
    {
        if (contactToEdit.FirstName.Trim().Length == 0)
            ModelState.AddModelError("FirstName", "First name is required.");
        if (contactToEdit.Lastname.Trim().Length == 0)
            ModelState.AddModelError("LastName", "Last name is required.");
        if (contactToEdit.Phone.Length > 0 && !Regex.IsMatch(contactToEdit.Phone, @"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
            ModelState.AddModelError("Phone", "Invalid phone number.");
        if (contactToEdit.Email.Length > 0 && !Regex.IsMatch(contactToEdit.Email, @"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
            ModelState.AddModelError("Email", "Invalid email address.");

        if (!ModelState.IsValid)
            return View();
        try
        {
            // TODO: Add update logic here
            var con = (from c in _entities.Contacts
                       where c.id == contactToEdit.id
                       select c).FirstOrDefault();
            _entities.ApplyCurrentValues(con.EntityKey.EntitySetName, contactToEdit);
            _entities.SaveChanges();


            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

Snippet of View code

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<JQGallery.Models.Contact>" %>
...
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>

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

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="id">id:</label>
            <%= Html.TextBox("id", Model.id) %>
            <%= Html.ValidationMessage("id", "*") %>
        </p>
        <p>
            <label for="FirstName">FirstName:</label>
            <%= Html.TextBox("FirstName", Model.FirstName) %>
            <%= Html.ValidationMessage("FirstName", "*") %>
        </p>
        <p>
        ...
D0cNet
  • 314
  • 4
  • 20

2 Answers2

0

Do you have a controller action that accepts non-post verbs and sets up the model for your view? The model will be null if you navigate directly to the view without an Action method that responds to a GET request and populates the model.

For example, your regular action could be something like

//
// Reponds to:  GET /Contact/Edit/5

public ActionResult Edit(int id)
{
   Contact contactToEdit = GetContactFromDatabase(id);
   return View(contactToEdit);
}

I can't see anything wrong with the POST action, but you do need a corresponding GET action to set up the form for you.

EDIT: One other thing you might want to consider since you're using ASP.NET MVC built-in model binders is that you should probably exclude the ID (or any sensitive field that the user shouldn't logically be able to change) from being changed and actually remove it from the form (or at least make it un-editable). You can do that with an attribute on the incoming contact object, like this:

//
// Reponds to:  POST /Contact/Edit/5

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit([Bind(Exclude="id")] Contact contactToEdit)
{
    // ... do edit logic/validation stuff
}
Scott Arrington
  • 12,325
  • 3
  • 42
  • 54
0

The Model object is null because you're not setting it. In your POST controller method, neither of the View results you return is setting a model (after the if (!ModelState.IsValid) line and in your catch block). In both those cases, you need to reload your model from somewhere so the view can redisplay its data.

Mike Powell
  • 5,914
  • 4
  • 28
  • 28
  • This is not true, actually, because of Model Binding. Check here for more information: http://www.asp.net/learn/mvc/tutorial-36-cs.aspx – Scott Arrington Dec 31 '09 at 15:10
  • Model Binding instantiates and sets properties on the contactToEdit argument in the OP's Edit method using the submitted form values. It does not instantiate and populate the Model object that's available to his View. (The examples in your tutorial link work using only the View() method because that particular sample view doesn't try to access the Model object.) – Mike Powell Dec 31 '09 at 15:19
  • Actually I sent you a link to only the Create action, but the edit will work in the same way: http://www.asp.net/%28S%28pdfrohu0ajmwt445fanvj2r3%29%29/learn/mvc/tutorial-28-cs.aspx -- The idea is that since the model was POST'ed to the Action, model binding will push it back down to the browser when the action simply returns back to the view. – Scott Arrington Dec 31 '09 at 15:42
  • I think that sample code is wrong. Here's a similar question: http://stackoverflow.com/questions/1226060/asp-net-mvc-adding-validation-causes-model-to-be-null. If you use the View() method with no args to return the ActionResult, you get a null Model, period. You *can* use model binding to populate your model if you want (see NerdDinner code here http://stackoverflow.com/questions/881281/what-is-modelstate-isvalid-valid-for-in-asp-net-mvc-in-nerddinner), but you still need to pass your automatically-bound model object back to the view using the View(modelObject) overload. – Mike Powell Dec 31 '09 at 15:58
  • Seems you're right on this one. I just tried it with a sample project. i wish I could take back the -1 but it won't let me :P Kudos to you on that one. The samples I linked are obviously incorrect unless something changed in ASP.NET MVC 2. – Scott Arrington Dec 31 '09 at 16:32
  • I think if you click the down arrow again it will undo your downvote. – Mike Powell Dec 31 '09 at 16:51
  • OK It works when i pass back the model object in the view call "View(contactToEdit)" So why would it work in VS2008, some implicit parameter passing thing ?? – D0cNet Dec 31 '09 at 17:24
  • Is your View the same in VS 2008? Is the View in the VS2008 version actually accessing anything from the model? – Scott Arrington Dec 31 '09 at 17:56