不使用配置文件构建和使用WCF服务(WCF Service)


不使用配置文件构建和使用WCF服务(WCF Service)

完全不使用配置文件构建和使用WCF服务

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

1、 服务端

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

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

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

C# Code:

[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

C# Code:

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

//Instantiate new ServiceHost

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


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



进程、应用程序域和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);

 

其中参数implementedContractContract的完全名称,即名称空间.类名。



C# Code:

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



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

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

ServiceDescription 是一个Service在内存中的一个完整的描述,包括服务的所有Endpoint,和每个Endpoint的各自的addressbindingcontractbehaviors

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

ServiceEndpoint(ContractDescription contract, Binding binding, EndpointAddress address)

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

ContractDescription.GetContract(Type contractType);

C# Code:

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



C# Code:

ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();

behavior.HttpGetEnabled = true;

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

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



要发布Metadata,需要对外提供一个Http的地址,由HttpGetUrl 属性指定。

如果HttpGetUrl指定了绝对地址,那么对外发布Metadata的地址就为:HttpGetUrl 后加?wsdl

如果HttpGetUrl指定了相对地址,那么对外发布Metadata的地址就为: ServiceHostbaseAddress + HttpGetUrl 后加?wsdl

如果没有设置HttpGetUrl,那么Metadata的地址就是ServiceHostbaseAddress后加?wsdl

不管HttpGetUrl属性怎么设置,ServiceHostbaseAddress总是作为这个ServiceHost提供服务的描述页面的URL

 

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

ServiceHost构建好了,添加了需要的Endpointbehavior后,使用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 就是服务端设置的httpbaseAddress。当然前提是服务端在ServiceHost. Behaviors加一个ServiceMetadataBehavior类型的Behavior,并设置HttpGetEnabled属性为true,允许对外暴露服务端Metadata描述

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

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

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

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

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

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

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

clip_image003

 

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

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

2.2.1.    使用ChannelFactory Generic

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

static TChannel CreateChannel(Binding binding, EndpointAddress endpointAddress);


C# Code:

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


这个方法包含了一个EndpointABC三个主要元素:

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

Bingding – new BasicHttpBinding() 是绑定。

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

 

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

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

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

 

SecondServiceClient(Binding binding, EndpointAddress remoteAddress)

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



C# Code:

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


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

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

Bingding – new BasicHttpBinding() 是绑定。

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

 

2.3.    使用代理实例的方法

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

C# Code:

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


完全不使用配置文件的例子代码下载:http://files.cnblogs.com/chnking/NoConfigWCF.rar

本文转自:cnblog 博客园

本文来源:
版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
C/S框架网
上一篇:承载 Service Host 和使用 WCF 服务
下一篇:使用ServiceHost建立WCF Console 服务器(WebService Console)
评论列表

发表评论

评论内容
昵称:
关联文章

使用配置文件构建使用WCF服务(WCF Service)
承载 Service Host 使用 WCF 服务
Web服务(Web Service)
WCF客户端服务配置要点
WCF快速开发框架 - IIS承载WCF服务wsHttpBindings配置详解(HTTP协议)
WCF与Web Service的区别与关系
面向服务的体系结构(Service-Oriented Architecture,SOA)
使用批处理文件(.bat)安装WCF服务失败解决方案
如何在Windows服务中安装部署WCF服务器?
IIS承载的WCF服务配置.svc文件页面的MIME类型及处理程序映射
使用批处理文件安装或卸载WCF服务(Windows服务)
C#源代码安全缺陷与提高源代码质量解决方案-WCF服务配置安全
C# ASP.NET WebApi服务器搭建详解 - Win服务承载(Windows Service Hosting宿主)
WCF服务.svc文件的代码分离到其它dll文件注意事项
WCF快速开发框架 - IIS承载WCF http协议BasicTcpBinding配置详解
WCF快速开发框架 - IIS承载WCF net.tcp协议NetTcpBinding配置详解
底层统一使用透明代理访问WCF服务
使用net.exesc.exe实用程序启动停止Windows服务
WCF服务保持在线状态(Keep Alive),长时间闲置状态下断线解决方案
WCF服务错误:MessageSecurityException: 从另一方收到未进行安全处理或安全处理正确的错误

热门标签
.NET5 .NET6 .NET7 APP Auth-软件授权注册系统 Axios B/S B/S开发框架 Bug Bug记录 C#加密解密 C#源码 C/S CHATGPT CMS系统 CodeGenerator CSFramework.DB CSFramework.EF CSFrameworkV1学习版 CSFrameworkV2标准版 CSFrameworkV3高级版 CSFrameworkV4企业版 CSFrameworkV5旗舰版 CSFrameworkV6.0 DAL数据访问层 Database datalock DbFramework Demo教学 Demo下载 DevExpress教程 DOM EF框架 Element-UI EntityFramework ERP ES6 Excel FastReport GIT HR IDatabase IIS JavaScript LINQ MES MiniFramework MIS NavBarControl Node.JS NPM OMS ORM PaaS POS Promise API Redis SAP SEO SQL SQLConnector TMS系统 Token令牌 VS2022 VSCode VUE WCF WebApi WebApi NETCore WebApi框架 WEB开发框架 Windows服务 Winform 开发框架 Winform 开发平台 WinFramework Workflow工作流 Workflow流程引擎 版本区别 报表 踩坑日记 操作手册 代码生成器 迭代开发记录 基础资料窗体 架构设计 角色权限 开发sce 开发技巧 开发教程 开发框架 开发平台 开发指南 客户案例 快速搭站系统 快速开发平台 秘钥 密钥 权限设计 软件报价 软件测试报告 软件简介 软件开发框架 软件开发平台 软件开发文档 软件体系架构 软件下载 软著证书 三层架构 设计模式 生成代码 实用小技巧 收钱音箱 数据锁 数据同步 微信小程序 未解决问题 文档下载 喜鹊ERP 喜鹊软件 系统对接 详细设计说明书 行政区域数据库 需求分析 疑难杂症 蝇量级框架 蝇量框架 用户管理 用户开发手册 用户控件 在线支付 纸箱ERP 智能语音收款机 自定义窗体 自定义组件 自动升级程序