ASP.NET MVC - Html.Textbox() 抛出“对象引用未设置为对象的实例”异常。

14

我遇到一个奇怪的问题……当我使用 UpdateModel()TryUpdateModel() 时,一切正常。但是当我尝试手动绑定(例如 MyObject.FirstName = collection["FirstName"])时,我会收到 "Object reference not set to an instance of an object" 错误。

这有点难以解释,所以我来给你展示代码:

    [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);
            }
        }

这是堆栈跟踪:

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个回答

22

我在这里找到了一些见解:http://forums.asp.net/p/1396019/3006051.aspx

如果您不想使用内置的模型绑定,但是想使用内置的验证(像 SanjaySutar 想要的那样),那么对于每个您添加的 ModelError,都需要添加一个 ModelValue: ModelState.AddModelError("Name", "Bad Name");

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

所以我更新了我的代码如下:

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));
我这样做的原因是:a.我希望尽可能多地在我的业务对象中进行验证,包括必填字段;b.我想在验证摘要中使用自己的消息(例如,“FieldX是必填字段”,而不是“需要一个值”)。如果有更好的方法,请参见我的另一个问题:ASP.NET MVC - Custom validation message for value types

我在一个表单上遇到了这个问题,我需要将两个字段组合在一起并验证结果,但是想要在各自的(源)字段上报告错误...谢谢 - 让我免去了撞头的痛苦! - GalacticCowboy
4
这就是为什么我喜欢使用 StackOverflow,我可以通过 Google 搜索我的异常信息,并在这里找到解决方案 :) 谢谢。 - Zhaph - Ben Duguid

0

enddate、startdate和trackId是从哪里来的?这甚至不应该编译,但也许我只是愚蠢,没有看到它们的声明。我相信它们只是藏在某个地方,对吧?

确保所有这些表单值实际上都有内容。


声明没有被包含(复制粘贴错误)。在GetRuleViolations()中应该捕获缺少的表单值。 - Giovanni Galbo
我主要考虑的是 evnt.IsActive = collection["IsActive"].Contains("true"); 这一行。如果 collection["IsActive"] 为空,你会因为试图在空对象上调用函数而得到错误提示。不过看到你已经有所进展,真是太好了! :) - Samantha Branham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接