为了账号安全,请及时绑定邮箱和手机立即绑定

Wcf:可配置的服务调用方式

标签:
安全

添加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 }

View Code

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

1 var students = new WcfClient<IStudent>().Call(c => c.GetStudents("jerry"));
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消