ModelState 在检查 null 时如何/为何抛出 System.NullReferenceException?

问题描述 投票:0回答:0

更新:为了避免这个问题,我尝试显式检查 null,认为肯定不可能仍然抛出异常。 确实如此。 以下行抛出 System.NullReferenceException:

if (ModelState == null)

如何?!


我们收到了一份自动错误报告,显示特定行正在抛出 NullReferenceException...但我无法弄清楚如何该特定行可能会这样做。

有问题的线路是

if (ModelState?.IsValid == false)
。但是...我那里有一个空条件运算符。它怎么会抛出 NullReferenceException?

我们无法弄清楚如何故意重现该错误,但它时不时地发生。

这是代码(稍微精简,但相关方法保持不变:)

using AutoMapper;
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;

namespace MyApp.Web.Controllers
{
    public class ServiceCallController : Controller
    {
        [NotNull] private readonly IMapper _mapper;
        [NotNull] private readonly IServiceCallService _service;

        public ServiceCallController([NotNull] IMapper mapper, [NotNull] IServiceCallService service)
        {
            _mapper = mapper;
            _service = service;
        }

        [HttpPost]
        public ActionResult Index(ServiceCallViewModel vm)
        {
            if (ModelState?.IsValid == false)//This line throws "System.NullReferenceException: Object reference not set to an instance of an object."
            {
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                Response.TrySkipIisCustomErrors = true;
                return Json(new { message = string.Join("<br/>", ModelState.GetErrorList()) });
            }

            try
            {
                vm.Attachments.RemoveAll(a => a == null);
                var serviceCall = _mapper.Map<ServiceCallDto>(vm);
                _service.SubmitServiceCall(serviceCall);
                return Json(new { url = Url.Action("CallSearch", "Search") });
            }
            catch (Exception ex)
            {
                Response.StatusCode = (int)HttpStatusCode.BadRequest;
                Response.TrySkipIisCustomErrors = true;
                return Json(new { message = ex.Message });
            }
        }
    }

    public class ServiceCallDto
    {
        // ...bunch of properties...
    }

    public class ServiceCallViewModel
    {
        public List<HttpPostedFileBase> Attachments { get; set; }
        // ...bunch of properties...
    }

    public interface IServiceCallService
    {
        void SubmitServiceCall(ServiceCallDto serviceCall);
    }

    public static class ModelStateExtensions
    {
        public static List<string> GetErrorList([NotNull] this ModelStateDictionary modelState) =>
            (from item in modelState.Values
             from error in item.Errors
             select error.ErrorMessage).ToList();
    }
}

这是我们收到的自动错误电子邮件:

User Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1
System.NullReferenceException: Object reference not set to an instance of an object.
   at MyApp.Web.Controllers.ServiceCallController.Index(ServiceCallViewModel vm) in C:\Atlassian\bamboo-home\local-working-dir\CMF-MyApp-JOB1\Web\Controllers\ServiceCallController.cs:line 26
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c.<BeginInvokeSynchronousActionMethod>b__9_0(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_0.<InvokeActionMethodFilterAsynchronouslyRecursive>b__0()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass11_2.<InvokeActionMethodFilterAsynchronouslyRecursive>b__2()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_6.<BeginInvokeAction>b__4()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3_1.<BeginInvokeAction>b__1(IAsyncResult asyncResult)

进一步说明问题:

我的理解是

ModelState?.IsValid
评估为
bool?
又名
Nullable<bool>
。正如下面的代码片段所示,哪个 c# 能够与
false
进行比较,即使在
null
时也是如此。那么...该行怎么可能抛出 NullReferenceException?

ModelStateDictionary nullState = null;
if (nullState?.IsValid == false)//Unlike what's happening in the real code in the wild, this line does NOT throw an error.
    System.Diagnostics.Debugger.Break();
else if (nullState?.IsValid == true)
    System.Diagnostics.Debugger.Break();
else if (nullState?.IsValid == null)
    System.Diagnostics.Debugger.Break();//The debugger stops on this line.
else
    System.Diagnostics.Debugger.Break();
c# nullreferenceexception modelstate
© www.soinside.com 2019 - 2024. All rights reserved.