添加wcf服务引用时,vs.net本来就会帮我们在app.config/web.config里生成各种配置,这没啥好研究的,但本文谈到的配置并不是这个。先看下面的图:

通常,如果采用.NET的WCF技术来架构SOA风格的应用,我们会把项目做一些基本的分层,如上图:

01. contract层:通常定义服务的接口(即服务契约ServiceContract,指明该服务提供了哪些方法可供外部调用)、以及接口方法中传输的Model定义(即:数据契约DataContract,指明方法中的对象参数的Class定义)

02. implementation层:即服务接口的实现

03. host层:wcf最终需要一个宿主环境,如果是web应用,最简单的办法莫过于直接寄宿在IIS上

04. client层:即服务的消费方,如果是b/s应用,通常就是一个web application

实际部署时,一般将wcf服务层和client层分开部署,如下图:

如果并发数随着业务的增长而增长,不管是client层的website,还是服务层的service,加上其它技术,比如集群或负载均衡之类,可以很方便进行扩充。服务的实现逻辑也可以方便的单独的修改替换(前提是服务契约相对稳定)

但如果应用的规模较小,出于成本考虑,完全有可能Service层和Website Client部署在一台机器上,虽然1个IIS上架2个站点完全没有问题,但是总归有点不爽,既然都在一台机器上了,为啥还要自己调用自己,增加无谓的开销呢?

最好是在不修改原来代码的前提下,通过简单的配置文件修改,就能让原来远程调用WCF的方式,改成直接调用本地DLL程序集,反过来也一样,这样就比较灵活了。事实上,我们公司很多项目就是这样处理的,规模小的应用,直接全都部署在一台机器上,等应用规模上去了,再分开部署,代码完全不用动,只要修改相关配置即可。

原理其实非常简单,反射即可,先在Client层的web.config或app.config中,增加类似以下节点:

  1. <appSettings>
  2. <!--调用方式:Remote远程调用,Local本地调用(注:本地调用时,bin目录下必须有[服务实现类]的dll)-->
  3. <add key="CallType" value="Remote"/>
  4. <!--本地调用时,程序集的名称-->
  5. <add key="AssemblyName" value="sjtu.wcf.demo.implementation"/>
  6. <!--本地调用时,[服务实现类]的名称-->
  7. <add key="ServiceTypeName" value="sjtu.wcf.demo.implementation.DemoService"/>
  8. </appSettings>

CallType就决定了调用方式:“远程调用”或“本地DLL调用”。然后在本地写一个调用的Client类:(注:wcf的调用方式,参考了dudu的文章“享受无止境 - 改进版WCF Client”)

  1. using System;
  2. using System.Linq.Expressions;
  3. using System.Reflection;
  4. using System.ServiceModel;
  5. using sjtu.wcf.demo.client.configs;
  6.  
  7. namespace sjtu.wcf.demo.client
  8. {
  9. /// <summary>
  10. /// Wcf客户端
  11. /// </summary>
  12. /// <typeparam name="T">ServiceContract接口</typeparam>
  13. public class WcfClient<T> where T : class
  14. {
  15.  
  16. private readonly string assemblyName;
  17. private readonly string implTypeName;
  18. private readonly string callType;
  19.  
  20. public WcfClient()
  21. {
  22. callType = ConfigHelper.CallType.ToLower();
  23. if (callType == CallType.Local.ToString().ToLower())
  24. {
  25. assemblyName = ConfigHelper.AssemblyName;
  26. implTypeName = ConfigHelper.ServiceTypeName;
  27. }
  28. }
  29.  
  30. /// <summary>
  31. /// 对外提供的Call方法
  32. /// </summary>
  33. /// <typeparam name="R"></typeparam>
  34. /// <param name="expression"></param>
  35. /// <returns></returns>
  36. public R Call<R>(Expression<Func<T, R>> expression)
  37. {
  38. if (callType == CallType.Local.ToString().ToLower())
  39. {
  40. return InvokeLocalMethod<R>(expression);
  41. }
  42. return InvokeRemoteMethod<R>(expression);
  43. }
  44.  
  45. /// <summary>
  46. /// 调用本地程序集方法
  47. /// </summary>
  48. /// <typeparam name="R"></typeparam>
  49. /// <param name="operation"></param>
  50. /// <returns></returns>
  51. private R InvokeLocalMethod<R>(Expression<Func<T, R>> operation)
  52. {
  53. Assembly asm = Assembly.Load(new AssemblyName(assemblyName));
  54. T t = (T)asm.CreateInstance(implTypeName);
  55. R result = operation.Compile().Invoke(t);
  56. return result;
  57. }
  58.  
  59. /// <summary>
  60. /// 调用远程wcf方法
  61. /// </summary>
  62. /// <typeparam name="R"></typeparam>
  63. /// <param name="operation"></param>
  64. /// <returns></returns>
  65. private R InvokeRemoteMethod<R>(Expression<Func<T, R>> operation)
  66. {
  67. ChannelFactory<T> channelFactory = new ChannelFactory<T>("*");
  68.  
  69. T channel = channelFactory.CreateChannel();
  70. var client = (IClientChannel)channel;
  71. client.Open();
  72. R result = operation.Compile().Invoke(channel);
  73. try
  74. {
  75. if (client.State != CommunicationState.Faulted)
  76. {
  77. client.Close();
  78. }
  79. }
  80. catch
  81. {
  82. client.Abort();
  83. }
  84. return result;
  85. }
  86. }
  87. }

这样调用时,只需要一行代码即可:

  1. var students = new WcfClient<IStudent>().Call(c => c.GetStudents("jerry"));

完整示例代码下载:http://files.cnblogs.com/yjmyzz/WcfInvoke.zip

Wcf:可配置的服务调用方式的更多相关文章

  1. 小D课堂 - 新版本微服务springcloud+Docker教程_4-06 Feign核心源码解读和服务调用方式ribbon和Feign选择

    笔记 6.Feign核心源码解读和服务调用方式ribbon和Feign选择         简介: 讲解Feign核心源码解读和 服务间的调用方式ribbon.feign选择             ...

  2. 小D课堂 - 新版本微服务springcloud+Docker教程_4-02 微服务调用方式之ribbon实战 订单调用商品服务

    笔记 2.微服务调用方式之ribbon实战 订单调用商品服务     简介:实战电商项目 订单服务 调用商品服务获取商品信息         1.创建order_service项目         2 ...

  3. 小D课堂 - 新版本微服务springcloud+Docker教程_4-05 微服务调用方式之feign 实战 订单调用商品服务

    笔记 5.微服务调用方式之feign 实战 订单调用商品服务     简介:改造电商项目 订单服务 调用商品服务获取商品信息         Feign: 伪RPC客户端(本质还是用http)    ...

  4. WCF服务调用方式

    WCF服务调用通过两种常用的方式:一种是借助代码生成工具SvcUtil.exe或者添加服务引用的方式,一种是通过ChannelFactory直接创建服务代理对象进行服务调用.

  5. SpringCloud商品服务调用方式之feign

    简介:改造电商项目 order-service服务 调用商品服务获取商品信息 Feign: 伪RPC客户端(本质还是用http) 官方文档: https://cloud.spring.io/sprin ...

  6. SpringCloud商品服务调用方式之Ribbon

    1.创建order_service项目 pom依赖 <dependency> <groupId>org.springframework.boot</groupId> ...

  7. dubbo2.7.X版本带来的服务注册和服务调用方式改变

    参考地址:https://www.cnblogs.com/alisystemsoftware/p/13064620.html 注册中心数据结构格式改变(service:接口服务,application ...

  8. Spring cloud 两种服务调用方式(Rest + Ribbon) 和 Fegin方式

    1:Rest + Ribbon @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } @Auto ...

  9. WCF学习笔记(基于REST规则方式)

    一.WCF的定义 WCF是.NET 3.0后开始引入的新技术,意为基于windows平台的通讯服务. 首先在学习WCF之前,我们也知道他其实是加强版的一个面向服务(SOA)的框架技术. 如果熟悉Web ...

随机推荐

  1. linux 中的 tar 解压

    Type at the command prompt tar xvzf file-1.0.tar.gz - tgfo uncompress a gzip tar file (.tgz or .tar. ...

  2. 体验最火的敏捷——SCRUM(厦门,2014.1.4)

    1.概述SCRUM是当前最火的一种敏捷开发方法,有用户故事.冲刺.燃尽图等很多很酷的玩法,有牛B的产品负责人.SCRUM Master,有超强的自组织团队.本沙龙将为您展现当前最火最酷的敏捷开发方法! ...

  3. js自执行函数的几种不同写法的比较

    经常需要一个函数自执行,可惜这一种写法是错的: function(){alert(1);}();  原因是前半段“function(){alert(1);}”被当成了函数声明,而不是一个函数表达式,从 ...

  4. Java类型擦除机制

    Java泛型是JDK 5引入的一个特性,它允许我们定义类和接口的时候使用参数类型,泛型在集合框架中被广泛使用.类型擦除是泛型中最让人困惑的部分,本篇文章将阐明什么是类型擦除,以及如何使用它. 一个常见 ...

  5. web项目修改名称问题

    第一步:鼠标点击项目按F2 ,然后修改名称 第二步:备份web.xml 第三步:鼠标点击项目右键  选properties(一般位于最后面)  再在弹出框中输入WEB 第四步:将备份的web.xml文 ...

  6. Linux使用汇总贴

    1. 服务开机启动 比如: update-rc.d ssh enable 2. 修改hostname [基于ubutun] hostname newname vi /etc/hostnamevi /e ...

  7. Sql Server之旅——第十一站 简单说说sqlserver的执行计划

    我们知道sql在底层的执行给我们上层人员开了一个窗口,那就是执行计划,有了执行计划之后,我们就清楚了那些烂sql是怎么执行的,这样 就可以方便的找到sql的缺陷和优化点. 一:执行计划生成过程 说到执 ...

  8. Nginx状态码499

    1.问题描述 140.207.202.187 - - [18/May/2016:10:30:58 +0800] "POST/v3/violations HTTP/1.1" 499 ...

  9. oracle DB_LINK

    1.先创建远程数据库服务名(注意,如果服务器既有oracle服务端又有客户端,需要在服务端的tnsnames.ora中配置服务名,否则会报如下错误): SQL> select count(*) ...

  10. Python基础之生成器

    1.生成器简介 首先请确信,生成器就是一种迭代器.生成器拥有next方法并且行为与迭代器完全相同,这意味着生成器也可以用于Python的for循环中.另外,对于生成器的特殊语法支持使得编写一个生成器比 ...