WCF配置文件与文件下载之坎坷路
题外话:本以为我会WCF了,精通WCF了,毕竟刚做过一个WCF的项目,不就是写写契约接口,然后实现接口,改下配置。最后用控制台或者服务发布一下,不就能用了。不就是简单ABC吗?不是So Easy吗?做第二个项目的时候我悲剧了,被碰的头破血流!忽然发现什么什么都不会(第一个项目比照网上教程一步一步弄的),连写一个简单hello world都写不出来。我之前还以为自己很懂了……
一、WCF文件配置
为了不重蹈覆辙,这次争取把他整懂整透(当然这才是入门而已)。WCF很强大,它的强大跟它的配置有很大的关系,所以我首先要先把它的配置搞懂。
WCF的配置文件共分为两部分:服务端配置与客户端配置。两者由于功能的不同,在配置文件的使用上也略有不同。
WCF的服务端配置
服务端的配置文件主要包括endpoint、binding、behavior的配置。一个标准的服务端配置文件所包含的主要xml配置节如下所示:
- <system.ServiceModel>
- <services>
- <service>
- <endpoint/>
- </service>
- </services>
- <bindings>
- <!—定义一个或多个系统提供的binding元素,例如<basicHttpBinding> -->
- <!—也可以是自定义的binding元素,如<customBinding>. -->
- <binding>
- <!—例如<BasicHttpBinding>元素. -->
- </binding>
- </bindings>
- <behaviors>
- <!—一个或多个系统提供的behavior元素. -->
- <behavior>
- <!—例如<throttling>元素. -->
- </behavior>
- </behaviors>
- </system.ServiceModel>
1.1 <services>配置节
在<services>配置节中可以定义多个服务,每一个服务都被放到<service>配置节中,WCF的宿主程序可以通过配置文件找到这些定义的服务并发布这些服务。
<service>配置节包含name和behaviorConfiguration属性。其中,name配置了实现Service Contract的类型名。类型名必须是完整地包含了命名空间和类型名。而behaviorConfiguration的配置值则与其后的<behaviors>配置节的内容有关。<endpoint>是<service>配置节的主体,其中,<endpoint>配置节包含了endpoint的三个组成部分:Address、Binding和Contract。由于具体的binding配置是在<bindings>配置节中完成,因而,在<endpoint>中配置了bindingConfiguration属性,指向具体的binding配置。如下所示:
- <services>
- <service name="MyService.Service1" behaviorConfiguration="MyBehavior">
- <endpoint address=""
- binding="netTcpBinding"
- bindingConfiguration="DuplexBinding"
- contract="MyService.IHello" />
- </service>
- </services>
我们也可以定义多个endpoint,例如:
- <services>
- <service
- name="Microsoft.ServiceModel.Samples.CalculatorService"
- behaviorConfiguration="CalculatorServiceBehavior">
- <endpoint address=""
- binding="wsHttpBinding"
- contract="Microsoft.ServiceModel.Samples.ICalculator" />
- <endpoint address="mex"
- binding="mexHttpBinding"
- contract=" Microsoft.ServiceModel.Samples.IMetadataExchange" />
- </service>
- </services>
如果address值为空,那么endpoint的地址就是默认的基地址(Base Address)。例如ICalculator服务的地址就是http://localhost/servicemodelsamples/service.svc,而IMetadataExchange服务的地址则为http://localhost/servicemodelsamples/service.svc/mex。这里所谓的基地址可以在
<service>中通过配置<host>来定义:
- <service
- name="Microsoft.ServiceModel.Samples.CalculatorService"
- behaviorConfiguration="CalculatorServiceBehavior">
- <host>
- <baseAddresses>
- <add baseAddress="http://127.0.0.1/ServiceModelSamples”/>
- </baseAddresses>
- </host>
- <endpoint … />
- </service>
1.2 <behaviors>配置节
当我们在定义一个实现了Service Contract的类时, binding和address信息是客户端必须知道的,否则无法调用该服务。然而,如果需要指定服务在执行方面的相关特性时,就必须定义服务的behavior。在WCF中,定义behavior就可以设置服务的运行时属性,甚至于通过自定义behavior插入一些自定义类型。例如通过指定ServiceMetadataBehavior,可以使WCF服务对外公布Metadata。配置如下:
- <behaviors>
- <serviceBehaviors>
- <behavior name="metadataSupport">
- <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
- </behavior>
- <serviceBehaviors>
- <behaviors>
在WCF中,behavior被定义为Attribute,其中,System.ServiceModel.ServiceBehaviorAttribute和System.ServiceModel.OperationBehaviorAttribute是最常用的behavior。虽然,behavior作为Attribute可以通过编程的方式直接施加到服务上,但出于灵活性的考虑,将behavior定义到配置文件中才是最好的设计方式。
利用ServiceBehavior与OperationBehavior可以控制服务的如下属性:
1、 对象实例的生命周期;
2、 并发与异步处理;
3、 配置行为;
4、 事务行为;
5、 序列化行为;
6、 元数据转换;
7、 会话的生命周期;
8、 地址过滤以及消息头的处理;
9、 模拟(Impersonation);
例如,通过ServiceBehavior设置对象实例的生命周期:
- <behaviors>
- <serviceBehaviors>
- <behavior name="metadataSupport">
- <instanceContextMode httpGetEnabled="true" httpGetUrl=""/>
- </behavior>
- <serviceBehaviors>
- <behaviors>
这是通过使用配置文件指定的地址
另外我们还可以通过代码的方式指定地址:代码如下
- private static void Main(string[] args)
- {
- using (ServiceHost serviceHost = new ServiceHost(typeof (Service1)))
- {
- serviceHost.AddServiceEndpoint(typeof (IService1), new WSHttpBinding(),
- "http://127.0.0.1:9999/Service1");
- serviceHost.AddServiceEndpoint(typeof (IService1), new NetTcpBinding()
- , "net.tcp://127.0.0.1:8888/Service1");
- serviceHost.Opened += (s, e) => Console.WriteLine("服务已打开!");
- serviceHost.Open();
- Console.Read();
- }
- }
这里调用了ServiceHost 类的AddServiceEndpoint方法:它的抽象方法为
public ServiceEndPoint AddServiceEndpoint(Type implementedContract,Binding binding,string address);
当然你还可以使用ServiceHost 继承自ServiceHostBase的方法AddServiceEndpoint:它的方法签名为:
public ServiceEndPoint AddServiceEndpoint(string implementedContract,Binding binding,string address);
这里只是将implementedContract以字符串的形式表示服务契约类型的有效名称。
上面添加终结地就变成了
serviceHost.AddServiceEndpoint(“命名空间.IService1”,new WSHttpBinding(),http://127.0.0.1:9999/Service1);
基地址与相对地址
除了向上面那样以绝对路径的方式指定服务的终结点地址外,还可以通过“基地址+相对地址”的方式进行设置。对于一个服务来说,可以指定一个或多个基地址,但是对于一种传输方式协议类型,只能具有一个唯一的基地址。服务的基地址与终结点相对地址可以通过编码的方式,在创建ServiceHost对象时在构造函数中指定。具体实现代码如下:
- internal class Program
- {
- private static void Main(string[] args)
- {
- Uri[] baseAddress =
- {
- new Uri("http://127.0.0.1:8888/myservices"),
- new Uri("net.tcp://127.0.0.1/:8888")
- };
- using (ServiceHost serviceHost = new ServiceHost(typeof (Service1),baseAddress))
- {
- serviceHost.AddServiceEndpoint(
- typeof (IService1),
- new BasicHttpBinding(),
- "Service1");
- serviceHost.AddServiceEndpoint(
- typeof (IService1),
- new NetTcpBinding(),
- "Service1");
- serviceHost.Opened += (s, e) => Console.WriteLine("服务已打开!");
- serviceHost.Open();
- Console.Read();
- }
- }
- }
上面的代码中,在寄宿Service1服务的时候,添加了两个基地址,一个是基于HTTP的,另外一个是基于net.tcp的。然后为Service1添加了两个终结地,基于HTTP的BasicHttpBinding和基于TCP的NetTcpBinding。添加的两个终结点均采用相对地址Service1。
由于AddServiceEndpoint指定的是相对地址,所以WCF会根据绑定采用的传输协议在ServiceHost的基地址列表中寻找与之匹配的基地址,相对地址与基地址组合确定终结点的绝对地址。(完整地址为:http://127.0.0.1:9999/myservices/Service1).
由于基地址与相对地址的匹配关系是根据绑定对象采用的传输协议确定的,所以对于一个确定的传输协议,最多只能有一个基地址。如果在上面的基地址中再加一个HTTP的基地址,那程序就会抛出异常。
如果采用上面配置文件的方式:
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.web>
- <compilation debug="true" />
- </system.web>
- <!-- 部署服务库项目时,必须将配置文件的内容添加到
- 主机的 app.config 文件中。System.Configuration 不支持库的配置文件。-->
- <system.serviceModel>
- <services>
- <service name="ConsoleApplication1.Service1">
- <host>
- <baseAddresses>
- <add baseAddress = "http://127.0.0.1:9999/myservice" />
- <add baseAddress="net.tcp://127.0.0.1:9999/myservice"/>
- </baseAddresses>
- </host>
- <!-- Service Endpoints -->
- <!-- 除非完全限定,否则地址将与上面提供的基址相关 -->
- <endpoint address ="Service1"
- binding="basicHttpBinding"
- contract="ConsoleApplication1.IService1"
- bindingConfiguration="HttpStreaming">
- </endpoint>
- <endpoint address="Service1"
- binding="netTcpBinding"
- contract="ConsoleApplication1.IService1"
- bindingConfiguration="netTcpBindingConfiguration"/>
- <!-- Metadata Endpoints -->
- <!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 -->
- <!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除-->
- <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
- </service>
- </services>
- <behaviors>
- <serviceBehaviors>
- <behavior>
- <!-- 为避免泄漏元数据信息,
- 请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
- <serviceMetadata httpGetEnabled="false"/>
- <!-- 要接收故障异常详细信息以进行调试,
- 请将以下值设置为 true。在部署前设置为 false
- 以避免泄漏异常信息-->
- <serviceDebug includeExceptionDetailInFaults="False" />
- <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
- </behavior>
- </serviceBehaviors>
- </behaviors>
- <bindings>
- <basicHttpBinding>
- <binding name="HttpStreaming" maxReceivedMessageSize="67108864" transferMode="Streamed"/>
- </basicHttpBinding>
- <netTcpBinding>
- <binding name="netTcpBindingConfiguration"
- closeTimeout="00:01:00"
- openTimeout="00:01:00"
- receiveTimeout="00:10:00"
- sendTimeout="00:10:00"
- transactionFlow="false"
- transferMode="Buffered"
- transactionProtocol="OleTransactions"
- hostNameComparisonMode="StrongWildcard"
- listenBacklog="10"
- maxBufferPoolSize="2147483647 "
- maxBufferSize="2147483647 "
- maxConnections="10"
- maxReceivedMessageSize="2147483647 ">
- <readerQuotas maxDepth="64" maxStringContentLength="2147483647 " maxArrayLength="2147483647 " maxBytesPerRead="4096" maxNameTableCharCount="16384" />
- <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
- <security mode="Transport">
- <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
- </security>
- </binding>
- </netTcpBinding>
- </bindings>
- </system.serviceModel>
- </configuration>
注:如果采用代码和配置的方式,两者都会生效,所以必须确保两者的设置的内容不会相互冲突。
这是服务端的配置,真的搞明白了,确实还挺有意思的。不过在调试过程中出现了错误
在服务“Service1”实现的协定列表中找不到协定名称,这个问题费我半天时间,
出错的原因有两个:
1. 看契约是否写对, 这个一般不会写错
2.看配置文件:service name="命名空间名+服务名称" endpoint contract="命名空间名+契约名称"
(这里有个小细节要注意, ""中不能出现空格,否则依然报错)
我出的问题原因是第二种,命名空间名前多了空格。费了半天劲原来是自己的粗心大意,唉,真想把自己杀了……
在编写配置中当然还出现了各种各样无法八门的问题,都是因为配置没有写对的原因,这也给我一个教训,编写代码一定不能粗心大意,不然都是血的代价……
下面是本文的重点了,文件的下载。
二、WCF文件的下载
其实WCF下载也没有什么可说的,就是写个返回Steam的接口就行了,关键就是写好配置文件就行了
(待续……)
WCF配置文件与文件下载之坎坷路的更多相关文章
- 坎坷路:ASP.NET Core 1.0 Identity 身份验证(中集)
上一篇:<坎坷路:ASP.NET 5 Identity 身份验证(上集)> ASP.NET Core 1.0 什么鬼?它是 ASP.NET vNext,也是 ASP.NET 5,以后也可能 ...
- WCF 配置文件(三)
配置文件概述 WCF服务配置是WCF服务编程的主要部分.WCF作为分布式开发的基础框架,在定义服务以及定义消费服务的客户端时,都使用了配置文件的方法.虽然WCF也提供硬编程的方式,通过在代码中直接设置 ...
- WPF刷新界面之坎坷路
WPF刷新界面之坎坷路 项目需要一个硬件检测功能,需要用到界面刷新,刚开始想用个定时器,对检测过的硬设定时添加后刷新界面. 但是很遗憾,定时器并不能进行刷新.后台检测List数据里面已经添加了很多了很 ...
- [转]使用代码去描述WCF配置文件
转自:使用代码去描述WCF配置文件 在应用程序部署的时候,WCF客户端因为服务器地址的变化,需要修改程序配置文件的地址URL,手动修改很不方便,还会造成错误,所以尽量把描述WCF配置文件的配置使用代码 ...
- WCF配置文件
因为要上传较大的图片,WCF传递数组的默认的最大数组16KB就不够了.以下讲解配置内容. 服务端配置 这里一个WCF项目中有1个服务,配置文件如下(位于system.serviceModel标签中): ...
- WCF配置文件的问题(位置)
引用过了远程的WCF服务,会自动生成配置文件,但是这个配置的位置,尽量放在applicationSettings的前面 刚才测试了,貌似放后面,会报错(执行的时候,这个问题,需要继续试验) (待验证) ...
- WCF 配置文件中的MaxStringContentLength & MaxReceivedMessageSize
中午测试员在测试系统模块时发现无法通过WCF从服务器下载数据,检查配置文件后,建议开发人员修改站点的WEB.CONFIG文件,具体修改对比如下: 旧的: <binding name=" ...
- WCF配置文件详解
今天来看看WCF的配置方法. 上图整理了服务配置过程中所用到的基本的元素,大致的步骤主要是首先要在调用服务的程序集中添加服务的一个引用,然后添加一个service并指定服务的名称.终结点,如果添加了b ...
- 坎坷路:ASP.NET 5 Identity 身份验证(上集)
之所以为上集,是因为我并没有解决这个问题,写这篇博文的目的是纪录一下我所遇到的问题,以免自己忘记,其实已经忘了差不多了,写的过程也是自己回顾的过程,并且之前收集有关 ASP.NET 5 身份验证的书签 ...
随机推荐
- leetcode 105 106 从前序与中序遍历序列构造二叉树 从中序与后序遍历序列构造二叉树
题目: 105 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = ...
- Atcoder Tenka1 Programmer Contest 2019题解
传送门 \(C\ Stones\) 最后肯定形如左边一段白+右边一段黑,枚举一下中间的断点,预处理一下前缀和就可以了 int main(){ // freopen("testdata.in& ...
- CISSP一次通过指南(文末附福利)
2017年12月19日,在上海黄浦区汉口路亚洲大厦17层通过了CISSP认证考试,拖拉了一年,终于成绩还算令人满意,为攒人品将自己一年多的复习心得和大家分享,希望能够帮到需要考证的朋友. 本文作者:i ...
- RabbitMQ交换机规则实例
RabbitMQ Exchange分发消息时根据类型的不同分发策略有区别,目前共四种类型:direct.fanout.topic.headers .headers 匹配 AMQP 消息的 header ...
- this引用逃逸(使用内部类获取未外部类未初始化完的变量),多态父类使用子类未初始化完的变量
1,this引用逃逸 并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了. 这是危及到线程安全的,因为其他线程有可能 ...
- 解决后台json数据返回的字段需要替换的问题
有时候后台json数据返回的字段含有“id”,也有可能是有时候为了减少代码的冗余,两页面之间只是数据模型个别属性的区别,所以这时候最好是用到模型属性的替换,用新的属性替换返回的json数据的字段.这里 ...
- window本地运行mapreduce程序
mapreduce的运行方式一般有两种,一是从本地导出一个jar包,在传到虚拟机上运行,这样调试起来非常的不方便,如果出现错误就需要重新导出jar包. 第二种方式是在本地直接运行,但是在运行前需要进行 ...
- 认识AngularJS
学习AngularJS所需技能 HTML & CSS JavaScript 为什么要使用AngularJS 如果你想用JavaScript制作动态Web站点,使用AngularJS有以下优点: ...
- Android自定义View创建流程
Android的framework提供了很多高质量的view,有时业务需求需要自定义View,其实现流程大致如下: 1.在values/attrs.xml中定义支持的自定义属性,示例如下:
- MySQL 5.7.14 win10安装
1. 下载: http://dev.mysql.com/downloads/mysql/