当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > 完全不使用配置文件构建和使用WCF服务

ASP.NET
不同映射模式下的直线输出的效果问题
ASP.NET开发下的MVC设计模式的实现
ASP.NET编写应用程序的十大技巧
ASP.NET中使用AJAX的简单方法
ASP.NET MVC实现自己的视图引擎
认识asp.net会话状态
ASP.NET实现页面传值的几种方法
.NET中容易混淆的几组重要概念
详解.NET中的动态编译技术
如何使用ASP.Net加密Cookie
ASP.NET 2.0跨网页提交的三种方法
ASP.NET 2.0创建母版页引来的麻烦
.Net整合其他平台的一些探讨
ASP.NET编程经验技巧10则
最佳实践 ADO.NET实用经验无保留曝光
在.NET上执行多线程操作要考虑的两大因素
.Net开发 细说Visual Basic.Net
ASP.NET网络编程中经常用到的27个函数集
ASP.NET防止用户多次登录的方法
对ASP.NET MVC项目中的视图做单元测试

ASP.NET 中的 完全不使用配置文件构建和使用WCF服务


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-23   浏览: 134 ::
收藏到网摘: n/a

只使用代码而不用配置文件的情况不适合IIS为宿主的情况,IIS宿主必须使用配置文件配置WCF的ServiceHost.

1、 服务端

1.1. 准备Contract和实现Contract的服务

很简单的一个Contract(Interface)和实现这个Contract(实现这个接口的类)的服务。

这是VS2005中使用add new item,选WCF Service后自动生成的一个模板例子服务代码。

以下为引用的内容:

[ServiceContract()]
 
  public interface IService

  {

  [OperationContract]

  string MyOperation1(string myValue);

  }

  public class Service : IService

  {

  public string MyOperation1(string myValue)

  {

  return "Hello: " + myValue;

  }

  }

1.2. 建立ServiceHost

一般使用public ServiceHost(Type serviceType, params Uri[] baseAddresses)构造方法建立ServicesHost.

参数:  

以下为引用的内容: Type serviceType —— 为实现了某些Contract的类的类型,为这个服务主机要host的服务。

  params Uri[] baseAddresses —— 为任意数量的baseAddress.

  Uri baseAddress = new Uri("http://localhost:8080/WCFService/Service");

  //Instantiate new ServiceHost

  myServiceHost = new ServiceHost(typeof(Service), baseAddress);

一个ServiceHost内只能驻留一个Service类,但是这个Service类可以实现多个Contract,每个Contract都能通过一个或多个(不同的bind)Endpoint向客户端暴露。

进程、应用程序域和ServiceHost

Dotnet出现之前,资源的分配是以进程为单位,进程是应用程序的安全边界,进程之间不能直接访问,一个进程的崩溃也不会直接影响到别的进程。

但是,进程有个缺点,为了维护进城的安全上下文,耗费的资源很大。

后来引入了线程,一个进程中可以包含多个线程,同一进程里的线程共享资源、切换方便,但是线程不具有隔离性,一个线程的崩溃将会影响到其他线程。

Dotnet引入了应用程序域,是介于进程和线程之间的逻辑概念,它既有进程的安全隔离性的优点,又有线程轻巧快捷的特性。应用程序域跟进程一样,一个应用程序域不能直接访问另一个应用程序域的资源,一个应用程序域的崩溃也不会影响其他应用程序域。同时应用程序域占用的资源比进程少的多,应用程序直接的切换也很快捷。

一个进程中可以包含多个应用程序域,一个应用程序域内有可以包含多个线程。

所有的win可执行文件(exe、dll等等)的开头都是一个被称作(Portable Executable)结构,dotnet的可执行文件同样也是用了这个PE头(结构同以前的兼容,只是增加了些内容),下面是dotnet的PE主要包含的信息:

运行这个可执行文件要求的最低CLR版本号

是否使用了强名称

程序的入口地址

可执行文件的元数据(metadata)

简单的dotnet的exe可执行文件的载入过程:

windows程序载入器(os loader)读取exe文件的PE头,获取入口地址,exe入口地址其实是个跳转指令指向mscoree.dll中的_corexemain函数。

_corexemain函数实际上是个入口程序,一般被称作shim(填隙物)。由这个入口程序来决定使用哪个类型的CLR(服务器类型或工作站类型),和什么版本的CLR来运行这个exe.

确定了使用哪个CLR后,动态载入这个CLR,把控制权交给CLR.

CLR拿到控制权后,首先创建一个工作进程,以便在进程内创建应用程序域。

CLR创建工作进程后,首先会创建一个缺省应用程序域,这个缺省应用程序域一般不用来加载用户代码。之后,开始在在新的应用程序域中加载用户代码,并运行。

具体到承载WCF的console应用,是个dotnet的exe程序,运行后被CLR加载到一个应用程序域后,ServiceHost就在这个应用程序内运行

在一个Application Domain中可以实例化多个 ServiceHost 实例,但每个应用程序域内只有一个 ServiceHost 实例更便于操作。您可以在一个宿主内使用多个端点公开多个服务接口。

1.3. 给ServiceHost添加Endpoint

Endpoint是直接暴露给客户端就行通讯的接口,经典的一个Endpoint可以用ABC来描述,即address – 这个Endpoint对外的访问地址,binding – 这个Endpoint是通过什么样的通讯手段暴露给客户端的,Contract —— 这个Endpoint对外暴露的是哪个Contract.

通过两个方法给ServiceHost添加Endpoint

1.3.1. ServiceHost.AddServiceEndpoint

AddServiceEndpoint方法有8种重载,ServiceHost提供了四种:

以下为引用的内容:

  ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address);

  ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address);

  ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address, Uri listenUri);

  ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address, Uri listenUri);

  ServiceHost的父类ServiceHostBase也提供了四种:

  ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, string address);

  ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, Uri address);

  ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, string address, Uri listenUri);

  ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, Uri address, Uri listenUri);

  其中参数implementedContract为Contract的完全名称,即名称空间。类名。

  myServiceHost.AddServiceEndpoint(typeof(WCFService.IService), new BasicHttpBinding(), "");

  1.3.2. ServiceHost.Description.Endpoints.Add(ServiceEndpoint item)

  ServiceHost.Description 是一个 ServiceDescription 类型的对象。

        ServiceDescription 是一个Service在内存中的一个完整的描述,包括服务的所有Endpoint,和每个Endpoint的各自的address、binding、contract和behaviors.

使用此方法先要根据Endpoint的ABC构造一个ServiceEndpoint 对象。

以下为引用的内容:

  ServiceEndpoint(ContractDescription contract, Binding binding, EndpointAddress address)

  其中ContractDescription这样通过ContractDescription的静态方法GetContract构造:

  ContractDescription.GetContract(Type contractType);

  ServiceEndpoint myServiceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(WCFService.IService)), new BasicHttpBinding(), new EndpointAddress(baseAddress));

  myServiceHost.Description.Endpoints.Add(myServiceEndpoint);

1.4. 视需要给ServiceHost添加behavior

以下为引用的内容:

  ServiceHost. Behaviors是一个 IServiceBehavior类型的对象集合。

  IserviceBehavior 提供了一个在整个服务范围内修改或则插入定制扩展的机制。

  如果需要把服务通过WSDL对外暴露对服务的Metadata描述,就需要加一个ServiceMetadataBehavior类型的Behavior:

  ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();

  behavior.HttpGetEnabled = true;

  behavior.HttpGetUrl = new Uri("http://localhost:8001/");

  myServiceHost.Description.Behaviors.Add(behavior); // myServiceHost是ServiceHost实例

要发布Metadata,ServiceHost必须有一个http的baseAddress,所以在构造ServiceHost实例时,就需要在构造方法中加入这个http的baseAddress,这个http的baseAddress就是对外发布的Metadata地址。

1.5. 打开ServiceHost,开始提供服务

ServiceHost构建好了,添加了需要的Endpoint、behavior后,使用ServiceHost.Open()方法开发ServiceHost实例,开始对外提供服务。

2、 客户端

2.1. 引用service

客户端要访问服务端的服务,首先要知道服务端的服务提供了什么方法,就是要知道服务的Contract.如何取得服务端的Contract有几种方法

2.1.1. 直接把服务端的Contract的副本拷贝到客户端

这个方法是最原始的一种方法,这样保证了服务端跟客户端使用同一份Contract.但是,这个方法不值得提倡,因为双方的Contract是同一个来源,但是毕竟是两个独立的物理存在,它们之间只能人为的来保证其一致性。

2.1.2. 使用Svcutil.exe工具获得服务端Contract并生成本地服务代理类

大家知道,web service是通过WSDL对外提供服务的描述,以便客户端能够通过wsdl知道这个web service所包含的方法、方法的签名等等信息,客户端通过wsdl就能知道怎么去调用这个web service.

到了WCF时代,微软依然采用WSDL来提供对WCF服务的描述。

前面服务端给ServiceHost添加了一个ServiceMetadataBehavior类型的Behavior,目的就是让服务端对外提供WSDL形式的服务Metadata描述。

微软提供了Svcutil.exe工具用来通过WSDL生成客户端Contract和代理功能:

以下为引用的内容:

  Svcutil.exe httpbaseAddress

httpbaseAddress 就是服务端设置的http的baseAddress.当然前提是服务端在ServiceHost. Behaviors添加一个ServiceMetadataBehavior类型的Behavior,并设置HttpGetEnabled属性为true,允许对外暴露服务端Metadata描述

运行Svcutil.exe后,生成两个文件,一个是WCF配置文件,一个是包含了服务端Contract和对应于服务端service的本地代理类的cs文件。

生成的cs文件有下面的规律:

l 引用服务端的服务所涉及的Contract(Interface类型)基本都原样引用到客户端(可能会自动给Contract添加一些Attribute)。

l 服务端的Endpoint到了客户端,每个具有不同Contract的Endpoint都会在客户端生成一个代理类。Contract相同,binding不同的Endpoint使用同一个客户端代理类。

2.1.3. 在客户端项目中添加Service reference

在vs2005中安装了WCF的extention后,在项目的References上点击右键,会多出来一个“Add Service Reference”的选项,这就是用来引用WCF服务的,引用地址就是服务端设置的http的baseAddress.

在这里引用WCF服务,跟使用Svcutil.exe命令一样,会在项目中生成同样的两个文件。

2.2. 生成客户端service代理实例

引用服务后,客户端生成了配置文件和包含了Contract和本地代理类的cs文件,这里我们完全不使用配置文件,所以把生成的配置文件从项目中排除。

2.2.1. 使用ChannelFactory Generic

以下为引用的内容:

使用ChannelFactory Generic类的CreateChannel静态方法CreateChannel,返回一个客户端代理。

  static TChannel CreateChannel(Binding binding, EndpointAddress endpointAddress);

localhost.IService proxy = ChannelFactory.CreateChannel(new BasicHttpBinding(), new EndpointAddress(http://localhost:8080/WCFService/Service));

这个方法包含了一个Endpoint的ABC三个主要元素:

以下为引用的内容:

  Address – new EndpointAddress("http://localhost:8080/WCFService/Service")是地址。

  Bingding – new BasicHttpBinding() 是绑定。

  Contract —— localhost. IService是引用服务后在在客户端生成的来自服务端的Contract(interface类型)。

2.2.2. 直接使用引用服务后形成的本地代理类

上面使用ChannelFactory的CreateChannel静态方法建立代理只使用到了引用WCF服务后在客户端生成的Contract,同时前面也说过,引用WCF服务后,还会在同时给每个Contract不同的Endpoint生成一个继承自System.ServiceModel.ClientBase的本地代理类。

客户端可以直接使用多个重载的代理类构造方法实例化这些代理类。如果不使用配置文件,使用这个构造方法:

以下为引用的内容:

  SecondServiceClient(Binding binding, EndpointAddress remoteAddress)

其中SecondServiceClient为本地的一个代理类。实例化一个代理类的代码是这样的:

localhost.ServiceClient proxy = new localhost.ServiceClient(new BasicHttpBinding(), new EndpointAddress(http://localhost:8080/WCFService/Service));

同样,实例化的proxy也包含了一个Endpoint的ABC三个主要元素:

以下为引用的内容:

  Address – new EndpointAddress("http://localhost:8080/WCFService/Service")是地址。

  Bingding – new BasicHttpBinding() 是绑定。

  Contract –localhost.ServiceClient本身就是继承自某一个Contract的

2.3. 使用代理实例的方法

有了WCF的本地代理类实例,就可以使用服务提供的方法了。

以下为引用的内容:

 string result = proxy.MyOperation1("myFirstWCF");