0

I’m replacing Elmah with Exceptional, but having an issue. It works fine if the exception is thrown inside my web project or if the error is a 404 (The controller for path '/blah/blah' was not found or does not implement IController).

But if I throw an exception from within one of my referenced projects that’s not my web project, then Exceptional throws an error when attempting to log. The following error and stacktrace only gets displayed in the console. The error gets swallowed at that point and doesn't get logged anywhere.

One of the beauties of open-source, is that I can see the code that’s throwing the exception, but no idea why…

Error.cs (line 107, 135, 126)

Exception thrown: 'System.ArgumentException' in Cms.Services.dll
'w3wp.exe' (CLR v4.0.30319: /LM/W3SVC/1/ROOT/wssp-18-131152201224510365): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\14.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.HttpRequest.CalcDynamicServerVariable(DynamicServerVariable var)
   at System.Web.HttpServerVarsCollectionEntry.GetValue(HttpRequest request)
   at System.Web.HttpServerVarsCollection.GetServerVar(Object e)
   at System.Web.HttpServerVarsCollection.Get(Int32 index)
   at System.Web.HttpServerVarsCollection.GetValues(Int32 index)
   at System.Collections.Specialized.NameValueCollection.Add(NameValueCollection c)
   at StackExchange.Exceptional.Error.<>c__DisplayClass22_0.<SetContextProperties>b__0(Func`2 getter) in C:\BuildAgent\work\d20fce4a5bb47bd3\StackExchange.Exceptional\Error.cs:line 126
   at StackExchange.Exceptional.Error.SetContextProperties(HttpContext context) in C:\BuildAgent\work\d20fce4a5bb47bd3\StackExchange.Exceptional\Error.cs:line 135
   at StackExchange.Exceptional.Error..ctor(Exception e, HttpContext context, String applicationName) in C:\BuildAgent\work\d20fce4a5bb47bd3\StackExchange.Exceptional\Error.cs:line 107
   at StackExchange.Exceptional.ErrorStore.LogException(Exception ex, HttpContext context, Boolean appendFullStackTrace, Boolean rollupPerServer, Dictionary`2 customData, String applicationName) in C:\BuildAgent\work\d20fce4a5bb47bd3\StackExchange.Exceptional\ErrorStore.cs:line 611

I am registering Exceptional like this:

  string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MyApp"].ConnectionString;
  ErrorStore.Setup("MyApp", new SQLErrorStore(connectionString));

And this is the only code in my web.config:

<modules runAllManagedModulesForAllRequests="true">
  <add name="ErrorStore" type="StackExchange.Exceptional.ExceptionalModule, StackExchange.Exceptional" />
</modules>
Ashley Lee
  • 3,810
  • 1
  • 18
  • 26
  • It's happening in the call to this line `ServerVariables = tryGetCollection(r => r.ServerVariables);`, specifically, there's something rotten within `HttpContext.Request.ServerValues` which results in `HttpRequest.CalcDynamicServerVariable(DynamicServerVariable var)` throwing. The question is... what is it? If you can interrupt this callstack and examine the server values to see which throws? –  Aug 09 '16 at 15:25
  • ServerVariables contain 56 keys and they seem normal. I'm not sure how to interrupt the callstack to examine which value throws? I was able to get to the Exception detail and attached the image. – Ashley Lee Aug 09 '16 at 16:23
  • It's always better to call ToString() on an exception and paste that in your question -- http://idownvotedyoubecause.com/so/ImageOfAnException –  Aug 09 '16 at 16:28
  • The ServerVariables that are throwing the exception are: AUTH_TYPE, AUTH_USER, REMOTE_USER. – Ashley Lee Aug 09 '16 at 18:35
  • Related http://forums.asp.net/t/1420729.aspx?System+Security+Principal+WindowsIdentity+get_AuthenticationType+throws+exception –  Aug 09 '16 at 18:50

1 Answers1

0

I finally found the issue. The code below is what I use to logout a user from my application.

var authenticationManager = HttpContext.GetOwinContext().Authentication;
authenticationManager.SignOut();
authenticationManager.User = new ClaimsPrincipal();

When the 3rd line executes and sets the user to a new ClaimsPrinciple, it removes the following 3 values (AUTH_TYPE, AUTH_USER, REMOTE_USER) and sets them to null inside the System.Web.HttpContext.Current.Request.ServerVariables object, even though the keys are still there inside the object.

So any exception thrown after that line is not logged by Stackexchange.Exceptional, as it tries to read those values and then throws a System.NullReferenceException.

Ashley Lee
  • 3,810
  • 1
  • 18
  • 26
  • Why do you assign a new ClaimsPrincipal after calling SignOut? Seems like just calling SignOut should be all you need if you're trying to logout. – CptRobby Aug 15 '16 at 13:33
  • The only tutorial I could find where a logout was actually coded (http://www.asp.net/identity/overview/getting-started/adding-aspnet-identity-to-an-empty-or-existing-web-forms-project) only called SignOut and didn't change the User. – CptRobby Aug 15 '16 at 13:46
  • Oh and one quick correction. You said that the values are set to null within the collection. That's not actually true, if it were, there would be no exception because null would be a valid value and it isn't used in a reference anywhere. The problem is that there's an unhandled NRE in the CalcDynamicServerVariable function, which is trying to figure out what the value is. So the value isn't null, it's incalculable (by CalcDynamicServerVariable at least). – CptRobby Aug 15 '16 at 14:00
  • 1
    In fact, as a continued debugging exercise, I would suggest adding a breakpoint to your first line of code there and check those ServerVariables before calling SignOut and then step through and check them after calling SignOut but before assigning to User. Then you can see what they are and if/how calling SignOut changes them. – CptRobby Aug 15 '16 at 14:10
  • All your points are true. After calling SignOut, all 3 values are still able to be accessed. Only after setting User does it throw that exception. I may be able to remove that line of code, but the reason it's there is I do the same thing when I sign in the user. Mainly because I wanted to access a claim immediately after calling SignIn, but the way OWIN works it's not immediately available (I think it's set during the response). Regardless, I only noticed it when troubleshooting another error, but that shouldn't prevent Exceptional from logging the original exception. – Ashley Lee Aug 15 '16 at 17:46
  • 1
    "that shouldn't prevent Exceptional from logging the original exception." - I totally agree. Even though the error condition seems to be unusual, I would still think that Exceptional should be as fail safe as possible to ensure that you're notified of any error that happens. I'm going to give some suggestions to further that effort on your pull request. ;) – CptRobby Aug 17 '16 at 11:37