我们在开篇中提到,希望能有一种办法,能自动适应系统的环境配置,在局域网小型应用中将直接访问数据库以获得最高的性能,在分布式环境中自动使用WCF来获得较好的安全性和连通性。

但是,我们不希望这样的特性使我们的开发变得过于复杂,需要在新特性和工作量之间寻求一个合理的平衡点。


原理分析:

用自动代理的业务层结构如下:

检测到局域网配置时的情况,将直接返回业务对象实例。

分布式配置的调用情况。

我们可以从图上看出,使用局域网配置或分布式配置完全取决于自动代理对象,而对于使用者(表现层)是完全透明的。当然,对于分布式配置的情况,传入业务端的参数和结果都是需要经过序列化的,否则将无法在WCF中传输,这是我们在开发业务层时需要注意的问题。

自动代理的对象实现很简单,我们需要做的就是拦截调用,将调用的信息(业务对象名,方法名,参数)等构建为WCF服务对象的参数,通过统一的服务接口调用服务端,服务端得到调用后,根据调用信息实例化合适的业务对象,调用相应的方法,完成后将结果以统一的返回格式返回给自动代理对象,而这些返回的数据将被反序列化后作为该方法的返回值。


代码实现:

在目前的开源框架中,Castle和Spring.net都提供了很好的自动代理的类库。我们将以Spring.net为例来实现自动代理对象。

public static class BizAutoWcfProxy
{public static T Get<T>(T instance) where T : class{var p = new ProxyFactory(instance);p.AddAdvice(new AroundAdvise());return p.GetProxy() as T;}internal static IWcfProxy GetMethodProxy(){var service = PubFunc.GetAppSetting("WcfService");if (string.IsNullOrEmpty(service)){return new WcfProxy();}var binding = new NetTcpBinding(SecurityMode.None, false);var f = new ChannelFactory<IWcfProxy>(binding, service);var proxy = f.CreateChannel();return proxy;}
}

上面是自动代理工厂的实现.这个工厂中,提供了一个供自动代理对象使用的方法GetMethodProxy,这个方法中检测应用程序配置文件的WcfService配置,如果配置不为空,则创建自动代理对象,否则直接返回.

public class AroundAdvise : IMethodInterceptor
{public object Invoke(IMethodInvocation invocation){Log.Get().Debug("方法{0}被调用被拦截", invocation.Method.Name);try{var p = BizAutoWcfProxy.GetMethodProxy();//调用信息var m = new MethodProxy{ClassName = invocation.TargetType.AssemblyQualifiedName,        //业务对象名MethodName = invocation.Method.Name                             //方法};//将调用参数也包含在调用信息中if (invocation.Arguments != null && invocation.Arguments.Length > 0)m.Params = invocation.Arguments.ToList().ConvertAll(PubFunc.Serialize.ObjToBytes).ToArray();//调用WCF服务var r = p.Execute(m);//正常的情况,没有异常出现if (!r.HasException){//返回值object returnValue = r.GetValue();var ind = 0;//处理ref和out的参数的返回invocation.Method.GetParameters().ToList().ForEach(mp =>{if (mp.IsOut){invocation.Arguments[mp.Position] = PubFunc.Serialize.BytesToObj(r.OutValue[ind++]);}});return returnValue;}//出现异常的情况,反序列号异常信息,重新在客户端抛出var ex = PubFunc.Serialize.BytesToObj(r.Exception) as Exception;if (ex != null) throw ex;throw new Exception("无法反序列化异常信息");}catch (CommunicationException oe){Log.Get().Debug("WCF通讯错误", oe);throw;}}
}

上面是方法拦截的实现。这里除了需要考虑正常情况下调用之外,还要考虑服务器端可能发生的异常,这里增加了对异常的处理。

//唯一的WCF接口
[ServiceContract]
public interface IWcfProxy
{[OperationContract]ReturnValue Execute(MethodProxy m);
}
//服务实现
public class WcfProxy : IWcfProxy
{public ReturnValue Execute(MethodProxy m){try{//服务端实例化业务对象var con = Type.GetType(m.ClassName).GetConstructor(BindingFlags.NonPublic| BindingFlags.Public| BindingFlags.Instance,null,new Type[0],null);var cls = con.Invoke(new object[0]);//处理参数的反序列化var method = cls.GetType().GetMethod(m.MethodName, BindingFlags.Instance | BindingFlags.Public);var pm = new object[0];if (m.Params != null && m.Params.Length > 0)pm = m.Params.ToList().ConvertAll(PubFunc.Serialize.BytesToObj).ToArray();//调用var rlt = method.Invoke(cls, pm);var r = new ReturnValue();r.SetValue(rlt);//处理out参数var outPlist = new List<byte[]>();method.GetParameters().ToList().ForEach(p =>{if(p.IsOut){outPlist.Add(PubFunc.Serialize.ObjToBytes(pm[p.Position]));}});if (outPlist.Count > 0)r.OutValue = outPlist.ToArray();//正常返回return r;}catch(TargetInvocationException ex1){var ex = ex1.InnerException;//处理服务器端发生的两种异常信息,这些属于正常的业务异常,需要返回到客户端if (ex is BizException || ex is DAException){var r = new ReturnValue();r.HasException = true;r.Exception = PubFunc.Serialize.ObjToBytes(ex);return r;}else{//非正常情况下的异常,统一包装为服务端异常返回var serverex = new ServerException(ex.Message);serverex.Trace = ex.StackTrace;var r = new ReturnValue();r.HasException = true;r.Exception = PubFunc.Serialize.ObjToBytes(serverex);return r;}}}
}
//服务返回对象
[DataContract]
public class ReturnValue
{[DataMember]public bool HasException { get; set; }[DataMember]public byte[] Exception { get; set; }[DataMember]public byte[] Value { get; set; }[DataMember]public byte[][] OutValue { get; set; }public void SetValue(object value){if (value == null){Value = null; return;}Value=PubFunc.Serialize.ObjToBytes(value);}public object GetValue(){if (Value == null){return null;}return PubFunc.Serialize.BytesToObj(Value);}
}
//调用信息
[DataContract]
public class MethodProxy
{[DataMember]public string ClassName { get; set; }[DataMember]public string MethodName { get; set; }[DataMember]public byte[][] Params{get;set;}
}

这里是完整的服务端的方法,提供WCF接口,处理业务层对象调用的过程。


实现不算复杂,代码也不多,欢迎讨论。不足之处请指正。

转载于:https://www.cnblogs.com/yiway/archive/2011/01/24/MY_FW_4.html

不是架构的架构之四:业务层的实现与自动代理相关推荐

  1. 架构语言ArchiMate -业务层(Business Layer)

    在线ArchiMate1.0中对ArchiMate进行了详细的介绍,想学习的一些同事不太喜欢看英文资料,而年后项目组要开始做业务架构了,所以在春节前最后一天把对业务层的介绍写完.以下我将会分别对不同层 ...

  2. 走向.NET架构设计—第四章—业务层分层架构(后篇)

    走向.NET架构设计-第四章-业务层分层架构(后篇) 前言: 在上一篇文章中,我们讨论了组织业务逻辑的模式:Transaction Script和Active Record,Domain Model. ...

  3. 走向.NET架构设计—第四章—业务层分层架构(前篇)

    走向.NET架构设计-第四章-业务层分层架构(前篇) 前言:在任何一个项目中业务层毫无疑问是最重要的层,所以在设计的过程中,如何组织业务层是至关重要的.本章的讨论将会涉及Flower的架构模式一书中的 ...

  4. 走向.NET架构设计—第五章—业务层模式,原则,实践(中篇)

    走向.NET架构设计-第五章-业务层模式,原则,实践(中篇) 前言:设计模式并不是什么很高深的东西,至少不是那么"神乎其神".说到底,设计模式就是一些设计思想.下面我们就走进项目, ...

  5. 走向.NET架构设计—第五章—业务层模式,原则,实践(后篇)

    走向.NET架构设计-第五章-业务层模式,原则,实践(后篇) 前言:在上一篇文章中,讲述了一些设计模式的使用,本篇首先接着介绍还没有讲完的一些设计模式,然后再讲述一些架构模式中的超类模式,作为本篇的结 ...

  6. 走向.NET架构设计—第四章—业务层分层架构(中篇)

    走向.NET架构设计-第四章-业务层分层架构(中篇) 前言: 在上一篇文章中,我们讨论了两种组织业务逻辑的模式:Transaction Script和Active Record.在本篇中开始讲述Dom ...

  7. java三层架构(表示层,业务逻辑层,数据访问层,与两层的区别,三层架构的优缺点)

    目录 1 什么是三层 2 为什么使用三层 3 与两层的区别 1 什么是三层 UI(表现层): 主要是指与用户交互的界面.用于接收用户输入的数据和显示处理后用户需要的数据. BLL:(业务逻辑层): U ...

  8. 三层架构理解(表现层、业务层、持久层)

    三层架构:即表现层.业务层.持久层. 大话一下这三个层. 举例1+1=? 你输入1+1=?的地方就是表现层,业务层把1+1=?拆成"1","+","1 ...

  9. JAVA三层架构,持久层,业务层,表现层的理解

    转自:https://blog.csdn.net/ljf_study/article/details/64443653 SSH: Struts(表示层)+Spring(业务层)+Hibernate(持 ...

最新文章

  1. 关于微分方程的初值条件和边界条件(狄里克雷(Dirichlet)条件、诺依曼(Neumann)条件、洛平(Robin)条件)
  2. python处理数据的优势-python处理excel的优势是什么
  3. 数据中心气流管理的基础:密闭系统的比较
  4. android权限机制6.0,Android6.0权限机制(二):封装
  5. hive报错:Call from hostname/127.0.1.1 to localhost:9000 failed on connection exception.主节点9000端口拒绝访问.
  6. python和c先学哪个-python和c先学哪个
  7. php phpmailer发送邮件
  8. JAVAweb JSP飞机订票系统航空机票预订销售系统(机票预订系统)
  9. 开源硬件USB抓包及协议分析工具分享
  10. 数字化制造的世界最高水平,看灯塔工厂如何推进数字化
  11. uni-app运行到微信开发工具无法预览
  12. 无废话ExtJs 入门教程七[登陆窗体Demo:Login]
  13. [虚拟机] 如何让VMware上的虚拟机识别到U盘
  14. 如何比较两个内容相似的Word文档
  15. 23吉林大学软件学硕经验贴
  16. 数组,es5,字符串,Math和Date
  17. 2013 年度回忆录
  18. 使用mysqladmin修改mysql数据库密码
  19. win7计算机没有光驱图标不见了,win7系统电脑光驱图标不见了怎么办?
  20. matlabpython绘图:一枝花

热门文章

  1. 电脑技巧:键盘上ESC按键的使用小技巧,你都知道吗?
  2. 后端技术:ELK不香了?企业级日志平台新框架 Graylog介绍
  3. java如何改注释_关于Java:更改字符串值的注释
  4. c语言深度剖析第三版pdf_入门到入坟,蕴含全网最强知识点3283页笔记、pdf教程,活到老,学到老...
  5. 用符号方法求下列极限或导数matlab,matlab实验
  6. Jersey注解详解
  7. Mysql数据库正则表达式
  8. 0-2岁的app开发人员必读,Android开发APP前的准备事项
  9. 深入 Adobe Reader 保护模式 —— 第一部分 —— 设计
  10. Tomcat乱码解决