14

I've encountered a strange issue....when I use UpdateModel() or TryUpdateModel(), everything works fine. When I try binding myself (e.g. MyObject.FirstName = collection["FirstName"]), I get a "Object reference not set to an instance of an object" error.

It's a little hard to explain, so I'll present the code:

    [HandleError]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(FormCollection collection)
    {
        try
        {
            Model.Event evnt = new Redline.RedlineTimeAttack.Model.Event();

            //When this is uncommented everything works fine.
            //TryUpdateModel<Model.Event>(evnt);

            //this will eventually lead to problems
            evnt.Description = collection["Description"];
            evnt.EndDate = enddate;
            evnt.EventName = collection["EventName"];
            evnt.IsActive = collection["IsActive"].Contains("true");
            evnt.StartDate = startdate;
            evnt.TrackId = trackId;
            evnt.WebContent = collection["WebContent"];


            if (!evnt.IsValid)
            {
              foreach (var error in evnt.GetRuleViolations())
              {
                ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
              } 
            }

            //If there are no validation issues then no problem, redirecttoaction
            //works properly
            if (ModelState.IsValid)
            {
                model.Events.InsertOnSubmit(evnt);
                model.SubmitChanges();
                ViewData["ControlMode"] = "Edit";
                return RedirectToAction("Edit");
            }
            else //returning to View so that user can correct issues causes a null reference error in the view (bombs at first Html.Textbox("ControlName"))
            {
                ViewData["Tracks"] = GetTracks();
                return View("Create", evnt);
            }
        }

Here's the stack trace:

System.NullReferenceException was unhandled by user code
Message="Object reference not set to an instance of an object."
Source="System.Web.Mvc"
StackTrace:
   at System.Web.Mvc.HtmlHelper.GetModelStateValue(String key, Type destinationType)
   at System.Web.Mvc.Html.InputExtensions.InputHelper(HtmlHelper htmlHelper, InputType inputType, String name, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, IDictionary`2 htmlAttributes)
   at System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name, Object value, IDictionary`2 htmlAttributes)
   at System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name)
   at ASP.views_event_create_aspx.__RenderContent2(HtmlTextWriter __w, Control parameterContainer) in d:\TFSProjects\Redline Time Attack\Main\Source\Redline.RedlineTimeAttack.Web\Views\Event\Create.aspx:line 18
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.Control.Render(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
   at ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in d:\TFSProjects\Redline Time Attack\Main\Source\Redline.RedlineTimeAttack.Web\Views\Shared\Site.Master:line 29
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.Control.Render(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.Page.Render(HtmlTextWriter writer)
   at System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
InnerException: 

2 Answers 2

22

I found some insight here: http://forums.asp.net/p/1396019/3006051.aspx

If you don't want to use Builtin Model Binding, then to use Bultin Validation (SanjaySutar want to use), for every ModelError you add, you will need to add a ModelValue: ModelState.AddModelError("Name", "Bad Name");

ModelState.SetModelValue("Name", ValueProvider["Name"]);

So I updated my code like so:

ModelState.SetModelValue("Description", new ValueProviderResult(ValueProvider["Description"].AttemptedValue, collection["Description"], System.Globalization.CultureInfo.CurrentCulture));
ModelState.SetModelValue("EventName", new ValueProviderResult(ValueProvider["EventName"].AttemptedValue, collection["EventName"], System.Globalization.CultureInfo.CurrentCulture));
ModelState.SetModelValue("EndDate", new ValueProviderResult(ValueProvider["EndDate"].AttemptedValue, collection["EndDate"], System.Globalization.CultureInfo.CurrentCulture));
ModelState.SetModelValue("StartDate", new ValueProviderResult(ValueProvider["StartDate"].AttemptedValue, collection["StartDate"], System.Globalization.CultureInfo.CurrentCulture));
ModelState.SetModelValue("TrackId", new ValueProviderResult(ValueProvider["TrackId"].AttemptedValue, collection["TrackId"], System.Globalization.CultureInfo.CurrentCulture));
ModelState.SetModelValue("WebContent", new ValueProviderResult(ValueProvider["WebContent"].AttemptedValue, collection["WebContent"], System.Globalization.CultureInfo.CurrentCulture));

The reason I am doing this is because I wanted to a. have all (or as much as possible) validation done in my Business Object, including required fields, and b. I wanted my own messages in the validation summary (e.g. "FieldX is a required field." instead of "A value is required."). If there's a better way to do this, please see my other question: ASP.NET MVC - Custom validation message for value types

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

2 Comments

I encountered this on a form where I was combining two fields together and validating the result, but wanted to report the errors on the individual (source) fields... Thanks - saved me a bruised forehead!
This is why I love stackoverflow, I can google my exceptions, and find the solution here :) Thanks.
0

Where is enddate, startdate, and trackId coming from? This shouldn't even compile, but maybe I am just dumb and not seeing their declarations. I'm sure it's just somewhere out of sight, right?

Make sure all of those form values actually have stuff in them as well.

2 Comments

The decelerations weren't included (copy and paste error). Missing form values should be caught in GetRuleViolations()
I was mainly thinking about the evnt.IsActive = collection["IsActive"].Contains("true"); line. If collection["IsActive"] is null you would get that error because of trying to call a function on a null object. Glad to see you made progress, though! :)

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.