NullReferenceException when calling Controller.Execute - c#

I have run into some code that calls Controller.Execute, via a derived controller class. The derived class, ErrorController doesn't override Execute though, and the RequestContext parameter passed in is not null, although several of its properties are. How can I determine which part of RequestContext is the problem that makes 'Execute' throw NullReferenceException?
Here is the code that calls 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);
}
}
}
I had to slip in the throw to reproduce the Execute exception. The other auth code only throws on very rare occasions.
As requested:
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;
}
}
And, the much awaited stack trace:
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
On closer inspection, I see this looks to be about the AuthorizeAttribute - that might requite some sort of context not present when the Execute is directly called.

Looking at the stack trace it can be seen that the exception is thrown in AuthorizeAttribute.AuthorizeCore. This is a simple method that will access the User property of the HttpContextBase and also the Identity property of this user property. As far as I can see one of these properties must be null for the NullReferenceException to be thrown.
Most likely the User property of HttpContext.Current is null. This does not seem surprising as you are invoking the ErrorController in AuthenticationManager which I assume is part of the authentication process. Before this process is complete the user is not known.
So you could fix your problem by making sure that the user is known before invoking the ErrorController but the real question is why do you require authorization on ErrorController? The best solution is probably to make sure that ErrorController does not require authorization. This will allow you to invoke the controller also when errors occur before or during authorization.

Are u trying to call this method from a running application? or from a unit test or anything else besides asp.net mvc runtime?
if the first is true than here is nothing I can think of that could cause the NRE, but if the second is true then make sure User property is provider with value.
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;
}

I am able to execute your code without any exception though the exact scenario in your case could be different.
I am not sure, if you did it already, and if you are doing this in Visual Studio then:
1) Wrap the code: controller.Execute(ctx); in a try...catch block so that you should be able to see the exception detail. You can click the "View Detail" at the bottom of exception window so that you can see complete exception details like InnerException,StackTrace etc., within a new window. They may help you to narrow down on the exception.
2) Put a break-point in Index action of ErrorController so that you can step line-by-line by hitting 'F10' to check: If the ErrorController is called or not in first place and also to check, if any of that code throwing exception.
However the basic areas you can cross check are:
1) The code within the "Index" action [you are setting this via:
routeData.Values.Add("action", "Index"); ] might have some uninitialized object that could be throwing.
2) The View you are returning from Index action of ErrorController is existing in a proper View folder.
3) If the Error View is existing as expected, then check within the view if it is not referencing any uninitialized object.

How can I determine which part of RequestContext is the problem that
makes 'Execute' throw NullReferenceException?
Put a breakpoint on the Execute call line
Enable auto breaking on exception in visual studio (Debug -> Exceptions... -> Common Language Runtime Exceptions -> System -> System.NullReferenceException -> 'check the thrown checkbox')
Press F5 to continue program execution and wait for the exception to be raise
Get the stack strace of the exception or open the call stack window (Debug -> Windows -> Call stack)
From the topmost call, you have to isolate the variable that is not initialized on which you are trying to perform an operation. To do this you can use the Auto window (Debug -> Windows -> Auto) or the Watch window (Debug -> Windows -> Watch) to inspect the content of your current variables (not lambdas though) and find which one is null.

Related

How to avoid HttpResponseExceptions when using Kerberos in ASP.net?

I took over a project is ASP.NET, C# and React which is not too well documented. In Visual Studio (Professional 2017)'s debug mode, I initially keep getting a bunch of errors which I ignore by clicking Continue a couple of times. The Output within Visual Studio reads:
An exception of type 'System.Web.Http.HttpResponseException' occurred in myProject.API.dll but was not handled in user code
Processing of the HTTP request resulted in an exception.
Please see the HTTP response returned by the 'Response' property of this exception for details.
The corresponding code is probably myProject.BSTB.API\Filters\UserAuthenticationFilter.cs:
namespace myProject.API.Filters
{
public class UserAuthenticationFilter : ActionFilterAttribute
{
// ... some other code
public override void OnActionExecuting(HttpActionContext actionContext)
{
var name = HttpContext.Current.User.Identity.Name;
ServiceLocator sl = new ServiceLocator();
User user = null;
try { user = sl.User.GetUserByName(name); } catch (Exception ex) { throw; }
if (user == null)
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.Unauthorized) {
ReasonPhrase = "Unauthorize request: User not valid: " + name});
}
HttpContext.Current.Items.Add(Common.CURRENT_CONTEXT_USER, user);
base.OnActionExecuting(actionContext);
}
}
}
I was told:
Since the system uses NTLM authentication and credentials are not sent on the first call to the server, the server sends an error response, and the credentials are sent with the second request. Thus it is expected that the server will have user == null towards the beginning, and spit out a lot of HTTP errors, this is the desired behaviour.
Edit: I believe that we are actually rather using Kerberos and we actually performing an authorization rather than an authentication, see e.g. Authentication versus Authorization.
Interestingly, other developers cannot reproduce this issue, so it might have to do something with the way I set up Visual Studio.
Clearly it is a waste of time that I have to click several times on the Continue button each time when I start running the code in Visual Studio. How should I adjust the code that this error does not show up any more? Is there maybe just a configuration in Visual Studio or some additional code I should add?
Edit
The user comes from an additional service my.Service\UserService.cs which reads
namespace myProject.Service
{
public class UserService
{
private projectContext _db;
internal UserService(projectContext db)
{
_db = db;
}
public User GetUserByName(string name)
{
return _db.Users.SingleOrDefault(x => x.UserName == name);
}

Determine if Server.Transfer[Request] was executed

I was debugging two things and discovered that when an action executed:
Server.TransferRequest(url);
return new EmptyResult();
that my Application_Error would fire and catch the exception "The SessionStateTempDataProvider class requires session state to be enabled."
(I do have session state enabled, specifically StateServer, and for the sake of discussion let's imagine I do not need to commit changes from this request back to the session)
I'd like to control how this scenario gets logged. Obviously I can detect the exception type and message text, but if I wanted to not do special logging when the Request was .TransferRequest'd (or .Transfer'd), how can I do this?
I have already examined Response.IsRequestBeingRedirected - it was false.
Each Server.Transfer will add an unsafe request completion call to the stack, therefore, if there are more than 1 of this, you may think that the request is internally redirected by one of the Server.Transfer or Server.TransferRequest methods
Here is a boolean function which you can add to your global.asax file, which will return true if it finds more than one instances of request completion frames in the current stack trace.
The new StackTrace() is an expensive operation, but, because this is executing in an Exceptional context here, it's overhead "may" be ignored.
private bool IsRequestTransferred()
{
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
int requestCompletionCount = 0;
foreach (var stackFrame in stackTrace.GetFrames())
{
System.Reflection.MethodBase methodBase = stackFrame.GetMethod();
if (methodBase.DeclaringType.Name == "UnsafeIISMethods" && methodBase.Name == "MgdIndicateCompletion")
{
if (++requestCompletionCount == 2)
{
return true;
}
}
}
return false;
}
void Application_Error(object sender, EventArgs e)
{
bool isRequestTransferred = IsRequestTransferred();
}
Server.TransferRequest accepts headers collection. You can add a special technical header and then look for it later.
Server.TransferRequest(url,
true,
method: "GET",
headers: new NameValueCollection() { { "transferred", "true" } });
//and then
bool isTransferred = (Request.Headers["transferred"] != null);

ELMAH exceptions generating generic "The service is unavailable" message

I'm trying to create an availability page which checks all the services that a site uses, wrapping each check in a try/catch and then displaying any failures to the users. One of those services is ELMAH, so I am calling that to double check that we can log errors there successfully.
Controller:
var a = new AvailabilityModel();
try {
a.ElmahConnectionString = ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString;
Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("Elmah availability test"));
a.ElmahSuccess = true;
} catch (Exception ex) {
a.ElmahSuccess = false;
a.ElmahException = ex;
Response.StatusCode = 503;
}
return View(a);
When ELMAH succeeds, all is well. When it throws any kind of error (DB permissions, etc.), I get an error which is not captured by the try/catch OR by any of the normal error-capturing pieces: ASP.NET MVC HandleError, customErrors redirects, or even httpErrors in system.webServer. The display is not the normal IIS generic message, instead I see a single line saying "The service is unavailable."
Response:
LTSB-W34511 C:\s\d\build % curl -i http://server/test/availability
HTTP/1.1 503 Service Unavailable
Cache-Control: public, max-age=14400, s-maxage=0
Content-Type: text/html
Server: Microsoft-IIS/7.5 X-AspNetMvc-Version: 4.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 06 Aug 2014 15:46:55 GMT
Content-Length: 27
The service is unavailable.
And that's it. At least I know my availability is not working, but I want to at least display to the user that it's ELMAH causing the problem, and show the connection string it's trying to use. So, I need to capture this exception somehow.
I've tried tweaking my web.config a number of different ways, but I suspect there's something about the way ELMAH inserts itself into the module pipeline which stops me from handling the issue.
Edit:
To clarify, this is a simplified example. I am not planning to expose this information to end users. This availability page will only be available to internal users who are troubleshooting future issues.
ELMAH is only one of the services/databases used by the application in question, and I want to give administrators a quick dashboard-like view of what is up and down. I can't do that if ELMAH errors lead to this insta-503.
Ok, basically this is not possible without any code. The Raise method in Elmah will not let you see any error except if you trace it:
// ErrorLogModule.LogException
try
{
Error error = new Error(e, context);
ErrorLog errorLog = this.GetErrorLog(context);
error.ApplicationName = errorLog.ApplicationName;
string id = errorLog.Log(error);
errorLogEntry = new ErrorLogEntry(errorLog, id, error);
}
catch (Exception value)
{
Trace.WriteLine(value);
}
However when the event is successfully logged the ErrorLogModule will call the logged event in order to let potential listeners know that the logging was a success. So let's quickly write a custom class that will override some methods from the ErrorLogModule and will allow us to notice that the event was not logged:
public class CustomErrorLogModule: Elmah.ErrorLogModule
{
public Boolean SomethingWasLogged { get; set; }
protected override void OnLogged(Elmah.ErrorLoggedEventArgs args)
{
SomethingWasLogged = true;
base.OnLogged(args);
}
protected override void LogException(Exception e, HttpContext context)
{
SomethingWasLogged = false;
base.LogException(e, context);
if (!SomethingWasLogged)
{
throw new InvalidOperationException("An error was not logged");
}
}
}
Swap the ErrorLogModule with the CustomErrorLogModule in your configuration file and Elmah will complain when something wrong is happening; calling Elmah.ErrorSignal.FromCurrentContext().Raise(new Exception("test")); in a test page lets the InvalidOperationException("An error was not logged") be thrown out of the call.
If you want to get back the exact exception that occured when trying to log the exception, you can use the fact that the ErrorLogModule traces the exception when it occurs. Create a listener class:
public class ExceptionInterceptor : DefaultTraceListener
{
public Exception TracedException { get; set; }
public override void WriteLine(object o)
{
var exception = o as Exception;
if (exception != null)
{
TracedException = exception;
}
}
}
Then your LogException method becomes
protected override void LogException(Exception e, HttpContext context)
{
var exceptionListener = new ExceptionInterceptor();
Trace.Listeners.Add(exceptionListener);
try
{
SomethingWasLogged = false;
base.LogException(e, context);
if (!SomethingWasLogged)
{
throw exceptionListener.TracedException;
}
}
finally
{
Trace.Listeners.Remove(exceptionListener);
}
}
EDIT: or even if you want to be as terse as possible
public class ExceptionInterceptor : DefaultTraceListener
{
public override void WriteLine(object o)
{
var exception = o as Exception;
if (exception != null)
{
throw exception;
}
}
}
// snip... LogException in your CustomErrorLogModule
protected override void LogException(Exception e, HttpContext context)
{
var exceptionListener = new ExceptionInterceptor();
Trace.Listeners.Add(exceptionListener);
try
{
base.LogException(e, context);
}
finally
{
Trace.Listeners.Remove(exceptionListener);
}
}
One final word: There is a smell in this way of checking for service availability, and you are going to pepper your error database with test exceptions which may not be the desired behavior. I understand that you aim to check the whole logging chain but perhaps there could be some other way to do it; I don't really know your context so I won't comment any further but don't hesitate to think on it.
Anyway, these changes should let you receive the exception you will need.
important edit: very important point: you may want to add a trigger to your CustomErrorLogModule so it doesn't throw when you are not testing. The resilience you are observing in Elmah is generally a good thing because you don't want a diagnostic platform to cause problems that may necessitate other diagnostics. That's why Elmah or logging frameworks don't throw, and that's why you should make the exception rethrowing mechanism triggerable so your program doesn't have to watch its step when raising exceptions in Elmah.
No, no no! Never display the connection string to the user and never tell them what the problem is. Doing so is a serious security vulnerability. Simply put, don't do it. Fix your underlying problems with Elmah.
Problems in your error handling pipeline are very bad, because it'll cause it to try to handle the new error that's generated, which basically causes a loop. The ASP.NET engine recognizes that something serious has gone wrong, so it gives a generic "the service is unavailable" message. Check the event logs on your server to find out the underlying Elmah error and correct it.

How can I correctly mock my controllercontext to test ViewResult.ExecuteResult()?

I am attempting to create integration tests to make sure my views do not have any runtime errors in them. Thus I need to create a test that checks if ViewResult.ExecuteResult() works correctly but it seems I have hit a snag.
I found this site which gave me a starting point, and I have the following code:
[TestMethod]
public void RegisterResultExecutes()
{
//arrange
RequestContext requestContext = new RequestContext(new MockHttpContext(), new RouteData());
AccountController controller = new AccountController
{
FormsService = new MockFormsAuthenticationService(),
MembershipService = new MockMembershipService(),
Url = new UrlHelper(requestContext)
};
var result = controller.Register();
var sb = new StringBuilder();
Mock<HttpResponseBase> response = new Mock<HttpResponseBase>();
response.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(y =>
{
sb.Append(y);
});
Mock<ControllerContext> controllerContext = new Mock<ControllerContext>();
controllerContext.Setup(x => x.HttpContext.Response).Returns(response.Object);
//act
result.ExecuteResult(controllerContext.Object);
}
The problem is that when result.ExecuteResult() is called I get the following exception
System.NullReferenceException: Object reference not set to an instance of an object.
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
MyApp.Tests.Controllers.AccountControllerTest.RegisterResultExecutes() in C:\Users\KallDrexx\Documents\Projects\MyApp\MyApp.Tests\Controllers\AccountControllerTests.cs: line 297
Unfortunately, that stack trace isn't very useful as I'm not sure what it's trying to access that is null. Does anyone have any suggestions on how I can create a test for ExecuteResult()?
Based on the stack trace, it is something in the ViewResultBase.ExecuteResult method that throws the exception. Using reflector, here is the definition of that method:
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (string.IsNullOrEmpty(this.ViewName))
{
this.ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (this.View == null)
{
result = this.FindView(context);
this.View = result.View;
}
TextWriter output = context.HttpContext.Response.Output;
ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output);
this.View.Render(viewContext, output);
if (result != null)
{
result.ViewEngine.ReleaseView(context, this.View);
}
}
Based on that code, an object reference exception could be thrown when the code tries to access the RouteData property from the context (if the name of the view wasn't explicitly given to the return type).
The exception could be thrown by accessing the HttpContext property. I haven't used Moq well enough to know if it can handle the fact that you haven't told it how to mock the HttpContext property, but you have told it how to mock the Response property from the HttpContext property's type, so that's another area that is suspect to me.
All other uses of context in the method are passing it into other methods, which if those were the problem, then the stack trace would have revealed that.
The easiest way to see which of the two I mentioned are the problem, I would write a quick test to pull those properties from your mocks and see which one causes the exception.
I hit the same problem as this just now and resolved it by setting the HttpContext.Current.
Try adding the following to your unit test code: e.g.
HttpContext.Current = new HttpContext(
new HttpRequest("", "http://mock", ""),
new HttpResponse(new StringWriter()));
One thing that I found useful for debugging this sort of problem rather than using reflector or ILSpy is to turn on debug symbols for the .Net framework code. That way you can attach to your NUnit process and see exactly what line of code is throwing the exception and therefore what you need to Mock in the test.
Shawn Burke has written an excellent blog article detailing how to set this up here: http://blogs.msdn.com/b/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx

Passing Errors (Exception Messages) from Repository to Controller Action in asp.net MVC2

I have been trying to develop an app using the repository pattern like in the Nerd Dinner application however I would like to handle exceptions in the repository and pass the exception messages back to the controller so that I can output the message in a nice page to the user.
How do I pass back this exception message, or even pass that an exception has occured in the repository.
http://www.asp.net/ajaxlibrary/jquery_errors.ashx
In the following example from the above url, "_repository.HasErrors" is used as a check but I want to know what the implementaion of this is in the repository in C# as I dont know how this is implemented and also if its possible to also get the error message as well.
01.// GET: /HandlejQueryErrors/Contact/Create
02.public ActionResult Create()
03.{
04. return View();
05.}
06.
07.// POST: /HandlejQueryErrors/Contact/Create
08.[HttpPost]
09.public ActionResult Create(ContactViewModel viewModel)
10.{
11. var response = new AjaxResponseViewModel();
12.
13. try
14. {
15. var contact = _repository.SaveOrUpdate(viewModel);
16. if (!_repository.HasErrors)
17. {
18. response.Success = true;
19. response.Message = "Your contact was successfully created!";
20. }
21. else
22. {
23. response.Message = "There was an error updating your contact!";
24. }
25. }
26. catch (Exception exception)
27. {
28. response.Success = false;
29. response.Messages exception.Message;
30. }
31.
32. return Json(response);
33.}
Thanks in advance.
You could allow your repository's exceptions to fall through, and override your controller's OnActionExecuted method to handle specific errors for you. Example:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception is RepositoryException)
{
filterContext.ExceptionHandled = true;
filterContext.Result = View("Exception", filterContext.Exception);
}
base.OnActionExecuted(filterContext);
}
So, in general in ASP.NET MVC you need to handle 2 kinds of errors: Validation errors, and System errors.
For System errors, those occurring because of some system rules violation (like foreign key constraint violation in database during insert), you should use try-catche operator and then pass them to the view in some way to show them to the user.
For validation errors, you should read about ASP.NET MVC Validation:
Validation with the Data Annotation Validators - here you can see how to validate simple validation rules using built-in annotation attributes.
Validating with a Service Layer - this is more advanced topic, where you can learn how to validate more complex validation rules (for example for inter-connected properties, etc.)
So, as a conclusion, think of separating the concerns about domain/business functionality from the concerns related to validation. The only common thing they should have (in the perfect scenario) is a view where you show the results of validation.
Personally I (taking 2-nd approach) even do a save in validation, so that Validation implementation knows about domain/business logic and manipulates it to validate all the rules. In the end of validation, if all rules were met, then it tries to save the data, and returns the validation error message in case of non-success. This is also a good start to go further and even localize your custom validation messages.
I hope this helps!
I personally still like the GetRuleViolations() approach started by ScottGu and would simply follow this through on the Repository.
In the controller I would do (pseudo here):
[HttpPost]
public ActionResult ControllerAction(MyViewModel viewModel)
{
ModelState.AddRuleViolations(viewModel.GetRuleViolations);
if (!ModelState.IsValid)
{
return View();
}
// Perform repository action (pseudo code to follow)
_repository.ClearErrorState();
_repository.DoSomething();
ModelState.AddRuleViolation(repository.GetRuleViolations());
if (!ModelState.IsValid)
{
return View();
}
return RedirectToAction("Foo","Bar");
}
class Repository
{
List<RuleViolation> _errors = new List<RuleViolation>();
public void ClearErrorState()
{
_errors.Clear();
}
public void DoSomething(...)
{
try
{
DoSomthingThatFails();
}
catch (Exception ex)
{
_errors.Add(new RuleViolation(null, "Error while saving customer");
_errors.Add(new RuleViolation("SSN", "SSN must be unique"); // This one I struggle with as bad design, tying UI element to data elements is bad, so generally I try to prevent everything when checking the viewmodel and only catch general (unforeseen) errors here.
}
}
public IEnumerable<RuleViolation> GetRuleViolations()
{
return _errors;
}
}

Categories

Resources