调用Controller.Execute时出现NullReferenceException

时间:2014-11-24 11:04:10

标签: c# .net asp.net-mvc asp.net-mvc-4 nullreferenceexception

我遇到了一些通过派生控制器类调用Controller.Execute的代码。虽然派生类ErrorController不会覆盖Execute,但传入的RequestContext参数不是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时不会出现某种情况。

4 个答案:

答案 0 :(得分:1)

我可以毫无例外地执行您的代码,但您案例中的确切方案可能会有所不同。

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

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

2)在ErrorController的Index操作中放置一个断点,以便你可以通过点击'F10'来逐行检查:如果首先调用ErrorController,还要检查,如果有的话抛出异常的代码

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

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

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

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

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

答案 1 :(得分:1)

  

如何确定RequestContext的哪个部分是问题所在   使'Execute'抛出NullReferenceException?

  • 在执行调用行
  • 上设置断点
  • 在visual studio中启用异常自动中断(Debug - > Exceptions ... - > Common Language Runtime Exceptions - > System - > System.NullReferenceException - >'check the thrown checkbox')
  • 按F5继续执行程序并等待异常提升
  • 获取异常的堆栈strace或打开调用堆栈窗口(Debug - > Windows - > Call stack)
  • 从最上面的调用中,您必须隔离未尝试执行操作的未初始化的变量。要执行此操作,您可以使用“自动”窗口(“调试” - >“Windows - >”>“自动”)或“监视”窗口(调试 - >> Windows - >监视)来检查当前变量的内容(不是lambdas)并查找哪一个是空的。

答案 2 :(得分:1)

查看堆栈跟踪,可以看出AuthorizeAttribute.AuthorizeCore中引发了异常。这是一个访问User的{​​{1}}属性以及此用户属性的HttpContextBase属性的简单方法。据我所知,其中一个属性必须为null才能抛出Identity

NullReferenceException的{​​{1}}属性很可能为null。这似乎并不令人惊讶,因为您在User中调用HttpContext.Current,我认为这是身份验证过程的一部分。在此过程完成之前,用户不知道。

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

答案 3 :(得分:1)

你是否试图从正在运行的应用程序中调用此方法?或者从单元测试或除了asp.net mvc运行时之外的任何其他东西? 如果第一个是真的,那么我认为没有什么可以导致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;
}