I have an MVC app running on IIS 7 using windows authentication and Elmah logging.
Normally when an error happens, we call something like "logger.LogError" which is a wrapper for:
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new Exception(message)));
We have a remote system set up to run jobs that pings the web application periodically, in order to wake it up and tell it to run a specific job. The remote application uses HttpClient::GetAsync(...) to connect to the site.
The page that the remote ping hits, executes the job it needs to run in a thread but does not await, since we want the ping to respond immediately. Unfortunately, this has the added drawback of breaking the Elmah logging.
If we have any kind of logged error occur during the job execution, when we get to the "LogError" method, Elmah throws an "ObjectDisposedException" with the message "Safe Handle has been closed" (probably bubbled up from trying to access the current users identity). I checked in the watch window while debugging, and the part that is throwing the error is:
new Elmah.Error(new Exception(message))
if I call just "new Elmah.Error()" it works fine, and "new Exception(message)" also works fine, but when passing an exception as the parameter to the error constructor, that's when it fails. Also, I cannot assign an exception after creating a new error object, as the property is read-only.
I'm pretty sure that it's because the current windows identity has gone out of scope in the parent thread when it finishes. Is there any way of getting around this issue without resorting to an await on the job execution? The problem is that the jobs can take a very long time to run, and we don't want the remote ping app to either timeout or hang for a long time while waiting for a response.
In case someone else runs across this, here's what I ended up doing:
In a situation where you'd normally call
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
Call this function instead:
public static void LogError(Exception ex)
{
if (HttpContext.Current == null)
{
var errorlog = Elmah.ErrorLog.GetDefault(null);
var error = new Elmah.Error();
error.Message = ex.Message;
error.Detail = ex.ToString();
error.Time = DateTime.Now;
error.Type = ex.GetType() + "[NoContext]";
error.HostName = Environment.MachineName;
errorlog.Log(error);
} else {
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
}
Caveats apply:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With