Browse Source

增加全局异常通知处理模块

pull/10/head
cKey 6 years ago
parent
commit
9b16b2852b
  1. 8
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN.Abp.ExceptionHandling.Emailing.csproj
  2. 46
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN/Abp/ExceptionHandling/AbpEmailExceptionHandlingOptions.cs
  3. 10
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN/Abp/ExceptionHandling/AbpEmailingExceptionHandlingModule.cs
  4. 37
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN/Abp/ExceptionHandling/AbpEmailingExceptionSubscriber.cs
  5. 13
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN.Abp.ExceptionHandling.Notifications.csproj
  6. 12
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingNotificationDefinitionProvider.cs
  7. 7
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingNotificationNames.cs
  8. 9
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpNotificationsExceptionHandlingModule.cs
  9. 38
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpNotificationsExceptionSubscriber.cs
  10. 12
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN.Abp.ExceptionHandling.csproj
  11. 8
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingModule.cs
  12. 24
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingOptions.cs
  13. 68
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/AbpExceptionSubscriberBase.cs
  14. 27
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/ExceptionSendNotifierContext.cs
  15. 9
      aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/IHasNotifierErrorMessage.cs
  16. 75
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs
  17. 1
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj
  18. 8
      aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs

8
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN.Abp.ExceptionHandling.Emailing.csproj

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
</Project>

46
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN/Abp/ExceptionHandling/AbpEmailExceptionHandlingOptions.cs

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
namespace LINGYUN.Abp.ExceptionHandling
{
public class AbpEmailExceptionHandlingOptions
{
/// <summary>
/// 默认异常收件人
/// </summary>
public string DefaultReceiveEmail { get; set; }
/// <summary>
/// 异常类型指定收件人处理映射列表
/// </summary>
public IDictionary<Exception, string> Handlers { get; set; }
public AbpEmailExceptionHandlingOptions()
{
Handlers = new Dictionary<Exception, string>();
}
/// <summary>
/// 把需要接受异常通知的用户加进处理列表
/// </summary>
/// <param name="ex">处理的异常类型</param>
/// <param name="receivedEmails">接收邮件的用户类别,群发用,符号分隔</param>
public void HandReceivedException(Exception ex, string receivedEmails)
{
if (Handlers.ContainsKey(ex))
{
Handlers[ex] += receivedEmails;
}
else
{
Handlers.Add(ex, receivedEmails);
}
}
public string GetReceivedEmailOrDefault(Exception ex)
{
if (Handlers.TryGetValue(ex, out string receivedUsers))
{
return receivedUsers;
}
return DefaultReceiveEmail;
}
}
}

10
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN/Abp/ExceptionHandling/AbpEmailingExceptionHandlingModule.cs

@ -0,0 +1,10 @@
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ExceptionHandling.Emailing
{
[DependsOn(typeof(AbpExceptionHandlingModule))]
public class AbpEmailingExceptionHandlingModule : AbpModule
{
}
}

37
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Emailing/LINGYUN/Abp/ExceptionHandling/AbpEmailingExceptionSubscriber.cs

@ -0,0 +1,37 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.Emailing;
namespace LINGYUN.Abp.ExceptionHandling
{
public class AbpEmailingExceptionSubscriber : AbpExceptionSubscriberBase
{
protected IEmailSender EmailSender { get; }
protected AbpEmailExceptionHandlingOptions EmailOptions { get; }
public AbpEmailingExceptionSubscriber(
IEmailSender emailSender,
IServiceScopeFactory serviceScopeFactory,
IOptions<AbpExceptionHandlingOptions> options,
IOptions<AbpEmailExceptionHandlingOptions> emailOptions)
: base(serviceScopeFactory, options)
{
EmailSender = emailSender;
EmailOptions = emailOptions.Value;
}
protected override async Task SendErrorNotifierAsync(ExceptionSendNotifierContext context)
{
var receivedUsers = EmailOptions.GetReceivedEmailOrDefault(context.Exception);
if (!receivedUsers.IsNullOrWhiteSpace())
{
// TODO: 使用 Template 格式化推送
await EmailSender.SendAsync(receivedUsers,
context.Exception.GetType().FullName,
context.Exception.Message);
}
}
}
}

13
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN.Abp.ExceptionHandling.Notifications.csproj

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.ExceptionHandling\LINGYUN.Abp.ExceptionHandling.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" />
</ItemGroup>
</Project>

12
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingNotificationDefinitionProvider.cs

@ -0,0 +1,12 @@
using LINGYUN.Abp.Notifications;
namespace LINGYUN.Abp.ExceptionHandling
{
public class AbpExceptionHandlingNotificationDefinitionProvider : NotificationDefinitionProvider
{
public override void Define(INotificationDefinitionContext context)
{
context.Add(new NotificationDefinition(AbpExceptionHandlingNotificationNames.NotificationName));
}
}
}

7
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingNotificationNames.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Abp.ExceptionHandling
{
public class AbpExceptionHandlingNotificationNames
{
public const string NotificationName = "Abp.ExceptionHandling.Notifier";
}
}

9
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpNotificationsExceptionHandlingModule.cs

@ -0,0 +1,9 @@
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ExceptionHandling
{
[DependsOn(typeof(AbpExceptionHandlingModule))]
public class AbpNotificationsExceptionHandlingModule : AbpModule
{
}
}

38
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling.Notifications/LINGYUN/Abp/ExceptionHandling/AbpNotificationsExceptionSubscriber.cs

@ -0,0 +1,38 @@
using LINGYUN.Abp.Notifications;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.ExceptionHandling
{
public class AbpNotificationsExceptionSubscriber : AbpExceptionSubscriberBase
{
protected ICurrentTenant CurrentTenant { get; }
public AbpNotificationsExceptionSubscriber(
ICurrentTenant currentTenant,
IServiceScopeFactory serviceScopeFactory,
IOptions<AbpExceptionHandlingOptions> options)
: base(serviceScopeFactory, options)
{
CurrentTenant = currentTenant;
}
protected override async Task SendErrorNotifierAsync(ExceptionSendNotifierContext context)
{
var notificationDispatcher = context.ServiceProvider.GetRequiredService<INotificationDispatcher>();
var notificationName = NotificationNameNormalizer
.NormalizerName(AbpExceptionHandlingNotificationNames.NotificationName);
var notificationData = new NotificationData();
// 写入通知数据
//TODO:集成TextTemplate完成格式化的推送
notificationData.WriteStandardData(
context.Exception.GetType().FullName, context.Exception.Message,
DateTime.Now, "System");
await notificationDispatcher.DispatchAsync(notificationName, notificationData,
CurrentTenant.Id, NotificationSeverity.Error);
}
}
}

12
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN.Abp.ExceptionHandling.csproj

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Core" Version="2.9.0" />
</ItemGroup>
</Project>

8
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingModule.cs

@ -0,0 +1,8 @@
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.ExceptionHandling
{
public class AbpExceptionHandlingModule : AbpModule
{
}
}

24
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/AbpExceptionHandlingOptions.cs

@ -0,0 +1,24 @@
using System;
using System.Linq;
using Volo.Abp.Collections;
namespace LINGYUN.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()));
}
}
}

68
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/AbpExceptionSubscriberBase.cs

@ -0,0 +1,68 @@
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 LINGYUN.Abp.ExceptionHandling
{
public abstract class AbpExceptionSubscriberBase : ExceptionSubscriber
{
protected IServiceScopeFactory ServiceScopeFactory { get; }
protected AbpExceptionHandlingOptions Options { get; }
public IServiceProvider ServiceProvider { get; set; }
protected readonly object ServiceProviderLock = new object();
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 Lazy<ILogger>(() => 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
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/ExceptionSendNotifierContext.cs

@ -0,0 +1,27 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using System;
using Volo.Abp;
namespace LINGYUN.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
aspnet-core/modules/common/LINGYUN.Abp.ExceptionHandling/LINGYUN/Abp/ExceptionHandling/IHasNotifierErrorMessage.cs

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

75
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs

@ -1,75 +0,0 @@
using LINGYUN.Abp.Notifications;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;
namespace LINGYUN.Abp.MessageService.Controllers
{
[Route("api/app/notifications")]
public class NotificationController : AbpController
{
private readonly INotificationDispatcher _notificationDispatcher;
public NotificationController(
INotificationDispatcher notificationDispatcher)
{
_notificationDispatcher = notificationDispatcher;
}
[HttpGet]
[Route("Test")]
public async Task<Dictionary<string, object>> Test()
{
await Task.CompletedTask;
return new Dictionary<string, object>()
{
{"thing2", "测试标题" },
{"name3", "测试人员" },
};
}
[HttpPost]
[Route("Send")]
public async Task SendNofitication([FromBody] SendNotification notification)
{
var notificationData = new NotificationData();
notificationData.Properties["title"] = notification.Title;
notificationData.Properties["message"] = notification.Message;
notificationData.Properties["datetime"] = Clock.Now;
notificationData.Properties["severity"] = notification.Severity;
notificationData.Properties.AddIfNotContains(notification.Data);
var notificationName = NotificationNameNormalizer.NormalizerName("TestApplicationNotofication");
await _notificationDispatcher.DispatchAsync(notificationName, notificationData,
notificationSeverity: notification.Severity);
// await _notificationDispatcher.DispatcheAsync(notificationInfo);
}
}
public class SendNotification
{
public Guid UserId { get; set; }
public string Title { get; set; }
public string Message { get; set; }
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
public NotificationSeverity Severity { get; set; } = NotificationSeverity.Success;
}
public class TestApplicationNotificationData : NotificationData
{
public object Message
{
get { return this[nameof(Message)]; }
set
{
Properties[nameof(Message)] = value;
}
}
}
}

1
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj

@ -43,6 +43,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.ExceptionHandling.Notifications\LINGYUN.Abp.ExceptionHandling.Notifications.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.Hangfire.MySqlStorage\LINGYUN.Abp.Hangfire.Storage.MySql.csproj" /> <ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.Hangfire.MySqlStorage\LINGYUN.Abp.Hangfire.Storage.MySql.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.BackgroundJobs.Hangfire\LINGYUN.Abp.BackgroundJobs.Hangfire.csproj" /> <ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.BackgroundJobs.Hangfire\LINGYUN.Abp.BackgroundJobs.Hangfire.csproj" />
<ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj" /> <ProjectReference Include="..\..\..\modules\common\LINGYUN.Abp.EventBus.CAP\LINGYUN.Abp.EventBus.CAP.csproj" />

8
aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs

@ -3,6 +3,7 @@ using Hangfire;
using IdentityModel; using IdentityModel;
using LINGYUN.Abp.BackgroundJobs.Hangfire; using LINGYUN.Abp.BackgroundJobs.Hangfire;
using LINGYUN.Abp.EventBus.CAP; using LINGYUN.Abp.EventBus.CAP;
using LINGYUN.Abp.ExceptionHandling;
using LINGYUN.Abp.Hangfire.Storage.MySql; using LINGYUN.Abp.Hangfire.Storage.MySql;
using LINGYUN.Abp.IM.SignalR; using LINGYUN.Abp.IM.SignalR;
using LINGYUN.Abp.MessageService.BackgroundJobs; using LINGYUN.Abp.MessageService.BackgroundJobs;
@ -51,6 +52,7 @@ namespace LINGYUN.Abp.MessageService
typeof(AbpIMSignalRModule), typeof(AbpIMSignalRModule),
typeof(AbpNotificationsSignalRModule), typeof(AbpNotificationsSignalRModule),
typeof(AbpNotificationsWeChatWeAppModule), typeof(AbpNotificationsWeChatWeAppModule),
typeof(AbpNotificationsExceptionHandlingModule),
typeof(AbpCAPEventBusModule), typeof(AbpCAPEventBusModule),
typeof(AbpBackgroundJobsHangfireModule), typeof(AbpBackgroundJobsHangfireModule),
typeof(AbpHangfireMySqlStorageModule), typeof(AbpHangfireMySqlStorageModule),
@ -84,6 +86,12 @@ namespace LINGYUN.Abp.MessageService
options.UseMySQL(); options.UseMySQL();
}); });
Configure<AbpExceptionHandlingOptions>(options =>
{
// 加入需要处理的异常类型
// options.Handlers.Add<Volo.Abp.Authorization.AbpAuthorizationException>();
});
Configure<AbpDistributedCacheOptions>(options => Configure<AbpDistributedCacheOptions>(options =>
{ {
// 滑动过期30天 // 滑动过期30天

Loading…
Cancel
Save