提问人:Sarov 提问时间:7/28/2023 最后编辑:Sarov 更新时间:8/4/2023 访问量:69
ModelState 在检查 null 时如何/为什么会抛出 System.NullReferenceException?
How/why does ModelState throw System.NullReferenceException when being checked for null?
问:
更新:为了避免这个问题,我尝试显式检查null,认为肯定不可能仍然抛出异常。 确实如此。 以下行引发 System.NullReferenceException:
if (ModelState == null)
如何?!
我们收到了一个自动错误报告,显示特定行抛出 NullReferenceException...但我无法弄清楚那条特定的线怎么可能做到这一点。
有问题的行是 。但。。。我那里有一个空条件运算符。它怎么会抛出 NullReferenceException?if (ModelState?.IsValid == false)
我们还没有弄清楚如何故意重现这个错误,但它时不时地发生。
这是代码(略有精简,但相关方法保持不变:)
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)
为了进一步说明该问题:
我的理解是,评估结果为 a aka a .如下面的代码片段所示,即使在 .所以。。。该行怎么可能抛出 NullReferenceException?ModelState?.IsValid
bool?
Nullable<bool>
false
null
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();
答: 暂无答案
评论
public ModelStateDictionary ModelState { get; }
if (ModelState == null)
ModelState?.IsValid
ControllerContext