I'm trying to use ElmahCore with an ASP.NET Razor pages application. I am purposefully throwing an exception in one of the pages to test out the error handling.
Desired Behavior
- Log the error to Elmah
- Show a red "An error occurred" message at the top of the screen when an error occurs.
Actual Behavior: I get the message at the top of the screen, but navigating to /elmah in my web app shows that no errors have occurred.
Some basics:
- .NET 7.0
- ElmahCore 2.1.2 NuGet package
- Visual Studio 2022
- Running the application in debug mode in Visual Studio by pressing F5
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddElmah(options =>
{
var settings = builder.Configuration.GetSection("Elmah")
.Get<ElmahSettings>();
settings.ApplyTo(options);
// ^^^^^^^^^^^^^^^^
// see ElmahSettings below
});
builder.Services.AddRazorPages(...);
builder.Services.AddAuthentication(...);
builder.Services.AddCookie(...);
// more services
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseElmah();
// ^^^^^^^^^^^
app.MapRazorPages();
app.Run();
ElmahSettings classes
public class ElmahSettings
{
public string ApplicationName { get; set; }
public ElmahEmailSettings Email { get; set; }
/// <summary>
/// Apply these settings to the given <see cref="ElmahOptions"/> object
/// </summary>
/// <param name="options"></param>
public void ApplyTo(ElmahOptions options)
{
options.ApplicationName = ApplicationName;
options.OnPermissionCheck = IsUserAuthorized;
if (Email != null && Email.Recipients != null)
{
foreach (var recipient in Email.Recipients)
{
options.Notifiers.Add(new ErrorMailNotifier(recipient.Key, new EmailOptions()
{
MailSender = Email.Sender,
MailRecipient = recipient.Value
}));
}
}
}
/// <summary>
/// Returns whether or not a request is authorized to view the Elmah error page.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public bool IsUserAuthorized(HttpContext context)
{
if (!context.User.Identity.IsAuthenticated || Email == null || Email.Recipients == null)
return false;
var emailClaim = context.User.Claims.FirstOrDefault(claim => claim.Type == ClaimTypes.Email);
if (emailClaim == null)
return false;
return Email.Recipients.Any(recipient => recipient.Value.Equals(emailClaim.Value, StringComparison.OrdinalIgnoreCase));
}
}
public class ElmahEmailSettings
{
public string Sender { get; set; }
public Dictionary<string, string> Recipients { get; set; }
}
Relevant contents of appsettings.json
{
"Logging": {
"EventLog": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
},
"AllowedHosts": "*",
// maps to ElmahSettings class
"Elmah": {
"ApplicationName": "My Application Name",
"Email": {
"Sender": "[email protected]",
"Recipients": {
"John Doe": "[email protected]",
"Jane Doe": "[email protected]"
}
}
}
}
Error handling in one of the pages
public class TestModel : PageModel
{
private readonly ILogger<TestModel> logger;
public TestModel(ILogger<TestModel> logger)
{
this.logger = logger;
}
public void OnGet()
{
try
{
throw new Exception("This is just a test!");
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// I want this to show up in the Elmah logs
// custom extension method to show a red error at the top of the page
// which works as intended.
this.ShowMessage("An error occurred, please try again.");
return Page();
}
}
}
I see that ElmahCore provides an implementation of ILoggerProvider in ElmahCore.Mvc.Logging.ElmahLoggingProvider, but its constructor requires an HttpContextAccessor object. I don't see where I can access this object in Program.cs, unless I have a fully initialized IServicesCollection object, but at that point it feels too late in the lifecycle of the application to configure a logging provider.
I really feel like this should be possible if I can just get the ElmahLoggingProvider registered properly. When I debug the application, I can see the logger field in my page model is a Microsoft.Extensions.Logging.Logger object, which mentions nothing about Elmah or ElmahCore.
Question: how to properly register the ElmahLoggerProvider so errors are logged to the Elmah error dashboard?

Based on examples in the github repo (one, two) if you catch exception explicitly you can/need to explicitly raise error:
For non-handled exceptions it should work out of the box.