我遇到了一些通过派生控制器类调用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
时不会出现某种情况。
答案 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?
答案 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;
}