调用 Controller.Execute 时的 NullReferenceException
本文关键字:NullReferenceException 时的 Execute Controller 调用 | 更新日期: 2023-09-27 18:31:37
我遇到了一些通过派生控制器类调用Controller.Execute
的代码。派生类 ErrorController
不会重写Execute
,传入的 RequestContext
参数不为 null,尽管它的几个属性是 null。如何确定RequestContext
的哪个部分是导致"执行"抛出NullReferenceException
的问题?
以下是调用Execute
的代码:
public class AuthenticationManager : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
try
{
throw new Exception();
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
{
signInClient.TransformClaimsBasedOnUserRole(incomingPrincipal.Identity.AsClaimsBasedIdentitiy());
}
return base.Authenticate(resourceName, incomingPrincipal);
}
catch (Exception e)
{
var context = HttpContext.Current;
var routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Index");
routeData.Values.Add("errorId", logId);
routeData.Values.Add("exceptionMessage", "");
IController controller = new ErrorController();
var ctx = new RequestContext(new HttpContextWrapper(context), routeData);
controller.Execute(ctx);
}
}
}
我不得不溜进投掷中以重现Execute
例外。其他身份验证代码仅在极少数情况下抛出。
根据要求:
public class ErrorController: Controller
{
public ActionResult Index(Guid? errorId, string exceptionMessage)
{
ErrorModel resultModel;
try
{
resultModel = new ErrorModel
{
ErrorId = errorId==null ? Guid.NewGuid() : Guid.Parse(errorId.ToString()) ,
ErrorMessage = (string.IsNullOrEmpty(exceptionMessage)) ? ConfigurationManager.AppSettings["GenericError"] : exceptionMessage,
};
if (User.IsInRole(RoleIdentifiers.InActive))
{
Authentication.AuthenticationManager.SignOut();
}
}
catch (Exception e)
{
LogProvider.Current.LogError(LogLevel.Fatal, e, "Error constructing error result model for error Id [{0}]", errorId);
return new HttpNotFoundResult();
}
return View(resultModel);
}
public ActionResult SessionTimeOut(string rtnController = "Home", string rtnAction="Index")
{
return View(new SessionTimeOutViewModel { RedirectAction = rtnAction, RedirectController = rtnController });
}
public ActionResult LogonAgain()
{
return null;
}
}
而且,期待已久的堆栈跟踪:
at System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext)
at System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext)
at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)
at MyCompany.Authentication.AuthenticationManager.Authenticate(String resourceName, ClaimsPrincipal incomingPrincipal) in c:'Development'Give4GoodGallery'ThreeFifteen.Plexus.Web'Authentication'AuthenticationManager.cs:line 63
仔细观察,我发现这看起来像是关于AuthorizeAttribute
的 - 这可能会重述直接调用Execute
时不存在的某种上下文。
查看堆栈跟踪可以看出异常是在AuthorizeAttribute.AuthorizeCore
中抛出的。这是一个简单的方法,它将访问HttpContextBase
的 User
属性以及此用户属性的 Identity
属性。据我所知,这些属性之一必须为 null 才能抛出NullReferenceException
。
最有可能的是,HttpContext.Current
的 User
属性为空。这似乎并不奇怪,因为您正在调用AuthenticationManager
中的ErrorController
,我认为这是身份验证过程的一部分。在此过程完成之前,用户是未知的。
因此,您可以通过确保在调用ErrorController
之前已知用户来解决您的问题,但真正的问题是为什么您需要ErrorController
授权?最好的解决方案可能是确保ErrorController
不需要授权。这将允许您在授权之前或期间发生错误时调用控制器。
您是否正在尝试从正在运行的应用程序调用此方法?还是从单元测试或除 MVC 运行时之外的任何其他内容 asp.net?如果第一个是真的,那么我能想到的没有什么可能导致 NRE 的,但如果第二个是真的,那么请确保 User 属性是具有值的提供者。
HttpContextBase GetContext(string userName)
{
var user = new GenericPrincipal(new GenericIdentity(userName, "Forms"), new string[] {});
var contextMock = new Mock<HttpContextBase>();
contextMock.Setup(context => context.User).Returns(user);
contextMock.Setup.....
return contextMock.Object;
}
我能够毫无例外地执行您的代码,尽管您情况下的确切情况可能会有所不同。
我不确定,如果你已经这样做了,如果你在Visual Studio中这样做,那么:
1)包装代码:controller.Execute(ctx);
尝试...catch 块,以便您应该能够看到异常详细信息。您可以单击异常窗口底部的"查看详细信息",以便您可以在新窗口中查看完整的异常详细信息,例如InnerException,StackTrace等。它们可能会帮助您缩小例外范围。
2)在ErrorController的索引操作中放置一个断点,以便您可以通过按"F10"逐行执行检查:是否首先调用了ErrorController,并检查是否有任何代码抛出异常。
但是,您可以交叉检查的基本领域是:
1) "索引"操作中的代码 [您通过以下方式设置:
routeData.Values.Add("action", "Index");
] 可能有一些可能正在抛出的未初始化对象。
2) 您从错误控制器的索引操作返回的视图存在于正确的视图文件夹中。
3) 如果错误视图按预期存在,则在视图中检查它是否未引用任何未初始化的对象。
如何确定请求上下文的哪个部分是问题所在 使"执行"抛出空引用异常?
- 在执行调用线路上放置断点
- 在Visual Studio中启用异常自动中断(调试 ->异常... ->公共语言运行时异常 ->系统 -> System.NullReferenceException ->"选中抛出的复选框")
- 按 F5 继续执行程序并等待引发异常
- 获取异常的堆栈跟踪或打开调用堆栈窗口(调试 -> 窗口 ->调用堆栈)
- 从最顶层的调用中,您必须隔离未初始化的变量,您尝试对其执行操作。为此,您可以使用"自动"窗口("调试"-> 窗口>"自动")或"监视"窗口("调试"->"窗口"->"监视")来检查当前变量的内容(尽管不是lambdas)并查找哪个变量为空。