Unity.Interception(AOP)

        在前面我们学习到的是Unity依赖注入(DI)与统一容器来松散耦合,这个设计已经对我们系统带来了很多的好处。但是我们还会想尝试和遵循单一职责,开放封闭原则。比如我们不应该在我们的Business层去实现日志、校验、缓存、异常处理等工作,Unity的Interception可以帮助我们横切关注点(Crosscutting concerns 即AOP),来独立处理这些关注点。
        什么是横切关注点(AOP)?横切关注点(AOP)是关注影响应用程序的许多区域。例如,你可能需要将信息写入日志文件在应用程序许多不同的区域,横切关注点(AOP)可以帮助你构建一致的应用程序方式与应用程序业务。
常见的LOB应用程序的横切关注点包括:
        1.日记(Log)
        2.校验(Validation
        3.异常处理(Exception handling
        4.瞬时故障处理(Transient fault handling
        5.权限处理(Authentication and authorization
        6.缓存(Caching
        7.性能监控(Performance monitoring
        8.加密(Encryption
        9.映射(Mapping
        10.压缩(Compression
 
        在使用Unity.Interception以前,我们先自己写一个简单的AOP功能的实现  --  代理模式:
1.业务接口
复制代码
    /// <summary>
    /// 接口
    /// </summary>
    public interface ITalk
    {
        void talk(string msg);
    }
复制代码

2.业务实现

复制代码
    public class PeopleTalk : ITalk
    {
        private string username;

        private int age;

        public string UserName
        {
            get { return username; }
        }

        public int Age
        {
            get { return age; }
        }

        public PeopleTalk(string userName, int age)
        {
            this.username = userName;
            this.age = age;
        }

        public virtual void talk(string msg)
        {
            Console.WriteLine(msg + "!你好,我是" + username + ",我的年龄" + age);
        }

    }
复制代码

3.代理对象

复制代码
    public class TalkProxy : ITalk
    {
        private ITalk talker;

        public TalkProxy(ITalk talker)
        {
            this.talker = talker;
        }

        public void talk(string msg)
        {
            talker.talk(msg);
        }

        public void talk(string msg, string singName)
        {
            talker.talk(msg);
            sing(singName);
        }

        public void sing(string singName)
        {
            Console.WriteLine("唱歌:" + singName);
        }
    }
复制代码

4.调用

复制代码
    class Program
    {
        static void Main(string[] args)
        {
            #region 静态代理

            ITalk people = new PeopleTalk("AOP", 18);

            people.talk("No ProXY Test!");

            Console.WriteLine("---------------------------------");

            TalkProxy talker = new TalkProxy(people);

            talker.talk("ProXY Test", "代理");

            #endregion

        }
    }
复制代码

  代理模式是一种简单的AOP,talk是一个切面,我们可以在代理类中添加日志、校验、异常处理等等。这样我们就实现了,核心关注点与横切关注点的分离。正如Avanade公司的高级方案架构师Adam Magee所说,AOP的核心思想就是”将应用程序中的商业逻辑同对其提供支持的通用服务进行分离“。

 

  下面我们来看看Unity.Interception是如何现实AOP的
 1.在Unity中实现IInterceptionBehavior接口
复制代码
    /// <summary>
    /// Unity为我们提供了一个IInterceptionBehavior接口需要实现这个接口
    /// 接口为我们提供了三个方式(GetRequiredInterfaces、Invoke、WillExecute)实现
    /// WillExecute表示是否执行该行为,如果是false这个方法被调用时,不会被捕捉。因为我们总是要执行的,所以为true
    /// GetRequiredInterfaces将你想要的接口类型和行为联系起来,我们暂时不需要,所以返回Type.EmptyTypes
    /// Invoke执行方式接口
    /// </summary>
    public class LoggingInterceptionBehavior : IInterceptionBehavior
    {
        public bool WillExecute
        {
            get { return true; }
        }

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

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("Method: {0}", input.MethodBase.Name);

            Console.WriteLine("参数:");
            for (var i = 0; i < input.Arguments.Count; i++)
            {
                Console.WriteLine("{0}: {1}", input.Arguments.ParameterName(i), input.Arguments[i]);
            }
            Console.WriteLine("执行前");
            var result = getNext()(input, getNext);//在这里执行方法
            if (result.Exception != null)
            {
                //发生错误记录日志
                Console.WriteLine(String.Format("Method {0} threw exception {1} at {2}", input.MethodBase, result.Exception.Message, DateTime.Now.ToLongTimeString()));
            }
            Console.WriteLine("执行后");
            return result;
        }
    }
复制代码

2.调用

复制代码
    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.AddNewExtension<Interception>();
            container.RegisterType<ITalk, PeopleTalk>(
                new InjectionConstructor("AOP", 18), 
                new Interceptor<InterfaceInterceptor>(), 
                new InterceptionBehavior<LoggingInterceptionBehavior>());
            ITalk talker = container.Resolve<ITalk>();
            talker.talk("ProXY Test!");
        }
    }
复制代码

以上基本完成了简单的Unity.Interception 

当然在Unity中不只有InterfaceInterceptor一种拦截器,它还包含其它两种拦截器:TransparentProxyInterceptor 与 VirtualMethodInterceptor 

这里就不详细介绍就提一下这三种:

InterfaceInterceptor只要是继承接口的方法都会被拦截。
TransparentProxyInterceptor只要是继承类使用的方法都会被拦截。
VirtualMethodInterceptor 意思是虚方法拦截器,继承类的方法必须是Virtual的,和继承类必须是公开的。满足这两个条件即可

 
 
 
----------------------------------------------------------------------------------------------------------------
 
同时在这里我还是没有回答在我Unity4.0的使用 中“一只老菜鸟”所提的问题,不过我会努力的
以上是本人比较初级的处理,主要用于本人学习Unity的一个记录

如果有不懂的可以先查看

Unity 依赖注入之一

Unity 依赖注入之二

 

 

出处:https://www.cnblogs.com/chengxuzhimei/p/5198381.html

=======================================================================================

Unity的三种Interceptor的区别

Unity默认提供了三种拦截器:TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor。

TransparentProxyInterceptor:代理实现基于.NET Remoting技术,它可拦截对象的所有函数。缺点是被拦截类型必须派生于MarshalByRefObject。示例如下:

复制代码
 1 public class MyObject : MarshalByRefObject
 2 {
 3   public String Name { get; set; }
 4 }
 5 
 6 IUnityContainer unityContainer = new UnityContainer();
 7 
 8 unityContainer.AddNewExtension<Interception>();
 9 unityContainer.RegisterType<MyObject>(new Interceptor<TransparentProxyInterceptor>(), new InterceptionBehavior(new NotifyPropertyChangedBehavior()));
10 
11 MyObject myObject = unityContainer.Resolve<MyObject>();
12 
13 ((INotifyPropertyChanged)myObject).PropertyChanged += new PropertyChangedEventHandler((sender, e) => Console.WriteLine(e.PropertyName));
14 
15 myObject.Name = “hello, world”;
复制代码

说明:NotifyPropertyChangedBehavior的代码,请参考 Unity Behaviors for Interception 中的内容

InterfaceInterceptor:只能对一个接口做拦截,好处时只要目标类型实现了指定接口就可以拦截。示例如下:

复制代码
 1 public class MyObject2 : IServiceProvider
 2 {
 3 
 4   #region IServiceProvider Members
 5 
 6   public object GetService(Type serviceType)
 7   {
 8     return null;
 9   }
10 
11   #endregion
12 }
13 
14 public sealed class MyInterceptionBehavior : IInterceptionBehavior
15 {
16   #region IInterceptionBehavior Members
17 
18   public Boolean WillExecute
19   {
20     get { return true; }
21   }
22 
23   public IEnumerable<Type> GetRequiredInterfaces()
24   {
25     return new Type[0];
26   }
27 
28   public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
29   {
30     return getNext()(input, getNext);
31   }
32 
33   #endregion
34 }
35 
36 IUnityContainer unityContainer = new UnityContainer();
37 
38 unityContainer.AddNewExtension<Interception>();
39 unityContainer.RegisterType<IServiceProvider, MyObject2>(“MyObject2″,
40   new Interceptor<InterfaceInterceptor>(),
41   new InterceptionBehavior<MyInterceptionBehavior>()
42 );
43 
44 IServiceProvider myObject = unityContainer.Resolve<IServiceProvider>(“MyObject2″);
45 
46 myObject.GetService(typeof(MyObject2));
复制代码

注册类型时需要显示指定被拦截接口类型。

VirtualMethodInterceptor:对virtual函数进行拦截。缺点是如果被拦截类型没有virtual函数则无法拦截,这个时候如果类型实现了某个特定接口可以改用InterfaceInterceptor。看一个简单示例:

复制代码
 1 public class MyObject3
 2 {
 3   public virtual void DoWork()
 4   {
 5 
 6   }
 7 }
 8 
 9 IUnityContainer unityContainer = new UnityContainer();
10 
11 unityContainer.AddNewExtension<Interception>();
12 unityContainer.RegisterType<MyObject3>(
13   new Interceptor<VirtualMethodInterceptor>(),
14   new InterceptionBehavior<MyInterceptionBehavior>()
15 );
16 
17 MyObject3 myObject = unityContainer.Resolve<MyObject3>();
18 
19 myObject.DoWork();
复制代码

 

出处:https://www.cnblogs.com/junchu25/archive/2012/08/10/2631583.html

=======================================================================================

C#unity按属性划分拦截

有没有办法在C#unity中如何使用属性拦截并将对象注册代码保存在XML文件中(如app.config)?如果是的话,你能为我提供代码,这样的注册应该怎么样?我做了很多解决方法,但没有找到解决此问题的方法.

我假设你的意思是使用自定义属性来指示拦截哪些方法.您可以使用策略注入来使用XML配置实现拦截.

首先,让我们定义一个自定义属性:

[AttributeUsage(AttributeTargets.Method)]
public class MyInterceptionAttribute : Attribute
{
}

接下来,我们可以创建一个ICallHandler来执行一些拦截工作.这个实现只会在方法之前和之后执行Console.WriteLine:

public class MyLoggingCallHandler : ICallHandler
{
    IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        Console.WriteLine("Invoking " + input.MethodBase.Name);
        IMethodReturn result = getNext()(input, getNext);
        Console.WriteLine("Done Invoke");
        return result;
    }

    int ICallHandler.Order { get; set; }
}

接下来让我们假设我们有一些接口和实现:

public interface IMyClass
{
    void Do();
    void DoAgain();
}

public class MyClass : IMyClass 
{
    [MyInterception]
    public void Do()
    {
        Console.WriteLine("Do!");
    }

    public void DoAgain()
    {
        Console.WriteLine("Do Again!");
    }
}

请注意,我已将自定义属性MyInterception仅应用于Do方法,但未应用于DoAgain方法.我们将拦截对Do方法的所有调用.

接下来,我们创建配置以定义策略,配置匹配规则并将类型与拦截器一起注册:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <namespace name="UnityCallHandlerConfig" />
    <assembly name="UnityCallHandlerConfig"  />
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
    <container>
      <extension type="Interception"/>
      <interception>
        <policy name="Policy">
          <matchingRule name="Match" type="Microsoft.Practices.Unity.InterceptionExtension.CustomAttributeMatchingRule, Microsoft.Practices.Unity.Interception">
            <constructor>
              <param name="attributeType" value="UnityCallHandlerConfig.MyInterceptionAttribute, UnityCallHandlerConfig" typeConverter="AssemblyQualifiedTypeNameConverter" />
              <param name="inherited">
                <value value="false"/>
              </param>
            </constructor>
          </matchingRule>
          <callHandler name="MyLogging" type="MyLoggingCallHandler">
            <lifetime type="singleton"/>
          </callHandler>
        </policy>
      </interception>
      <register type="IMyClass" mapTo="MyClass">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="PolicyInjectionBehavior"/>
      </register>
    </container>
  </unity>

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

我们还需要一个类型转换器来将自定义属性的字符串表示转换为正确的类型:

public class AssemblyQualifiedTypeNameConverter : ConfigurationConverterBase
{
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (value != null)
        {
            Type typeValue = value as Type;
            if (typeValue == null)
            {
                throw new ArgumentException("Cannot convert type", typeof(Type).Name);
            }

            if (typeValue != null) return (typeValue).AssemblyQualifiedName;
        }
        return null;
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        string stringValue = (string)value;
        if (!string.IsNullOrEmpty(stringValue))
        {
            Type result = Type.GetType(stringValue, false);
            if (result == null)
            {
                throw new ArgumentException("Invalid type", "value");
            }

            return result;
        }
        return null;
    }
}

完成所有设置后,我们可以创建一个容器并加载配置:

var container = new UnityContainer().LoadConfiguration();

var myClass = container.Resolve<IMyClass>();
myClass.Do();
myClass.DoAgain();

输出将是:

Invoking Do
Do!
Done Invoke
Do Again!

显示第一种方法被截获而第二种方法没有被截获.

 

 

出处:https://qa.1r1g.com/sf/ask/1196335871/

=======================================================================================

【Unity-Interception】AOP编程--拦截,缓存和异常处理

他们都继承接口:IInterceptionBehavior (程序集 Microsoft.Practices.Unity.Interception.dll, v2.1.505.0

命名空间:Microsoft.Practices.Unity.InterceptionExtension)

需要实现连个接口:

public IEnumerable<Type> GetRequiredInterfaces()

public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)

CachingBehavior.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Keasy5.Infrastructure.Caching;
using Microsoft.Practices.Unity.InterceptionExtension; namespace Keasy5.Infrastructure.InterceptionBehaviors {
/// <summary>
/// 表示用于方法缓存功能的拦截行为。
/// </summary>
public class CachingBehavior : IInterceptionBehavior
{
#region Private Methods
/// <summary>
/// 根据指定的<see cref="CachingAttribute"/>以及<see cref="IMethodInvocation"/>实例,
/// 获取与某一特定参数值相关的键名。
/// </summary>
/// <param name="cachingAttribute"><see cref="CachingAttribute"/>实例。</param>
/// <param name="input"><see cref="IMethodInvocation"/>实例。</param>
/// <returns>与某一特定参数值相关的键名。
/// <remarks>
/// 例如:<see cref="ICacheProvider.Add"/>
/// </remarks>
/// </returns>
private string GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input)
{
switch (cachingAttribute.Method)
{
// 如果是Remove,则不存在特定值键名,所有的以该方法名称相关的缓存都需要清除
case CachingMethod.Remove:
return null;
// 如果是Get或者Put,则需要产生一个针对特定参数值的键名
case CachingMethod.Get:
case CachingMethod.Put:
if (input.Arguments != null &&
input.Arguments.Count > )
{
var sb = new StringBuilder();
for (int i = ; i < input.Arguments.Count; i++)
{
sb.Append(input.Arguments[i].ToString());
if (i != input.Arguments.Count - )
sb.Append("_");
}
return sb.ToString();
}
else
return "NULL";
default:
throw new InvalidOperationException("无效的缓存方式。");
}
}
#endregion #region IInterceptionBehavior Members
/// <summary>
/// 获取当前行为需要拦截的对象类型接口。
/// </summary>
/// <returns>所有需要拦截的对象类型接口。</returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} /// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var method = input.MethodBase;
var key = method.Name;
if (method.IsDefined(typeof(CachingAttribute), false))
{
var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[];
var valKey = GetValueKey(cachingAttribute, input);
switch (cachingAttribute.Method)
{
case CachingMethod.Get:
try
{
if (CacheManager.Instance.Exists(key, valKey))
{
var obj = CacheManager.Instance.Get(key, valKey);
var arguments = new object[input.Arguments.Count];
input.Arguments.CopyTo(arguments, );
return new VirtualMethodReturn(input, obj, arguments);
}
else
{
var methodReturn = getNext().Invoke(input, getNext);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Put:
try
{
var methodReturn = getNext().Invoke(input, getNext);
if (CacheManager.Instance.Exists(key))
{
if (cachingAttribute.Force)
{
CacheManager.Instance.Remove(key);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Remove:
try
{
var removeKeys = cachingAttribute.CorrespondingMethodNames;
foreach (var removeKey in removeKeys)
{
if (CacheManager.Instance.Exists(removeKey))
CacheManager.Instance.Remove(removeKey);
}
var methodReturn = getNext().Invoke(input, getNext);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
default: break;
}
} return getNext().Invoke(input, getNext);
} /// <summary>
/// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
/// 某些操作。
/// </summary>
public bool WillExecute
{
get { return true; }
} #endregion
}
}

ExceptionLoggingBehavior.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity.InterceptionExtension; namespace Keasy5.Infrastructure.InterceptionBehaviors
{
/// <summary>
/// 表示用于异常日志记录的拦截行为。
/// </summary>
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
#region IInterceptionBehavior Members
/// <summary>
/// 获取当前行为需要拦截的对象类型接口。
/// </summary>
/// <returns>所有需要拦截的对象类型接口。</returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} /// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.Exception != null)
{
Utils.Log(methodReturn.Exception);
}
return methodReturn;
}
/// <summary>
/// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
/// 某些操作。
/// </summary>
public bool WillExecute
{
get { return true; }
} #endregion
}
}

例如如下的配置,是为实现了接口

Keasy5.ServiceContract.IProductService

的类的所以方法添加拦截行为。

web/app.config文件:

  <!--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" />
。。。。。 <register type="Keasy5.ServiceContract.IProductService, Keasy5.ServiceContract" mapTo="Keasy5.Application.Implementation.ProductServiceImpl, Keasy5.Application">
<interceptor type="InterfaceInterceptor" />
<interceptionBehavior type="Keasy5.Infrastructure.InterceptionBehaviors.CachingBehavior, Keasy5.Infrastructure" />
<interceptionBehavior type="Keasy5.Infrastructure.InterceptionBehaviors.ExceptionLoggingBehavior, Keasy5.Infrastructure" />
</register> 。。。。

比如:对于ExceptionLoggingBehavior的拦截行为作用于IProductService接口的实现类的所有方法:

        /// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.Exception != null)
{
Utils.Log(methodReturn.Exception);
}
return methodReturn;
}

效果是:如果IProductService接口的实现类的所有方法如果抛出了异常,将调用

Utils.Log(methodReturn.Exception);

将异常信息写入日志系统(这就是我们进行拦截的目的)。


------------------------------------------------

第一:定义特性:CachingAttribute

CachingAttribute.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Keasy5.Infrastructure.Caching
{
/// <summary>
/// 表示由此特性所描述的方法,能够获得来自基础结构层所提供的缓存功能。
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class CachingAttribute : Attribute
{
#region Ctor
/// <summary>
/// 初始化一个新的<c>CachingAttribute</c>类型。
/// </summary>
/// <param name="method">缓存方式。</param>
public CachingAttribute(CachingMethod method)
{
this.Method = method;
}
/// <summary>
/// 初始化一个新的<c>CachingAttribute</c>类型。
/// </summary>
/// <param name="method">缓存方式。</param>
/// <param name="correspondingMethodNames">
/// 与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。
/// </param>
public CachingAttribute(CachingMethod method, params string[] correspondingMethodNames)
: this(method)
{
this.CorrespondingMethodNames = correspondingMethodNames;
}
#endregion #region Public Properties
/// <summary>
/// 获取或设置缓存方式。
/// </summary>
public CachingMethod Method { get; set; }
/// <summary>
/// 获取或设置一个<see cref="Boolean"/>值,该值表示当缓存方式为Put时,是否强制将值写入缓存中。
/// </summary>
public bool Force { get; set; }
/// <summary>
/// 获取或设置与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。
/// </summary>
public string[] CorrespondingMethodNames { get; set; }
#endregion
}
}

第二:将特性CachingAttribute应用于IProductService的接口方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using ByteartRetail.DataObjects;
using Keasy5.DataObject;
using Keasy5.Infrastructure;
using Keasy5.Infrastructure.Caching; namespace Keasy5.ServiceContract
{
/// <summary>
/// 表示与“商品”相关的应用层服务契约。
/// </summary>
[ServiceContract(Namespace = "http://www.ByteartRetail.com")]
public interface IProductService : IApplicationServiceContract
{
#region Methods
/// <summary>
/// 创建商品信息。
/// </summary>
/// <param name="productDataObjects">需要创建的商品信息。</param>
/// <returns>已创建的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsWithPagination",
"GetFeaturedProducts",
"GetProductsForCategoryWithPagination",
"GetProducts",
"GetProductByID")]
ProductDataObjectList CreateProducts(ProductDataObjectList productDataObjects);
/// <summary>
/// 创建商品分类。
/// </summary>
/// <param name="categoryDataObjects">需要创建的商品分类。</param>
/// <returns>已创建的商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetCategories")]
CategoryDataObjectList CreateCategories(CategoryDataObjectList categoryDataObjects);
/// <summary>
/// 更新商品信息。
/// </summary>
/// <param name="productDataObjects">需要更新的商品信息。</param>
/// <returns>已更新的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsWithPagination",
"GetFeaturedProducts",
"GetProductsForCategoryWithPagination",
"GetProducts", "GetProductByID")]
ProductDataObjectList UpdateProducts(ProductDataObjectList productDataObjects);
/// <summary>
/// 更新商品分类。
/// </summary>
/// <param name="categoryDataObjects">需要更新的商品分类。</param>
/// <returns>已更新的商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetCategories", "GetCategoryByID")]
CategoryDataObjectList UpdateCategories(CategoryDataObjectList categoryDataObjects);
/// <summary>
/// 删除商品信息。
/// </summary>
/// <param name="productIDs">需要删除的商品信息的ID值。</param>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsWithPagination",
"GetFeaturedProducts",
"GetProductsForCategoryWithPagination",
"GetProducts", "GetProductByID")]
void DeleteProducts(IDList productIDs);
/// <summary>
/// 删除商品分类。
/// </summary>
/// <param name="categoryIDs">需要删除的商品分类的ID值。</param>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetCategories", "GetCategoryByID")]
void DeleteCategories(IDList categoryIDs);
/// <summary>
/// 设置商品分类。
/// </summary>
/// <param name="productID">需要进行分类的商品ID值。</param>
/// <param name="categoryID">商品分类ID值。</param>
/// <returns>带有商品分类信息的对象。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsForCategoryWithPagination")]
CategorizationDataObject CategorizeProduct(Guid productID, Guid categoryID);
/// <summary>
/// 取消商品分类。
/// </summary>
/// <param name="productID">需要取消分类的商品ID值。</param>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Remove, "GetProductsForCategory",
"GetProductsForCategoryWithPagination")]
void UncategorizeProduct(Guid productID);
/// <summary>
/// 根据指定的ID值获取商品分类。
/// </summary>
/// <param name="id">商品分类ID值。</param>
/// <param name="spec">查询方式。</param>
/// <returns>商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
CategoryDataObject GetCategoryByID(Guid id, QuerySpec spec);
/// <summary>
/// 获取所有的商品分类。
/// </summary>
/// <param name="spec">查询方式。</param>
/// <returns>所有的商品分类。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
CategoryDataObjectList GetCategories(QuerySpec spec);
/// <summary>
/// 根据指定的ID值获取商品信息。
/// </summary>
/// <param name="id">商品信息ID值。</param>
/// <param name="spec">查询方式。</param>
/// <returns>商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObject GetProductByID(Guid id, QuerySpec spec);
/// <summary>
/// 获取所有的商品信息。
/// </summary>
/// <param name="spec">查询方式。</param>
/// <returns>商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectList GetProducts(QuerySpec spec);
/// <summary>
/// 以分页的方式获取所有商品信息。
/// </summary>
/// <param name="pagination">带有分页参数信息的对象。</param>
/// <returns>经过分页的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectListWithPagination GetProductsWithPagination(Pagination pagination);
/// <summary>
/// 根据指定的商品分类ID值,获取该分类下所有的商品信息。
/// </summary>
/// <param name="categoryID">商品分类ID值。</param>
/// <returns>所有的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectList GetProductsForCategory(Guid categoryID);
/// <summary>
/// 根据指定的商品分类ID值,以分页的方式获取该分类下所有的商品信息。
/// </summary>
/// <param name="categoryID">商品分类ID值。</param>
/// <param name="pagination">带有分页参数信息的对象。</param>
/// <returns>所有的商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectListWithPagination GetProductsForCategoryWithPagination(Guid categoryID, Pagination pagination);
/// <summary>
/// 获取所有的特色商品信息。
/// </summary>
/// <param name="count">需要获取的特色商品信息的个数。</param>
/// <returns>特色商品信息。</returns>
[OperationContract]
[FaultContract(typeof(FaultData))]
[Caching(CachingMethod.Get)]
ProductDataObjectList GetFeaturedProducts(int count);
#endregion
}
}

第三:拦截IProductService接口的实现类的所有方法的所有方法,

并通过CachingAttribute特性进行方法 的筛选,

还进一步根据CachingAttribute的属性值进行一步的处理:

CachingBehavior .cs

        /// <summary>
/// 通过实现此方法来拦截调用并执行所需的拦截行为。
/// </summary>
/// <param name="input">调用拦截目标时的输入信息。</param>
/// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
/// <returns>从拦截目标获得的返回信息。</returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var method = input.MethodBase;
var key = method.Name;
if (method.IsDefined(typeof(CachingAttribute), false))
{
var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[];
var valKey = GetValueKey(cachingAttribute, input);
switch (cachingAttribute.Method)
{
case CachingMethod.Get:
try
{
if (CacheManager.Instance.Exists(key, valKey))
{
var obj = CacheManager.Instance.Get(key, valKey);
var arguments = new object[input.Arguments.Count];
input.Arguments.CopyTo(arguments, );
return new VirtualMethodReturn(input, obj, arguments);
}
else
{
var methodReturn = getNext().Invoke(input, getNext);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Put:
try
{
var methodReturn = getNext().Invoke(input, getNext);
if (CacheManager.Instance.Exists(key))
{
if (cachingAttribute.Force)
{
CacheManager.Instance.Remove(key);
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue);
}
else
CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
case CachingMethod.Remove:
try
{
var removeKeys = cachingAttribute.CorrespondingMethodNames;
foreach (var removeKey in removeKeys)
{
if (CacheManager.Instance.Exists(removeKey))
CacheManager.Instance.Remove(removeKey);
}
var methodReturn = getNext().Invoke(input, getNext);
return methodReturn;
}
catch (Exception ex)
{
return new VirtualMethodReturn(input, ex);
}
default: break;
}
} return getNext().Invoke(input, getNext);
}

--------------------------------

ServiceLocator.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration; namespace Keasy5.Infrastructure
{
/// <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>();
} public IEnumerable<T> ResolveAll<T>()
{
return container.ResolveAll<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
}
}

 

出处:https://www.lmlphp.com/user/58024/article/item/933671/

posted on 2021-10-11 15:12  jack_Meng  阅读(625)  评论(0编辑  收藏  举报

导航