Tro*_*sGP 10 error-handling unhandled-exception blazor
我希望能够在构建 Blazor 单页应用程序的一个地方捕获所有未处理的异常。就像在 WPF 应用程序中使用“Current.DispatcherUnhandledException”一样。
这个问题完全是关于客户端(webassembly)异常处理的。我正在使用 Blazor 版本 3.0.0-preview8.19405.7
我一直在寻找解决方案,但似乎它不存在。在 Microsoft 的文档 ( https://docs.microsoft.com/en-us/aspnet/core/blazor/handle-errors?view=aspnetcore-3.0 ) 上,有一个可能发生错误的地方列表以及有关如何操作的演练处理每一个。它相信必须有一种更防弹的方法来捕获所有。
这适用于 v3.2+
using Microsoft.Extensions.Logging;
using System;
namespace UnhandledExceptions.Client
{
public interface IUnhandledExceptionSender
{
event EventHandler<Exception> UnhandledExceptionThrown;
}
public class UnhandledExceptionSender : ILogger, IUnhandledExceptionSender
{
public event EventHandler<Exception> UnhandledExceptionThrown;
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception exception, Func<TState, Exception, string> formatter)
{
if (exception != null)
{
UnhandledExceptionThrown?.Invoke(this, exception);
}
}
}
public class UnhandledExceptionProvider : ILoggerProvider
{
UnhandledExceptionSender _unhandledExceptionSender;
public UnhandledExceptionProvider(UnhandledExceptionSender unhandledExceptionSender)
{
_unhandledExceptionSender = unhandledExceptionSender;
}
public ILogger CreateLogger(string categoryName)
{
return new UnhandledExceptionLogger(categoryName, _unhandledExceptionSender);
}
public void Dispose()
{
}
public class UnhandledExceptionLogger : ILogger
{
private readonly string _categoryName;
private readonly UnhandledExceptionSender _unhandeledExceptionSender;
public UnhandledExceptionLogger(string categoryName, UnhandledExceptionSender unhandledExceptionSender)
{
_unhandeledExceptionSender = unhandledExceptionSender;
_categoryName = categoryName;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
// Unhandled exceptions will call this method
// Blazor already logs unhandled exceptions to the browser console
// but, one could pass the exception to the server to log, this is easily done with serilog
Serilog.Log.Fatal(exception, exception.Message);
}
public IDisposable BeginScope<TState>(TState state)
{
return new NoopDisposable();
}
private class NoopDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
将此添加到 Program.cs
var unhandledExceptionSender = new UnhandledExceptionSender();
var unhandledExceptionProvider = new UnhandledExceptionProvider(unhandledExceptionSender);
builder.Logging.AddProvider(unhandledExceptionProvider);
builder.Services.AddSingleton<IUnhandledExceptionSender>(unhandledExceptionSender);
Run Code Online (Sandbox Code Playgroud)
这是实现此解决方案的示例项目。
.NET 6ErrorBoundary
即将到来。
<ErrorBoundary>
@Body
</ErrorBoundary>
Run Code Online (Sandbox Code Playgroud)
对于全局异常处理,我将其视为一个选项:创建CustomErrorBoundary
(继承ErrorBoundary
)并覆盖OnErrorAsync(Exception exception)
.
这是 的示例CustomErrorBoundary
。
ErrorBoundary
(YouTube)的对于 .NET 5 Blazor服务器端,这篇文章Create Your Own Logging Provider to Log to Text Files in .NET Core对我有用。对于我的情况,我对此进行了调整以捕获未处理的异常以写入 Azure 存储表。
public class ExceptionLoggerOptions
{
public virtual bool Enabled { get; set; }
}
[ProviderAlias("ExceptionLogger")]
public class ExceptionLoggerProvider : ILoggerProvider
{
public readonly ExceptionLoggerOptions Options;
public ExceptionLoggerProvider(IOptions<ExceptionLoggerOptions> _options)
{
Options = _options.Value;
}
public ILogger CreateLogger(string categoryName)
{
return new ExceptionLogger(this);
}
public void Dispose()
{
}
}
public class ExceptionLogger : ILogger
{
protected readonly ExceptionLoggerProvider _exceptionLoggerProvider;
public ExceptionLogger([NotNull] ExceptionLoggerProvider exceptionLoggerProvider)
{
_exceptionLoggerProvider = exceptionLoggerProvider;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel == LogLevel.Error;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (false == _exceptionLoggerProvider.Options.Enabled) return;
if (null == exception) return;
if (false == IsEnabled(logLevel)) return;
var record = $"{exception.Message}"; // string.Format("{0} {1} {2}", logLevel.ToString(), formatter(state, exception), exception?.StackTrace);
// Record exception into Azure Table
}
}
public static class ExceptionLoggerExtensions
{
public static ILoggingBuilder AddExceptionLogger(this ILoggingBuilder builder, Action<ExceptionLoggerOptions> configure)
{
builder.Services.AddSingleton<ILoggerProvider, ExceptionLoggerProvider>();
builder.Services.Configure(configure);
return builder;
}
}
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStaticWebAssets().UseStartup<Startup>();
}).ConfigureLogging((hostBuilderContext, logging) =>
{
logging.AddExceptionLogger(options => { options.Enabled = true; });
});
Run Code Online (Sandbox Code Playgroud)
目前没有中央位置来捕获和处理客户端异常。
这是史蒂夫桑德森的一段话:
所以总的来说,每个组件都必须处理自己的错误。如果你愿意,你可以创建你自己的 ErrorHandlingComponentBase 来继承,并在所有生命周期方法周围放置一个 try/catch,并拥有你自己的逻辑,用于在出现任何问题时在该组件上显示“哦,亲爱的,对不起,我死了”UI。但这不是今天框架的功能。
我希望这会在未来改变,我相信应该支持框架。
归档时间: |
|
查看次数: |
8167 次 |
最近记录: |