第三讲:WCF介绍(3)
代码
https://yunpan.cn/cPns5DkGnRGNs 密码:3913
典型传输协议下的URI
(1)HTTP和HTTPS
HTTPS(安全超文本传输协议).它是为了在WWW上解决安全的数据传输
而设计的。HTTS是采用了SSL的HTTP,SSL是一种加密协议。它们默认的端口
号分别是80和443
(2)TCP
WCF通过NetTcpBinding支持基于TCP的传输。对于TCP的URI,其传输协议前缀均为
net.tcp://。默认端口号808
net.tcp://127.0.0.1:808/calculatorService
(3):Pipe
对于同一台机器上不同进程间的通信(IPC),WCF具有专门的实现方式:命名管道(Named Pipes).
通过命名管道进行跨进程通信能够获得最好的性能优势。WCF将命名管道专门用于同一台机器的跨
进程通信,所以基于IPC的URI的主机名|域名|IP地址部分只能是本机的机器名,或者直接是localhost
或127.0.0.1
基于IPC的URI, 都具有net.pipe前缀,端口没有任何意义.
net.pipe://127.0.0.1/calculatorService
(4):Msmq 消息队列
net.msmq://xxx.com/calculatorService (公有队列)
net.msmq://xxx.com/private/calculatorService(私有队列)
为服务指定地址 ( 逻辑地址和物理地址 )
1:通过代码方式指定地址.
2:通过配置指定地址.
默认的情况下,监听地址与终结点地址是统一的。只有在逻辑地址和物理地址相互分离的情况下,才需要指定不同于终结点地址的监听地址.(也就是说服务器启动之后,我们上面配置服务器终结点 http://127.0.0.1:6666/calculatorservice 这个地址会被服务器不断的监听。 我们上面的例子都是 这种方式 去 监听的,因为我们上面的例子并没有配置 物理地址。)
在WCF中,每个终结点(服务端以及客户端的终结点)都包含两个不同的地址:逻辑地址和物理地址。逻辑地址就是以终结点Address属性表示的地址。(我们上面 第一讲与第二讲 的例子配置的都是 逻辑地址 )
至于物理地址,对于消息发送端来讲,就是消息被真正发送的目的地址:而对于消息的接收端来讲,就是监听器真正监听的地址。
之前第一讲的时候 我们 使用代码方式完成服务端的 服务寄宿 时候需要 填写 A,B,C
其实后面还有一个选项参数 ,就是我们的 物理地址 参数了,只不过之前我们都没有写
[ 3-01 ]
看上图 我们 服务器的 物理地址 配置就是这里,如果这里配置了 物理地址 ,那么服务器的监听地址就不是配置的 参数 A 了,而是配置的物理地址。
[ 3-02 ]
我们配置一下服务端的 (以代码的方式去配置)
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Policy;
- using System.ServiceModel;
- using System.ServiceModel.Description;
- using System.Text;
- using System.Threading.Tasks;
- using Contracts;
- using Services;
- namespace Hosting
- {
- class Program
- {
- static void Main(string[] args)
- {
- //首先提供一个主机进程,实际上就是完成寄宿的主机( CalculatorService 完成了对契约的实现,所以我们这里就寄宿就寄宿它了 )
- using (var host = new ServiceHost(typeof(CalculatorService)))
- {
- /*
- 然后 当我们把寄宿后,就要完成我们的EndPoint(终结点) 了,之前提过EndPoint=A,B,C 那么这里就要绑定了
- 之前的图片 [ 1-05 ] 已经展示 过这个 EndPoint
- 这里的 WSHttpBinding 就是 指定 HTTP 协议 当然还有很多种,后面说到
- 添加终结点 首先 C,然后 B 最后 A
- */
- host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:6666/calculatorservice", new Uri("http://127.0.0.1:8888/calculatorservice"));
- //这里检测 元数据 为不为空 这里的元数据也不管是什么东西,下面我们说到
- if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
- {
- //也就是说这里我们是以元数据的形式发布出去进行客户端与服务器的交互
- //控制服务元数据和相关信息的发布
- ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
- behavior.HttpGetEnabled = true;//是否可以通过 HTTP Get 形式 去访问
- // 元数据的地址,可以通过这个地址 在 浏览器中 进行访问
- behavior.HttpGetUrl = new Uri("http://127.0.0.1:6666/calculatorservice/metadata");
- //添加到元数据中去
- host.Description.Behaviors.Add(behavior);
- }
- //指定一个事件,当服务启动之后 需要做什么,这里指定一个委托,在 Open 成功后,就执行这里的事件
- host.Opened += (sender, eventArgs) => Console.WriteLine("服务已经启动,按任何按钮停止");
- //开启服务
- host.Open();
- Console.Read();
- }
- }
- }
- }
[ 3-03 ]
当然也可以使用 配置文件的方式去配置服务端
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <behaviors>
- <serviceBehaviors>
- <behavior name="metadataBehavior">
- <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:9999/calculatorservice/metadata"/>
- </behavior>
- </serviceBehaviors>
- </behaviors>
- <services>
- <service behaviorConfiguration="metadataBehavior" name="Services.CalculatorService">
- <!--服务端 配置 物理地址 也就是 真正监听的地址 listenUri="" -->
- <endpoint address="http://127.0.0.1:9999/calculatorservice"
- listenUri="http://127.0.0.1:8888/calculatorservice"
- binding="wsHttpBinding" contract="Contracts.ICalculator"></endpoint>
- </service>
- </services>
- </system.serviceModel>
- </configuration>
那么我们客户端的配置就是 ( 这里就说WebConfig 去配置物理地址了。代码方式配置 物理地址没有找到,如果有朋友知道通知一声,谢谢! )
[ 3-04 ]
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <behaviors>
- <endpointBehaviors>
- <behavior name="clientViaBehavior">
- <!--客户端配置物理地址 (也就是信息具体发送地址) viaUri 这个 参数 -->
- <clientVia viaUri="http://127.0.0.1:8888/calculatorservice"/>
- </behavior>
- </endpointBehaviors>
- </behaviors>
- <client>
- <endpoint behaviorConfiguration="clientViaBehavior" address="http://127.0.0.1:9999/calculatorservice"
- binding="wsHttpBinding" contract="Contracts.ICalculator" name="calculatorservice"></endpoint>
- </client>
- </system.serviceModel>
- </configuration>
(1)服务端逻辑地址与物理地址。
对于消息接收放的终结点来讲,物理地址就是监听地址。
public ServiceEndpoint AddServiceEndpoint(string implementedContract,Binding binding,string address,Uri listenUri)
(2):客户端逻辑地址与物理地址
对于消息的发送端来讲,物理地址其实就是消息发送的真正目的地址。通过
ClientVia定义客户端URI代表物理地址.

- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.ServiceModel;
- using System.ServiceModel.Description;
- using Contracts;
- using Services;
- namespace Hosting
- {
- class Program
- {
- static void Main(string[] args)
- {
- //两个不同协议的基地址
- Uri[] baseAddress = new Uri[];
- baseAddress[] = new Uri("http://127.0.0.1:9999");
- baseAddress[] = new Uri("net.tcp://127.0.0.1:8888");
- using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddress))
- {
- //两个不同协议的相对地址
- host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "calculatorservice");
- host.AddServiceEndpoint(typeof(ICalculator), new NetTcpBinding(), "calculatorservice");
- host.Opened += delegate
- {
- Console.WriteLine("服务已经启动,请按任意键中止服务");
- };
- host.Open();
- Console.Read();
- }
- }
- }
- }
客户端
[ 3-06 ]
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ServiceModel;
- using Contracts;
- namespace Client
- {
- class Program
- {
- static void Main(string[] args)
- {
- //这里按照之前不变
- using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(new WSHttpBinding(), "http://127.0.0.1:9999/calculatorservice"))
- {
- ICalculator proxy = channelFactory.CreateChannel();
- using (proxy as IDisposable)
- {
- Console.WriteLine("x+y={2} when x={0} and y={1}", , , proxy.Add(, ));
- Console.ReadKey();
- }
- }
- }
- }
- }

- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.ServiceModel;
- using System.ServiceModel.Description;
- using Contracts;
- using Services;
- namespace Hosting
- {
- class Program
- {
- static void Main(string[] args)
- {
- //以下是通过配置文件更改了终结点的添加和服务行为的定义.
- using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
- {
- host.Opened += delegate
- {
- Console.WriteLine("CalculaorService已经启动");
- };
- host.Open();
- Console.Read();
- }
- }
- }
- }
服务端 App.config
[ 3-08 ]
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <services>
- <service name="Services.CalculatorService">
- <!--配置两个不同协议的想相对地址-->
- <endpoint address="calculatorservice" binding="wsHttpBinding" contract="Contracts.ICalculator"></endpoint>
- <endpoint address="calculatorservice" binding="netTcpBinding" contract="Contracts.ICalculator"></endpoint>
- <host>
- <baseAddresses>
- <!--配置两个不同协议的基地址-->
- <add baseAddress="http://127.0.0.1:9999"/>
- <add baseAddress="net.tcp://127.0.0.1:8888"/>
- </baseAddresses>
- </host>
- </service>
- </services>
- </system.serviceModel>
- </configuration>
服务端配置好了
客户端 Program.cs
[ 3-09 ]
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.ServiceModel;
- using Contracts;
- namespace Client
- {
- class Program
- {
- static void Main(string[] args)
- {
- using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice"))
- {
- ICalculator proxy = channelFactory.CreateChannel();
- using (proxy as IDisposable)
- {
- Console.WriteLine("x+y={2} when x={0} and y={1}", , , proxy.Add(, ));
- Console.ReadKey();
- }
- }
- }
- }
- }
客户端 App.config
[ 3-10 ]
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
- <client>
- <endpoint address="http://127.0.0.1:9999/calculatorservice" binding="wsHttpBinding" contract="Contracts.ICalculator" name="calculatorservice"></endpoint>
- <!--<endpoint address="net.tcp://127.0.0.1:8888/calculatorservice" binding="netTcpBinding" contract="Contracts.ICalculator" name="calculatorservice"></endpoint>-->
- </client>
- </system.serviceModel>
- </configuration>
从上面的代码中我们可以看到 服务端 写了 两个 不同协议的监控地址 这是可以的,但不能配置同一协议的 两个不同的地址
而客户端则只能写一个 地址,不管是HTTP协议还是TCP谐音,有且只能写一个地址。
基地址与相对地址
除了以绝对路径的方式指定某个服务的终结点地址外,还可以通过”基地址+相对地址”的方式进行设置.对于一个服务来说,可以指定一个或多个基地址,但是对一种传输协议类型,只能就有一个唯一的基地址。
好了 我们的补充 就到这里了
我们来看我们这节的主要知识:服务契约
服务契约:
是相关操作的集合.
契约就是双方或多方就某个关注点达成的一种共识,是一方向另一方的一种承诺。签署了某个契约就意味着自己有义务履行契约中规定的各项规定,一旦违约势必影响契约双方的正常交互.
我们主张通过抽象将接口和实现相互分离,鼓励接口的依赖,避免基于实现的依赖。接口是稳定的,而实现则是易变的,基于接口的服务调用能够更有效地应对实现的变化带来的影响。
接口从本质上就是一种契约,当某个类实现了某个接口,就相当于签署了一份契约。所以契约关心的是“我能做到”,不在于”我如何做到”。所以,服务契约是以接口的形式进行定义的。
有了服务契约,那我们如何去描述 服务契约?
对于服务契约来说,它涉及的参与者就是服务的提供者和服务的消费者,服务的提供者通过服务契约的形式将服务公布出来,服务的消费者通过服务契约进行服务的消费。那么,要保证服务的正常消费,有一个根本的前提:服务的消费者能够正确“理解”服务提供者公布出来的服务契约。
也就是必须有一个统一的标准:XML因其简单,表意能力强,已经成为了事实上的标准。如何表达通过XML的数据结构?XSD是最好的选择。而对于WEB服务的描述,它有自己专门的标准,最基本的就是WSDL。
所以,如果希望服务契约能被基于不同平台的客户端所理解的话,就应以一种平台无关的标准进行描述,而在WCF中服务契约就是最终可以通过WSDL描述的。
就是我们上面说的 元数据
看这里的 GIF 图片 :
[ 3-11 ]
[ 3-12 ]
[ 3-13 ]
仔细看这里的XML:
[ 3-14 ]
- <?xml version="1.0" encoding="UTF-8"?>
- <xs:schema xmlns:tns=" " xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace=" " elementFormDefault="qualified">
- <xs:element name="Add">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="x" type="xs:double" minOccurs="0"/>
- <xs:element name="y" type="xs:double" minOccurs="0"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="AddResponse">
- <xs:complexType>
- <xs:sequence>
- <xs:element name="AddResult" type="xs:double" minOccurs="0"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- </xs:schema>
这很明显的 描述了 我们的服务契约: 有一个Add 的方法 两个参数 x,y ,以及返回值 也是 double 类型
第三讲:WCF介绍(3)的更多相关文章
- 第二讲:WCF介绍(2)
代码 https://yunpan.cn/cPns5DkGnRGNs 密码:3913 在上一讲中我们说到 在代码 当中 完成了 服务的寄宿. 这里我们说下 在实际的开发 当中 我们一般不会去 ...
- 第一讲:WCF介绍
代码 https://yunpan.cn/cPns5DkGnRGNs 密码:3913 ...
- Spring注解驱动第三讲--@Filter介绍
上一讲主要针对@ComponentScan注解做了一些说明,本文主要对@Filter的扫描条件,再做一些详细的介绍 1,FilterType.ANNOTATION 按照注解的方式进行扫描.后面clas ...
- 菜鸟学习WCF笔记-概念
背景 WCF这个词语一直不陌生,以前也使用过多次在实际的项目中,但是一直没有时间来做个系统的学习,最近抽点时间,看看 蒋金楠的<WCF全面解析>学习下,顺带做些笔记,如有错误,欢迎各路大神 ...
- 【转】《我的WCF之旅》博文系列汇总
转自:http://www.cnblogs.com/artech/archive/2007/09/15/893838.html WCF是构建和运行互联系统的一系列技术的总称,它是建立在Web Serv ...
- dotNet Linux 学习记录 - Jexus寄宿WCF服务
让WCF运行在Linux上(寄宿于服务器程序) WCF介绍请自行 bing 搜索 使用的开发工具为vs2017,系统为 Ubuntu16.04 服务器软件为Jexus ( 详情请看: Jexus官网 ...
- .NET跨平台 - WCF & Mono
让WCF运行在Linux上(寄宿于服务器程序) WCF介绍请自行 bing 搜索 使用的开发工具为vs2017,系统为 Ubuntu16.04 服务器软件为Jexus ( 详情请看: Jexus官网 ...
- 大海教你学手游2015CocosLua第一季_00课程介绍
话说大盘从5100直掉到3500点,千仅仅股票跌幅超过20%,跌跌不休.散户.证监会.做空机构開始斗气地主来了: 散户:叫地主 空头:抢地主,3分 证监会:pass 空头:压死 证监会:不要 散户:不 ...
- (一)WCF基础
我们近期在做项目的时候用到了WCF,之前已经看了部分视频,对于WCF有了一定的了解,但仅限于能够根据搭建好的框架使用WCF,还不了解.所以就进行了研究,这样既有实践也能增加理论,二者结合,使用起来更胜 ...
随机推荐
- JavaScript正则表达式下——相关方法
上篇博客JavaScript 正则表达式上——基本语法介绍了JavaScript正则表达式的语法,有了这些基本知识,可以看看正则表达式在JavaScript的应用了,在一切开始之前,看看RegExp实 ...
- JavaScript 常用功能总结
小编吐血整理加上翻译,太辛苦了~求赞! 本文主要总结了JavaScript 常用功能总结,如一些常用的JS 对象,基本数据结构,功能函数等,还有一些常用的设计模式. 目录: 众所周知,JavaScri ...
- lua表排序
对于lua的table排序问题,一般的按照value值来排序,使用table.sort( needSortTable , func)即可(可以根据自己的需要重写func,否则会根据默认来:默认的情形之 ...
- Atitit 拦截数据库异常的处理最佳实践
Atitit 拦截数据库异常的处理最佳实践 需要特殊处理的ex 在Dao层异常转换并抛出1 Server层转换为业务异常1 需要特殊处理的ex 在Dao层异常转换并抛出 } catch (SQLExc ...
- 可能是一场很 IN 的技术分享
从去年的 Swift 到今年的 iOS 9,每一个新的技术.新的设备都"紧紧牵动 iOS 开发者的心". 好在有这样一群开发者,他们乐于第一时间尝试.挑战并分享. 有一类开发者他们 ...
- iOS-MVC模式
提到ios中的mvc不得不提2011秋季斯坦福课程的老头,他的iphone开发公开课是所有描述ios中mvc模式最为准确并且最为浅显易懂的. 模型-视图-控制器 这个模式其实应该叫做MCV,用控制器把 ...
- EasyUI Field
效果: JS: var sortIndex = $("#ListDiv").find(".datagrid-view2").find(".datagr ...
- ajax获取json对象
ajax获取json对象 ajax获取json数据,都是一个原理,设置response 的Content-Type:application/json,这样浏览器自动会解析为json对象 $result ...
- 【WP 8.1开发】手机客户端应用接收推送通知
上一篇文章中,已经完成了用于发送通知的服务器端,接下来我们就用这个服务端来测试一下. 在开始测试之前,我们要做一个接收通知的WP应用. 1.启动VS Express for Windows,新建项目, ...
- structs2之多文件上传
//首先是Action部分import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; i ...