zoukankan      html  css  js  c++  java
  • 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"));

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

  • 相关阅读:
    Linux终端设置免密登陆ssh(以 XShell 为例)
    Docker入门(一)-安装
    find命令总结
    CentOS 恢复 rm -rf 误删除数据
    CentOS系统登陆root用户后发现提示符显示-bash-4.2#(已解决)
    一次在CentOS系统单用户模式下使用passwd命令破密失败的案例
    Ubuntu下配置IP地址
    安装CentOS 6.x报错"Disk sda contains BIOS RAID metadata"解决方法
    YUM命令总结
    git从安装到多账户操作一套搞定(二)多账户使用
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/3372390.html
Copyright © 2011-2022 走看看