Browse Source

ExceptionHandling

master
wwwk 3 years ago
parent
commit
e36e0c578f
  1. 14
      Sanhe.Abp.Framework.sln
  2. 3
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/FodyWeavers.xml
  3. 37
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/README.md
  4. 33
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe.Abp.ExceptionHandling.Emailing.csproj
  5. 73
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/AbpEmailExceptionHandlingOptions.cs
  6. 33
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/AbpEmailingExceptionHandlingModule.cs
  7. 68
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/AbpEmailingExceptionSubscriber.cs
  8. 8
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Localization/ExceptionHandlingResource.cs
  9. 8
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Localization/Resources/en.json
  10. 8
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Localization/Resources/zh-Hans.json
  11. 19
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/ExceptionHandlingTemplateDefinitionProvider.cs
  12. 6
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/ExceptionHandlingTemplates.cs
  13. 48
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/SendEmail/en.tpl
  14. 48
      modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/SendEmail/zh-Hans.tpl
  15. 3
      modules/common/Sanhe.Abp.ExceptionHandling/FodyWeavers.xml
  16. 26
      modules/common/Sanhe.Abp.ExceptionHandling/README.md
  17. 14
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe.Abp.ExceptionHandling.csproj
  18. 17
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/AbpExceptionHandlingModule.cs
  19. 24
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/AbpExceptionHandlingOptions.cs
  20. 66
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/AbpExceptionSubscriberBase.cs
  21. 27
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/ExceptionSendNotifierContext.cs
  22. 9
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/IHasNotifierErrorMessage.cs
  23. 8
      modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/Localization/ExceptionHandlingResource.cs
  24. 3
      services/book-store/BookStore.csproj
  25. 41
      services/book-store/BookStoreModule.cs
  26. 3
      services/book-store/Controllers/WrapController.cs
  27. 10
      services/book-store/Data/BookStoreDbMigrationService.cs
  28. 3
      services/book-store/Data/BookStoreEFCoreDbSchemaMigrator.cs
  29. 4
      services/book-store/Data/IdentityServerDataSeedContributor.cs
  30. 7
      services/book-store/Program.cs

14
Sanhe.Abp.Framework.sln

@ -21,6 +21,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "book-store", "book-store",
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BookStore", "services\book-store\BookStore.csproj", "{64178F61-A488-4182-A409-C32AE51E33A1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BookStore", "services\book-store\BookStore.csproj", "{64178F61-A488-4182-A409-C32AE51E33A1}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.ExceptionHandling", "modules\common\Sanhe.Abp.ExceptionHandling\Sanhe.Abp.ExceptionHandling.csproj", "{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sanhe.Abp.ExceptionHandling.Emailing", "modules\common\Sanhe.Abp.ExceptionHandling.Emailing\Sanhe.Abp.ExceptionHandling.Emailing.csproj", "{0692C2EA-7119-4065-8504-D7FDA70135A9}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -39,6 +43,14 @@ Global
{64178F61-A488-4182-A409-C32AE51E33A1}.Debug|Any CPU.Build.0 = Debug|Any CPU {64178F61-A488-4182-A409-C32AE51E33A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64178F61-A488-4182-A409-C32AE51E33A1}.Release|Any CPU.ActiveCfg = Release|Any CPU {64178F61-A488-4182-A409-C32AE51E33A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64178F61-A488-4182-A409-C32AE51E33A1}.Release|Any CPU.Build.0 = Release|Any CPU {64178F61-A488-4182-A409-C32AE51E33A1}.Release|Any CPU.Build.0 = Release|Any CPU
{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD}.Release|Any CPU.Build.0 = Release|Any CPU
{0692C2EA-7119-4065-8504-D7FDA70135A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0692C2EA-7119-4065-8504-D7FDA70135A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0692C2EA-7119-4065-8504-D7FDA70135A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0692C2EA-7119-4065-8504-D7FDA70135A9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -51,6 +63,8 @@ Global
{FDC1A6FC-DDAC-4119-9AF3-005F26030B94} = {2A768109-31B7-4C52-928C-3023DAB9F254} {FDC1A6FC-DDAC-4119-9AF3-005F26030B94} = {2A768109-31B7-4C52-928C-3023DAB9F254}
{928FDD8C-1EE8-455E-952F-11039B52FE03} = {BBE3B270-DF4F-47F5-9705-89FCFDE2779F} {928FDD8C-1EE8-455E-952F-11039B52FE03} = {BBE3B270-DF4F-47F5-9705-89FCFDE2779F}
{64178F61-A488-4182-A409-C32AE51E33A1} = {928FDD8C-1EE8-455E-952F-11039B52FE03} {64178F61-A488-4182-A409-C32AE51E33A1} = {928FDD8C-1EE8-455E-952F-11039B52FE03}
{FBEB7703-CF8A-4E5B-B1C7-ED9DC1ABC7BD} = {2A768109-31B7-4C52-928C-3023DAB9F254}
{0692C2EA-7119-4065-8504-D7FDA70135A9} = {2A768109-31B7-4C52-928C-3023DAB9F254}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB69BFDE-9DDB-4D16-8CB8-72472C0319CD} SolutionGuid = {AB69BFDE-9DDB-4D16-8CB8-72472C0319CD}

3
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

37
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/README.md

@ -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");
});
}
}
```

33
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe.Abp.ExceptionHandling.Emailing.csproj

@ -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>

73
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/AbpEmailExceptionHandlingOptions.cs

@ -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;
}
}

33
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/AbpEmailingExceptionHandlingModule.cs

@ -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");
});
}
}

68
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/AbpEmailingExceptionSubscriber.cs

@ -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;
}
}

8
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Localization/ExceptionHandlingResource.cs

@ -0,0 +1,8 @@
using Volo.Abp.Localization;
namespace Sanhe.Abp.ExceptionHandling.Emailing.Localization;
[LocalizationResourceName("AbpExceptionHandlingEmailing")]
public class ExceptionHandlingResource
{
}

8
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Localization/Resources/en.json

@ -0,0 +1,8 @@
{
"culture": "en",
"texts": {
"TextTemplate:ExceptionHandlingTemplates.SendEmail": "Apply the exception message sending template",
"SendEmailTitle": "Application exception push",
"SendEmailHeader": "Application exception"
}
}

8
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Localization/Resources/zh-Hans.json

@ -0,0 +1,8 @@
{
"culture": "zh-Hans",
"texts": {
"TextTemplate:ExceptionHandlingTemplates.SendEmail": "应用异常邮件发送模板",
"SendEmailTitle": "应用程序异常推送",
"SendEmailHeader": "应用程序异常"
}
}

19
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/ExceptionHandlingTemplateDefinitionProvider.cs

@ -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)
);
}
}

6
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/ExceptionHandlingTemplates.cs

@ -0,0 +1,6 @@
namespace Sanhe.Abp.ExceptionHandling.Emailing.Templates;
public class ExceptionHandlingTemplates
{
public const string SendEmail = "Abp.ExceptionHandling.SendEmail";
}

48
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/SendEmail/en.tpl

@ -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 &nbsp;:&nbsp;{{ model.type }}</li>
<li>Message &nbsp;:&nbsp;{{ model.message }}</li>
<li>Alarm level&nbsp;:&nbsp;{{ model.loglevel }}</li>
<li>TriggerTime&nbsp;:&nbsp;{{ 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>

48
modules/common/Sanhe.Abp.ExceptionHandling.Emailing/Sanhe/Abp/ExceptionHandling/Emailing/Templates/SendEmail/zh-Hans.tpl

@ -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>异常类型&nbsp;:&nbsp;{{ model.type }}</li>
<li>异常信息&nbsp;:&nbsp;{{ model.message }}</li>
<li>告警级别&nbsp;:&nbsp;{{ model.loglevel }}</li>
<li>触发时间&nbsp;:&nbsp;{{ 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>

3
modules/common/Sanhe.Abp.ExceptionHandling/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

26
modules/common/Sanhe.Abp.ExceptionHandling/README.md

@ -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>();
});
}
}
```

14
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe.Abp.ExceptionHandling.csproj

@ -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>

17
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/AbpExceptionHandlingModule.cs

@ -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");
});
}
}

24
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/AbpExceptionHandlingOptions.cs

@ -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()));
}
}

66
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/AbpExceptionSubscriberBase.cs

@ -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);
}

27
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/ExceptionSendNotifierContext.cs

@ -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();
}
}

9
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/IHasNotifierErrorMessage.cs

@ -0,0 +1,9 @@
namespace Sanhe.Abp.ExceptionHandling;
/// <summary>
/// 需要发送异常通知的自定义异常需要实现此接口。
/// </summary>
public interface IHasNotifierErrorMessage
{
}

8
modules/common/Sanhe.Abp.ExceptionHandling/Sanhe/Abp/ExceptionHandling/Localization/ExceptionHandlingResource.cs

@ -0,0 +1,8 @@
using Volo.Abp.Localization;
namespace Sanhe.Abp.ExceptionHandling.Localization;
[LocalizationResourceName("AbpExceptionHandling")]
public class ExceptionHandlingResource
{
}

3
services/book-store/BookStore.csproj

@ -2,8 +2,6 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@ -93,6 +91,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\modules\common\Sanhe.Abp.ExceptionHandling.Emailing\Sanhe.Abp.ExceptionHandling.Emailing.csproj" />
<ProjectReference Include="..\..\modules\mvc\Sanhe.Abp.AspNetCore.Mvc.Wrapper\Sanhe.Abp.AspNetCore.Mvc.Wrapper.csproj" /> <ProjectReference Include="..\..\modules\mvc\Sanhe.Abp.AspNetCore.Mvc.Wrapper\Sanhe.Abp.AspNetCore.Mvc.Wrapper.csproj" />
</ItemGroup> </ItemGroup>

41
services/book-store/BookStoreModule.cs

@ -1,11 +1,20 @@
using BookStore.Data; using BookStore.Data;
using BookStore.Localization; using BookStore.Localization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Sanhe.Abp.AspNetCore.Mvc.Wrapper; using Sanhe.Abp.AspNetCore.Mvc.Wrapper;
using Sanhe.Abp.ExceptionHandling;
using Sanhe.Abp.ExceptionHandling.Emailing;
using Sanhe.Abp.Wrapper; using Sanhe.Abp.Wrapper;
using StackExchange.Redis; using StackExchange.Redis;
using System;
using System.Linq;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Account; using Volo.Abp.Account;
using Volo.Abp.Account.Web; using Volo.Abp.Account.Web;
@ -21,7 +30,6 @@ using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.PostgreSql; using Volo.Abp.EntityFrameworkCore.PostgreSql;
using Volo.Abp.FeatureManagement; using Volo.Abp.FeatureManagement;
@ -96,7 +104,8 @@ namespace BookStore;
typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementHttpApiModule), typeof(AbpSettingManagementHttpApiModule),
typeof(AbpAspNetCoreMvcWrapperModule) typeof(AbpAspNetCoreMvcWrapperModule),
typeof(AbpEmailingExceptionHandlingModule)
)] )]
public class BookStoreModule : AbpModule public class BookStoreModule : AbpModule
{ {
@ -125,7 +134,7 @@ public class BookStoreModule : AbpModule
options.IsEnabled = true; options.IsEnabled = true;
options.IgnoreNamespaces.Clear(); options.IgnoreNamespaces.Clear();
}); });
ConfigureExceptionHandling();
ConfigureBundles(); ConfigureBundles();
ConfigureMultiTenancy(); ConfigureMultiTenancy();
ConfigureUrls(configuration); ConfigureUrls(configuration);
@ -140,6 +149,32 @@ public class BookStoreModule : AbpModule
ConfigureEfCore(context); ConfigureEfCore(context);
} }
private void ConfigureExceptionHandling()
{
// 自定义需要处理的异常
Configure<AbpExceptionHandlingOptions>(options =>
{
// 加入需要处理的异常类型
options.Handlers.Add<Volo.Abp.Data.AbpDbConcurrencyException>();
options.Handlers.Add<AbpInitializationException>();
options.Handlers.Add<ObjectDisposedException>();
options.Handlers.Add<StackOverflowException>();
options.Handlers.Add<OutOfMemoryException>();
options.Handlers.Add<System.Data.Common.DbException>();
options.Handlers.Add<Microsoft.EntityFrameworkCore.DbUpdateException>();
options.Handlers.Add<System.Data.DBConcurrencyException>();
});
// 自定义需要发送邮件通知的异常类型
Configure<AbpEmailExceptionHandlingOptions>(options =>
{
// 是否发送堆栈信息
options.SendStackTrace = true;
// 未指定异常接收者的默认接收邮件
// 请指定自己的邮件地址
// options.DefaultReceiveEmail = "";
});
}
private void ConfigureBundles() private void ConfigureBundles()
{ {
Configure<AbpBundlingOptions>(options => Configure<AbpBundlingOptions>(options =>

3
services/book-store/Controllers/WrapController.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Authorization; using Volo.Abp.Authorization;
@ -41,6 +42,6 @@ public class WrapController : AbpControllerBase
public class Person public class Person
{ {
public string? Name { get; set; } public string Name { get; set; }
public int Age { get; set; } public int Age { get; set; }
} }

10
services/book-store/Data/BookStoreDbMigrationService.cs

@ -1,6 +1,12 @@
using System.Diagnostics; using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity; using Volo.Abp.Identity;

3
services/book-store/Data/BookStoreEFCoreDbSchemaMigrator.cs

@ -1,4 +1,7 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace BookStore.Data; namespace BookStore.Data;

4
services/book-store/Data/IdentityServerDataSeedContributor.cs

@ -1,4 +1,8 @@
using IdentityServer4.Models; using IdentityServer4.Models;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions; using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;

7
services/book-store/Program.cs

@ -1,7 +1,12 @@
using System;
using BookStore.Data; using BookStore.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace BookStore; namespace BookStore;

Loading…
Cancel
Save