当前位置:坤哥网-kungge-Unity使用(二):Unity.Interception实现AOP

Unity使用(二):Unity.Interception实现AOP

2017/8/27 10:57:23 kungge阅读(59) 评论(0)


前面的文章介绍了Unity实现依赖注入的几种方式。如果要实现AOP,则需要额外引用另一个安装包Unity.Interception,安装命令:Install-Package Unity.Interception,或者通过界面安装:

e18d68cd-1fa2-432d-aa50-ef77f6362ab0.png

特性实现

用特性作为AOP编程的体现,不用修改原来的类,就可以实现很多功能了,比如在新增的时候可以做一些数据的校验、日志的记录、异常的处理,下面分别用三个特性实现这三个功能。新增特性前,先创建这三个特性对应的行为类,实现ICallHandler接口,实现Invoke方法:

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("ExceptionHandler 无异常");
            }
            else
            {
                Console.WriteLine($"ExceptionHandler 有异常{methodReturn.Exception.Message}");
            }
            return methodReturn;
        }
    }
    public class InsertHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            User user=input.Inputs[0] as User;
            if (user.Pwd.Length < 6)
            {
                return input.CreateExceptionMethodReturn(new Exception("InsertHandler_CreateExceptionMethodReturn 密码长度不能小于6位"));
            }
            Console.WriteLine("InsertHandler 参数检测无误");
            IMethodReturn methodReturn = getNext()(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;
            Console.WriteLine($"LogHandler 日志记录{user.ToString()}");
            return getNext()(input, getNext);
        }
    }

属性Order表示处理程序执行的顺序,使用特性的时候可以指定。


再分别创建三个特性:

 public class ExceptionHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new ExceptionHandler() { Order = this.Order };
        }
    }
    public class InsertHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new InsertHandler() { Order = this.Order };
        }
    }
    public class LogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogHandler() { Order = this.Order };
        }
    }

把特性用到ISqlHelper上,并指定执行的顺序:

  [InsertHandler(Order =1)]
    [LogHandler(Order =2)]
    [ExceptionHandler(Order =3)]
    public interface ISqlHelper
    {
        ProcessResult Insert<T>(T t)
            where T : new();
    }


调用代码在之前的代码基础上增加一行代码即可:

               IUnityContainer container = new UnityContainer();
                container.RegisterType<ISqlHelper, MySqlHelper>();
                container.RegisterType<IValidateInput, ValidateStrictly>();

                container.AddNewExtension<Interception>().Configure<Interception>()
                .SetInterceptorFor<ISqlHelper>(new InterfaceInterceptor());

                ISqlHelper helper = container.Resolve<ISqlHelper>();

                User u = new User();
                u.Name = "东方不败5";
                u.Account = "dongfangbubai";
                u.Pwd = "123456789123";
                        ...

                ProcessResult processResult = helper.Insert<User>(u);
                if (processResult.Success)
                {
                    Console.WriteLine("新增成功!");
                }
                else
                {
                    Console.WriteLine($"新增失败:{processResult.Message}!");
                }

输出:

461d9667-1b2d-44b4-b313-3a62a192cc61.png

通过配置方式的调用和其他注入的配置使用是一样的,当然还可以在配置文件中配置要使用的特性,这里暂不做介绍。


IInterceptionBehavior实现


除了使用特性实现AOP,还可以通过实现接口IInterceptionBehavior来实现,新建一个类OneBehavior:

public class OneBehavior : IInterceptionBehavior
{
    public bool WillExecute { get { return true; } }

    public IEnumerable<Type> GetRequiredInterfaces()
    {
        return Type.EmptyTypes;
    }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    {
        Console.WriteLine($"OneBehavior_Invoke() methodName={input.MethodBase.Name}");
        Console.WriteLine("Parameters:");
        for(int i = 0; i < input.Arguments.Count; i++)
        {
            Console.WriteLine("{0}: {1}", input.Arguments.ParameterName(i), input.Arguments[i]);
        }
        Console.WriteLine("OneBehavior_Invoke() method invoke before");
        //IMethodReturn method= getNext()(input, getNext);
        IMethodReturn method = getNext().Invoke(input, getNext);
        Console.WriteLine("OneBehavior_Invoke() method invoke after");
        return method;
    }
}

在实现Invoke方法中可以对类成员访问进行拦截,如获取当前要调用的方法名和参数,可实现额外的功能,如在方法调用前后做日志记录,方法调用发生异常时进行相应的处理。

新建一个测试接口和测试类:

public interface IOneBehaviorTest
{
    void MethodTest(string p1, int p2);
}

public class OneBehaviorTest: IOneBehaviorTest
{
    public void MethodTest(string p1,int p2)
    {
        string result = string.Format($"{p1} {p2} years");
        Console.WriteLine(result);
    }
}

在配置文件中配置,在前面的文章中介绍了Unity注入的配置,在原有基础上添加拦截:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
    <container name="oneBehaviorTestContainer">
      <extension type="Interception" />
      <register type="TeXingAOP.BehaviorTest.IOneBehaviorTest, TeXingAOP" mapTo="TeXingAOP.BehaviorTest.OneBehaviorTest, TeXingAOP">
        <interceptor type="InterfaceInterceptor" />
        <interceptionBehavior name="MyBehavior" type="TeXingAOP.MyBehavior.OneBehavior, TeXingAOP" />
      </register>
    </container>
  </unity>
</configuration>

在Unity中支持三种拦截器:

  1. InterfaceInterceptor:继承接口的方法都会被拦截。

  2. TransparentProxyInterceptor:继承类使用的方法都会被拦截。

  3. VirtualMethodInterceptor:继承的方法必须是虚方法且必须是公开的方法才会被拦截。

本次在配置文件中配置的拦截器是InterfaceInterceptor。

调用:

UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
IUnityContainer container = new UnityContainer();
unitySection.Configure(container, "oneBehaviorTestContainer");

IOneBehaviorTest helper = container.Resolve<IOneBehaviorTest>();

helper.MethodTest("I Love You",10000);

输出:

88c6fc21-d52b-4c08-b44f-fc439b921569.png


本文由“IT乐族”发布,2017年8月27日

Unity.Interception

发表评论 没有账号,注册评论

博主

  • 用户名:kungge
  • 昵称:kungge

文章标签