首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

使用通道

我们可以直接使用通道调用服务的操作,而无须借助于代理类。ChannelFactory<T>类(以及它所支持的类型)有助于我们轻松地创建代理,如例1-21所示。

例1-21:ChannelFactory<T>类

public class ContractDescription

{

   public Type ContractType

   {get;set;}

   //更多成员

}

public class ServiceEndpoint

{

   public ServiceEndpoint(ContractDescription contract,Binding binding,

                                                          EndpointAddress address);

   public EndpointAddress Address

   {get;set;}

   public Binding Binding

   {get;set;}

   public ContractDescription Contract

   {get;}

   //更多成员

}

public abstract class ChannelFactory : ...

{

   public ServiceEndpoint Endpoint

   {get;}

   //更多成员

}

public class ChannelFactory<T> : ChannelFactory,...

{

   public ChannelFactory(ServiceEndpoint endpoint);

   public ChannelFactory(string configurationName);

   public ChannelFactory(Binding binding,EndpointAddress endpointAddress);

   public static T CreateChannel(Binding binding,EndpointAddress endpointAddress);

   public T CreateChannel();

   //更多成员

}

我们需要向ChannelFactory<T>类的构造函数传递一个终结点对象,终结点名称可以从客户端配置文件中获取;或者传递绑定与地址对象,或者传递ServiceEndpoint对象。接着,调用CreateChannel()方法获得代理的引用,然后使用代理的方法。最后,通过将代理强制转换为IDisposable类型,调用Dispose()方法关闭代理。当然,也可以将代理强制转换为ICommunicationObject类型,通过调用Close()方法关闭代理:

ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>();

IMyContract proxy1 = factory.CreateChannel();

using(proxy1 as IDisposable)

{

   proxy1.MyMethod();

}

IMyContract proxy2 = factory.CreateChannel();

proxy2.MyMethod();

ICommunicationObject channel = proxy2 as ICommunicationObject;

Debug.Assert(channel != null);

channel.Close();

我们还可以直接调用CreateChannel()静态方法,根据给定的绑定和地址值创建代理,这样就不需要创建ChannelFactory<T>类的实例了。

Binding binding = new NetTcpBinding();

EndpointAddress address = new EndpointAddress("net.tcp://localhost:8000");

IMyContract proxy = ChannelFactory<IMyContract>.CreateChannel(binding,address);

using(proxy as IDisposable)

{

   proxy1.MyMethod();

}

InProcFactory类

为了演示ChannelFactory<T>类的强大功能,考虑静态辅助类InProcFactory,定义如下:

public static class InProcFactory

{

   public static I CreateInstance<S,I>() where I : class

                                         where S : I;

   public static void CloseProxy<I>(I instance) where I : class;

   //更多成员

}

设计InProcFactory类的目的在于简化并自动实现进程内托管。CreateInstance()方法定义了两个泛型类型参数:服务类型S以及服务支持的契约类型I。CreateInstance()要求S必须派生自I。可以直接使用InProcFactory类:

IMyContract proxy = InProcFactory.CreateInstance<MyService,IMyContract>();

proxy.MyMethod();

InProcFactory.CloseProxy(proxy);

InProcFactory能够接收一个服务类,并将它升级为WCF服务。这就好比我们可以在WCF中调用旧的Win32函数LoadLibrary()。

InProcFactory<T>的实现

所有的进程内调用都应该使用命名管道,同时还应该传递所有事务。我们可以使用编程配置自动地配置客户端和服务,同时使用ChannelFactory<T>,以避免对代理对象的使用。例1-22演示了InProcFactory的实现。为简便起见,省略了一部分与此无关的代码。

例1-22:InProcFactory类

public static class InProcFactory

{

   struct HostRecord

   {

      public HostRecord(ServiceHost host,string address)

      {

         Host = host;

         Address = address;

      }

      public readonly ServiceHost Host;

      public readonly string Address;

   }

   static readonly Uri BaseAddress = new Uri("net.pipe://localhost/" + Guid.NewGuid().ToString());

   static readonly Binding NamedPipeBinding;

   static Dictionary<Type,HostRecord> m_Hosts = new Dictionary<Type,HostRecord>();

  

   static InProcFactory()

   {

      NetNamedPipeBinding binding = new NetNamedPipeBinding();

      binding.TransactionFlow = true;

      NamedPipeBinding = binding;

      AppDomain.CurrentDomain.ProcessExit += delegate

                                             {

                             foreach(KeyValuePair<Type,HostRecord> pair in m_Hosts)

                                                 {

                                                   pair.Value.Host.Close();

                                                 }

                                              };

   }

   public static I CreateInstance<S,I>() where I : class

                                          where S : I

   {

      HostRecord hostRecord = GetHostRecord<S,I>();

      return ChannelFactory<I>.CreateChannel(NamedPipeBinding,

                                          new EndpointAddress(hostRecord.Address));

   }

   static HostRecord GetHostRecord<S,I>() where I : class

                                           where S : I

   {

      HostRecord hostRecord;

      if(m_Hosts.ContainsKey(typeof(S)))

      {

         hostRecord = m_Hosts[typeof(S)];

      }

      Else

      {

         ServiceHost host = new ServiceHost(typeof(S), BaseAddress);

         string address = BaseAddress.ToString() + Guid.NewGuid().ToString();

         hostRecord = new HostRecord(host,address);

         m_Hosts.Add(typeof(S),hostRecord);

         host.AddServiceEndpoint(typeof(I),NamedPipeBinding,address);

         host.Open();

      }

      return hostRecord;

   }

   public static void CloseProxy<I>(I instance) where I : class

   {

      ICommunicationObject proxy = instance as ICommunicationObject;

      Debug.Assert(proxy != null);

      proxy.Close();

   }

}

实现InProcFactory所面临的最大挑战,就是如何实现CreateInstance()方法,使得它能够为每个类型创建服务实例。由于每个服务类型都必须有一个对应的宿主(ServiceHost的一个实例),如果为每次调用都分配一个宿主实例,算不上是一个好的办法。问题在于,如果需要为相同的类型实例化第二个对象,CreateInstance()方法应该怎么做:

IMyContract proxy1 = InProcFactory.CreateInstance<MyService,IMyContract>();

IMyContract proxy2 = InProcFactory.CreateInstance<MyService,IMyContract>();

解决办法是在内部管理一个字典(Dictionary)集合,以建立服务类型与特定的宿主实例之间的映射。调用CreateInstance()方法创建指定类型的实例时,通过调用辅助方法GetHostRecord()查找字典集合,只有不存在该服务类型,才会创建宿主实例。如果需要创建宿主,GetHostRecord()方法会以编程方式为宿主添加一个终结点,并生成GUID作为唯一标识的管道名。GetHostRecord()方法会返回一个HostRecord对象。HostRecord是一个结构类型,定义了ServiceHost实例与地址值。然后,CreateInstance()根据HostRecord对象获得终结点地址,调用ChannelFactory<T>类的方法创建代理。在InProcFactory类的静态构造函数(静态构造函数会在初始化类时调用)中,InProcFactory订阅了ProcessExit事件,使用了匿名方法在停止进程时关闭所有宿主。最后,为了方便客户端关闭代理,InProcFactory定义了CloseProxy()方法,它将代理强制转换为ICommunicationObject类型以关闭代理。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论