Reputation: 18783
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
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:
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?
Upvotes: 2
Views: 883
Reputation: 141565
Based on examples in the github repo (one, two) if you catch exception explicitly you can/need to explicitly raise error:
catch (Exception ex)
{
logger.LogError(ex, "An error occurred");
HttpContext.RaiseError(ex);
// or
// ElmahExtensions.RaiseError(ex);
// ...
}
For non-handled exceptions it should work out of the box.
Upvotes: 0