代码

https://yunpan.cn/cPns5DkGnRGNs   密码:3913


 
前面我们通过一个小的例子,大概了解的WCF。
这里我们补充下  EndPoint 配置  A,B,C  中的  A ( Address ),  格式 是:  [传输协议]://[主机名称|域名|IP地址]:[可选端口号]/[资源路径]   就是  URI(统一资源标识) ,它唯一标识一个确定的网络资源,同时也表示资源所处的位置及访问的方式(资源访问所用的网络协议)。
 

典型传输协议下的URI

(1)HTTP和HTTPS

HTTPS(安全超文本传输协议).它是为了在WWW上解决安全的数据传输

而设计的。HTTS是采用了SSL的HTTP,SSL是一种加密协议。它们默认的端口

号分别是80和443

http://127.0.0.1:80/calculatorService

https://127.0.0.1:443/calculatorService

这里的端口好必须写,如果不写 的话 是默认的,而  配置  EndPoint 的 A  为 http和https  默认的端口号的时候会 报错,因为端口号 被占用了,所以这里注意 ,一定要把端口号写上  
 

(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代表物理地址.

 
 
 
 
 
 

 
 
 
为服务指定地址  ( 基地址与相对地址)
 
这里说白了 就是 将  地址 分开来写  
例如  我们上面配置的    http://127.0.0.1:8888/calculatorservice  这个 服务器 终结点地址   把它 拆开来写   http://127.0.0.1:8888  就是  基地址    而  calculatorservice 就是相对地址  可以这么理解
 
 
我们来看下程序中怎么做:
 
我们先看以 代码的方式 去配置基地址  
 
服务端 
 
[ 3-05 ]
 
 
 

 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();
}
}
}
}
}
代码的方式  可以不去管 Appconfig 的配置
 
 
 
再看  以 appconfig 配置的 方式 去配置  基地址与相对地址
 
服务端  Program.cs
 
[ 3-07 ]
 
 
 

 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谐音,有且只能写一个地址。

基地址与相对地址

除了以绝对路径的方式指定某个服务的终结点地址外,还可以通过”基地址+相对地址”的方式进行设置.对于一个服务来说,可以指定一个或多个基地址,但是对一种传输协议类型,只能就有一个唯一的基地址。

好了  我们的补充 就到这里了


我们来看我们这节的主要知识:服务契约

服务契约:

是相关操作的集合.

契约就是双方或多方就某个关注点达成的一种共识,是一方向另一方的一种承诺。签署了某个契约就意味着自己有义务履行契约中规定的各项规定,一旦违约势必影响契约双方的正常交互.

我们主张通过抽象将接口和实现相互分离,鼓励接口的依赖,避免基于实现的依赖。接口是稳定的,而实现则是易变的,基于接口的服务调用能够更有效地应对实现的变化带来的影响。

接口从本质上就是一种契约,当某个类实现了某个接口,就相当于签署了一份契约。所以契约关心的是“我能做到”,不在于”我如何做到”。所以,服务契约是以接口的形式进行定义的。

有了服务契约,那我们如何去描述 服务契约?

WSDL、XSD与服务契约

对于服务契约来说,它涉及的参与者就是服务的提供者和服务的消费者,服务的提供者通过服务契约的形式将服务公布出来,服务的消费者通过服务契约进行服务的消费。那么,要保证服务的正常消费,有一个根本的前提:服务的消费者能够正确“理解”服务提供者公布出来的服务契约。

也就是必须有一个统一的标准: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)的更多相关文章

  1. 第二讲:WCF介绍(2)

    代码 https://yunpan.cn/cPns5DkGnRGNs   密码:3913   在上一讲中我们说到 在代码 当中  完成了 服务的寄宿. 这里我们说下 在实际的开发 当中 我们一般不会去 ...

  2. 第一讲:WCF介绍

    代码 https://yunpan.cn/cPns5DkGnRGNs   密码:3913                                                         ...

  3. Spring注解驱动第三讲--@Filter介绍

    上一讲主要针对@ComponentScan注解做了一些说明,本文主要对@Filter的扫描条件,再做一些详细的介绍 1,FilterType.ANNOTATION 按照注解的方式进行扫描.后面clas ...

  4. 菜鸟学习WCF笔记-概念

    背景 WCF这个词语一直不陌生,以前也使用过多次在实际的项目中,但是一直没有时间来做个系统的学习,最近抽点时间,看看 蒋金楠的<WCF全面解析>学习下,顺带做些笔记,如有错误,欢迎各路大神 ...

  5. 【转】《我的WCF之旅》博文系列汇总

    转自:http://www.cnblogs.com/artech/archive/2007/09/15/893838.html WCF是构建和运行互联系统的一系列技术的总称,它是建立在Web Serv ...

  6. dotNet Linux 学习记录 - Jexus寄宿WCF服务

    让WCF运行在Linux上(寄宿于服务器程序) WCF介绍请自行 bing 搜索 使用的开发工具为vs2017,系统为 Ubuntu16.04 服务器软件为Jexus ( 详情请看:  Jexus官网 ...

  7. .NET跨平台 - WCF & Mono

    让WCF运行在Linux上(寄宿于服务器程序) WCF介绍请自行 bing 搜索 使用的开发工具为vs2017,系统为 Ubuntu16.04 服务器软件为Jexus ( 详情请看:  Jexus官网 ...

  8. 大海教你学手游2015CocosLua第一季_00课程介绍

    话说大盘从5100直掉到3500点,千仅仅股票跌幅超过20%,跌跌不休.散户.证监会.做空机构開始斗气地主来了: 散户:叫地主 空头:抢地主,3分 证监会:pass 空头:压死 证监会:不要 散户:不 ...

  9. (一)WCF基础

    我们近期在做项目的时候用到了WCF,之前已经看了部分视频,对于WCF有了一定的了解,但仅限于能够根据搭建好的框架使用WCF,还不了解.所以就进行了研究,这样既有实践也能增加理论,二者结合,使用起来更胜 ...

随机推荐

  1. ubuntu:solve the problem of 'E:Problem with MergeList /var/lib/apt/lists/'

    just run this command: sudo rm /var/lib/apt/lists/* -vfR it will remove all the software package wit ...

  2. CGLib与JDKProxy的区别

    Spring AOP 的实现主要有两种:CGLib与JDK自带的Proxy. 他们主要的区别是,需要JDKProxy修改的类必须实现接口(因此也只能代理public方法),在创建Proxy时可以使用c ...

  3. AFNetworking+Python+Flask+pyOpenSSL构建iOS HTTPS客户端&服务器端

    对于HTTPS我在网上找了一堆资料看了下, 各种协议和证书已经有点晕了 最后我现有的感觉是, 在HTTP服务器上放一个证书, 在原本的HTTP访问之前客户端先检查证书是否正确 如果客户端证书检查正确, ...

  4. Ubuntu 12.04下GAMIT10.40安装说明

    转载于:http://www.itxuexiwang.com/a/liunxjishu/2016/0225/164.html?1456481297 Ubuntu 12.04下GAMIT10.40安装步 ...

  5. Node.js入门:前后端模块的异同

        通常有一些模块可以同时适用于前后端,但是在浏览器端通过script标签的载入JavaScript文件的方式与Node.js不同.Node.js在载入到最终的执行中,进行了包装,使得每个文件中的 ...

  6. redis基本配置和相关设置

    redis-cli:the redis command line interface command line usage: $redis-cli incr mycounter 输出的结果只会显示在终 ...

  7. SSH框架详解

    1.什么是ssh? SSH对应 struts spring hibernate struts 采用MVC模式,主要是作用于用户交互 spring 采用IOC和AOP~作用比较抽象,是用于项目的松耦合 ...

  8. rabbitmq消息队列——"Hello World!"

    RabbitMQ 一."Hello World!" 1.简介: RabbitMQ是一种消息中间件,主要思想很简单:接收消息并转发.你可以将它设想为一个邮局:你往里面发送邮件并确保邮 ...

  9. cordova填坑

    cordova填坑

  10. iBatis + SQL Server 项目开发实战小结

    几年前跟随项目经理做的一个ERP小项目,自己业余时间整理的开发手册,供参考. 开发环境配置:编程环境为Microsoft Visual Studio 2010,数据库是SQL Server 2008 ...