Enterprise Library深刻解析及活应用(9):个人认为相比较严重的关于CachingCallHandler的Bug

共5步:

微软EnterLib的Policy Injection Application
Block(PIAB)是一个比好用之轻量级的AOP框架,你可透过创建于定义的CallHandler实现某些CrossCutting的逻辑,并以起定义特性或者配备的计下至目标措施方面。PIAB自身也供了同等名目繁多的CallHandler,其中CachingCallHandler直利用HttpRuntime的Cache实现了遵照方法级别之休养生息存。可是,PIAB宣布到现在,CachingCallHandler就直接满怀正一个题目:要是目的措施有Out参数并且重返路不是void,会抛出IndexOutOfRangeException,假设回到路也void,out参数也无会见给缓存。不亮微软对那个作何考虑,反正我认为就是一个不可原谅的Bug。(Source
Code从这里下载)

1、安装jdk

一如既往、问题重现

2、安装eclipse

其一题材还尚重现,为了相比大家先行来看望正常情况下CachingCallHandler的变现。下边我定义了一个概括的接口:IMembership瑟维斯(Service)(Service),
包含一个道GetUserName依照传入的User ID重临User
Name。Membership瑟维斯(Service)(Service)实现了该接口,为了有利于我们确定方法执行的结果是否被缓存,我受每回执行都回去一个GUID。CachingCallHandler直接为由定义特性的艺术采取至GetUserName方法齐。

3、安装android-sdk

   1: using System;

   2: using System.Threading;

   3: using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;

   4: namespace CachingCallHandler4OutParam

   5: {

   6:     public interface IMembershipService

   7:     {

   8:         string GetUserName(string userId);

   9:     }

  10:  

  11:     public class MembershipService : IMembershipService

  12:     {        

  13:         [CachingCallHandler]

  14:         public string GetUserName(string userId)

  15:         {

  16:             return Guid.NewGuid().ToString();

  17:         }

  18:     }

  19: }

4、安装adb

如今,在Main方法被,编写如下的代码:通过PolicyInjection的Create<TType,
TInterface>创设可以被PIAB截获的Proxy对象,并于一个极其循环中传来相同的参数调用GetUserName方法。从出口结果我们来看,重回的UserName都是相同的,从而证实了第一不成举行之结果为成功缓存。

5、在eclipse中安装ADT

   1: using System;

   2: using System.Threading;

   3: using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;

   4: namespace CachingCallHandler4OutParam

   5: {

   6:     class Program

   7:     {

   8:         static void Main(string[] args)

   9:         {

  10:             IMembershipService svc = PolicyInjection.Create<MembershipService, IMembershipService>();

  11:             while(true)

  12:             {                

  13:                 Console.WriteLine(svc.GetUserName("007"));

  14:                 Thread.Sleep(1000);

  15:             }

  16:         }

  17:     }    

  18: }

 

出口结果:

1、安装jdk

E1E8EA0F-7620-4879-BA5D-33356568336E

E1E8EA0F-7620-4879-BA5D-33356568336E

E1E8EA0F-7620-4879-BA5D-33356568336E

E1E8EA0F-7620-4879-BA5D-33356568336E

E1E8EA0F-7620-4879-BA5D-33356568336E

E1E8EA0F-7620-4879-BA5D-33356568336E

前边就装好了。

今大家修改我们的次第:将GetUserName改化TryGetUserName,将UserName以出口参数的款型反悔,Bool类型的再次来到值表示UserId是否存在,相信我们都汇合以为当下是一个生广阔的API定义格局。

就此脚的授命安装,只需要有日子,它便会下载许多底文书,所暨您一旦包您的大网环境得天独厚:

using System;

using System.Threading;

using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;

using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers;

namespace CachingCallHandler4OutParam

{

    class Program

    {

        static void Main(string[] args)

        {

            IMembershipService svc = PolicyInjection.Create<MembershipService, IMembershipService>();

            string userName;

            while (true)

            {

                svc.TryGetUserName("007", out userName);

                Console.WriteLine(userName);

                Thread.Sleep(1000);

            }

        }

    }

 

    public interface IMembershipService

    {

        bool TryGetUserName(string userId, out string userName);

    }

 

    public class MembershipService : IMembershipService

    {

        [CachingCallHandler]

        public bool TryGetUserName(string userId, out string userName)

        {

            userName = Guid.NewGuid().ToString();

            return true;

        }       

    }

}

sudo add-apt-repository ppa:webupd8team/java

运作方面一样段先后之后,会弃来如下一个IndexOutOfRangeException,从StatckTrace我们好清楚,该老实际上是于用计调用再次来到音信转换成为相应的出口参数是失误导致的:

sudo apt-get update

图片 1Stack
Trace:

sudo apt-get install oracle-java8-installer

at System.Runtime.Remoting.Proxies.RealProxy.PropagateOutParameters(IMessage msg, Object[] outArgs, Object returnValue)

at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

at CachingCallHandler4OutParam.IMembershipService.TryGetUserName(String userId, String& userName)

at CachingCallHandler4OutParam.Program.Main(String[] args) in e:\EnterLib\CachingCallHandler4OutParam\CachingCallHandler4OutParam\Program.cs:line 15

at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)

at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

at System.Threading.ThreadHelper.ThreadStart()

sudo apt-get install oracle-java8-set-default

老二、是呀招大的舍弃来?

由此命令执行安装的功利是不要配置环境变量。

我们现在经过CachingCallHandler的Invoke方法的兑现,可以望有些问题:该CallHander仅仅会缓存方法的重临值(this.AddToCache(key,
return2.ReturnValue);),而休是缓存输出参数;由于只唯有回值为缓存,所以最终创制的IMethodReturn不含输出参数,从而导致重临的消息及参数列表不相同,导致大的发出。

 

   1: public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)

   2: {

   3:     if (this.TargetMethodReturnsVoid(input))

   4:     {

   5:         return getNext()(input, getNext);

   6:     }

   7:     object[] inputs = new object[input.Inputs.Count];

   8:     for (int i = 0; i < inputs.Length; i++)

   9:     {

  10:         inputs[i] = input.Inputs[i];

  11:     }

  12:     string key = this.keyGenerator.CreateCacheKey(input.MethodBase, inputs);

  13:     object[] objArray2 = (object[])HttpRuntime.Cache.Get(key);

  14:     if (objArray2 == null)

  15:     {

  16:         IMethodReturn return2 = getNext()(input, getNext);

  17:         if (return2.Exception == null)

  18:         {

  19:             this.AddToCache(key, return2.ReturnValue);

  20:         }

  21:         return return2;

  22:     }

  23:     return input.CreateMethodReturn(objArray2[0], new object[] { input.Arguments });

  24: }

2、安装eclipse

老三、问题如何缓解?

下载地址http://www.eclipse.org/downloads/,选择linux 32bit

现大家来Fix这一个Bug,让它们襄助出口参数并针对输出参数和归值一并缓存。为夫,我首先创立了如下一个OutputParamter类表示输出参数,属性Value和Index分别代表参数值和在道参数列表中的职位:

双击eclipse就得启动eclipse程序,启动之早晚择好的workspace

   1: public class OutputParameter

   2: {

   3:     public object Value

   4:     { get; private set; }

   5:  

   6:     public int Index

   7:     { get; private set; }

   8:  

   9:     public OutputParameter(object value, int index)

  10:     {

  11:         this.Value = value;

  12:         this.Index = index;

  13:     }

  14: }

此时eclipse也就到底安装好了

然后用急需进行缓存的方法重回值和输出参数封装于一个单独的接近吃,我以它打名叫也InvocationResult.
六只属于性ReturnValue和Outputs分别代表回去回值和输出参数。StreamlineArguments方法结合传入的之所以参数列表重回一个情势参数值的一再组,该数组的因素顺序需要与法的参数列表相包容。

3、安装android-sdk

   1: public class InvocationResult

   2: {

   3:     public object ReturnValue

   4:     { get; private set; }

   5:  

   6:     public OutputParameter[] Outputs

   7:     { get; set; }

   8:  

   9:     public InvocationResult(object returnValue, OutputParameter[] outputs)

  10:     {

  11:         Guard.ArgumentNotNull(returnValue, "returnValue");

  12:         this.ReturnValue = returnValue;

  13:         if (null == outputs)

  14:         {

  15:             this.Outputs = new OutputParameter[0];

  16:         }

  17:         else

  18:         {

  19:             this.Outputs = outputs;

  20:         }

  21:     }

  22:  

  23:     public bool TryGetParameterValue(int index, out object parameterValue)

  24:     {

  25:         parameterValue = null;

  26:         var result = this.Outputs.Where(param => param.Index == index);

  27:         if (result.Count() > 0)

  28:         {

  29:             parameterValue = result.ToArray()[0].Value;

  30:             return true;

  31:         }

  32:         return false;

  33:     }

  34:  

  35:     public object[] StreamlineArguments(IParameterCollection arguments)

  36:     {

  37:         var list = new List<object>();

  38:         object paramValue;

  39:         for (int i = 0; i < arguments.Count; i++)

  40:         {

  41:             if (this.TryGetParameterValue(i, out paramValue))

  42:             {

  43:                 list.Add(paramValue);

  44:             }

  45:             else

  46:             {

  47:                 list.Add(arguments[i]);

  48:             }

  49:         }

  50:  

  51:         return list.ToArray();

  52:     }

  53: }

官方下载地址http://developer.android.com/sdk/index.html

下一场在存活CachingCallHandler的根底及,添加如下两单援救方法:AddToCache和GetInviocationResult,分别用于将InvocationResult对象参预缓存,以及依据IMethodInvocation和IMethodReturn对象创立InvocationResult对象。最终用类名改成为FixedCachingCallHandler以体现区别。

选择android-sdk_r24.3.4-linux.tgz

   1: public class FixedCachingCallHandler : ICallHandler

   2: {

   3:     //其他成员

   4:     private void AddToCache(string key, InvocationResult result)

   5:     {

   6:         HttpRuntime.Cache.Insert(key, result, null, Cache.NoAbsoluteExpiration, this.expirationTime, CacheItemPriority.Normal, null);

   7:     }

   8:  

   9:     

  10:     private InvocationResult GetInvocationResult(IMethodInvocation input, IMethodReturn methodReturn)

  11:     {

  12:         var outParms = new List<OutputParameter>();

  13:  

  14:         for (int i = 0; i < input.Arguments.Count; i++)

  15:         {

  16:             ParameterInfo paramInfo = input.Arguments.GetParameterInfo(i);

  17:             if (paramInfo.IsOut)

  18:             {

  19:                 OutputParameter param = new OutputParameter(input.Arguments[i], i);

  20:                 outParms.Add(param);

  21:             }

  22:         }

  23:  

  24:         return new InvocationResult(methodReturn.ReturnValue, outParms.ToArray());

  25:     }

  26:     

  27: }

下载好了下双击打开,解压形式与此前的jdk解压模式一样,不再另行

终极大家再一次写Invoke方法,
去处对回路void的过滤,并促成对基于InvocationResult对象的缓存和取:

在/root/.bashrc末尾行添加 

export ANDROID_HOME="/home/work/software/android-sdk-linux"
export PATH="$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools"
   1: public class FixedCachingCallHandler : ICallHandler

   2: {

   3:     //其他成员

   4:     public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)

   5:     {

   6:         object[] inputs = new object[input.Inputs.Count];

   7:         for (int i = 0; i < inputs.Length; i++)

   8:         {

   9:             inputs[i] = input.Inputs[i];

  10:         }

  11:         string key = this.keyGenerator.CreateCacheKey(input.MethodBase, inputs);

  12:         InvocationResult result = (InvocationResult)HttpRuntime.Cache.Get(key);

  13:         if (result == null)

  14:         {

  15:             IMethodReturn return2 = getNext()(input, getNext);

  16:             if (return2.Exception == null)

  17:             {

  18:                 this.AddToCache(key, this.GetInvocationResult(input, return2));

  19:             }

  20:             return return2;

  21:         }

  22:         return input.CreateMethodReturn(result.ReturnValue, result.StreamlineArguments(input.Arguments));

  23:  

  24:         return returnValue;

  25:     }

  26:  

  27:     private InvocationResult GetInvocationResult(IMethodInvocation input, IMethodReturn methodReturn)

  28:     {

  29:         var outParms = new List<OutputParameter>();

  30:  

  31:         for (int i = 0; i < input.Arguments.Count; i++)

  32:         {

  33:             ParameterInfo paramInfo = input.Arguments.GetParameterInfo(i);

  34:             if (paramInfo.IsOut)

  35:             {

  36:                 OutputParameter param = new OutputParameter(input.Arguments[i], i);

  37:                 outParms.Add(param);

  38:             }

  39:         }

  40:  

  41:         return new InvocationResult(methodReturn.ReturnValue, outParms.ToArray());

  42:     }    

  43: }

此时此sdk十分给一个软件管理器,假如只要举办android开发来说,至少要发生一个android版本的,此时凡拖欠的,接下去当eclipse中配置ADT插件

利用新的CachingCallHandler,你用汇合获取不错的结果:

好就此命令执行启动android :

4DD83AE8-070B-49df-9781-6F4673C85189

4DD83AE8-070B-49df-9781-6F4673C85189

4DD83AE8-070B-49df-9781-6F4673C85189

4DD83AE8-070B-49df-9781-6F4673C85189

4DD83AE8-070B-49df-9781-6F4673C85189
#android

作者:Artech
出处:http://artech.cnblogs.com
本文版权归作者和天涯论坛共有,欢迎转载,但未经作者同意要保留这一个段子注脚,且在著作页面彰着地点于来原文连接,否则保留追究法律责任的权利。

 

4、安装adb(跟第三步可能操作有点重,可是为了清晰思路,浏览者可以忽略这同步)

1、下载android-sdk

2、解压缩后在有一个索引下,设置环境变量,在~/.bash_profile 或者
~/.bashrc文件中,

自身是身处bashrc里之,插足一行

export PATH=${PATH}:<存放目录>/tools

3、启动android,下载android sdk tools | android sdk platform tools |
android sdk build-tools | android support repository | android support
library 那一个文本。

chmod 777 <存放目录>/tools/adb    #想必得开这同样步

3、连接上手机,通过终点,进入到tools目录下,首蹩脚举办,输入命令adb
kill-server。

4、现在既足以利用adb了。adb工具分外好用,可以调试android手机,下边是有常用命令,可能会晤减出来详细总计一篇稿子介绍。

5、adb devices

6、adb root

7、adb shell

 

 

5、在eclipse中安装ADT

官提供零星种安装模式http://developer.android.com/sdk/eclipse-adt.html#installing,第一栽是在线安装,第二种植是预先下载安装包,然后用eclipse直接装,三种办法结果是一致的,在那么些推荐在线安装形式(当时以此间折腾了老深切,安装的时刻平素指示缺乏什么东西之类的,第二上突然同时可以安装了,莫名其妙,希望读者会五回性安装成功!)

打开eclipse—>help—>Install New Software

点击work with前面的输入框前边的Add

每当Name后边输入:ADT Plugin(能够不管起名)

于Location前边输入:https://dl-ssl.google.com/android/eclipse/

点击OK,行了,按照指示,一步一步安装吧,中间会出提示是否又开动eclipse,拔取restart
now就推行了。之后虽配置OK了。

 

  

作者:chsry
出处:www.cnblogs.com/chsry
日期:2015-09-05-16:40:01
本博客文章,大多系个人整理开发,转载请注明出处

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图