调用 Controller.Execute 时出现 NullReferenceException

NullReferenceException when calling Controller.Execute

提问人:ProfK 提问时间:11/24/2014 最后编辑:ProfK 更新时间:12/5/2014 访问量:1965

问:

我遇到了一些通过派生控制器类调用的代码。但是,派生类不会重写,并且传入的参数不是 null,尽管它的几个属性是 null。如何确定问题的哪一部分是导致“执行”抛出的问题?Controller.ExecuteErrorControllerExecuteRequestContextRequestContextNullReferenceException

下面是调用的代码: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

仔细观察,我发现这看起来是关于 - 当直接调用时,可能会出现某种不存在的上下文。AuthorizeAttributeExecute

C# asp.net-mvc-4 nullreferenceexception

评论

3赞 Jason Evans 11/28/2014
是否有与异常关联的堆栈跟踪?这将告诉 NRE 在代码中的哪个位置被提出。
1赞 ProfK 11/28/2014
我没有堆栈跟踪,并且 的实现应该无关紧要,因为异常是由基类引发的,而不是由 .ErrorControllerControllerErrorController
6赞 Jason Evans 11/28/2014
堆栈跟踪非常重要。堆栈跟踪中的信息将准确指向代码中抛出 NRE 的位置。我看过.该方法正在被 使用,并且有很多地方可以抛出 NRE。获取堆栈跟踪将有很大帮助。IController.Execute()dotPeekControllerBase
1赞 Faris Zacina 11/28/2014
完全。堆栈跟踪始终很重要。它可以将问题缩小到更具体的事情。没有它,我们只是在黑暗中拍摄。
1赞 Siva Gopal 11/28/2014
@ProfK:你能把试试吗?如果您在抛出的异常对象中看到任何 InnerException/StackTrace 对象,请抓住抛出代码并发布错误?您可以在跟踪中替换任何机密对象名称等,以找到有意义的内容。

答:

1赞 Siva Gopal 11/28/2014 #1

我能够毫无例外地执行您的代码,尽管您的具体情况可能会有所不同。

我不确定,如果你已经这样做了,如果你在Visual Studio中这样做了,那么:

1) 包装代码:在尝试中...catch 块,以便您应该能够看到异常详细信息。您可以单击异常窗口底部的“查看详细信息”,以便在新窗口中查看完整的异常详细信息,如 InnerException、StackTrace 等。它们可以帮助您缩小例外范围。controller.Execute(ctx);

2)在ErrorController的Index操作中放置一个断点,以便您可以通过点击“F10”来逐行执行检查:是否首先调用了ErrorController,并检查是否有任何代码引发异常。

但是,您可以交叉检查的基本区域是:

1) “索引”操作中的代码 [您通过以下方式进行设置:

routeData.Values.Add("action", "Index");] 可能有一些未初始化的对象可能会抛出。

2)从ErrorController的Index操作返回的视图存在于正确的View文件夹中。

3)如果错误视图按预期存在,则在视图中检查它是否未引用任何未初始化的对象。

评论

0赞 ProfK 11/28/2014
根本没有达到 Index 方法。我添加了一个覆盖,并在其他任何内容运行之前抛出。Executebase.Execute()
0赞 Siva Gopal 11/28/2014
所以路线可能会有一些问题。此外,由于索引是“GET”操作,是否可以在浏览器中放置相关 url 以查看断点是否命中?
0赞 Liran 12/2/2014
1+ 对 IDE 的疑惑并指出内部异常,我认为这将回答他的问题
0赞 Siva Gopal 12/2/2014
@Liran,谢谢你,让我们看看他的情况如何。
1赞 John-Philip 12/2/2014 #2

如何确定 RequestContext 的哪一部分是问题 使“执行”抛出 NullReferenceException?

  • 在 Execute 调用行上放置断点
  • 在 Visual Studio 中启用异常时自动中断 (调试 -> 异常... -> 公共语言运行时异常 -> 系统 -> System.NullReferenceException -> '检查抛出的复选框')
  • 按 F5 继续执行程序并等待引发异常
  • 获取异常的堆栈跟踪或打开调用堆栈窗口(调试 -> Windows ->调用堆栈)
  • 从最顶层的调用中,您必须隔离您尝试对其执行操作的未初始化的变量。为此,您可以使用“自动”窗口(“调试”->“Windows”->“自动”)或“监视”窗口(“调试”-> “Windows”->“监视”)来检查当前变量(但不是 lambda)的内容,并找出哪个变量为 null。
2赞 Martin Liversage 12/4/2014 #3

查看堆栈跟踪,可以看出异常被抛出。这是一种简单的方法,它将访问 的属性以及此用户属性的属性。据我所知,这些属性之一必须为 null 才能抛出。AuthorizeAttribute.AuthorizeCoreUserHttpContextBaseIdentityNullReferenceException

最有可能的是 的属性为 null。这似乎并不奇怪,因为您正在调用我假设是身份验证过程的一部分。在此过程完成之前,用户是未知的。UserHttpContext.CurrentErrorControllerAuthenticationManager

因此,您可以通过确保在调用之前知道用户来解决您的问题,但真正的问题是为什么需要授权?最好的解决方案可能是确保这不需要授权。这将允许您在授权之前或期间发生错误时调用控制器。ErrorControllerErrorControllerErrorController

评论

0赞 ProfK 12/4/2014
谢谢@Martin。上的身份验证只是全局过滤器的结果。我一定会删除它。ErrorController
1赞 Ibrahim ben Salah 12/5/2014 #4

您是否正在尝试从正在运行的应用程序调用此方法?还是来自单元测试或除 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;
}

评论

0赞 ProfK 12/5/2014
它正在正在运行的应用程序中调用,但使用用户 - 用户尚未登录。测试提示的奖励积分 - 我也许也可以在调用代码中嘲笑用户。null