Well, having spent the day working on this, I thought I'd share my solution. Very similar to Myster's solution above, the difference being I modify the error object used by elmah instead of the request server variables, like so:
public static void LogError(Exception e, IDictionary<string, string> customFields = null)
{
var logger = ErrorLog.GetDefault(HttpContext.Current);
customFields = customFields ?? new Dictionary<string, string>();
// Used to tell elmah not to log this twice (See global.asax)
e.Data.Add("Logged", true);
var error = new Error(e, HttpContext.Current);
customFields.ForEach(pair => error.ServerVariables.Add(pair.Key, pair.Value));
logger.Log(error);
}
Then, depending on your application to call logger.LogError:
mvc add a custom error filter (http://maheshde.blogspot.ca/2012/09/error-handing-with-mvc-using-custom.html)
webforms override Application_Error in global.asax
Then, just one final step in the global.asax, dismiss any errors that have already been logged:
public void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e)
{
if (e.Exception.Data.Contains("Logged"))
{
if (e.Exception.Data["Logged"].Equals(true)) e.Dismiss();
}
}