尽管条件运算符为空,ModelState 如何/为何抛出 System.NullReferenceException?

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

我们收到了一份自动错误报告,显示特定行正在抛出 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
1个回答
0
投票

正如MSDOC所说:

如果

a
计算结果为
null
,则为
a?.x
a?[x] is null
的结果。

因此,当

if
null == false
时,您的
ModelState
语句将评估为
null
,这就是您收到错误的原因。 null 合并运算符
??
可能会对您有所帮助。另外,由于您要比较布尔值,因此可以使用
!value
而不是
value == false

假设

null
ModelState
应被视为无效,以下内容应该适合您:

if(!(ModelState?.isValid ?? false)) {
  ...
}

或者,您可以自己进行空检查,而不使用花哨的运算符,在这种情况下,我个人认为更容易阅读。

if(ModelState == null || !ModelState.isValid) {
  ...
}
© www.soinside.com 2019 - 2024. All rights reserved.