利用Unity实现AOP

.NET程序中,可以利用Unity来实现AOP,用来进行日志、缓存或权限的处理。这里我们来写一个简单的程序,让其实现简单的AOP功能。

1.使用NuGet,在项目中获取Microsoft.Practices.Unity。

2.新建一个ITalk类及其实现

    public interface ITalk
    {
        string Speak(string msg);
    }


    public class Talk : ITalk
    {
        public string Speak(string msg)
        {
            Console.WriteLine(msg);
            return msg;
        }
    }

3.再进一个ServiceLocator类,用来实现接口的依赖反转

using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;

namespace AopDemo
{
    /// <summary>
    /// Represents the Service Locator.
    /// </summary>
    public sealed class ServiceLocator : IServiceProvider
    {
        #region Private Fields
        private readonly IUnityContainer container;
        #endregion

        #region Private Static Fields
        private static readonly ServiceLocator instance = new ServiceLocator();
        #endregion

        #region Ctor
        /// <summary>
        /// Initializes a new instance of <c>ServiceLocator</c> class.
        /// </summary>
        private ServiceLocator()
        {
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            container = new UnityContainer();
            section.Configure(container);
        }
        #endregion

        #region Public Static Properties
        /// <summary>
        /// Gets the singleton instance of the <c>ServiceLocator</c> class.
        /// </summary>
        public static ServiceLocator Instance
        {
            get { return instance; }
        }
        #endregion

        #region Private Methods
        private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments)
        {
            List<ParameterOverride> overrides = new List<ParameterOverride>();
            Type argumentsType = overridedArguments.GetType();
            argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .ToList()
                .ForEach(property =>
                {
                    var propertyValue = property.GetValue(overridedArguments, null);
                    var propertyName = property.Name;
                    overrides.Add(new ParameterOverride(propertyName, propertyValue));
                });
            return overrides;
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Gets the service instance with the given type.
        /// </summary>
        /// <typeparam name="T">The type of the service.</typeparam>
        /// <returns>The service instance.</returns>
        public T GetService<T>()
        {
            return container.Resolve<T>();
        }
        /// <summary>
        /// Gets the service instance with the given type by using the overrided arguments.
        /// </summary>
        /// <typeparam name="T">The type of the service.</typeparam>
        /// <param name="overridedArguments">The overrided arguments.</param>
        /// <returns>The service instance.</returns>
        public T GetService<T>(object overridedArguments)
        {
            var overrides = GetParameterOverrides(overridedArguments);
            return container.Resolve<T>(overrides.ToArray());
        }
        /// <summary>
        /// Gets the service instance with the given type by using the overrided arguments.
        /// </summary>
        /// <param name="serviceType">The type of the service.</param>
        /// <param name="overridedArguments">The overrided arguments.</param>
        /// <returns>The service instance.</returns>
        public object GetService(Type serviceType, object overridedArguments)
        {
            var overrides = GetParameterOverrides(overridedArguments);
            return container.Resolve(serviceType, overrides.ToArray());
        }
        #endregion

        #region IServiceProvider Members
        /// <summary>
        /// Gets the service instance with the given type.
        /// </summary>
        /// <param name="serviceType">The type of the service.</param>
        /// <returns>The service instance.</returns>
        public object GetService(Type serviceType)
        {
            return container.Resolve(serviceType);
        }

        #endregion
    }
}
View Code

4.接下来是错误和缓存处理的类。我们这边只是简单的在控制台输出一句话,证明代码有执行。

ExceptionLoggingBehavior.cs

public class ExceptionLoggingBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("ExceptionLoggingBehavior");
            return getNext().Invoke(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
View Code

CachingBehavior.cs

  public class CachingBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("CachingBehavior");
            return getNext().Invoke(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
View Code

5.配置App.Config文件

<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" />
    </startup>
  <!--BEGIN: Unity-->
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
    <container>
      <extension type="Interception"/>
      <!--Cache Provider-->
      <register type="AopDemo.ITalk, AopDemo" mapTo="AopDemo.Talk, AopDemo">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="AopDemo.InterceptionBehaviors.CachingBehavior, AopDemo"/>
        <interceptionBehavior type="AopDemo.InterceptionBehaviors.ExceptionLoggingBehavior, AopDemo"/>
      </register>
    </container>
  </unity>
  <!--END: Unity-->
</configuration>

6.调用

    static void Main(string[] args)
        {
            ITalk talk = ServiceLocator.Instance.GetService<ITalk>();
            talk.Speak("Hello");
        }

7.结果

可以看到在打印出Hello前,代码先执行到了缓存与错误处理的方法。

PS:如果IOC的时候报类似错误

Exception is: InvalidOperationException - The type OAManageClient has multiple constructors of length 2. Unable to disambiguate.则配置文件应该增加<constructor></constructor>

 <register type="AopDemo.ITalk, AopDemo" mapTo="AopDemo.Talk, AopDemo">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="AopDemo.InterceptionBehaviors.CachingBehavior, AopDemo"/>
        <interceptionBehavior type="AopDemo.InterceptionBehaviors.ExceptionLoggingBehavior, AopDemo"/>
        <constructor></constructor>
 </register>

 

posted @ 2013-06-06 23:18  Gyoung  阅读(5326)  评论(6编辑  收藏  举报