From 858f57f7f4f789255b3f3864868f5c85956f2a8e Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Mon, 9 Jul 2018 15:28:53 +0300 Subject: [PATCH] Redesigned audit logging. --- ...pNetCoreMvcApplicationBuilderExtensions.cs | 27 ------ .../Volo.Abp.AspNetCore.Mvc.csproj | 1 - .../AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 1 - .../Mvc/Auditing/AbpAuditActionFilter.cs | 58 ++++++++---- .../AspNetCore/Mvc/Uow/AbpUowActionFilter.cs | 4 +- .../AbpApplicationBuilderExtensions.cs | 28 ++++++ .../Volo.Abp.AspNetCore.csproj | 8 +- .../AspNetCore}/AbpActionInfoInHttpContext.cs | 2 +- .../Abp/AspNetCore/AbpAspNetCoreModule.cs | 24 ++++- .../Auditing/AbpUnitOfWorkMiddleware.cs | 33 +++++++ .../Auditing/HttpContextClientInfoProvider.cs | 2 +- .../AbpExceptionHandlingMiddleware.cs | 4 +- .../DefaultExceptionToErrorInfoConverter.cs | 0 .../DefaultHttpExceptionStatusCodeFinder.cs | 0 .../ExceptionHttpStatusCodeOptions.cs | 0 .../IExceptionToErrorInfoConverter.cs | 0 .../IHttpExceptionStatusCodeFinder.cs | 0 .../Uow/AbpUnitOfWorkMiddleware.cs | 6 +- .../Volo.Abp.Auditing.csproj | 1 + .../Volo/Abp/Auditing/AbpAuditingModule.cs | 4 + .../Volo/Abp/Auditing/AuditInfo.cs | 55 ------------ .../Auditing/AuditInfoContributionContext.cs | 17 ---- .../Volo/Abp/Auditing/AuditLogActionInfo.cs | 25 ++++++ .../Auditing/AuditLogContributionContext.cs | 18 ++++ .../Volo/Abp/Auditing/AuditLogContributor.cs | 9 ++ .../Volo/Abp/Auditing/AuditLogInfo.cs | 79 ++++++++++++++++ .../Volo/Abp/Auditing/AuditLogScope.cs | 12 +++ .../Volo/Abp/Auditing/AuditScope.cs | 10 +++ .../Volo/Abp/Auditing/AuditingHelper.cs | 47 +++++----- .../Volo/Abp/Auditing/AuditingInterceptor.cs | 70 +++++++++------ .../Volo/Abp/Auditing/AuditingManager.cs | 90 +++++++++++++++++++ .../Volo/Abp/Auditing/AuditingOptions.cs | 14 ++- .../Abp/Auditing/AuditingStoreExtensions.cs | 2 +- ...or.cs => ClientInfoAuditLogContributor.cs} | 4 +- .../Volo/Abp/Auditing/EntityChangeInfo.cs | 29 ++++++ .../Volo/Abp/Auditing}/EntityChangeType.cs | 2 +- .../Abp/Auditing/EntityPropertyChangeInfo.cs | 13 +++ .../Auditing/IAuditInfoContributionContext.cs | 9 -- .../Abp/Auditing/IAuditInfoContributor.cs | 9 -- .../Volo/Abp/Auditing/IAuditLogSaveHandle.cs | 12 +++ .../Volo/Abp/Auditing/IAuditingHelper.cs | 10 +-- .../Volo/Abp/Auditing/IAuditingManager.cs | 12 +++ .../Volo/Abp/Auditing/IAuditingStore.cs | 2 +- .../Abp/Auditing/SimpleLogAuditingStore.cs | 7 +- .../Generic/AbpDictionaryExtensions.cs | 15 ++++ .../Entities/Events/EntityChangeEntry.cs | 1 + .../Events/EntityChangeEventHelper.cs | 1 + .../Volo/Abp/Threading/AbpThreadingModule.cs | 1 + .../AmbientDataContextAmbientScopeProvider.cs | 86 ++++++++++++++++++ .../Threading/AsyncLocalAmbientDataContext.cs | 23 +++++ .../Volo/Abp/Threading/IAmbientDataContext.cs | 9 ++ .../Abp/Threading/IAmbientScopeProvider.cs | 11 +++ .../Mvc/AbpAspNetCoreMvcTestModule.cs | 1 + .../Abp/Auditing/AuditingInterceptor_Tests.cs | 15 ++-- .../MyProjectNameWebModule.cs | 2 + 55 files changed, 701 insertions(+), 224 deletions(-) delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Builder/AbpAspNetCoreMvcApplicationBuilderExtensions.cs rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/AbpActionInfoInHttpContext.cs (64%) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpUnitOfWorkMiddleware.cs rename framework/src/Volo.Abp.AspNetCore/{Microsoft => Volo/Abp}/AspNetCore/Auditing/HttpContextClientInfoProvider.cs (97%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/ExceptionHandling/AbpExceptionHandlingMiddleware.cs (96%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs (100%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs (100%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/ExceptionHandling/ExceptionHttpStatusCodeOptions.cs (100%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/ExceptionHandling/IExceptionToErrorInfoConverter.cs (100%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/ExceptionHandling/IHttpExceptionStatusCodeFinder.cs (100%) rename framework/src/{Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc => Volo.Abp.AspNetCore/Volo/Abp/AspNetCore}/Uow/AbpUnitOfWorkMiddleware.cs (77%) delete mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfo.cs delete mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfoContributionContext.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributionContext.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributor.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogScope.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditScope.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs rename framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/{ClientInfoAuditInfoContributor.cs => ClientInfoAuditLogContributor.cs} (84%) create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs rename framework/src/{Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events => Volo.Abp.Auditing/Volo/Abp/Auditing}/EntityChangeType.cs (74%) create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs delete mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributionContext.cs delete mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributor.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs create mode 100644 framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs create mode 100644 framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AmbientDataContextAmbientScopeProvider.cs create mode 100644 framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AsyncLocalAmbientDataContext.cs create mode 100644 framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientDataContext.cs create mode 100644 framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientScopeProvider.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Builder/AbpAspNetCoreMvcApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Builder/AbpAspNetCoreMvcApplicationBuilderExtensions.cs deleted file mode 100644 index 91d0df29bb..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Microsoft/AspNetCore/Builder/AbpAspNetCoreMvcApplicationBuilderExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; -using Volo.Abp.AspNetCore.Mvc.Uow; - -namespace Microsoft.AspNetCore.Builder -{ - public static class AbpAspNetCoreMvcApplicationBuilderExtensions - { - public static IApplicationBuilder UseUnitOfWork(this IApplicationBuilder app) - { - return app - .UseAbpExceptionHandling() - .UseMiddleware(); - } - - public static IApplicationBuilder UseAbpExceptionHandling(this IApplicationBuilder app) - { - //Prevent multiple add - if (app.Properties.ContainsKey("_AbpExceptionHandlingMiddleware_Added")) //TODO: Constant - { - return app; - } - - app.Properties["_AbpExceptionHandlingMiddleware_Added"] = true; - return app.UseMiddleware(); - } - } -} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj index 0cc5ebc49d..851d2b791d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo.Abp.AspNetCore.Mvc.csproj @@ -17,7 +17,6 @@ - diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 50b2d621c9..a5e3f0b0bf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -30,7 +30,6 @@ namespace Volo.Abp.AspNetCore.Mvc [DependsOn(typeof(AbpAspNetCoreModule))] [DependsOn(typeof(AbpLocalizationModule))] [DependsOn(typeof(AbpApiVersioningAbstractionsModule))] - [DependsOn(typeof(AbpHttpModule))] [DependsOn(typeof(AbpDddApplicationModule))] [DependsOn(typeof(AbpUiModule))] public class AbpAspNetCoreMvcModule : AbpModule diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs index 76907c4e65..660d979048 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs @@ -14,16 +14,18 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing { protected AuditingOptions Options { get; } private readonly IAuditingHelper _auditingHelper; + private readonly IAuditingManager _auditingManager; - public AbpAuditActionFilter(IOptions options, IAuditingHelper auditingHelper) + public AbpAuditActionFilter(IOptions options, IAuditingHelper auditingHelper, IAuditingManager auditingManager) { Options = options.Value; _auditingHelper = auditingHelper; + _auditingManager = auditingManager; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { - if (!ShouldSaveAudit(context)) + if (!ShouldSaveAudit(context, out var auditLog, out var auditLogAction)) { await next(); return; @@ -31,41 +33,65 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.Auditing)) { - var auditInfo = _auditingHelper.CreateAuditInfo( - context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(), - context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo, - context.ActionArguments - ); - var stopwatch = Stopwatch.StartNew(); try { var result = await next(); + if (result.Exception != null && !result.ExceptionHandled) { - auditInfo.Exception = result.Exception; + auditLog.Exceptions.Add(result.Exception); } } catch (Exception ex) { - auditInfo.Exception = ex; + auditLog.Exceptions.Add(ex); throw; } finally { stopwatch.Stop(); - auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - await _auditingHelper.SaveAsync(auditInfo); + auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditLog.Actions.Add(auditLogAction); } } } - private bool ShouldSaveAudit(ActionExecutingContext actionContext) + private bool ShouldSaveAudit(ActionExecutingContext context, out AuditLogInfo auditLog, out AuditLogActionInfo auditLogAction) { - return Options.IsEnabled && - actionContext.ActionDescriptor.IsControllerAction() && - _auditingHelper.ShouldSaveAudit(actionContext.ActionDescriptor.GetMethodInfo(), true); + auditLog = null; + auditLogAction = null; + + if (!Options.IsEnabled) + { + return false; + } + + if (!context.ActionDescriptor.IsControllerAction()) + { + return false; + } + + var auditLogScope = _auditingManager.Current; + if (auditLogScope == null) + { + return false; + } + + if (!_auditingHelper.ShouldSaveAudit(context.ActionDescriptor.GetMethodInfo(), true)) + { + return false; + } + + auditLog = auditLogScope.Log; + auditLogAction = _auditingHelper.CreateAuditLogAction( + context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(), + context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo, + context.ActionArguments + ); + + return true; } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs index 50029da296..5a330eb7a9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Options; +using Volo.Abp.AspNetCore.Uow; using Volo.Abp.DependencyInjection; using Volo.Abp.Uow; @@ -11,7 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow { public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency { - public const string UnitOfWorkReservationName = "_AbpActionUnitOfWork"; private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly UnitOfWorkDefaultOptions _defaultOptions; @@ -47,7 +47,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow var options = CreateOptions(context, unitOfWorkAttr); //Trying to begin a reserved UOW by AbpUnitOfWorkMiddleware - if (_unitOfWorkManager.TryBeginReserved(UnitOfWorkReservationName, options)) + if (_unitOfWorkManager.TryBeginReserved(AbpUnitOfWorkMiddleware.UnitOfWorkReservationName, options)) { var result = await next(); if (!Succeed(result)) diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs index 0e584d8536..61b5fc6455 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs @@ -1,6 +1,9 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; using Volo.Abp; +using Volo.Abp.AspNetCore.Auditing; +using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; +using Volo.Abp.AspNetCore.Uow; using Volo.Abp.DependencyInjection; namespace Microsoft.AspNetCore.Builder @@ -14,5 +17,30 @@ namespace Microsoft.AspNetCore.Builder app.ApplicationServices.GetRequiredService>().Value = app; app.ApplicationServices.GetRequiredService().Initialize(app.ApplicationServices); } + + public static IApplicationBuilder UseAuditing(this IApplicationBuilder app) + { + return app + .UseMiddleware(); + } + + public static IApplicationBuilder UseUnitOfWork(this IApplicationBuilder app) + { + return app + .UseAbpExceptionHandling() + .UseMiddleware(); + } + + public static IApplicationBuilder UseAbpExceptionHandling(this IApplicationBuilder app) + { + //Prevent multiple add + if (app.Properties.ContainsKey("_AbpExceptionHandlingMiddleware_Added")) //TODO: Constant + { + return app; + } + + app.Properties["_AbpExceptionHandlingMiddleware_Added"] = true; + return app.UseMiddleware(); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj index da63af44b6..541e917198 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj +++ b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj @@ -15,8 +15,14 @@ + + + + - + + + diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpActionInfoInHttpContext.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpActionInfoInHttpContext.cs similarity index 64% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpActionInfoInHttpContext.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpActionInfoInHttpContext.cs index 31620cbf5d..28853c2237 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpActionInfoInHttpContext.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpActionInfoInHttpContext.cs @@ -1,6 +1,6 @@ namespace Volo.Abp.AspNetCore.Mvc { - public class AbpActionInfoInHttpContext + public class AbpActionInfoInHttpContext //Rename? { public bool IsObjectResult { get; set; } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs index 724e7243c5..99b1dfd1ca 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/AbpAspNetCoreModule.cs @@ -1,15 +1,31 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Auditing; +using Volo.Abp.Authorization; +using Volo.Abp.Domain; +using Volo.Abp.Http; +using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Security; -using Volo.Abp.Threading; +using Volo.Abp.UI; +using Volo.Abp.Uow; +using Volo.Abp.Validation; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.AspNetCore { - [DependsOn(typeof(AbpThreadingModule))] - [DependsOn(typeof(AbpSecurityModule))] - [DependsOn(typeof(AbpVirtualFileSystemModule))] + [DependsOn( + typeof(AbpAuditingModule), + typeof(AbpSecurityModule), + typeof(AbpVirtualFileSystemModule), + typeof(AbpUnitOfWorkModule), + typeof(AbpHttpModule), + typeof(AbpAuthorizationModule), + typeof(AbpDddDomainModule), //TODO: Can we remove this? + typeof(AbpLocalizationModule), + typeof(AbpUiModule), //TODO: Can we remove this? + typeof(AbpValidationModule) + )] public class AbpAspNetCoreModule : IAbpModule { public void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpUnitOfWorkMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpUnitOfWorkMiddleware.cs new file mode 100644 index 0000000000..600d200ff9 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/AbpUnitOfWorkMiddleware.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Volo.Abp.Auditing; + +namespace Volo.Abp.AspNetCore.Auditing +{ + public class AbpAuditingMiddleware + { + private readonly RequestDelegate _next; + private readonly IAuditingManager _auditingManager; + + public AbpAuditingMiddleware(RequestDelegate next, IAuditingManager auditingManager) + { + _next = next; + _auditingManager = auditingManager; + } + + public async Task Invoke(HttpContext httpContext) + { + using (var scope = _auditingManager.BeginScope()) + { + try + { + await _next(httpContext); + } + finally + { + await scope.SaveAsync(); + } + } + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Auditing/HttpContextClientInfoProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/HttpContextClientInfoProvider.cs similarity index 97% rename from framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Auditing/HttpContextClientInfoProvider.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/HttpContextClientInfoProvider.cs index 07fb8a3a23..8cd1d30cc7 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Auditing/HttpContextClientInfoProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Auditing/HttpContextClientInfoProvider.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Auditing; -namespace Microsoft.AspNetCore.Auditing +namespace Volo.Abp.AspNetCore.Auditing { public class HttpContextClientInfoProvider : IClientInfoProvider { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionHandlingMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs similarity index 96% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionHandlingMiddleware.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs index fa611b426c..502fbda5bb 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionHandlingMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/AbpExceptionHandlingMiddleware.cs @@ -1,12 +1,10 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; -using Volo.Abp.AspNetCore.Mvc.Uow; +using Volo.Abp.AspNetCore.Uow; using Volo.Abp.Http; using Volo.Abp.Json; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultExceptionToErrorInfoConverter.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/DefaultHttpExceptionStatusCodeFinder.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionHttpStatusCodeOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/ExceptionHttpStatusCodeOptions.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/ExceptionHttpStatusCodeOptions.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/ExceptionHttpStatusCodeOptions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/IExceptionToErrorInfoConverter.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IExceptionToErrorInfoConverter.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/IExceptionToErrorInfoConverter.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IExceptionToErrorInfoConverter.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/IHttpExceptionStatusCodeFinder.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IHttpExceptionStatusCodeFinder.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/IHttpExceptionStatusCodeFinder.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ExceptionHandling/IHttpExceptionStatusCodeFinder.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs similarity index 77% rename from framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs rename to framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs index 3f63bf70e1..d2cb4685b9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Uow/AbpUnitOfWorkMiddleware.cs @@ -2,10 +2,12 @@ using Microsoft.AspNetCore.Http; using Volo.Abp.Uow; -namespace Volo.Abp.AspNetCore.Mvc.Uow +namespace Volo.Abp.AspNetCore.Uow { public class AbpUnitOfWorkMiddleware { + public const string UnitOfWorkReservationName = "_AbpActionUnitOfWork"; + private readonly RequestDelegate _next; private readonly IUnitOfWorkManager _unitOfWorkManager; @@ -17,7 +19,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow public async Task Invoke(HttpContext httpContext) { - using (var uow = _unitOfWorkManager.Reserve(AbpUowActionFilter.UnitOfWorkReservationName)) + using (var uow = _unitOfWorkManager.Reserve(UnitOfWorkReservationName)) { await _next(httpContext); await uow.CompleteAsync(httpContext.RequestAborted); diff --git a/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj b/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj index 428d905f6b..485b352227 100644 --- a/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj +++ b/framework/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj @@ -18,6 +18,7 @@ + diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs index 482fc9fa02..f76ba425ae 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs @@ -1,16 +1,20 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Data; +using Volo.Abp.Json; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.Security; +using Volo.Abp.Threading; using Volo.Abp.Timing; namespace Volo.Abp.Auditing { [DependsOn( typeof(AbpDataModule), + typeof(AbpJsonModule), typeof(AbpTimingModule), typeof(AbpSecurityModule), + typeof(AbpThreadingModule), typeof(AbpMultiTenancyAbstractionsModule) )] public class AbpAuditingModule : AbpModule diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfo.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfo.cs deleted file mode 100644 index 81e71e28ed..0000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using Volo.Abp.Data; - -namespace Volo.Abp.Auditing -{ - public class AuditInfo : IHasExtraProperties - { - public Guid? TenantId { get; set; } - - public Guid? UserId { get; set; } - - public Guid? ImpersonatorUserId { get; set; } - - public Guid? ImpersonatorTenantId { get; set; } - - public string ServiceName { get; set; } - - public string MethodName { get; set; } - - public string Parameters { get; set; } - - public DateTime ExecutionTime { get; set; } - - public int ExecutionDuration { get; set; } - - public string ClientIpAddress { get; set; } - - public string ClientName { get; set; } - - public string BrowserInfo { get; set; } - - public Exception Exception { get; set; } - - public Dictionary ExtraProperties { get; } - - public AuditInfo() - { - ExtraProperties = new Dictionary(); - } - - public override string ToString() - { - var loggedUserId = UserId.HasValue - ? "user " + UserId.Value - : "an anonymous user"; - - var exceptionOrSuccessMessage = Exception != null - ? "exception: " + Exception.Message - : "succeed"; - - return $"AUDIT LOG: {ServiceName}.{MethodName} is executed by {loggedUserId} in {ExecutionDuration} ms from {ClientIpAddress} IP address with {exceptionOrSuccessMessage}."; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfoContributionContext.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfoContributionContext.cs deleted file mode 100644 index 344e717cee..0000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditInfoContributionContext.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Volo.Abp.Auditing -{ - public class AuditInfoContributionContext : IAuditInfoContributionContext - { - public IServiceProvider ServiceProvider { get; } - - public AuditInfo AuditInfo { get; set; } - - public AuditInfoContributionContext(IServiceProvider serviceProvider, AuditInfo auditInfo) - { - ServiceProvider = serviceProvider; - AuditInfo = auditInfo; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs new file mode 100644 index 0000000000..abc8a9fcd0 --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.Auditing +{ + public class AuditLogActionInfo + { + public string ServiceName { get; set; } + + public string MethodName { get; set; } + + public string Parameters { get; set; } + + public DateTime ExecutionTime { get; set; } + + public int ExecutionDuration { get; set; } + + public Dictionary ExtraProperties { get; } + + public AuditLogActionInfo() + { + ExtraProperties = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributionContext.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributionContext.cs new file mode 100644 index 0000000000..d6e0c28344 --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributionContext.cs @@ -0,0 +1,18 @@ +using System; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Auditing +{ + public class AuditLogContributionContext : IServiceProviderAccessor + { + public IServiceProvider ServiceProvider { get; } + + public AuditLogInfo AuditInfo { get; } + + public AuditLogContributionContext(IServiceProvider serviceProvider, AuditLogInfo auditInfo) + { + ServiceProvider = serviceProvider; + AuditInfo = auditInfo; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributor.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributor.cs new file mode 100644 index 0000000000..b523e3a6e9 --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogContributor.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Auditing +{ + public abstract class AuditLogContributor + { + public abstract Task ContributeAsync(AuditLogContributionContext context); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs new file mode 100644 index 0000000000..887d45b5bf --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Auditing +{ + public class AuditLogInfo : IMultiTenant + { + public Guid? UserId { get; set; } + + public Guid? TenantId { get; set; } + + public Guid? ImpersonatorUserId { get; set; } + + public Guid? ImpersonatorTenantId { get; set; } + + public DateTime ExecutionTime { get; set; } + + public int ExecutionDuration { get; set; } + + public string ClientIpAddress { get; set; } + + public string ClientName { get; set; } + + public string BrowserInfo { get; set; } + + public List Actions { get; set; } + + public List Exceptions { get; } + + public Dictionary ExtraProperties { get; } + + public IList EntityChanges { get; } + + public AuditLogInfo() + { + Actions = new List(); + Exceptions = new List(); + ExtraProperties = new Dictionary(); + EntityChanges = new List(); + } + + public override string ToString() + { + var sb = new StringBuilder(); + + sb.AppendLine("AUDIT LOG:"); + sb.AppendLine($"- UserId : {UserId}"); + sb.AppendLine($"- ClientIpAddress : {ClientIpAddress}"); + sb.AppendLine($"- ExecutionDuration : {ExecutionDuration}"); + + if (Actions.Any()) + { + sb.AppendLine("- Actions:"); + foreach (var action in Actions) + { + sb.AppendLine($" - {action.ServiceName}.{action.MethodName} ({action.ExecutionDuration} ms.)"); + sb.AppendLine($" - {action.Parameters}"); + } + } + + if (Exceptions.Any()) + { + sb.AppendLine("- Exceptions:"); + foreach (var exception in Exceptions) + { + sb.AppendLine($" - {exception.Message}"); + sb.AppendLine($" - {exception}"); + } + } + + //TODO: EntityChanges + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogScope.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogScope.cs new file mode 100644 index 0000000000..a804f9a99a --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogScope.cs @@ -0,0 +1,12 @@ +namespace Volo.Abp.Auditing +{ + public class AuditLogScope : IAuditLogScope + { + public AuditLogInfo Log { get; } + + public AuditLogScope(AuditLogInfo log) + { + Log = log; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditScope.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditScope.cs new file mode 100644 index 0000000000..23277c625a --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditScope.cs @@ -0,0 +1,10 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.Auditing +{ + public interface IAuditLogScope + { + [NotNull] + AuditLogInfo Log { get; } + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs index 775c84bdb9..677a24a095 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -89,19 +88,31 @@ namespace Volo.Abp.Auditing return defaultValue; } - public virtual AuditInfo CreateAuditInfo(Type type, MethodInfo method, object[] arguments) + public virtual AuditLogInfo CreateAuditLogInfo() { - return CreateAuditInfo(type, method, CreateArgumentsDictionary(method, arguments)); - } - - public virtual AuditInfo CreateAuditInfo(Type type, MethodInfo method, IDictionary arguments) - { - var auditInfo = new AuditInfo + var auditInfo = new AuditLogInfo { TenantId = CurrentTenant.Id, UserId = CurrentUser.Id, //ImpersonatorUserId = AbpSession.ImpersonatorUserId, //TODO: Impersonation system is not available yet! //ImpersonatorTenantId = AbpSession.ImpersonatorTenantId, + ExecutionTime = Clock.Now + }; + + ExecuteContributors(auditInfo); + + return auditInfo; + } + + public virtual AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, object[] arguments) + { + return CreateAuditLogAction(type, method, CreateArgumentsDictionary(method, arguments)); + } + + public virtual AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, IDictionary arguments) + { + var actionInfo = new AuditLogActionInfo + { ServiceName = type != null ? type.FullName : "", @@ -110,22 +121,22 @@ namespace Volo.Abp.Auditing ExecutionTime = Clock.Now }; - ExecuteContributors(auditInfo); + //TODO Execute contributors - return auditInfo; + return actionInfo; } - protected virtual void ExecuteContributors(AuditInfo auditInfo) + protected virtual void ExecuteContributors(AuditLogInfo auditLogInfo) { using (var scope = ServiceProvider.CreateScope()) { - var context = new AuditInfoContributionContext(scope.ServiceProvider, auditInfo); + var context = new AuditLogContributionContext(scope.ServiceProvider, auditLogInfo); foreach (var contributor in Options.Contributors) { try { - contributor.Contribute(context); + contributor.ContributeAsync(context); } catch (Exception ex) { @@ -135,16 +146,6 @@ namespace Volo.Abp.Auditing } } - public virtual void Save(AuditInfo auditInfo) - { - AuditingStore.Save(auditInfo); - } - - public virtual async Task SaveAsync(AuditInfo auditInfo) - { - await AuditingStore.SaveAsync(auditInfo); - } - protected virtual string SerializeConvertArguments(IDictionary arguments) { try diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs index 94df027751..0db0b7bb98 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs @@ -10,28 +10,22 @@ namespace Volo.Abp.Auditing public class AuditingInterceptor : AbpInterceptor, ITransientDependency { private readonly IAuditingHelper _auditingHelper; + private readonly IAuditingManager _auditingManager; - public AuditingInterceptor(IAuditingHelper auditingHelper) + public AuditingInterceptor(IAuditingHelper auditingHelper, IAuditingManager auditingManager) { _auditingHelper = auditingHelper; + _auditingManager = auditingManager; } public override void Intercept(IAbpMethodInvocation invocation) { - if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.Auditing)) + if (!ShouldIntercept(invocation, out var auditLog, out var auditLogAction)) { invocation.Proceed(); return; } - if (!_auditingHelper.ShouldSaveAudit(invocation.Method)) - { - invocation.Proceed(); - return; - } - - var auditInfo = _auditingHelper.CreateAuditInfo(invocation.TargetObject.GetType(), invocation.Method, invocation.Arguments); - var stopwatch = Stopwatch.StartNew(); try @@ -40,35 +34,25 @@ namespace Volo.Abp.Auditing } catch (Exception ex) { - auditInfo.Exception = ex; + auditLog.Exceptions.Add(ex); throw; } finally { stopwatch.Stop(); - auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - _auditingHelper.Save(auditInfo); + auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditLog.Actions.Add(auditLogAction); } } public override async Task InterceptAsync(IAbpMethodInvocation invocation) { - //Try to reduce duplication with Intercept - - if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.Auditing)) + if (!ShouldIntercept(invocation, out var auditLog, out var auditLogAction)) { - await invocation.ProceedAsync(); - return; - } - - if (!_auditingHelper.ShouldSaveAudit(invocation.Method)) - { - await invocation.ProceedAsync(); + invocation.Proceed(); return; } - var auditInfo = _auditingHelper.CreateAuditInfo(invocation.TargetObject.GetType(), invocation.Method, invocation.Arguments); - var stopwatch = Stopwatch.StartNew(); try @@ -77,14 +61,44 @@ namespace Volo.Abp.Auditing } catch (Exception ex) { - auditInfo.Exception = ex; + auditLog.Exceptions.Add(ex); + throw; } finally { stopwatch.Stop(); - auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); - await _auditingHelper.SaveAsync(auditInfo); + auditLogAction.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditLog.Actions.Add(auditLogAction); + } + } + + protected virtual bool ShouldIntercept(IAbpMethodInvocation invocation, out AuditLogInfo auditLog, out AuditLogActionInfo auditLogAction) + { + auditLog = null; + auditLogAction = null; + + if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.Auditing)) + { + return false; } + + var auditLogScope = _auditingManager.Current; + if (auditLogScope == null) + { + return false; + } + + if (!_auditingHelper.ShouldSaveAudit(invocation.Method)) + { + return false; + } + + auditLog = auditLogScope.Log; + auditLogAction = _auditingHelper.CreateAuditLogAction( + invocation.TargetObject.GetType(), invocation.Method, invocation.Arguments + ); + + return true; } } } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs new file mode 100644 index 0000000000..6d3a982e4f --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; + +namespace Volo.Abp.Auditing +{ + public class AuditingManager : IAuditingManager, ITransientDependency + { + private const string AmbientContextKey = "Volo.Abp.Auditing.IAuditLogScope"; + + private readonly IAmbientScopeProvider _ambientScopeProvider; + private readonly IAuditingHelper _auditingHelper; + private readonly IAuditingStore _auditingStore; + + public AuditingManager( + IAmbientScopeProvider ambientScopeProvider, + IAuditingHelper auditingHelper, + IAuditingStore auditingStore) + { + _ambientScopeProvider = ambientScopeProvider; + _auditingHelper = auditingHelper; + _auditingStore = auditingStore; + } + + public IAuditLogScope Current => _ambientScopeProvider.GetValue(AmbientContextKey); + + public IAuditLogSaveHandle BeginScope() + { + var ambientScope = _ambientScopeProvider.BeginScope( + AmbientContextKey, + new AuditLogScope(_auditingHelper.CreateAuditLogInfo()) + ); + + Debug.Assert(Current != null, "Current != null"); + + var stopWatch = Stopwatch.StartNew(); + + return new DisposableSaveHandle(_auditingStore, ambientScope, Current.Log, stopWatch); + } + + private class DisposableSaveHandle : IAuditLogSaveHandle + { + private readonly IAuditingStore _auditingStore; + private readonly IDisposable _scope; + private readonly AuditLogInfo _auditLog; + private readonly Stopwatch _stopWatch; + + private bool _saved; + + public DisposableSaveHandle(IAuditingStore auditingStore, IDisposable scope, AuditLogInfo auditLog, Stopwatch stopWatch) + { + _auditingStore = auditingStore; + _scope = scope; + _auditLog = auditLog; + _stopWatch = stopWatch; + } + + private void BeforeSave() + { + _stopWatch.Stop(); + _saved = true; + _auditLog.ExecutionDuration = Convert.ToInt32(_stopWatch.Elapsed.TotalMilliseconds); + } + + public async Task SaveAsync() + { + BeforeSave(); + await _auditingStore.SaveAsync(_auditLog); + } + + public void Save() + { + BeforeSave(); + _auditingStore.Save(_auditLog); + } + + public void Dispose() + { + if (!_saved) + { + Save(); + } + + _scope.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingOptions.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingOptions.cs index e9e1aeb9d8..e4abafa949 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingOptions.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingOptions.cs @@ -7,11 +7,19 @@ namespace Volo.Abp.Auditing { public class AuditingOptions { + //TODO: Consider to add an option to disable auditing for application service methods? + + /// + /// Default: true. + /// public bool IsEnabled { get; set; } + /// + /// Default: true. + /// public bool IsEnabledForAnonymousUsers { get; set; } - public List Contributors { get; } + public List Contributors { get; } public List IgnoredTypes { get; } @@ -20,9 +28,9 @@ namespace Volo.Abp.Auditing IsEnabled = true; IsEnabledForAnonymousUsers = true; - Contributors = new List + Contributors = new List { - new ClientInfoAuditInfoContributor() + new ClientInfoAuditLogContributor() }; IgnoredTypes = new List diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingStoreExtensions.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingStoreExtensions.cs index 3fdfc0e3ab..f08dcc14b6 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingStoreExtensions.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingStoreExtensions.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Auditing { public static class AuditingStoreExtensions { - public static void Save(this IAuditingStore auditingStore, AuditInfo auditInfo) + public static void Save(this IAuditingStore auditingStore, AuditLogInfo auditInfo) { AsyncHelper.RunSync(() => auditingStore.SaveAsync(auditInfo)); } diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ClientInfoAuditInfoContributor.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ClientInfoAuditLogContributor.cs similarity index 84% rename from framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ClientInfoAuditInfoContributor.cs rename to framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ClientInfoAuditLogContributor.cs index 158b04618f..9d1fd9f10a 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ClientInfoAuditInfoContributor.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/ClientInfoAuditLogContributor.cs @@ -4,9 +4,9 @@ using Microsoft.Extensions.DependencyInjection; namespace Volo.Abp.Auditing { - public class ClientInfoAuditInfoContributor : IAuditInfoContributor + public class ClientInfoAuditLogContributor : AuditLogContributor { - public Task Contribute(IAuditInfoContributionContext context) + public override Task ContributeAsync(AuditLogContributionContext context) { var clientInfoProvider = context.ServiceProvider.GetRequiredService(); diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs new file mode 100644 index 0000000000..d931cfb789 --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Auditing +{ + public class EntityChangeInfo : IMultiTenant + { + public DateTime ChangeTime { get; set; } + + public EntityChangeType ChangeType { get; set; } + + public string EntityId { get; set; } + + public string EntityTypeFullName { get; set; } + + public Guid? TenantId { get; set; } + + public ICollection PropertyChanges { get; set; } + + #region Not mapped + + [NotMapped] + public virtual object EntityEntry { get; set; } //TODO: ??? + + #endregion + } +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeType.cs similarity index 74% rename from framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs rename to framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeType.cs index 152745d2a7..3cb57e47ad 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeType.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeType.cs @@ -1,4 +1,4 @@ -namespace Volo.Abp.Domain.Entities.Events +namespace Volo.Abp.Auditing { public enum EntityChangeType : byte { diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs new file mode 100644 index 0000000000..2a68fb3da6 --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs @@ -0,0 +1,13 @@ +namespace Volo.Abp.Auditing +{ + public class EntityPropertyChangeInfo + { + public virtual string NewValue { get; set; } + + public virtual string OriginalValue { get; set; } + + public virtual string PropertyName { get; set; } + + public virtual string PropertyTypeFullName { get; set; } + } +} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributionContext.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributionContext.cs deleted file mode 100644 index d562e57417..0000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributionContext.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.Auditing -{ - public interface IAuditInfoContributionContext : IServiceProviderAccessor - { - AuditInfo AuditInfo { get; set; } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributor.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributor.cs deleted file mode 100644 index 19299522ea..0000000000 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditInfoContributor.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace Volo.Abp.Auditing -{ - public interface IAuditInfoContributor - { - Task Contribute(IAuditInfoContributionContext context); - } -} diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs new file mode 100644 index 0000000000..596f67523a --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditLogSaveHandle.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; + +namespace Volo.Abp.Auditing +{ + public interface IAuditLogSaveHandle : IDisposable + { + void Save(); + + Task SaveAsync(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs index 0cdf850afc..bdc3aadff0 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs @@ -1,20 +1,18 @@ using System; using System.Collections.Generic; using System.Reflection; -using System.Threading.Tasks; namespace Volo.Abp.Auditing { + //TODO: Move ShouldSaveAudit and rename to IAuditingFactory public interface IAuditingHelper { bool ShouldSaveAudit(MethodInfo methodInfo, bool defaultValue = false); - AuditInfo CreateAuditInfo(Type type, MethodInfo method, object[] arguments); + AuditLogInfo CreateAuditLogInfo(); - AuditInfo CreateAuditInfo(Type type, MethodInfo method, IDictionary arguments); + AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, object[] arguments); - void Save(AuditInfo auditInfo); - - Task SaveAsync(AuditInfo auditInfo); + AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, IDictionary arguments); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs new file mode 100644 index 0000000000..6681b12e4b --- /dev/null +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingManager.cs @@ -0,0 +1,12 @@ +using JetBrains.Annotations; + +namespace Volo.Abp.Auditing +{ + public interface IAuditingManager + { + [CanBeNull] + IAuditLogScope Current { get; } + + IAuditLogSaveHandle BeginScope(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs index 561878136d..7166af642b 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingStore.cs @@ -4,6 +4,6 @@ namespace Volo.Abp.Auditing { public interface IAuditingStore { - Task SaveAsync(AuditInfo auditInfo); + Task SaveAsync(AuditLogInfo auditInfo); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs index 4737f5827c..4c0450d565 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/SimpleLogAuditingStore.cs @@ -15,12 +15,9 @@ namespace Volo.Abp.Auditing Logger = NullLogger.Instance; } - public Task SaveAsync(AuditInfo auditInfo) + public Task SaveAsync(AuditLogInfo auditInfo) { - Logger.LogWithLevel( - auditInfo.Exception == null ? LogLevel.Information : LogLevel.Warning, - auditInfo.ToString() - ); + Logger.LogInformation(auditInfo.ToString()); return Task.FromResult(0); } diff --git a/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpDictionaryExtensions.cs b/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpDictionaryExtensions.cs index 488294c77f..2d2ae9d6dc 100644 --- a/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpDictionaryExtensions.cs +++ b/framework/src/Volo.Abp.Core/System/Collections/Generic/AbpDictionaryExtensions.cs @@ -1,3 +1,5 @@ +using System.Collections.Concurrent; + namespace System.Collections.Generic { /// @@ -65,6 +67,19 @@ namespace System.Collections.Generic { return dictionary.TryGetValue(key, out var obj) ? obj : default; } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrDefault(this ConcurrentDictionary dictionary, TKey key) + { + return dictionary.TryGetValue(key, out var obj) ? obj : default; + } /// /// Gets a value from the dictionary with given key. Returns default value if can not find. diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs index 844bf2a421..e4c03ff32a 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEntry.cs @@ -1,4 +1,5 @@ using System; +using Volo.Abp.Auditing; namespace Volo.Abp.Domain.Entities.Events { diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index 9f4fe25fcf..832f511eaa 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; using Volo.Abp.DynamicProxy; using Volo.Abp.EventBus; diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpThreadingModule.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpThreadingModule.cs index 226ec6d5fb..21b89d9db2 100644 --- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpThreadingModule.cs +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpThreadingModule.cs @@ -8,6 +8,7 @@ namespace Volo.Abp.Threading public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddSingleton(NullCancellationTokenProvider.Instance); + context.Services.AddSingleton(typeof(IAmbientScopeProvider<>), typeof(AmbientDataContextAmbientScopeProvider<>)); context.Services.AddAssemblyOf(); } diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AmbientDataContextAmbientScopeProvider.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AmbientDataContextAmbientScopeProvider.cs new file mode 100644 index 0000000000..822361638e --- /dev/null +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AmbientDataContextAmbientScopeProvider.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using JetBrains.Annotations; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; + +namespace Volo.Abp.Threading +{ + public class AmbientDataContextAmbientScopeProvider : IAmbientScopeProvider + { + public ILogger> Logger { get; set; } + + private static readonly ConcurrentDictionary ScopeDictionary = new ConcurrentDictionary(); + + private readonly IAmbientDataContext _dataContext; + + public AmbientDataContextAmbientScopeProvider([NotNull] IAmbientDataContext dataContext) + { + Check.NotNull(dataContext, nameof(dataContext)); + + _dataContext = dataContext; + + Logger = NullLogger>.Instance; + } + + public T GetValue(string contextKey) + { + var item = GetCurrentItem(contextKey); + if (item == null) + { + return default; + } + + return item.Value; + } + + public IDisposable BeginScope(string contextKey, T value) + { + var item = new ScopeItem(value, GetCurrentItem(contextKey)); + + if (!ScopeDictionary.TryAdd(item.Id, item)) + { + throw new AbpException("Can not add item! ScopeDictionary.TryAdd returns false!"); + } + + _dataContext.SetData(contextKey, item.Id); + + return new DisposeAction(() => + { + ScopeDictionary.TryRemove(item.Id, out item); + + if (item.Outer == null) + { + _dataContext.SetData(contextKey, null); + return; + } + + _dataContext.SetData(contextKey, item.Outer.Id); + }); + } + + private ScopeItem GetCurrentItem(string contextKey) + { + var objKey = _dataContext.GetData(contextKey) as string; + return objKey != null ? ScopeDictionary.GetOrDefault(objKey) : null; + } + + private class ScopeItem + { + public string Id { get; } + + public ScopeItem Outer { get; } + + public T Value { get; } + + public ScopeItem(T value, ScopeItem outer = null) + { + Id = Guid.NewGuid().ToString(); + + Value = value; + Outer = outer; + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AsyncLocalAmbientDataContext.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AsyncLocalAmbientDataContext.cs new file mode 100644 index 0000000000..87fc3d6a3a --- /dev/null +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AsyncLocalAmbientDataContext.cs @@ -0,0 +1,23 @@ +using System.Collections.Concurrent; +using System.Threading; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Threading +{ + public class AsyncLocalAmbientDataContext : IAmbientDataContext, ISingletonDependency + { + private static readonly ConcurrentDictionary> AsyncLocalDictionary = new ConcurrentDictionary>(); + + public void SetData(string key, object value) + { + var asyncLocal = AsyncLocalDictionary.GetOrAdd(key, (k) => new AsyncLocal()); + asyncLocal.Value = value; + } + + public object GetData(string key) + { + var asyncLocal = AsyncLocalDictionary.GetOrAdd(key, (k) => new AsyncLocal()); + return asyncLocal.Value; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientDataContext.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientDataContext.cs new file mode 100644 index 0000000000..bc137f72ed --- /dev/null +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientDataContext.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.Threading +{ + public interface IAmbientDataContext + { + void SetData(string key, object value); + + object GetData(string key); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientScopeProvider.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientScopeProvider.cs new file mode 100644 index 0000000000..50847695b4 --- /dev/null +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/IAmbientScopeProvider.cs @@ -0,0 +1,11 @@ +using System; + +namespace Volo.Abp.Threading +{ + public interface IAmbientScopeProvider + { + T GetValue(string contextKey); + + IDisposable BeginScope(string contextKey, T value); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs index 7d618e73db..f8e9989a34 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs @@ -56,6 +56,7 @@ namespace Volo.Abp.AspNetCore.Mvc var app = context.GetApplicationBuilder(); app.UseMiddleware(); + app.UseAuditing(); app.UseUnitOfWork(); app.UseMvcWithDefaultRoute(); } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs index 7a6c8f6d18..b32d94e1e1 100644 --- a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditingInterceptor_Tests.cs @@ -12,10 +12,11 @@ namespace Volo.Abp.Auditing public class AuditingInterceptor_Tests : AbpIntegratedTest { private IAuditingStore _auditingStore; + private IAuditingManager _auditingManager; public AuditingInterceptor_Tests() { - + _auditingManager = GetRequiredService(); } protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) @@ -33,11 +34,15 @@ namespace Volo.Abp.Auditing public async Task Should_Write_AuditLog_For_Classes_That_Implement_IAuditingEnabled() { var myAuditedObject1 = GetRequiredService(); - await myAuditedObject1.DoItAsync(new InputObject {Value1 = "fourty-two", Value2 = 42}); - #pragma warning disable 4014 - _auditingStore.Received().SaveAsync(Arg.Any()); - #pragma warning restore 4014 + using (_auditingManager.BeginScope()) + { + await myAuditedObject1.DoItAsync(new InputObject { Value1 = "fourty-two", Value2 = 42 }); + } + +#pragma warning disable 4014 + _auditingStore.Received().SaveAsync(Arg.Any()); +#pragma warning restore 4014 } [DependsOn( diff --git a/templates/mvc/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs b/templates/mvc/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs index 36e92b3b30..d4697b9948 100644 --- a/templates/mvc/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs +++ b/templates/mvc/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs @@ -189,6 +189,8 @@ namespace MyCompanyName.MyProjectName options.SwaggerEndpoint("/swagger/v1/swagger.json", "MyProjectName API"); }); + app.UseAuditing(); + app.UseMvc(routes => { routes.MapRoute(