1

Upon POST of an ActionController I am receiving the great ole' object reference not set to an instance of an object error.

Basically I need the ID of the userRequest to be saved WITH the requestResponse. (Foreign Key here)

Here is the code.

ViewModel:

public class RequestResponseViewModel
{
    public Models.Request userRequest { get; set; }

    public Models.RequestResponse requestResponse { get; set; }

}

View: In debug here there is value in model.userRequest.ID

    @model UserRequests.ViewModels.RequestResponseViewModel

  @{
    ViewBag.Title = "Create";
  }

  <h2>Admin Response to Request</h2>

  @using (Html.BeginForm())
  {
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.requestResponse.Response, 
  htmlAttributes: new { @class = "control-label col-md-1" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => model.requestResponse.Response, new { 
  @class = "form-control", @rows = 5 })
                @Html.ValidationMessageFor(model => 
  model.requestResponse.Response, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
              @Html.LabelFor(model => model.userRequest.ID, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-2">

                @Html.DisplayFor(model => model.userRequest.ID)             
                @Html.ValidationMessageFor(model => model.userRequest.ID, "", new { @class = "text-danger" })
            </div>
            @Html.LabelFor(model => model.requestResponse.Author, htmlAttributes: new { @class = "control-label col-md-1" })
            <div class="col-md-3">
                @Html.EditorFor(model => model.requestResponse.Author, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.requestResponse.Author, "", new { @class = "text-danger" })
            </div>
            @Html.LabelFor(model => model.requestResponse.CreateDate, htmlAttributes: new { @class = "control-label col-md-1" })
            <div class="col-md-3">
                <h5>@DateTime.Now</h5>
                @Html.ValidationMessageFor(model => model.requestResponse.CreateDate, "", new { @class = "text-danger" })
            </div>
        </div>



        <div class="form-group">
            <div class="col-md-offset-1">
                <button type="reset" class="btn btn-default">Cancel</button>
                <input type="submit" value="Create" class="btn btn-success" />
            </div>
        </div>
    </div>

    <hr />
    <h3 class="text-success">Original Request</h3>
    <div class="row">
        <div class="col-md-10">
          <h4>@Html.DisplayFor(model => model.userRequest.Title)</h4>
        </div>
    </div>

    <div class="row">
        <div class="col-md-10">
            <h4>@Html.DisplayFor(model => model.userRequest.Description)</h4>
        </div>
    </div>

    }

    <div>
      @Html.ActionLink("Back to Browse", "Browse","Change")
    </div>

Get ActionResult:

public ActionResult Create(int id)
    {


        UserRequestContextDataContext db = new UserRequestContextDataContext();
        var request = (from m in db.Requests
                       where m.ID == id
                       select new Models.Request()
                       {

                           ID = m.ID,
                           Title = m.Title,
                           Description = m.Description,
                           BusinessUnit = m.BusinessUnit,
                           Author = m.Author,
                           ModuleName = m.MenuItem,
                           RequestStatus = 2,
                           SubmitDate = m.SubmitDate,
                           Type = m.Type,
                           UrgencyNum = m.UrgencyLevel


                       }).FirstOrDefault();

        var reqResponse = new Models.RequestResponse();


        var viewModel = new RequestResponseViewModel
        {
            userRequest = request,
            requestResponse = reqResponse

        };

        return View(viewModel);
    }

The "viewModel" here has everything I need. It's lost somewhere between the ActionResults..

And Finally the Post ActionResult:

 [HttpPost]
    public ActionResult Create(RequestResponseViewModel _requestResponseViewModel) 
    {
        try
        {

            if (ModelState.IsValid)
            {
                using (UserRequestContextDataContext db = new UserRequestContextDataContext())
                {

                    RequestResponse reqRes = new RequestResponse();
                    reqRes.Response = _requestResponseViewModel.requestResponse.Response.ToString();

                    reqRes.RequestID = _requestResponseViewModel.userRequest.ID;
                    reqRes.Author = _requestResponseViewModel.requestResponse.Author.ToString();
                    reqRes.CreateDate = DateTime.Now;

                    db.RequestResponses.InsertOnSubmit(reqRes);
                    db.SubmitChanges();
                }
            }

            return RedirectToAction("Browse","Change");
        }
        catch (Exception ex)
        {

            return View("Error", new HandleErrorInfo(ex, "Change", "Create"));
        }
    }

Using debug mode the userRequest object is NULL in the view model parameter of the POST method but requestResponse is FINE and populated as should.

Searching on this, it seemed most had issues with the naming convention in the view model but I've made sure there are no discrepancies there.

If there is a more clear way to do this workflow please mention.

1
  • Can you post the stack trace of the error.. Commented Aug 25, 2017 at 22:26

2 Answers 2

3

@Html.DisplayFor does not create an HTML input element, but a simple string literal (for most types, some exceptions are listed in the docs: https://msdn.microsoft.com/en-us/library/ee407420(v=vs.118).aspx#Anchor_1). So when you press submit, your browser will not send the ID back to the server because it sends only form data (e.g. data from input, textare, select fields). Using your browsers developer tools (F12) you can examine what is actually send to the server.

You can add a hidden input field using @Html.HiddenFor(model => model.userRequest.ID) or use a custom display template for the ID to automatically add a hidden input field. You could further use UIHint attributes to automatically select a display template. Both approaches are thoroughly documented (e.g. http://www.codeguru.com/csharp/.net/net_asp/mvc/using-display-templates-and-editor-templates-in-asp.net-mvc.htm).

Sign up to request clarification or add additional context in comments.

1 Comment

Great answer, clear explanation and links to further info. Adding the HiddenFor worked fine. I noticed I must match hiddenFor() fields with the GET method fields I retrieve in my controller or my model state is no longer valid.
2

Another reason the object could be NULL in the POST is due to forgetting to add the setters { get; set; } in your view model:

public Orders orders; --> missing { get; set; }

public class OrderViewModel
{
    public Orders orders { get; set; }

    public List<VendorJobTitleView> Jobs { get; set; }

    public List<ManagerView> Managers { get; set; }


}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.