diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs index 9574f30717..2202e70cd1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpController.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.Aspects; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectMapping; @@ -11,7 +13,7 @@ using Volo.Abp.Users; namespace Volo.Abp.AspNetCore.Mvc { - public abstract class AbpController : Controller + public abstract class AbpController : Controller, IAvoidDuplicateCrossCuttingConcerns { public IUnitOfWorkManager UnitOfWorkManager { get; set; } @@ -29,6 +31,8 @@ namespace Volo.Abp.AspNetCore.Mvc public IClock Clock { get; set; } + public List AppliedCrossCuttingConcerns { get; } = new List(); + protected ILogger Logger => _lazyLogger.Value; private Lazy _lazyLogger => new Lazy(() => LoggerFactory?.CreateLogger(GetType().FullName) ?? NullLogger.Instance, true); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs index b18d155573..dd509b1746 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc.Auditing; using Volo.Abp.AspNetCore.Mvc.Conventions; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc.Uow; @@ -23,8 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc private static void AddFilters(MvcOptions options) { - //options.Filters.AddService(typeof(AbpAuthorizationFilter)); - //options.Filters.AddService(typeof(AbpAuditActionFilter)); + options.Filters.AddService(typeof(AbpAuditActionFilter)); options.Filters.AddService(typeof(AbpValidationActionFilter)); options.Filters.AddService(typeof(AbpUowActionFilter)); options.Filters.AddService(typeof(AbpExceptionFilter)); 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 new file mode 100644 index 0000000000..4f2abc198c --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; +using Volo.Abp.Aspects; +using Volo.Abp.Auditing; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.Auditing +{ + public class AbpAuditActionFilter : IAsyncActionFilter, ITransientDependency + { + protected AuditingOptions Options { get; } + private readonly IAuditingHelper _auditingHelper; + + public AbpAuditActionFilter(IOptions options, IAuditingHelper auditingHelper) + { + Options = options.Value; + _auditingHelper = auditingHelper; + } + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + if (!ShouldSaveAudit(context)) + { + await next(); + return; + } + + 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; + } + } + catch (Exception ex) + { + auditInfo.Exception = ex; + throw; + } + finally + { + stopwatch.Stop(); + auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditInfo.ServiceName = "AbpAuditActionFilter->" + auditInfo.ServiceName; + await _auditingHelper.SaveAsync(auditInfo); + } + } + } + + private bool ShouldSaveAudit(ActionExecutingContext actionContext) + { + return Options.IsEnabled && + actionContext.ActionDescriptor.IsControllerAction() && + _auditingHelper.ShouldSaveAudit(actionContext.ActionDescriptor.GetMethodInfo(), true); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/HttpContextClientInfoProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/HttpContextClientInfoProvider.cs new file mode 100644 index 0000000000..0b1d661330 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/HttpContextClientInfoProvider.cs @@ -0,0 +1,59 @@ +using System; +using Castle.Core.Logging; +using Microsoft.AspNetCore.Http; +using Volo.Abp.Auditing; + +namespace Volo.Abp.AspNetCore.Mvc.Auditing +{ + public class HttpContextClientInfoProvider : IClientInfoProvider + { + public string BrowserInfo => GetBrowserInfo(); + + public string ClientIpAddress => GetClientIpAddress(); + + public string ComputerName => GetComputerName(); + + public ILogger Logger { get; set; } + + private readonly IHttpContextAccessor _httpContextAccessor; + + private readonly HttpContext _httpContext; + + /// + /// Creates a new . + /// + public HttpContextClientInfoProvider(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + _httpContext = httpContextAccessor.HttpContext; + + Logger = NullLogger.Instance; + } + + protected virtual string GetBrowserInfo() + { + var httpContext = _httpContextAccessor.HttpContext ?? _httpContext; + return httpContext?.Request?.Headers?["User-Agent"]; + } + + protected virtual string GetClientIpAddress() + { + try + { + var httpContext = _httpContextAccessor.HttpContext ?? _httpContext; + return httpContext?.Connection?.RemoteIpAddress?.ToString(); + } + catch (Exception ex) + { + Logger.Warn(ex.ToString()); + } + + return null; + } + + protected virtual string GetComputerName() + { + return null; //TODO: Implement! + } + } +} 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..c3ed008dd2 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs @@ -47,6 +47,7 @@ namespace Volo.Abp.Auditing { stopwatch.Stop(); auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditInfo.ServiceName = "AuditingInterceptor->" + auditInfo.ServiceName; _auditingHelper.Save(auditInfo); } } @@ -83,6 +84,7 @@ namespace Volo.Abp.Auditing { stopwatch.Stop(); auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); + auditInfo.ServiceName = "AuditingInterceptor->" + auditInfo.ServiceName; await _auditingHelper.SaveAsync(auditInfo); } } 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 cea72e0f92..d778f2f597 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingOptions.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingOptions.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq.Expressions; namespace Volo.Abp.Auditing { @@ -15,7 +17,12 @@ namespace Volo.Abp.Auditing { IsEnabled = true; IsEnabledForAnonymousUsers = true; - IgnoredTypes = new List(); + + IgnoredTypes = new List + { + typeof(Stream), + typeof(Expression) + }; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs index 8d720363c5..47693be751 100644 --- a/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs +++ b/framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.Aspects; -using Volo.Abp.Authorization; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectMapping; @@ -20,9 +19,6 @@ namespace Volo.Abp.Application.Services { public static string[] CommonPostfixes { get; set; } = { "AppService", "ApplicationService", "Service" }; - /// - /// Gets the applied cross cutting concerns. - /// public List AppliedCrossCuttingConcerns { get; } = new List(); public IUnitOfWorkManager UnitOfWorkManager { get; set; } diff --git a/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyCompanyName.MyProjectName.Domain.csproj b/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyCompanyName.MyProjectName.Domain.csproj index d90a10cbc7..4602d90b59 100644 --- a/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyCompanyName.MyProjectName.Domain.csproj +++ b/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyCompanyName.MyProjectName.Domain.csproj @@ -7,6 +7,7 @@ + diff --git a/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyProjectNameDomainModule.cs b/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyProjectNameDomainModule.cs index 24c04cff1c..353ef75c1c 100644 --- a/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyProjectNameDomainModule.cs +++ b/templates/mvc/src/MyCompanyName.MyProjectName.Domain/MyProjectNameDomainModule.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using MyCompanyName.MyProjectName.Localization.MyProjectName; using MyCompanyName.MyProjectName.Settings; +using Volo.Abp.Auditing; using Volo.Abp.Identity; using Volo.Abp.Localization; using Volo.Abp.Localization.Resources.AbpValidation; @@ -10,7 +11,9 @@ using Volo.Abp.VirtualFileSystem; namespace MyCompanyName.MyProjectName { - [DependsOn(typeof(AbpIdentityDomainModule))] + [DependsOn( + typeof(AbpIdentityDomainModule), + typeof(AbpAuditingModule))] //TODO: Replace with AbpAuditLoggingDomainModule when it's done. public class MyProjectNameDomainModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context)