我们收到了一份自动错误报告,显示特定行正在抛出 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();
正如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) {
...
}