Fody-AOP 面向切片编程

AOP的基本定义及作用

“AOP(Aspect-Oriented Programming)是一种将函数的辅助性功能与业务逻辑相分离的编程泛型(programming paradigm),其目的是将横切关注点(cross-cutting concerns)分离出来,使得程序具有更高的模块化特性。AOP是面向方面软件开发(Aspect-Oriented Software Development)在编码实现层面上的具体表现(面向方面软件开发AOSD是一个囊括面向方面分析、面向方面设计和面向方面编程等一系列概念的完整工程系统——笔者注)。AOP包括编程模型和具体用于实现AOP的框架两部分。”

下面上代码

演示了Fody如何拦截 属性值改变、方法调用、方法执行时间。

1.调用逻辑

Services.FodyTest.SampleA sample = new Services.FodyTest.SampleA
{
    A = "A",
    AA = "AA",
    B = 1,
    BB = 2,
    C = 1.123m,
    CC = 1.223m,
    D = true,
    DD = false
}; 
sample.PropertyChanged += (obj, args) =>
{
    _logger.LogInformation("sample.PropertyChanged:{0}", args.PropertyName);
};
sample.A += "_";
sample.B += 10;
sample.C += 10.999m;
sample.D = false;
sample.MethodA();
sample.MethodTime("TTTTime);
Services.FodyTest.SampleB sampleB = new Services.FodyTest.SampleB
{
    A = "B",
    AA = "BB",
    B = 2,
    BB = 22,
    C = 2.123m,
    CC = 2.223m,
    D = true,
    DD = false
};
sampleB.PropertyChanged += (obj, args) =>
{
    _logger.LogInformation("sample.PropertyChanged:{0}", args.PropertyName);
};
sampleB.A += "_";
sampleB.B += 20;
sampleB.C += 20.999m;
sampleB.D = false;
sampleB.MethodB();
sampleB.MethodTimeB("BBBTime");

2.代码实现

// Attribute should be "registered" by adding as module or assembly custom attribute
[module: FodyMethodInspect]
//静态类重写读取哪个程序集下的(如:PropertyChangedNotificationInterceptor 分别在Services与Services.FodyTest中,将读取Services中的)
[assembly: PropertyChanged.FilterType("NetCoreTemp.WebApi.Services")]

namespace NetCoreTemp.WebApi.Services.FodyTest
{
    //https://github.com/Fody/MethodDecorator
    // Any attribute which provides OnEntry/OnExit/OnException with proper args
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Assembly | AttributeTargets.Module)]
    public class FodyMethodInspectAttribute : Attribute, IMethodDecorator
    {
        AppDbContext _appDbContext;
        UserService _userService;
        ILogger _logger;
        object _instance;
        MethodBase _method;
        object[] _args;

        public string Modual { get; set; }

        // instance, method and args can be captured here and stored in attribute instance fields
        // for future usage in OnEntry/OnExit/OnException
        public void Init(object instance, MethodBase method, object[] args)
        {
            _instance = instance;
            _method = method;
            _args = args;

            _userService = FodyGetService.GetIService<UserService>();
            _appDbContext = _userService?.GetDBContext();
            _logger = FodyGetService.GetILogger<FodyMethodInspectAttribute>();
            _logger.LogInformation("Microsoft.Extension.ILogger-Init: {0} [{1}]", method.DeclaringType.FullName + "." + method.Name, args.Length);
            LogTo.Info(string.Format("Init: {0} [{1}]", method.DeclaringType.FullName + "." + method.Name, args.Length));
        }

        public void OnEntry()
        {
            var num = _userService.Query(x => x.Status > Models.EnumType.EnumRepo.UseStatusEnum.Draft).Count();
            _logger.LogInformation($"Microsoft.Extension.ILogger-Init: OnEntry-User:Count-{num}");
            LogTo.Info("OnEntry");
        }

        public void OnExit()
        {
            _logger.LogInformation("Microsoft.Extension.ILogger-Init: OnExit");
            LogTo.Info("OnExit");
        }

        public void OnException(Exception exception)
        {
            _logger.LogError(exception, "Microsoft.Extension.ILogger-OnException: {0}: {1}", exception.GetType(), exception.InnerException?.Message ?? exception.Message);
            LogTo.ErrorException($"OnException: {exception.GetType()}: {exception.InnerException?.Message ?? exception.Message}", exception);
        }
    }
    //手动实现改变值前后委托
    public delegate void PropertyValueChanedEventHandler(object sender, PropertyChangedEventArgs args, object oldVal,object newVal);
    /// <summary>
    /// https://github.com/Fody/PropertyChanged/wiki/Attributes#donotnotifyattribute
    /// <remark>
    /// AddINotifyPropertyChangedInterface 会自动添加 且无需添加 继承INotifyPropertyChanged接口
    /// public event PropertyChangedEventHandler PropertyChanged 事件
    /// [assembly: PropertyChanged.FilterType("My.Specific.OptIn.Namespace.")] 会自动把命名空间下 所有类加上PropertyChanged通知
    /// </remark>
    /// </summary>
    public class SampleA : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        //public event PropertyValueChanedEventHandler PropertyValueChaned;

        public string A { get; set; }

        public string AA { get; set; }

        public string A_AA
        {
            get
            {
                return $"{(A??"").Replace("-", "__")}-{AA}";
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    var arr = value.Split("-").ToList();
                    A = arr[0].Replace("__", "-");
                    AA = arr?.Count > 1 ? string.Join("", arr.Skip(1)) : "";
                }
            }
        }

        public int B { get; set; }
        private void OnBChanged(int oldValue, int newValue)
        {
            LogTo.Info("B Changed:" + oldValue + " => " + newValue);
            //PropertyValueChaned?.Invoke(this, new PropertyChangedEventArgs("B"), oldValue, newValue);
        }

        [OnChangedMethod(nameof(OnChangedC))]
        public decimal C { get; set; }
        private void OnChangedC(object oldValue, object newValue)
        {
            LogTo.Info("C Changed:" + oldValue + " => " + newValue);
            //PropertyValueChaned?.Invoke(this, new PropertyChangedEventArgs("C"), oldValue, newValue);
        }

        [DoNotNotify]
        public bool D { get; set; }

        public int? BB { get; set; }

        public decimal? CC { get; set; }

        public bool? DD { get; set; }

        [FodyMethodInspect]
        public void MethodA()
        {
            LogTo.Info(JsonSerializer.Serialize(this));
        }

        [Time("MethodTime-Time Field Arg:{TimeField}")]
        public void MethodTime(string TimeField)
        {
            LogTo.Info($"MethodTime:{TimeField}");
        }
    }

    /// <summary>
    /// 自动加PropertityChangeEvent
    /// </summary>
    [AddINotifyPropertyChangedInterface]
    public class SampleB
    {
        public string A { get; set; }

        public string AA { get; set; }

        public string A_AA
        {
            get
            {
                return $"{(A ?? "").Replace("-", "__")}-{AA}";
            }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    var arr = value.Split("-").ToList();
                    A = arr[0].Replace("__", "-");
                    AA = arr?.Count > 1 ? string.Join("", arr.Skip(1)) : "";
                }
            }
        }

        public int B { get; set; }
        private void OnBChanged(int oldValue, int newValue)
        {
            LogTo.Info("B Changed:" + oldValue + " => " + newValue);
            //PropertyValueChaned?.Invoke(this, new PropertyChangedEventArgs("B"), oldValue, newValue);
        }

        [OnChangedMethod(nameof(OnChangedC))]
        public decimal C { get; set; }
        private void OnChangedC(object oldValue, object newValue)
        {
            LogTo.Info("C Changed:" + oldValue + " => " + newValue);
            //PropertyValueChaned?.Invoke(this, new PropertyChangedEventArgs("C"), oldValue, newValue);
        }

        [DoNotNotify]
        public bool D { get; set; }

        public int? BB { get; set; }

        public decimal? CC { get; set; }

        public bool? DD { get; set; }

        [FodyMethodInspect]
        public void MethodB()
        {
            LogTo.Info(JsonSerializer.Serialize(this));
        }

        [Time("MethodTimeB-Time Field Arg:{TimeField}")]
        public void MethodTimeB(string TimeField)
        {
            LogTo.Info($"MethodTime:{TimeField}");
        }
    }

    /// <summary>
    /// 方法事件计算日志实例
    /// </summary>
    public static class MethodTimeLogger
    {
        public static void Log(MethodBase methodBase, TimeSpan elapsed, string message)
        {
            LogTo.Info("MethodTimeLogger:{0}-{1}-{2}", methodBase.Name, elapsed.TotalSeconds, message);
        }
    }

    /// <summary>
    /// 属性改变通知实例
    /// </summary>
    public static class PropertyChangedNotificationInterceptor
    {
        public static void Intercept(object target, Action onPropertyChangedAction,
                                     string propertyName, object before, object after)
        {
            onPropertyChangedAction();

            LogTo.Info("PropertyChangedNotificationInterceptor:{0}-{1}-{2}", propertyName, before, after);
        }
    }

    /// <summary>
    /// DI-serviceProvider 静态储存
    /// </summary>
    public static class FodyGetService
    {
        private static IServiceProvider _serviceProvider;

        public static void Configration(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        /// <summary>
        /// 获取BaseService
        /// </summary>
        /// <typeparam name="TEntity">Entity类</typeparam>
        /// <returns></returns>
        public static Base.BaseService<TEntity> GetBaseService<TEntity>() where TEntity : class, NetCoreTemp.WebApi.Models.BaseModel.IEntity_
        {
            return _serviceProvider.GetService<Base.BaseService<TEntity>>();
        }

        /// <summary>
        /// 获取Entity服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public static TService GetIService<TService>() where TService : class, Base.IEntityService
        {
            return _serviceProvider.GetService<TService>();
        }

        /// <summary>
        /// 获取日志服务
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <returns></returns>
        public static ILogger<T> GetILogger<T>() where T : class, new()
        {
            return _serviceProvider.GetService<ILogger<T>>();
        }
    }
}

namespace NetCoreTemp.WebApi.Services
{
    /// <summary>
    /// 属性改变通知实例
    /// </summary>
    public static class PropertyChangedNotificationInterceptor
    {
        public static void Intercept(object target, Action onPropertyChangedAction,
                                     string propertyName, object before, object after)
        {
            onPropertyChangedAction();

            LogTo.Info("PropertyChangedNotificationInterceptor:{0}-{1}-{2}", propertyName, before, after);
        }
    }
}

 

参考:https://github.com/Fody

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值