tags:

views:

6018

answers:

3

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, IDictionary2 htmlAttributes) at System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name, Object value, IDictionary2 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:

A: 

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.

Stuart Branham
The decelerations weren't included (copy and paste error). Missing form values should be caught in GetRuleViolations()
Giovanni Galbo
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! :)
Stuart Branham
+19  A: 

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: http://stackoverflow.com/questions/646270/asp-net-mvc-custom-validation-message-for-value-types

Giovanni Galbo
Thanks for the insight!
John
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!
GalacticCowboy
This is why I love stackoverflow, I can google my exceptions, and find the solution here :) Thanks.
Zhaph - Ben Duguid
A: 

Thank you very much....

Same problem with my code...

Its really works thank man

Anil Desai