30 changed files with 662 additions and 9 deletions
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,37 @@ |
|||||||
|
# Sanhe.Abp.ExceptionHandling.Emailing |
||||||
|
|
||||||
|
基于abp框架底层的**IExceptionSubscriber**的邮件通知类型 |
||||||
|
|
||||||
|
## 配置使用 |
||||||
|
|
||||||
|
使用前需要配置**AbpExceptionHandlingOptions**定义需要发送通知的异常 |
||||||
|
然后配置**AbpEmailExceptionHandlingOptions**定义具体异常类型通知方式 |
||||||
|
|
||||||
|
```csharp |
||||||
|
|
||||||
|
[DependsOn( |
||||||
|
typeof(AbpEmailingExceptionHandlingModule) |
||||||
|
)] |
||||||
|
public class YouProjectModule : AbpModule |
||||||
|
{ |
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
// 自定义需要处理的异常 |
||||||
|
Configure<AbpExceptionHandlingOptions>(options => |
||||||
|
{ |
||||||
|
// 加入需要处理的异常类型 |
||||||
|
options.Handlers.Add<AbpException>(); |
||||||
|
}); |
||||||
|
// 自定义需要发送邮件通知的异常类型 |
||||||
|
Configure<AbpEmailExceptionHandlingOptions>(options => |
||||||
|
{ |
||||||
|
// 是否发送堆栈信息 |
||||||
|
options.SendStackTrace = true; |
||||||
|
// 未指定异常接收者的默认接收邮件 |
||||||
|
options.DefaultReceiveEmail = "colin.in@foxmail.com"; |
||||||
|
// 指定某种异常发送到哪个邮件 |
||||||
|
options.HandReceivedException<AbpException>("colin.in@foxmail.com"); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,33 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<None Remove="Sanhe\Abp\ExceptionHandling\Emailing\Localization\Resources\en.json" /> |
||||||
|
<None Remove="Sanhe\Abp\ExceptionHandling\Emailing\Localization\Resources\zh-Hans.json" /> |
||||||
|
<None Remove="Sanhe\Abp\ExceptionHandling\Emailing\Templates\SendEmail\en.tpl" /> |
||||||
|
<None Remove="Sanhe\Abp\ExceptionHandling\Emailing\Templates\SendEmail\zh-Hans.tpl" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<EmbeddedResource Include="Sanhe\Abp\ExceptionHandling\Emailing\Localization\Resources\en.json" /> |
||||||
|
<EmbeddedResource Include="Sanhe\Abp\ExceptionHandling\Emailing\Localization\Resources\zh-Hans.json" /> |
||||||
|
<EmbeddedResource Include="Sanhe\Abp\ExceptionHandling\Emailing\Templates\SendEmail\en.tpl" /> |
||||||
|
<EmbeddedResource Include="Sanhe\Abp\ExceptionHandling\Emailing\Templates\SendEmail\zh-Hans.tpl" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Emailing" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="..\Sanhe.Abp.ExceptionHandling\Sanhe.Abp.ExceptionHandling.csproj" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -0,0 +1,73 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling.Emailing; |
||||||
|
|
||||||
|
public class AbpEmailExceptionHandlingOptions |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 发送堆栈信息 |
||||||
|
/// </summary> |
||||||
|
public bool SendStackTrace { get; set; } = false; |
||||||
|
/// <summary> |
||||||
|
/// 默认邮件标题 |
||||||
|
/// </summary> |
||||||
|
public string DefaultTitle { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 默认邮件内容头 |
||||||
|
/// </summary> |
||||||
|
public string DefaultContentHeader { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 默认邮件内容底 |
||||||
|
/// </summary> |
||||||
|
public string DefaultContentFooter { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 默认异常收件人 |
||||||
|
/// </summary> |
||||||
|
public string DefaultReceiveEmail { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 异常类型指定收件人处理映射列表 |
||||||
|
/// </summary> |
||||||
|
public IDictionary<Type, string> Handlers { get; set; } |
||||||
|
|
||||||
|
public AbpEmailExceptionHandlingOptions() |
||||||
|
{ |
||||||
|
Handlers = new Dictionary<Type, string>(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 把需要接受异常通知的用户加进处理列表 |
||||||
|
/// </summary> |
||||||
|
/// <typeparam name="TException">处理的异常类型</typeparam> |
||||||
|
/// <param name="receivedEmails">接收邮件的用户类别,群发用,符号分隔</param> |
||||||
|
public void HandReceivedException<TException>(string receivedEmails) where TException : Exception |
||||||
|
{ |
||||||
|
HandReceivedException(typeof(TException), receivedEmails); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 把需要接受异常通知的用户加进处理列表 |
||||||
|
/// </summary> |
||||||
|
/// <param name="ex">处理的异常类型</param> |
||||||
|
/// <param name="receivedEmails">接收邮件的用户类别,群发用,符号分隔</param> |
||||||
|
public void HandReceivedException(Type exceptionType, string receivedEmails) |
||||||
|
{ |
||||||
|
if (Handlers.ContainsKey(exceptionType)) |
||||||
|
{ |
||||||
|
Handlers[exceptionType] += receivedEmails; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
Handlers.Add(exceptionType, receivedEmails); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public string GetReceivedEmailOrDefault(Type exceptionType) |
||||||
|
{ |
||||||
|
if (Handlers.TryGetValue(exceptionType, out string receivedUsers)) |
||||||
|
{ |
||||||
|
return receivedUsers; |
||||||
|
} |
||||||
|
return DefaultReceiveEmail; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Sanhe.Abp.ExceptionHandling.Emailing.Localization; |
||||||
|
using Volo.Abp.Emailing; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
using Volo.Abp.Modularity; |
||||||
|
using Volo.Abp.VirtualFileSystem; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling.Emailing; |
||||||
|
|
||||||
|
[DependsOn( |
||||||
|
typeof(AbpExceptionHandlingModule), |
||||||
|
typeof(AbpEmailingModule))] |
||||||
|
public class AbpEmailingExceptionHandlingModule : AbpModule |
||||||
|
{ |
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
var configuration = context.Services.GetConfiguration(); |
||||||
|
Configure<AbpEmailExceptionHandlingOptions>( |
||||||
|
configuration.GetSection("ExceptionHandling:Emailing")); |
||||||
|
|
||||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||||
|
{ |
||||||
|
options.FileSets.AddEmbedded<AbpEmailingExceptionHandlingModule>(); |
||||||
|
}); |
||||||
|
|
||||||
|
Configure<AbpLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.Resources |
||||||
|
.Add<ExceptionHandlingResource>("en") |
||||||
|
.AddVirtualJson("/Sanhe/Abp/ExceptionHandling/Emailing/Localization/Resources"); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.Localization; |
||||||
|
using Microsoft.Extensions.Options; |
||||||
|
using Sanhe.Abp.ExceptionHandling.Emailing.Localization; |
||||||
|
using Sanhe.Abp.ExceptionHandling.Emailing.Templates; |
||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Volo.Abp.Emailing; |
||||||
|
using Volo.Abp.TextTemplating; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling.Emailing; |
||||||
|
|
||||||
|
public class AbpEmailingExceptionSubscriber : AbpExceptionSubscriberBase |
||||||
|
{ |
||||||
|
protected IEmailSender EmailSender { get; } |
||||||
|
protected IStringLocalizer StringLocalizer { get; } |
||||||
|
protected ITemplateRenderer TemplateRenderer { get; } |
||||||
|
protected AbpEmailExceptionHandlingOptions EmailOptions { get; } |
||||||
|
|
||||||
|
public AbpEmailingExceptionSubscriber( |
||||||
|
IEmailSender emailSender, |
||||||
|
ITemplateRenderer templateRenderer, |
||||||
|
IServiceScopeFactory serviceScopeFactory, |
||||||
|
IOptions<AbpExceptionHandlingOptions> options, |
||||||
|
IOptions<AbpEmailExceptionHandlingOptions> emailOptions, |
||||||
|
IStringLocalizer<ExceptionHandlingResource> stringLocalizer) |
||||||
|
: base(serviceScopeFactory, options) |
||||||
|
{ |
||||||
|
EmailSender = emailSender; |
||||||
|
EmailOptions = emailOptions.Value; |
||||||
|
StringLocalizer = stringLocalizer; |
||||||
|
TemplateRenderer = templateRenderer; |
||||||
|
} |
||||||
|
|
||||||
|
protected override async Task SendErrorNotifierAsync(ExceptionSendNotifierContext context) |
||||||
|
{ |
||||||
|
// 需不需要用 SettingProvider 来获取? |
||||||
|
var receivedUsers = EmailOptions.GetReceivedEmailOrDefault(context.Exception.GetType()); |
||||||
|
|
||||||
|
if (!receivedUsers.IsNullOrWhiteSpace()) |
||||||
|
{ |
||||||
|
var emailTitle = EmailOptions.DefaultTitle ?? L("SendEmailTitle"); |
||||||
|
var templateContent = await TemplateRenderer |
||||||
|
.RenderAsync(ExceptionHandlingTemplates.SendEmail, |
||||||
|
new |
||||||
|
{ |
||||||
|
title = emailTitle, |
||||||
|
header = EmailOptions.DefaultContentHeader ?? L("SendEmailHeader"), |
||||||
|
type = context.Exception.GetType().FullName, |
||||||
|
message = context.Exception.Message, |
||||||
|
loglevel = context.LogLevel.ToString(), |
||||||
|
triggertime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), |
||||||
|
sendstacktrace = EmailOptions.SendStackTrace, |
||||||
|
stacktrace = context.Exception.ToString(), |
||||||
|
footer = EmailOptions.DefaultContentFooter ?? $"Copyright to Sanhe © {DateTime.Now.Year}" |
||||||
|
}); |
||||||
|
|
||||||
|
await EmailSender.SendAsync(receivedUsers, |
||||||
|
emailTitle, |
||||||
|
templateContent); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected string L(string name, params object[] args) |
||||||
|
{ |
||||||
|
return StringLocalizer[name, args].Value; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling.Emailing.Localization; |
||||||
|
|
||||||
|
[LocalizationResourceName("AbpExceptionHandlingEmailing")] |
||||||
|
public class ExceptionHandlingResource |
||||||
|
{ |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"culture": "en", |
||||||
|
"texts": { |
||||||
|
"TextTemplate:ExceptionHandlingTemplates.SendEmail": "Apply the exception message sending template", |
||||||
|
"SendEmailTitle": "Application exception push", |
||||||
|
"SendEmailHeader": "Application exception" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"culture": "zh-Hans", |
||||||
|
"texts": { |
||||||
|
"TextTemplate:ExceptionHandlingTemplates.SendEmail": "应用异常邮件发送模板", |
||||||
|
"SendEmailTitle": "应用程序异常推送", |
||||||
|
"SendEmailHeader": "应用程序异常" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
using Sanhe.Abp.ExceptionHandling.Emailing.Localization; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
using Volo.Abp.TextTemplating; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling.Emailing.Templates; |
||||||
|
|
||||||
|
public class ExceptionHandlingTemplateDefinitionProvider : TemplateDefinitionProvider |
||||||
|
{ |
||||||
|
public override void Define(ITemplateDefinitionContext context) |
||||||
|
{ |
||||||
|
context.Add( |
||||||
|
new TemplateDefinition( |
||||||
|
ExceptionHandlingTemplates.SendEmail, |
||||||
|
displayName: LocalizableString.Create<ExceptionHandlingResource>("TextTemplate:ExceptionHandlingTemplates.SendEmail"), |
||||||
|
defaultCultureName: "en" |
||||||
|
).WithVirtualFilePath("/Sanhe/Abp/ExceptionHandling/Emailing/Templates/SendEmail", false) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
namespace Sanhe.Abp.ExceptionHandling.Emailing.Templates; |
||||||
|
|
||||||
|
public class ExceptionHandlingTemplates |
||||||
|
{ |
||||||
|
public const string SendEmail = "Abp.ExceptionHandling.SendEmail"; |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<title>{{ model.title }}</title> |
||||||
|
</head> |
||||||
|
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> |
||||||
|
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<br /> <b><font color="#0B610B">{{ model.header }}</font></b> |
||||||
|
<hr size="2" width="100%" align="center" /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<ul> |
||||||
|
<li>Type : {{ model.type }}</li> |
||||||
|
<li>Message : {{ model.message }}</li> |
||||||
|
<li>Alarm level : {{ model.loglevel }}</li> |
||||||
|
<li>TriggerTime : {{ model.triggertime }}</li> |
||||||
|
</ul> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{{ if model.sendstacktrace }} |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<b><font color="#0B610B">Stack trace</font></b> |
||||||
|
<hr size="2" width="100%" align="center" /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">{{ model.stacktrace }}</pre> |
||||||
|
<br /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{{ end }} |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<br /> |
||||||
|
<b style="float: right"><font color="#0B610B">{{ model.footer }}</font></b> |
||||||
|
<hr size="2" width="100%" align="center" /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,48 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="zh-Hans"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<title>{{ model.title }}</title> |
||||||
|
</head> |
||||||
|
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> |
||||||
|
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<br /> <b><font color="#0B610B">{{ model.header }}</font></b> |
||||||
|
<hr size="2" width="100%" align="center" /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<ul> |
||||||
|
<li>异常类型 : {{ model.type }}</li> |
||||||
|
<li>异常信息 : {{ model.message }}</li> |
||||||
|
<li>告警级别 : {{ model.loglevel }}</li> |
||||||
|
<li>触发时间 : {{ model.triggertime }}</li> |
||||||
|
</ul> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{{ if model.sendstacktrace }} |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<b><font color="#0B610B">异常堆栈</font></b> |
||||||
|
<hr size="2" width="100%" align="center" /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">{{ model.stacktrace }}</pre> |
||||||
|
<br /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{{ end }} |
||||||
|
<tr> |
||||||
|
<td> |
||||||
|
<br /> |
||||||
|
<b style="float: right"><font color="#0B610B">{{ model.footer }}</font></b> |
||||||
|
<hr size="2" width="100%" align="center" /> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
</table> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,26 @@ |
|||||||
|
# Sanhe.Abp.ExceptionHandling |
||||||
|
|
||||||
|
基于abp框架底层的**IExceptionSubscriber**实现二次扩展,用于自定义异常通知方式 |
||||||
|
|
||||||
|
## 配置使用 |
||||||
|
|
||||||
|
使用前只需配置**AbpExceptionHandlingOptions**定义需要发送通知的异常即可。 |
||||||
|
|
||||||
|
```csharp |
||||||
|
|
||||||
|
[DependsOn( |
||||||
|
typeof(AbpExceptionHandlingModule) |
||||||
|
)] |
||||||
|
public class YouProjectModule : AbpModule |
||||||
|
{ |
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
// 自定义需要处理的异常 |
||||||
|
Configure<AbpExceptionHandlingOptions>(options => |
||||||
|
{ |
||||||
|
// 加入需要处理的异常类型 |
||||||
|
options.Handlers.Add<AbpException>(); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,14 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
<RootNamespace /> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Localization" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
@ -0,0 +1,17 @@ |
|||||||
|
using Sanhe.Abp.ExceptionHandling.Localization; |
||||||
|
using Volo.Abp.Localization; |
||||||
|
using Volo.Abp.Modularity; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling; |
||||||
|
|
||||||
|
[DependsOn(typeof(AbpLocalizationModule))] |
||||||
|
public class AbpExceptionHandlingModule : AbpModule |
||||||
|
{ |
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
Configure<AbpLocalizationOptions>(options => |
||||||
|
{ |
||||||
|
options.Resources.Add<ExceptionHandlingResource>("en"); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
using System; |
||||||
|
using System.Linq; |
||||||
|
using Volo.Abp.Collections; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling; |
||||||
|
|
||||||
|
public class AbpExceptionHandlingOptions |
||||||
|
{ |
||||||
|
public ITypeList<Exception> Handlers { get; } |
||||||
|
|
||||||
|
public AbpExceptionHandlingOptions() |
||||||
|
{ |
||||||
|
Handlers = new TypeList<Exception>(); |
||||||
|
} |
||||||
|
|
||||||
|
public bool HasNotifierError(Exception ex) |
||||||
|
{ |
||||||
|
if (typeof(IHasNotifierErrorMessage).IsAssignableFrom(ex.GetType())) |
||||||
|
{ |
||||||
|
return true; |
||||||
|
} |
||||||
|
return Handlers.Any(x => x.IsAssignableFrom(ex.GetType())); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||||
|
using Microsoft.Extensions.Options; |
||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Volo.Abp.ExceptionHandling; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling; |
||||||
|
|
||||||
|
public abstract class AbpExceptionSubscriberBase : ExceptionSubscriber |
||||||
|
{ |
||||||
|
protected IServiceScopeFactory ServiceScopeFactory { get; } |
||||||
|
protected AbpExceptionHandlingOptions Options { get; } |
||||||
|
protected IServiceProvider ServiceProvider { get; set; } |
||||||
|
protected readonly object ServiceProviderLock = new(); |
||||||
|
|
||||||
|
protected TService LazyGetRequiredService<TService>(ref TService reference) |
||||||
|
=> LazyGetRequiredService(typeof(TService), ref reference); |
||||||
|
|
||||||
|
protected TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference) |
||||||
|
{ |
||||||
|
if (reference == null) |
||||||
|
{ |
||||||
|
lock (ServiceProviderLock) |
||||||
|
{ |
||||||
|
if (reference == null) |
||||||
|
{ |
||||||
|
reference = (TRef)ServiceProvider.GetRequiredService(serviceType); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return reference; |
||||||
|
} |
||||||
|
|
||||||
|
protected ILoggerFactory LoggerFactory => LazyGetRequiredService(ref _loggerFactory); |
||||||
|
private ILoggerFactory _loggerFactory; |
||||||
|
|
||||||
|
protected ILogger Logger => _lazyLogger.Value; |
||||||
|
private Lazy<ILogger> _lazyLogger => new(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true); |
||||||
|
|
||||||
|
|
||||||
|
protected AbpExceptionSubscriberBase( |
||||||
|
IServiceScopeFactory serviceScopeFactory, |
||||||
|
IOptions<AbpExceptionHandlingOptions> options) |
||||||
|
{ |
||||||
|
Options = options.Value; |
||||||
|
ServiceScopeFactory = serviceScopeFactory; |
||||||
|
} |
||||||
|
|
||||||
|
public override async Task HandleAsync(ExceptionNotificationContext context) |
||||||
|
{ |
||||||
|
if (context.Handled && |
||||||
|
Options.HasNotifierError(context.Exception)) |
||||||
|
{ |
||||||
|
using (var scope = ServiceScopeFactory.CreateScope()) |
||||||
|
{ |
||||||
|
await SendErrorNotifierAsync( |
||||||
|
new ExceptionSendNotifierContext(scope.ServiceProvider, context.Exception, context.LogLevel)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract Task SendErrorNotifierAsync(ExceptionSendNotifierContext context); |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
using JetBrains.Annotations; |
||||||
|
using Microsoft.Extensions.Logging; |
||||||
|
using System; |
||||||
|
using Volo.Abp; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling; |
||||||
|
|
||||||
|
public class ExceptionSendNotifierContext |
||||||
|
{ |
||||||
|
[NotNull] |
||||||
|
public Exception Exception { get; } |
||||||
|
|
||||||
|
[NotNull] |
||||||
|
public IServiceProvider ServiceProvider { get; } |
||||||
|
|
||||||
|
public LogLevel LogLevel { get; } |
||||||
|
|
||||||
|
internal ExceptionSendNotifierContext( |
||||||
|
[NotNull] IServiceProvider serviceProvider, |
||||||
|
[NotNull] Exception exception, |
||||||
|
LogLevel? logLevel = null) |
||||||
|
{ |
||||||
|
ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider)); |
||||||
|
Exception = Check.NotNull(exception, nameof(exception)); |
||||||
|
LogLevel = logLevel ?? exception.GetLogLevel(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
namespace Sanhe.Abp.ExceptionHandling; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// 需要发送异常通知的自定义异常需要实现此接口。 |
||||||
|
/// </summary> |
||||||
|
public interface IHasNotifierErrorMessage |
||||||
|
{ |
||||||
|
|
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
using Volo.Abp.Localization; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.ExceptionHandling.Localization; |
||||||
|
|
||||||
|
[LocalizationResourceName("AbpExceptionHandling")] |
||||||
|
public class ExceptionHandlingResource |
||||||
|
{ |
||||||
|
} |
Loading…
Reference in new issue