–这一篇翻译的有点渣渣,下次再来改吧,主要按照书中的步骤,有些会出错,之前又没有搞过AN。
这一章看看如何构造XML Web Services和你怎么样消耗XML web service界面并且将它们集成到你的应用中。我们开始介绍.NET世界中XML网页服务的基础,例如SOAP,WSDL等等。这一章中间的部分集中于Windows Communication Foundation。这一章的最后一部分主要集中于讨论最新的communication framework WebAPI。这个相对较新的框架使你能够迅速和方便的通过API铺路核心功能。
COMMUNICATION BETWEEN DISPARATE SYSTEMS
这是一个变化多样的世界。在一个大企业,你基本找不到整个机构和它的数据储藏室用的是单个供应商的平台。在大多数的例子中,机构是有很多不同的系统拼凑而成,有一些基于UNIX,有一些基于微软,有些基于别的系统。基本上不可能会有一天,所有的东西都驻留在一个平台上,所有的数据在每个机构的服务器之间都是无缝的转移。正因为这样,这些不同的系统必须能够相互交流。如果不同的系统能够顺畅地交流,将数据集合在企业间流转会变得非常简单-能够缓解重复系统和数据商店的需要。
XML的强大在于它无视系统平台,语言和系统商店的差异。XML起源于SGML。因为SGML这样的复杂,我们需要更简单的东东-由此诞生了XML。
XML被认为是表现数据意图的理想方式,因为它是的开发者能够按照他们看为合适的方式构造XML。也正是因为这个原因,XML有时候看起来有点混乱。发送自己构造的XML文档在不同的系统间没多大意义-你需要为每对交流的对象定制的构造这个暴露消化系统。
供应商和整个工业意识到XML需要一个特别的结构来设置一些规则澄清通讯的方式。这个定义XML结构的规则使得不同系统间的通讯变得简单。工具供应商现在自动化这个通信过程,也提供了使用这个通信协议创建应用所有部件的自动化。
工业使用SOAP来让标准的XML结构起作用。之前解决通讯问题的尝试引发了例如DCOM,RMI,CORBA和IIOP。这些期初的尝试都失败了,因为这些技术要么是由单个供应商驱动的,要么就是跟供应商黏连的。将它们在整个工业中推广是不可能的。
SOAP使你能够暴露和消化复杂的数据结构,这个数据结构包括DataSets,或者表数据。SOAP相对来说非常简单,也便于理解。和ASP.NET一样,XML Web Services也是站在HTTP这个伟大协议的肩膀上工作的。你发送或者消耗的DataSets可以流动在HTTP协议中,因为能越过许多防火墙。
所以wire上到底存在着什么?ASP.NET Web Services一般使用HTTP上的SOAP。一个SOAP1.2请求(从客户端发送到网页服务器上的网页服务)结构如下所示。
POST /WebService.asmx HTTP/1.1
Host: localhost
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 19
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<HelloWorld xmlns="http://tempuri.org/" />
</soap12:Body>
</soap12:Envelope>
这个请求发送到网页服务,来调用HelloWorld WebMethod。下面展示了SOAP响应
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 14
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<HelloWorldResponse xmlns="http://tempuri.org/">
<HelloWorldResult>Hello World </HelloWorldResult>
</HelloWorldResponse>
</soap12:Body>
</soap12:Envelope>
从这两个例子可以看到,消息中包含的是一个XML文件。除了正常的XML申明即xml节点,你可以看到XML的结构是一个SOAP消息。一个SOAP消息使用soap:Envelope作为根节点,包含了soap:Body。SOAP消息中可以包含soap:Header和一个soap:Fault。
BUILDING A SIMPLE XML WEB SERVICE
构造一个XML网页服务意味着你想要想机构里的另一个实体,对一个合作伙伴或者你的消费者暴露某些信息或者逻辑。对开发者来说,构建一个web service,仅仅就是在一个类里生成几个方法可以进行SOAP通信。
你可以使用VS来构造XML web service。首先生成一个新的网站。
The WebService Page Directive
打开这个webservice.asmx文件,你会看到这个文件只包括了WebService page directive。
<%@ WebService Language="C#" CodeBehind="~/App_Code/WebService.cs"
Class="WebService" %>
对于.asmx web service,你使用@WebService指令而不是@Page指令。这个简单的WebService指令只有4个属性。
- Class:必须的。指明用来定义方法和数据类型的类。
- CodeBehind:使你能够在两部分和web services打交道。
- Debug:可选,如果Debug设为True,这个XML web service是和调试符号一起编译的。如果设为false确保web service编译后没有调试符号。
- Language:必须的。指明了这个web service使用的语言。
Looking at the Base Web Service Class File
现在看看这个WebService.vb或者WebService.cs文件-这个XML web service的code-behind file。默认的,这个文件中已经包含了一些结构代码。
你在这里应该注意几点。第一,包含了System.Linq命名空间。
Exposing Custom DataSets as SOAP
为了构建你的web service,将WebService.asmx文件删除,生成一个新的文件名字为Customers.asmx。这个web service会将Customers table暴露。
The WebService Attribute
所有的web services都封装在一个class中。这个类是由类声明前的WebService属性定义为web service的。
这个WebService属性可以有一些特征。默认情况下,这个WebService属性是伴随着Namespace特征,这个Namespace又一个初始值http://tempuri.org/。这意味着是一个临时的命名空间,你应该用更有意义的名字,例如你将要把这个XML web service放到哪里的URL。在这个例子中,这个Namespace值改为http://adventureworks/customers。记住,这个值不需要是一个真是的url,它可以是任何你想要的字符串值。只要它是唯一的。
WebService其余的可能特征包含Name和Description。Name允许你改变呈现给开发者的WebService的名字。Description能提供这个WebService的文字描述。这个描述也是呈现在ASP.NET网页服务测试网页上。
The WebMethod Attribute
在这个例子中,这个名字为Customers的类只有一个WebMethod。一个WebService类可以包含任意数量的WebMethod,也可以是标准method和WebMethod的混合。和WebService属性一样,WebMethod也可以包含一些特征。
- BufferResponse 当这个设为True时,XML web service的响应安置在memory。如果设置为false,也是默认设置。
- CacheDuration 设置响应在系统缓存里的时间。默认设置为0,意味着缓存是禁止的。将XML web service的响应放在缓存里提高了web service 的性能。
- Description 对这个WebMethod的文字描述。
- EnableSession 设为true,启动了session state。默认是false。
- MessageName 给WebMethod一个唯一的名字。如果你重载了Webme,这一步是必须的。
- TransactionOption 指明了WebMethod的transactional支持。默认的设置是Disabled。
The XML Web Service Interface
这个Customers web service只有一个WebMethod,返回DataSet包含了完整的Customers表。
在浏览器中运行这个Customers.asmx拉出了ASP.NET web service 测试网页。这个web service的视图界面是用来测试或者给你的使用者作为指引。
这个接口在网页顶部显示了这个web service的名字。默认情况下,web service的名字使用这个类的名字,除非你改变了WebService属性的Description特征。
这个网页也有一个链接指向这个web service的WSDL。这个WSDL文件是Customers web service的实际接口。这个XML文档其实不是让人类看的。它设计成这样是由VS打交道的。每一个web service需要一个请求符合特定的参数类型。当发起这个请求时,这个web service响应特殊的数据集合。任何对请求和响应的规格都是在这个WSDL文档中。
点击这个GetCustomers链接带你来到了一个新的网页,不仅仅详细描述了WebMethod,也允许你直接在浏览器中测试这个WebMethod。
在网页的顶部是这个XML Web Service的名字,下面是这个WebMethod的名字。这个网页展示了这个SOAP消息在请求和响应中的结构。在SOAP例子下面是一个使用HTTP POST消耗这个XML web service的例子。使用这个方法而不是使用SOAP消耗这个web service是可能的。
你可以在这个网页直接测试这个WebMethod。在测试部分,你发现了一个表单,如果这个WebMethod需要输入参数来得到相应,你会看到一些文本框。如果这个WebMethod不需要参数,你只看到调用按钮,没有其他。
点击调用实际上发送了一个SOAP请求到web service。现在所有需要曝露这个XML web service的准备事项都已预备妥当。你可以在ASP.NET应用中消耗它。
CONSUMING A SIMPLE XML WEB SERVICE
到目前为止,你只看到这个XML web service故事的一半。将数据和逻辑作为SOAP曝露给散落在企业或者整个世界是一个简单的任务。故事的另一半是在ASP.NET中实际消耗这个XML web service。
你不局限于在AN应用中消耗这个XML web service。但是因为这是一本谈论AN的书,主要涉及在AN中消耗这个web service。在其他类型中消耗XML web service也不困难,跟你在AN中消耗都差不多。记住你碰到的web service可以再Windows Form,mobile application和其他中被消耗。你甚至可以使用其他的webservice消耗该XML web service,这样你可以有单个web service,这个web service是其余web service 的聚合。
Adding a Web Reference
为了消耗你之前创造的Customers web service,生成一个新的AN web site叫做CustomerConsume。在AN应用中消耗一个XML web service的第一步是增加一个引用到这个远程对象-这个web service。
Invoking the Web Service from the Client Application
因为一个XML web service的引用已经做完,你可以在你的AN应用中使用它。在你的工程中生成一个新的WebForm。这个想法是,当终端用户点击按钮的时候,这个应用发送一个SOAP请求到Customers· web service然后得到一个SOAP响应,将返回的Customers表绑定到GridView控件上。
<%@ Page Language="C#" %>
<!DOCTYPE html>
<script runat="server">
protected void Button1_Click(Object sender, EventArgs e)
{
AdventureWorksCustomers.Customers ws = new AdventureWorksCustomers.Customers();
GridView1.DataSource = ws.GetCustomers();
GridView1.DataBind();
}
</script>
随着你开发或者消耗更多的web services,你会看到他们的强大和便利。
OVERLOADING WEBMETHODS
在.NET面向对象的世界,使用method overloading在你的代码开发中是很容易的。一个真的面向对象语言支持多态,方法的重载是其一部分。方法重载允许你有多个不同的方法,使用相同的名字,但是有不同的签名。利用方法重载,一个方法可以被调用,但是能够被导向最合适的方法。下面的例子显示了一个标准方法重载。
public string HelloWorld()
{
return "Hello";
}
public string HelloWorld(string FirstName)
{
return "Hello " + FirstName;
}
在这个例子中,两个方法有相同的名字,HelloWorld。所以,哪一个是你调用的HelloWorld。这取决于你传递到这个方法的签名。
方法重载是一个非常棒的特色,使你的AN应用可以有效的利用。
如果你已经试过重载你的WebMethod,当你将这个WebService拉到浏览器上可能得到下面的错误。
Both System.String HelloWorld(System.String) and System.String HelloWorld() use the message
name ‘HelloWorld’. Use the MessageName property of the WebMethod custom attribute to
specify unique message names for the methods
正如错误指示的,重载WebMethod需要你使用这个MessageName特征。
[WebMethod(MessageName = "HelloWorld")]
public string HelloWorld() {
return "Hello World";
}
[WebMethod(MessageName = "HelloWorldWithFirstName")]
public string HelloWorld(string FirstName)
{
return "Hello " + FirstName;
}
除了添加MessageName特征,你还要将你的service所遵循的WS-I Basic Profile specification禁掉-如果你不禁掉,在使用WebMethod重载时,它不会工作。你可以有好几种方法禁止这个。
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.None)]
public class WebService : System.Web.Services.WebService
{
// Code here...
}
尽管你看到WebMethod的名字是一样的,这个MessageName特征显示它们是不同的方法。当开发者消耗这个web service,它们只看到一个方法名字。
CACHING WEB SERVICE RESPONSE
缓存可以说是.NET中几乎每个应用中重要的特色。第22章涵盖AN中你能用到的大多数缓存功能,但是.NET中web services的一些特色允许你缓存SOAP响应。
首先,记住缓存是将数据,对象和不同的items存储在内存中以备复用。这个特色提高了应用的响应性。有时候,返回缓存的数据能够极大的影响性能。
XML Web Service使用一个属性来控制SOAP响应的缓存-CacheDuration特征。
[WebMethod(CacheDuration = 60)]
public string GetServerTime()
{
return DateTime.Now.ToLongTimeString();
}
正如你看到的,CacheDuration在WebMethod中和Description还有Name特征一样。CacheDuration接受一个Integer值,等于SOAP响应缓存的秒数。
当第一个请求来时,这个SOAP响应由服务器缓存,然后消费者在下一分钟内得到的是相同的SOAP响应。当一分钟过了后,存储的缓存被抛弃,一个新的响应产生了,存储在缓存中。
USING SOAP HEADERS
另一种扩展SOAP功能的常用形式是增加metadata到这个SOAP消息中。这个metadata通常增加到SOAP envelope的一个所谓SOAP header的部分。
整个SOAP消息称为SOAP envelope。在SOAP消息中的是一个SOAP body-SOAP消息中必须要有的部分。
SOAP消息中可选的一部分是SOAP header。它是SOAP消息中你能放置metadata的部分。将meta数据和实际的request分开非常重要。
什么样的信息应该放在header中?它可以包含很多东西。一个常见的放在SOAP header中的item是认证授权功能。将用户姓名和密码放在你的消息中的SOAP header中是一个很好的例证。
Building a Web Service with SOAP Headers
你可以在VS中拉出来的默认.asmx文件中的HelloWorld上做文章。将这个新的.asmx文件命名为HelloSoapHeader.asmx。第一步是增加一个类来代表SOAP header。如下列代码所示
public class HelloHeader : System.Web.Services.Protocols.SoapHeader
{
public string Username;
public string Password;
}
这个代表SOAP header对象的类,必须继承于System.Web.Service.Protocols.SoapHeader。这个SoapHeader类将soap:header中的负载序列化为XML。在这个例子中,你可以看到SOAP header需要两个元素,一个简单的用户和一个简单的密码,都是string类型。你在类中生成的名字是用来SOAP header中子元素的构建用的,所以使用描述性的名字很重要。
下面是这个web service怎么样包含soap header
public class HelloSoapHeader : System.Web.Services.WebService {
public HelloHeader myHeader;
[WebMethod]
[SoapHeader("myHeader")]
public string HelloWorld()
{
if (myHeader == null)
{
return "Hello World";
}
else
{
return "Hello " + myHeader.Username + ". " +
"<br>Your password is: " + myHeader.Password;
}
}
}
这个webservice,HelloSoapHeader,只有一个WebMethod-HelloWorld。在这个web service中,但是在WebMethod外,你生成了一个SoapHeader类的实例。
现在你有了这个HelloHeader实例,你可以使用这个实例在你的WebMethod中。因为web service可以包含任意数量的WebMethod,不是所有的WebMethod都使用实例化的SOAP header。你指明WebMethod要不要一个SOAP header类的实例,通过放一个SoapHeader属性在WebMethod声明之前。
[WebMethod]
[SoapHeader("myHeader")]
public string HelloWorld()
{
// Code here...
}
在这个例子中,SoapHeader属性拾取了实例化的HelloHeader的名字,即myHeader。
从现在看是,这个WebMethod会使用这个myHeader对象,如果这个myHeader没有发现(客户端没有发送SOAPHeader在SOAP消息中),返回简单的Hello World。然而,如果SOAP请求中的SOAP header提供了值,那些值会返回。
Consuming a Web Service Using SOAP Headers
构建一个AN应用,发起一个SOAP请求,带有SOAP headers不是非常困难。就跟不带有SOAP headers的web service一样,你在VS中添加一个到远程web service的web reference。
protected void Page_Load(object sender, System.EventArgs e)
{
helloSoapHeader.HelloSoapHeader ws = new helloSoapHeader.HelloSoapHeader();
helloSoapHeader.HelloHeader wsHeader = new helloSoapHeader.HelloHeader();
wsHeader.Username = "Jason Gaylord ";
wsHeader.Password = "Lights";
ws.HelloHeaderValue = wsHeader;
Label1.Text = ws.HelloWorld();
}
两个对象呗实例化了。第一个是这个实际的web service,HelloSoapHeader。第二个,wsHeader,是SoapHeader对象。两个对象都实例化后,在应用中发起soap请求前。你构造SOAP header。这很简单,给Username和Password赋值。然后使用HelloSoapHeaderValue特征将wsHeader和ws对象关联起来。这以后,你可以发起SOAP请求和你平时一样。
Label1.Text=ws.HelloWorld();
Requesting Web Services Using SOAP 1.2
在一个消耗web service的AN应用中,你可以控制SOAP请求使用1.1还是1.2消息。下面的代码将使用SOAP1.2
protected void Page_Load(object sender, System.EventArgs e)
{
helloSoapHeader.HelloSoapHeader ws = new helloSoapHeader.HelloSoapHeader();
helloSoapHeader.HelloHeader wsHeader = new helloSoapHeader.HelloHeader();
wsHeader.Username = "Jason Gaylord";
wsHeader.Password = "Lights";
ws.HelloHeaderValue = wsHeader;
ws.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Soap12;
Label1.Text = ws.HelloWorld();
}
你可以在web.config文件中关闭SOAP1.1或者1.2的功能。
<?xml version="1.0"?>
<configuration>
<system.web>
<webServices>
<protocols>
<remove name="HttpSoap"/> <!-- Removes SOAP 1.1 abilities -->
<remove name="HttpSoap1.2"/> <!-- Removes SOAP 1.2 abilities -->
</protocols>
</webServices>
</system.web>
</configuration>
CONSUMING WEB SERVICES ASYNCHRONOUSLY
到目前为止,所有的web service都是同步执行的。这意味着整个AN应用在发出SOAP请求后处于停滞状态,知道SOAP响应返回。
调用一个WebMethod得到结果的过程可能对某些请求会花费很多时间。有些时候,你并没有web service的控制权,因为,你无法控制这些services的性能或者响应时间。由于这些原因,你应该考虑异步地消耗web service。
一个AN应用发起异步请求后可以工作在其它任务上,当AN应用完成了其它的事项后,它可以返回来得到web service的结果。
福音就是构建一个允许异步通信的XML web service,你不需要执行额外的操作。所有的asmx web service有内置的异步通信能力。
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class HelloWorldAsyncService : System.Web.Services.WebService {
[WebMethod]
public string HelloWorld() {
System.Threading.Thread.Sleep(1000);
return "Hello World";
}
}
这个web service返回Hello World字符串作为响应,但是在这之前,这个web service做了1000ms的暂停。你通过将web service 的thread休眠来完成这个。
protected void Page_Load(object sender, System.EventArgs e)
{
helloWorldAsync.HelloWorldAsyncService ws =
new helloWorldAsync.HelloWorldAsyncService();
IAsyncResult myIar;
myIar = ws.BeginHelloWorld(null, null);
int x = 0;
while (myIar.IsCompleted == false)
{
x += 1;
}
Label1.Text = "Result from Web service: " + ws.EndHelloWorld(myIar) +
"<br>Local count while waiting: " + x.ToString();
}
当你在AN中添加了这个对远程web service的web reference后,把你不进可以看到HelloWorld WebMethord,你也看到BeginHelloWorld和一个EndHelloWorld方法。为了让web service异步工作,你必须使用BeginHelloWorld和EndHelloWorld()方法。
使用BeginHelloWorld方法来发送一个SOAP请求到web service,AN应用之后不是等着response,而是去完成其他任务。
当一个SOAP请求从AN发出后,你可以使用IAsyncResult对象来测试SOAP响应是否在等待。你使用myIar.Completed方法。如果这个异步调用没完成,AN应用增加x的值。AN应用直到XML web service返回响应才停止加x。这个响应通过EndHelloWorld方法获取。
WINDOWS COMMUNICATION FOUNDATION
在过去,构造从一个点到另一个点传递消息的设施不是一件简单的事,因为微软提供了不止一个技术,你可以用来完成这样的目的。由于这个困扰,微软创造了WCF来帮助你决定走哪条路径。WCF是一个构筑源于服务的结构所使用的框架。微软想要为开发者提供一个框架,能够帮助开发者搭建合适的源于服务的结构。使用WCF,你可以尽情享用使得发布技术强大的所有好处。WCF为所有之前的消息发布技术提供了答案和继承者。
WCF Overview
正如陈述的一样,WCF是微软环境中构造分布应用的手段。虽然分布应用在这个环境中搭建,这不意味着消费者必须是微软的客户或者需要采取微软的技术来完成消耗任务。另一方面,建造WCF服务意味着你同样在构建那些坚持SOA核心原理的服务,这些服务能够被任何人消耗。
如果你已经熟悉了WCF,注意有些改进发生在WCF4.5.很多聚焦于提高开发者的生产效率和为常用任务提供快速选项,一路创造异步web service,简化WCF配置,启用HTML5 WebSocket支持。另外特色包括多个认证方法。
Building a WCF Service
构建一个WCF服务很容易。前提是你已经安装了.NET 框架4.5。
当你以这种方式构建WCF工程时,这个想法是你构建一个传统的类库,它编译成一个DLL,然后可以被加到另外的工程。代码和工程的分离是一个强大的特色。你可以,在你的.NET工程中那个构建一个WCF service,不管它是一个控制台应用,还是Windows Form应用。这章例子采取的方法是向你展示如何构造一个WCF service贮存在控制台应用中。记住对于你实际构造和部署的services,以WCF Service Library project的方式直接构造他们,然后使用生成的DLL在你的工程中或者IIS里面通常是更好的。
在你涉足WCF service之前,首先想象在WCF框架之上的service 由什么构成。
What Makes a WCF Service
当你看到一个WCF service时,你应该理解它由三部分构成,这个service本身,一个过多个终点,还有一个这个service驻留的环境。
一个service是由.NET语言之一写的类。这个类可以包含一个或者多个方法。一个service可以有一个或者多个终点。一个终点是用来和客户端交流的。
终点本身是由三个部分组成。微软通常定义为WCF的ABC。每一个字母在WCF模型中代表着一个特别的东西。
- address
- binding
- contract
基本上,你可以这样想,A是哪里,B是怎么样,C是什么。最后,一个驻留环境包含着service。这组成了一个应用领域和进程。所有的三个元素(服务,终点还有贮存环境)连起来生成了WCF。下一步使用WCF生成一个基本的service
Creating Your First WCF Service
构建你的service,在hosting之前,你必须要执行两个步骤。首先,你必须创造一个service contract。第二,你必须要创造一个data contract。这个service contract是一个类。这个data contract是一个类,指明了你从接口暴露的结构。
在你有了一个service类后,你可以将它host在任何地方。当从VS2102运行这个service时,你能够使用同样的内置的hosting机制。
Working with the Interface
为了生成你的service,你需要一个service contract。这个service contract是service的接口。为了完成这个任务,转到ICalculator.cs文件。
using System.ServiceModel;
[ServiceContract]
public interface ICalculator
{
[OperationContract]
int Add(int a, int b);
[OperationContract]
int Subtract(int a, int b);
[OperationContract]
int Multiply(int a, int b);
[OperationContract]
int Divide(int a, int b);
}
这就是你期待的通常的接口定义,但是有一些新的属性加在其中。为了访问这些必须的属性,你需要加一个引用到System.ServiceModel命名空间。这让你能够访问ServiceContract和OperationContract属性。
你使用ServiceContract属性来定义这个类或者interface是service class,而且需要放在类或者接口的声明之前。在这个例子中
[ServiceContract]
public interface ICalculator
{
// Code removed for clarity
}
在接口内,定义了4个方法。每一个方法作为service contract的一部分通过WCF暴露出来。每一个方法需要OperationContract属性。
[OperationContract]
int Add(int a, int b);
Utilizing the Interface
接下来一步是生成一个实现这个接口的类。这个新的类不仅实现了这个定义的接口,也实现了这个service contract。从这些新加的内容来看,这仅仅是一个实现了ICalculator接口并且提供了实现的类。
随着接口和类的存在,你现在已经构建好了你的WCF service而且能够起航了。下一步是让这个service hosted。注意这是一个简单的service-只暴露了简单的类型,而不是复杂类型。这是你只需要构建一个service contract不需要构建data contract。
Hosting the WCF Service in a Console Application
下一步是将刚刚开发的service host到某种类型的应用进程中。许多hosting选项可供选择。
- 控制台应用
- Windows Forms applications
- Windows Presentation Foundation applications
- Managed Windows Services
- Internet Information Services 5.1 and later
- IIS Express
正如前面所叙述的,这个例子在IIS Express中host该service。你可以有好几种方法hosting。要么通过直接编码要么通过声明编程。
编译并且运行这个程序生成了下面的结果。你会发现结果网页和你构造ANweb service相似。
Reviewing the WSDL Document
注意这个service的WSDSL文件。和AN web service一样,一个WCF service可以自动产生WSDL文件。WCF4.5的一个特色就是可以选择单个WSDL文件。点击这个WSDL链接,在浏览器中显示这个WSDL。在这个WSDL文件中,你可以通过HTTP binding消耗这个service。注意文档底部的元素。
<wsdl:service name="Calculator">
<wsdl:port name="BasicHttpBinding_ICalculator" binding="tns:BasicHttpBinding_ICalculator">
<soap:address location="http://localhost:2109/Calculator.svc"/>
</wsdl:port>
</wsdl:service>
XML文档中的这个元素表明,为了消耗这个service,终端用户必须使用HTTP上的SOAP。这是通过文档中的soap:address元素表明的。使用这个WSDL文档,你可以构造一个消耗该WCF的应用。
Building the WCF Consumer
现在一个HTTP service在那里,这个service是你使用WCF框架构造的。下一步是构造一个AN应用使用这个简单的Calculator service。这个consumer通过HTTP使用SOAP消息。这一部分描述如何消耗这个service。打开VS2012生成一个新的AN应用。
称呼这个AN应用为WCFConsumer。这个应用消耗Calculator service,所以放置两个textboxe和一个按钮来发动这个service call。在这个例子中,你只使用service的Add方法。
Adding a Service Reference
当你布置了你的AN网页后,添加一个对这个WCF service的引用。这个和你对web service添加引用非常相似。
Configuration File Changes
看看web.config文件,你会看到VS已经将这个service 的信息放置在这个文档里面。
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICalculator" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:2109/Calculator.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICalculator"
contract="CalcServiceReference.ICalculator"
name="BasicHttpBinding_ICalculator" />
</client>
</system.serviceModel>
这个配置文档的重要部分是这个client元素。这个元素包含了一个子元素叫做endpoint,定义了service consumption哪里和怎么样消耗的过程。
这个endpoint元素提供了service的地址,它指明了WCF binding的哪个binding应该被使用,在这个例子中,basicHttpBinding是使用的binding。虽然你正在使用从WCF框架来的的binding。从客户端,你可以定制这个binding的行为。定义binding行为的设置在bindingConfiguration这个属性。在这个例子中,bindingConfiguration属性的值是BasicHttpBinding_Icalculator,是basicHttpBinding元素中包含的binding元素的引用。
正如演示的一样,VS2012使得services的消耗想到简单,事实上,如果你之前和WCF打过交道,你会注意这个配置比之前的版本都要简单。
下一步就是编码。
Writing the Consumption Code
终端用户在两个文本框里放置一个数字,然后点击按钮来调用这个service。
protected void Button1_Click(object sender, EventArgs e)
{
CalcServiceReference.CalculatorClient ws = new
CalcServiceReference.CalculatorClient();
int result = ws.Add(int.Parse(TextBox1.Text), int.Parse(TextBox2.Text));
Label1.Text = result.ToString();
ws.Close();
}
这个代码和XML web service打交道时的web reference很类型。首先是实例化这个proxy class。
Working with Data Contract
目前为止,当构建WCF service时,定义的数据合同依赖于简单或者原始的数据类型。在这个WCF service中,.NET的Integer类型被曝露在外,这个类型被影射为一个XML int类型的方案。
虽然你可能在WCF产生的WSDL文档中看不到这个输入和输出类型,它们确确实实地在那里。当你使用单个WSDL文件时,单个WSDL文档的类型都曝露了出来。
如果你没在使用单个WSDL文件,XML schema类型是通过导入的xsd文档定义的。
作为这个WCF service的工匠,你不需要构建data contract,因为这个service使用简单的类型,当使用复杂类型的时候,你需要构建service contract和data contract。
Building a Service with a Data Contract
举个和data contract打交道的例子。创造一个新的WCF service叫做MyCustomDataContractService。在这个例子中,你仍然需要一个接口定义你的service contract,一个类实现你的接口。除了这些,你还需要一个类定义data contract。
service contract使用[ServiceContract]和[OperationContract]属性一样,data contract使用[DataContract]和[DataMember]属性。为了能够访问这些属性,你需要有System.Runtime.Serialization命名空间的引用在你的工程里。
using System.Runtime.Serialization;
using System.ServiceModel;
[DataContract]
public class Customer
{
[DataMember]
public string Firstname;
[DataMember]
public string Lastname;
}
[ServiceContract]
public interface IMyCustomDataContractService
{
[OperationContract]
string HelloFirstName(Customer cust);
[OperationContract]
string HelloFullName(Customer cust);
}
这里你看到System.Runtime.Serialization命名空间被导入了,这个文件中的第一个类是这个service的data contract。这个类,Customer,有两个members,FirstName和LastName。都是string类型的特征。你使用[DataContract]来指明一个类是data contract。
现在,类中的任意特征通过[DataMember]成为data contract的一部分。
[DataContract]
public class Customer
{
[DataMember]
public string Firstname;
[DataMember]
public string Lastname;
}
最后,这个Customer对象在接口中被使用,也使用在实现这个接口的类中。
public class MyCustomDataContractService : IMyCustomDataContractService
{
public string HelloFirstName(Customer cust)
{
return "Hello " + cust.Firstname;
}
public string HelloFullName(Customer cust)
{
return "Hello " + cust.Firstname + " " + cust.Lastname;
}
}
Building the Consumer
现在这个service在运行了,下一步就是构造这个consumer。
protected void Button1_Click(object sender, EventArgs e)
{
MyCustomDataContractServiceReference.MyCustomDataContractServiceClient ws = new
MyCustomDataContractServiceReference.MyCustomDataContractServiceClient();
MyCustomDataContractServiceReference.Customer myCustomer = new
MyCustomDataContractServiceReference.Customer();
myCustomer.Firstname = "Jason";
myCustomer.Lastname = "Gaylord";
Label1.Text = ws.HelloFullName(myCustomer);
ws.Close();
}
作为消费者,当你生成了这个引用后,你会注意service reference提供了MyCustomDataContractServiceClient对象和Customer对象。因崔,之前的代码实例化了这些对象,构建了Customer,然后将其放到HelloFullName中。
Defining Namesapces
注意这一章构建的services没有定义的命名空间,如果你观察产生的WSDl文件,你会看到提供的命名空间是http://tempuri.org。明显的,你不会想要这个默认的命名空间,
为了完成这个任务,接口的[ServiceContract]属性允许你设定命名空间,如下所示
[ServiceContract(Namespace="http://jasongaylord.com/ns/")]
public interface IMyCustomDataContractService
{
[OperationContract]
string HelloFirstName(Customer cust);
[OperationContract]
string HelloFullName(Customer cust);
}
这里[ServiceContract]属性使用这个Namespace特征来提供一个命名空间。
Using WCF Data Services
Creating Your First Service
Adding Your Entity Data Model
Creating the Service
现在你的应用处在这样一个状态,数据库,EDM和service都就位了。
ASP.NET WEB API
ASP.NET4.5平台引进了许多新特色。一个特别有用的特色时Web API。在AN4.5以前,许多开发者会抱怨配置WCF创造RESTful服务比开发这个服务更花时间。
因为Web API是一个AN MVC应用,开发者可以使用HTTP动词和有意义的路由,构造坚固的REST服务。
Building Your First Web API
构造Web API工程很简单。VS2012有一个很棒的模板。你会使用这个来构造你的第一个Web API工程。在某些情形,开发者可以生成完全的web API。
当你创建你的工程后,你立即被盗到一个默认的控制器名叫ValuesController,删除这个控制器,因为你马上会创建你自己的。
当你在web曝露你的API时,很大的可能,你会和一个data source互动。在这种情形下,使用AdventureWorks数据库。将这个数据库放置在App_Data文件夹。
然后,生成一个EF模型,就像你之前连接到WCF一样。然而,在这种情形下,你会在Models文件夹添加这个AdventureWorks.edmx。在你继续之前,build下。当你build这个工程时,你的模型被编译到这个工程的二进制。
接下来,你需要构造一个新的控制器。命名为ProductsController。在这个控制器模板中,选择API controller with read/write actions,using Entity Framework。
这个ProductsController文件会包含这个API的核心功能。你会注意到每个方法有个注解,通知开发者使用哪个HTTP动词,还有恰当的URL结构来取得希望的结果。
SUMMARY
这一章是对.NET平台上web services旋风般的游览。这绝对是一个需要开辟一本书的主题。这一章向你展示了以SOAP形式暴露数据和逻辑的强大,并且在AN中如何消耗这些SOAP消息。
尽管不是全部,这一章大致的描绘了WCF框架的基础,当你更加深入地挖掘这个技术时,你会发现性能很强大。
WCF Data Service是一种暴露你数据库内容的强大方式。你可以使用许多命令作为URI的一部分,来获取你感兴趣的内容。然而,使用代码和LINQ,也是可以获取结果的。
最后,这一章匆匆地涉及了Web API。这是目前为止生成RESTful web services最简单的方法。