C# Unity依赖注入利用Attribute实现AOP功能

使用场景?

很多时候, 我们定义一个功能, 当我们要对这个功能进行扩展的时候, 按照常规的思路, 我们一般都是利用OOP的思想, 在原有的功能上进行扩展。

那么有没有一种东西, 可以实现当我们需要扩展这个功能的时候, 在不修改原来的功能代码的情况下实现, 这就是下面要说的到Unity。

1.准备工作

为项目添加NuGet包, 搜索Unity并且安装。

在使用的项目中添加Unity的相关引用

using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.Practices.Unity;

2.假设场景

刚才上面说道, Unity可实现在不修改原功能的情况下, 添加额外的扩展功能。在我们的实际开发中, 也可以举个简单的例子。

当我们去做一个用户注册的功能, 最初的版本是完成了基本的注册功能, 后来我们需要扩展了, 给他加上注册校验, 日志处理, 和异常捕捉的几个功能, 那么接下来就演示, 如何用Unity给功能扩展。

3.如何使用

首先, 我们定义好一个最原始的注册功能

        public static void Show()
        {
            User user = new User()
            {
                Name = "Eleven",
                Password = "123123123123"
            };            IUserProcessor porcessor = new UserProcessor();            porcessor.RegUser(user); //简单的用户注册
        }
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        public class UserProcessor : IUserProcessor//MarshalByRefObject,
        {
            public void RegUser(User user)
            {
                Console.WriteLine("注册。");
            }
        }

接下来, 我们要对这个注册进行扩展了, 添加注册校验, 日志处理, 和异常捕捉的几个功能。

1.先定义3个特性与对应的特性行为实现, 分别是注册, 日志, 和异常。

       public class UserHandlerAttribute : HandlerAttribute  //注册校验
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                ICallHandler handler = new UserHandler() { Order = this.Order };
                return handler;
            }
        }

        public class LogHandlerAttribute : HandlerAttribute   //日志处理
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new LogHandler() { Order = this.Order };
            }
        }

        public class ExceptionHandlerAttribute : HandlerAttribute  //异常处理
        {
            public override ICallHandler CreateHandler(IUnityContainer container)
            {
                return new ExceptionHandler() { Order = this.Order };
            }
        }

对应的每个特性的实现行为, 分别实现 注册校验, 日志记录, 与 异常处理

        public class UserHandler : ICallHandler  //注册校验的行为
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                User user = input.Inputs[0] as User;
                if (user.Password.Length < 10)
                {
                    return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
                }
                Console.WriteLine("参数检测无误");

                IMethodReturn methodReturn = getNext.Invoke().Invoke(input, getNext);

                return methodReturn;
            }
        }

        public class LogHandler : ICallHandler    //日志处理的行为
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                User user = input.Inputs[0] as User;
                string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
                Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", message, DateTime.Now);
                return getNext()(input, getNext);
            }
        }

        public class ExceptionHandler : ICallHandler   //异常处理的行为
        {
            public int Order { get; set; }
            public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
            {
                IMethodReturn methodReturn = getNext()(input, getNext);
                if (methodReturn.Exception == null)
                {
                    Console.WriteLine("无异常");
                }
                else
                {
                    Console.WriteLine("异常:{0}", methodReturn.Exception.Message);
                }
                return methodReturn;
            }
        }

按照现在思路, 我们要把这上面写好的几个功能添加在原来的注册功能上, 首先, 我们回到最开始定义接口的地方, 给接口添加我们定义按的3个特性

        [UserHandlerAttribute(Order = 1)] //注册校验
        [LogHandlerAttribute(Order = 2)]  //日志处理
        [ExceptionHandlerAttribute(Order = 3)] //遗产处理
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

//PS: 在上面的特性声明中, 每个对应的Order 这个属于排序, 相对于一个行为的执行顺序, 这个内部是Unity的一个实现, 所以我们使用的过程中只需要声明好标量即可。

然后, 我们在定义好的注册方法中, 首先声明一个Unity容器UnityContainer , 然后注册其上面的接口 IUserProcessor, 最后调用其接口的注册方法。

            //声明一个容器
            IUnityContainer container = new UnityContainer();

            //声明UnityContainer并注册IUserProcessor
            container.RegisterType<IUserProcessor, UserProcessor>();

            container.AddNewExtension<Interception>().Configure<Interception>()
                .SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());
            IUserProcessor userprocessor = container.Resolve<IUserProcessor>();
            userprocessor.RegUser(user); //调用注册方法。

最后, 我们看一下实际效果, 很轻松的实现了用于注册时候扩展其他更多的行为

小结:

不难发现, Unity的实现 主要以在接口上定义的特性与实现行为  与其内部Unity容器的结合  实现的AOP功能。

因为上面是属于静态的写法, 便于学习, 真正的实现AOP可动态配置, 在IOC里会有详细的介绍。

时间: 2024-08-29 06:13:05

C# Unity依赖注入利用Attribute实现AOP功能的相关文章

验证Unity依赖注入的对象是否为同一个实例

在使用Unity的时候,能够很好的解耦,解除层与层之间的依赖性.这里有一个问题,每次向Unity中要对象实例的时候,这时候给出的是同一个吗?还是每次都是new一个新的?我来写代码验证一下.怎么验证两个对象是否为同一个呢,看这个对象在内存中的地址就行了,通过Hash码查看就可以. namespace UnityApplication { public interface IService { string Show(); } } namespace UnityApplication { publi

WPF PRISM开发入门二(Unity依赖注入容器使用)

这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点击这里下载. 运行效果如下: 下面将引入Unity类库,使用Unity来生成需要的对象实例. 先查看一下CalculateRelpLoop类, public class CalculateRelpLoop : ICalculateRelpLoop { ICalculateService _calcu

Unity 依赖注入

关于Ioc的框架有很多,比如astle Windsor.Unity.Spring.NET.StructureMap,我们这边使用微软提供的Unity做示例,你可以使用Nuget添加Unity,也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll,下面我们就一步一步的学习下Unity依赖注入的详细使用.如果不明白什么是控制反转和依赖注入,请参考控制反转和依赖注入模式 下面通过一个示例来讲解Uni

Unity依赖注入使用详解

Unity依赖注入使用详解 写在前面 构造器注入 Dependency属性注入 InjectionMethod方法注入 非泛型注入 标识键 ContainerControlledLifetimeManager单例 Unity注册配置问题 Unity的app.config节点配置 后记 关于 控制反转 (Inversion of Control)和 依赖注入 (Dependency Injection)大家网上可以找下相关概念,在 <小菜学习设计模式(五)—控制反转(Ioc)> 这篇文章中本人也

使用Unity依赖注入的时候,最上层的类是Resolve还是New的问题

在使用Unity的时候,很多时候是这样一种引用的关系.就是一个类需要另一个类在其中做工具类.因为是构造方法注入,所以要在构造方法中加入一个引用参数. public interface IRepository { void Execute(); } public class Repository : IRepository { public void Execute() { // Some database operation } } public interface IService { voi

使用Microsoft.Practices.Unity 依赖注入

Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,它支持常用的三种依赖注入方式:构造器注入(Constructor Injection).属性注入(Property Injection),以及方法调用注入(Method Call Injection). 假设我们有下面的场景代码,在代码里面有一个很简单的customer对象,customer 对象有个save 方法, 这个方法通过调用ICusto

c# Unity依赖注入WebService

1.IOC与DI简介 IOC全称是Inversion Of Control(控制反转),不是一种技术,只是一种思想,一个重要的面相对象编程的法则,它能知道我们如何设计出松耦合,更优良的程序.传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之 间高耦合,难于测试:有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活.其实IoC 对编程带来的最大改变不是

DDD实战8_2 利用Unity依赖注入,实现接口对应实现类的可配置

1.在Util类库下新建DIService类 /// <summary> /// 创建一个类,对应在配置文件中配置的DIServices里面的对象的 key /// </summary> public class DIService { public string InterfaceType { get; set; } public string ImplementationType { get; set; } } 2 在webapi的appsettings.json文件中配置 要

WebApi学习笔记06:使用webapi模板--仓储模式--Unity依赖注入

1.Web项目 1.1概述 对数据操作封装使用存储模式是很常见的方式,而使用依赖注入来降低耦合度(方便创建对象,可以抛弃经典的工厂模式)…… 1.2创建项目 1.3添加模型 在Models下,添加Product.cs: namespace WebApi06.Models { public class Product { public int ID { get; set; } public string Name { get; set; } public decimal Price { get;