• 审计日志中的AOP


    审计跟踪(也称为审核日志)是一个安全相关的时间顺序记录,记录这些记录的目的是为已经影响在任何时候的详细操作,提供程序运行的证明文件记录、源或事件

    MVC

    自定义一个过滤器

    public class AuditFilter : IActionFilter
    {
        /// <summary>
        ///     在执行操作方法后调用。
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            var auditData = AbpAuditFilterData.GetOrNull(filterContext.HttpContext);
            if (auditData == null)
                return;
            auditData.Stopwatch.Stop();
            var path = AppDomain.CurrentDomain.BaseDirectory + "log.txt";
            if (filterContext.Exception != null)
                File.AppendAllText(path,
                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "异常:" + filterContext.Exception + "
    ");
            else
                File.AppendAllText(path,
                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "耗时:" +
                    Convert.ToInt32(auditData.Stopwatch.Elapsed.TotalMilliseconds) + "
    ");
        }
        /// <summary>
        ///     在执行操作方法之前调用。
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var actionStopwatch = Stopwatch.StartNew();
            AbpAuditFilterData.Set(
                filterContext.HttpContext,
                new AbpAuditFilterData(actionStopwatch)
            );
        }
    }
    

    定义一个数据存储

    public class AbpAuditFilterData
    {
        private const string AbpAuditFilterDataHttpContextKey = "__AbpAuditFilterData";
    
    
        public AbpAuditFilterData(
            Stopwatch stopwatch)
        {
            Stopwatch = stopwatch;
        }
    
        public Stopwatch Stopwatch { get; }
    
        public static void Set(HttpContextBase httpContext, AbpAuditFilterData auditFilterData)
        {
            GetAuditDataStack(httpContext).Push(auditFilterData);
        }
    
        public static AbpAuditFilterData GetOrNull(HttpContextBase httpContext)
        {
            var stack = GetAuditDataStack(httpContext);
            return stack.Count <= 0
                ? null
                : stack.Pop();
        }
    
        /// <summary>
        ///     获取一个可变大小的后进先出 (LIFO) 集合
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        private static Stack<AbpAuditFilterData> GetAuditDataStack(HttpContextBase httpContext)
        {
            if (httpContext.Items[AbpAuditFilterDataHttpContextKey] is Stack<AbpAuditFilterData> stack)
                return stack;
            stack = new Stack<AbpAuditFilterData>();
            httpContext.Items[AbpAuditFilterDataHttpContextKey] = stack;
            return stack;
        }
    }
    

    HomeController 如下

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var a = 0;
            for (var i = 0; i < 10000; i++)
                for (var j = 0; j < 10000; j++)
                    a = i - j;
            ViewBag.A = a;
            return View();
        }
    
        public ActionResult About()
        {
            var a = Convert.ToInt32("a");
            ViewBag.Message = "Your application description page.";
    
            return View();
        }
    }
    

    访问home/index 日志记录如下:

    2018-01-22 19:11:09耗时:342
    
    

    访问home/about 日志记录如下:

    image

    Web Api

    自定义过滤器

    public class AuditFilter : IActionFilter
    {
        //
        // 摘要:
        //     获取或设置一个值,该值指示是否可以为单个程序元素指定多个已指示特性的实例。
        //
        // 返回结果:
        //     如果可以指定多个实例,则为 true;否则为 false。默认值为 false。
        public bool AllowMultiple => false;
    
        /// <summary>
        /// 异步执行筛选器操作
        /// </summary>
        /// <param name="actionContext"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="continuation"></param>
        /// <returns></returns>
        public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
        {
            var method = actionContext.ActionDescriptor is ReflectedHttpActionDescriptor descriptor ? descriptor.MethodInfo : null;
            var str = $"{actionContext.ActionDescriptor.ControllerDescriptor.ControllerType.Name}/{method?.Name}/{JsonConvert.SerializeObject(actionContext.ActionArguments)}";
    
    
            var stopwatch = Stopwatch.StartNew();
            var path = AppDomain.CurrentDomain.BaseDirectory + "log.txt";
            try
            {
                return await continuation();
            }
            catch (Exception ex)
            {
                File.AppendAllText(path,
                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + str + "异常:" + ex + "
    ");
                throw;
            }
            finally
            {
                stopwatch.Stop();
                File.AppendAllText(path,
                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + str + "耗时:" +
                    Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds) + "
    ");
            }
        }
    }
    

    ValuesController代码如下

    public class ValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            Thread.Sleep(new Random().Next(500, 1000));
            return new[] { "Get" };
        }
    
        // GET api/values/5
        public string Get(int id)
        {
            Thread.Sleep(new Random().Next(500, 1000));
            return id + "";
        }
    
        [Route("api/values/GetError")]
        public void GetError()
        {
            var a = Convert.ToInt32("a");
        }
    }
    

    访问api/values 日志记录如下

    2018-01-22 19:23:27 ValuesController/Get/{}耗时:978
    

    访问api/values/1 日志记录如下

    2018-01-22 19:24:21 ValuesController/Get/{"id":1}耗时:727
    

    访问api/values/GetError 日志记录如下

    image

    Unity

    自定义一个拦截器

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)]
    public class UnityAopAttribute : HandlerAttribute, ICallHandler
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return this;
        }
    
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            var s = new Stopwatch();
            s.Start();
            var result = getNext()(input, getNext);
            if (result.Exception != null)
            {
                WriteLog(result.Exception.ToString());
                //表示处理异常 Unity就不会抛出
                result.Exception = null;
            }
            s.Stop();
            WriteLog("方法:{0},参数:{1},耗时:{2}",
                input.MethodBase.Name, JsonConvert.SerializeObject(input.Arguments), s.Elapsed.TotalMilliseconds);
            return result;
        }
    
        private void WriteLog(string format, params object[] arg)
        {
            var path = AppDomain.CurrentDomain.BaseDirectory + "log.txt";
            File.AppendAllText(path, string.Format(format, arg) + "
    ");
        }
    
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }
    
        public bool WillExecute => false;
    }
    

    接口定义如下

    public interface IOrderService
    {
        string GetOrder();
    
        string GetOrderDetail();
    }
    

    实现如下

    加上UnityAop标记

    [UnityAop]
    public class OrderService : IOrderService
    {
        public string GetOrder()
        {
            Thread.Sleep(new Random().Next(500, 1000));
            return "GetOrder";
        }
    
        public string GetOrderDetail()
        {
            var i = Convert.ToInt32("a");
            return i + "GetOrder";
        }
    }
    

    注入及调用如下

    image

    示例代码:https://github.com/sunven/Abp1

    Reference

    Unity AOP 处理异常的方法

  • 相关阅读:
    JS编码解码详解
    web的几种返回顶部
    图片的懒加载的两种效果
    获取两个日期差
    C#虚方法
    依赖注入(DI)和Ninject
    在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的
    PetShop的系统架构设计
    C#综合揭秘——细说多线程(下)
    C# Socket编程(4)初识Socket和数据流
  • 原文地址:https://www.cnblogs.com/sunven/p/8343705.html
Copyright © 2020-2023  润新知