读书笔记摘要- 第一个WCF程序
1.定义一个服务契约使用ServiceContract特性:用于类或者接口亦可,且允许重复
2.一个服务契约由一组操作服务构成,定义操作服务用OperationContract特性,只有定义了操作服务的方法才会放入氛围中如下实例:
//引入命名空间:using System.ServiceModel;
[ServiceContract] public interface IService { [OperationContract] void Work(); //被引入服务 [OperationContract] void Eat(); //被放入服务 void Run();//不被放入服务 } [ServiceContract] public class Service { [OperationContract] public void Work() //被放入服务 { //业务实现 } [OperationContract] public void Eat() //被放入服务 { //业务实现 } public void Run() //不被放入服务 { //业务实现 }
}
备注:WCF或构造一个定义的接口,并使用该接口作为服务契约的定义,所以服务契约的定义都是由接口完成的。不建议定义在类里,原因是不可重用。
[ServiceContract] interface IService //服务的定义 { [OperationContract] string HelloWorld(string name);//服务操作 } public class Service : IService //服务的实现 { public string HelloWorld(string name) //服务操作实现 { return name + "speak:HelloWorld!";//拼接字符串并返回 } }
注意:服务需要寄宿到每个特定的程序之后才可以被访问。
3、服务宿主程序需要使用ServiceHost类型,当使用IIS或者WAS作为宿主程序时,IIS和WAS会主动创建ServiceHost类型对象,如果是针对于的宿主服务需要手动创建ServiceHost对象,常见的构造方法:
/// <summary>
/// ServiceHost构造函数
/// </summary>
/// <param name="serviceType">契约定义类型</param>
/// <param name="baseAddress">基地址数组</param>
public ServiceHost(Type serviceType, params Uri[] baseAddress);
一个完整的服务宿主程序还需要定义服务的绑定和地址
基于宿主程序和客户端都是运行在同一主机,所以服务选择性能最佳但不能跨越主机的NetNamedPipeBinding.该绑定使用IPC协议进行通信,可跨越应用程序域和进程。但不能跨越主机。
public Binding GetBinding() { return new NetNamedPipeBinding();//返回NetNamedPipeBinding对象 }
接下来定义服务地址:两部分组成,即基地址和可选地址,基地址包含通信协议和主机名,可选地址定义服务位置。这里用的是
NetNamedPipeBinding绑定。所以级地震为net.pipe://localhost.可选地址为Hellword.基地址在ServiceHost对象构造时被党作为参数传入。可选地址在终结点被添加时使用,添加终结点使用
ServiceHost的AddServiceEndpoint()方法。
HelloWorld定义了MyServiceHost类型来封装ServiceHost,如下:
//封装了ServiceHost和起构造过程 public class MyServiceHost { private ServiceHost _myHost; //ServiceHost对象 public const string BaseAddress = "net.pipe://localhost";//基地址 public const string HelloWorldServiceAddress = "HelloWorld";//可选地址 //服务契约定义类型 public static readonly Type ContractType = typeof(HelloWorldService.IService); //服务契约实现类型 public static readonly Type ServiceType = typeof(HelloWorldService.Service); //服务只定义了一个绑定 public static readonly Binding HelloWorldBing = new NetNamedPipeBinding(); //构造ServiceHost对象 protected void ConstructServiceHost() { //初始化ServiceHost对象 _myHost = new ServiceHost(ServiceType,new Uri[] { new Uri(BaseAddress)}); _myHost.AddServiceEndpoint(ContractType,HelloWorldBing,HelloWorldServiceAddress); } //ServiceHost只读属性 public ServiceHost Host { get { return _myHost; } } //打开服务 public void Open() { _myHost.Open(); } //构造方法 public MyServiceHost() { ConstructServiceHost(); } //ServiceHost实现了IDisposable接口,这里调用它的Dispose()方法 public void Dispose() { //ServiceHost显示实现了IDisposable的Dispose()方法,所以要先强制转换成IDisposable类型 if (_myHost != null) (_myHost as IDisposable).Dispose(); } }
注意:以上实例采用编程配置的方式定义服务的绑定、终结点、地址等信息。后期推荐用配置文件来配置(无需编译、直观简单)。
调用示例:
public class ServiceHostMainClass //服务的宿主 { static void Main(string[] args) //入口方法调用 { //由于MyServiceHost实现了IDisposable接口,所以使用using 自动关闭 using (MyServiceHost host=new MyServiceHost()) { host.Open(); Console.Read();//待客户端访问 } } }
4、手动创建客户端代理方式访问服务端:
第一、导入服务元数据,服务元数据的内容包含服务提供的终结点,每个终结点的地址、绑定和契约。元数据又称元数据的交换,一般用二种方法获取,即HTTP-GET和元数据终结点方法。此处采用编码方式定义服务的契约地址和绑定。
第二、定义访问服务的代理类型。WCF提供了ClientBase<T>来定义代理类型。泛型参数T被访问契约类型实例化,绑定和地址在ClientBase<T>的构造方法中被传入,对象构造完毕后,采用用Channel属性对服务进行调用。以下示例采用HelloWorlProxy类型用于封装ClientBase<T>类型:
[ServiceContract] interface Iservice //硬编码定义服务契约 { [OperationContract] string HelloWorld(string name);//服务操作 } //客户端代理类型 public class HelloWorldProxy : ClientBase<Iservice>, Iservice { //硬编码定义绑定 public static readonly Binding HelloWorldBinding = new NetNamedPipeBinding(); //硬编码定义地址 public static readonly EndpointAddress HelloWorldAddress = new EndpointAddress(new Uri("net.pipe://localhost/HelloWorld")); //构造方法 public HelloWorldProxy() : base(HelloWorldBinding, HelloWorldAddress) { } public string HelloWorld(string name) { return Channel.HelloWorld(name);//使用Channel属性对服务进行调用 } }
定义代理类型后可在入口使用,因ClienBase<T>实现了IDisposable接口,所以要用using自动关闭:
public class Client { static void Main(string[] args) { using (HelloWorldProxy proxy = new HelloWorldProxy()) { Console.WriteLine( proxy.HelloWorld("WCF"));//利用代理调用服务 Console.Read(); } } }
必选先启动服务再启动客户端调用生效。