ASP-NET-Web-API-全-
ASP.NET Web API(全)
零、前言
ASP.NET Web API 是一个轻量级的、基于 Web 的架构,您可以使用它来构建使用 HTTP 作为协议的 Web 服务。 这本书是一个明确和简明的指南 ASP.NET Web API 框架,有大量的代码示例。 它探索了使用 ASP 使用 Web API 服务的方法.NET 4.5, ASP.NET MVC 4、WPF 和 Silverlight 客户端。
这本书的内容
第 1 章,理解具象状态传输服务,介绍了 REST 的概念及其相关术语。
第二章,理解面向资源和服务的架构,探讨了面向资源的架构,并讨论了 ROA 和 SOA 之间的差异。
第三章、和讨论了在。net 中实现 Restful 服务的基础知识以及需要的技巧和技术。
第四章、使用 Restful 服务讨论了如何使用 Restful 服务。 它还讨论了相关的指导方针和最佳实践。
第五章, NET 4.5,讨论了我们如何使用 ASP.NET 4.5 和 Web API。
第六章,使用 Silverlight 处理 Restful 数据,讨论了如何在 Silverlight 客户端处理 Restful 服务。
第七章、高级功能讨论了 Web API 中的一些高级概念,以及在使用 WCF 和 ASP 时应该遵循的最佳实践。 净 Web API。
附录,库参考讨论了流行的基于 rest 的服务框架和 API,我们如何开始使用 Visual Studio 2013 IDE,并包含了对 Web API 类库的引用。
你需要什么来写这本书
- Visual Studio 2013
- SQL Server 2008 R2 / SQL Server 2012
这本书是写给谁的
本书面向的是那些想要利用 Web API 框架的特性和优点,使用. net 4.5 框架构建可伸缩的基于 rest 的服务的专业人士。
约定
在这本书中,你会发现许多不同类型的信息之间的区别。 下面是这些风格的一些例子,以及对它们含义的解释。
文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 url、用户输入和 Twitter 句柄如下所示:“SOAP 请求的Body部分包含所发送的实际 XML 请求对象。”
一段代码设置如下:
<SOAP: Envelope>
<SOAP: Header>
</SOAP: Header>
<SOAP: Body>
</SOAP: Body>
</SOAP: Envelope>
新词语、重要词语以粗体显示。 例如,您在屏幕上、菜单中或对话框中看到的文字会出现在如下文本中:“单击Restart Now按钮,重新启动系统并完成 Visual Studio 2013 的安装。”
注意事项
警告或重要说明显示在这样的框中。
提示
提示和技巧是这样的。
读者反馈
我们欢迎读者的反馈。 让我们知道你对这本书的看法——你喜欢或不喜欢这本书。 读者反馈对于我们开发游戏非常重要,你可以从中获得最大收益。
要向我们发送一般性的反馈,只需发送一封电子邮件到<[feedback@packtpub.com](mailto:feedback@packtpub.com)>,并通过邮件的主题提到书名。
如果有一个主题,你有专业知识,你有兴趣写或贡献一本书,请参阅我们的作者指南www.packtpub.com/authors。
客户支持
现在,你已经自豪地拥有了一本书,我们有一些东西可以帮助你从购买中获得最大的好处。
示例代码下载
您可以从您的帐户http://www.packtpub.com下载已购买的所有 Packt 图书的示例代码文件。 如果您在其他地方购买这本书,您可以访问http://www.packtpub.com/support并注册,将文件直接通过电子邮件发送给您。
勘误表
尽管我们已经竭尽全力确保内容的准确性,但错误还是会发生。 如果你在我们的书中发现错误,也许是文本或代码上的错误,如果你能向我们报告,我们将不胜感激。 通过这样做,您可以使其他读者免受挫折,并帮助我们改进这本书的后续版本。 如果你发现任何错误,请报告通过访问 http://www.packtpub.com/submit-errata,选择你的书,点击勘误表提交链接,并输入你的勘误表的细节。 一旦您的勘误表被核实,您的提交将被接受,勘误表将被上载到我们的网站上,或添加到该标题的勘误表部分的任何现有勘误表列表中。 任何现有的勘误表都可以从http://www.packtpub.com/support中选择您的标题查看。
**## 盗版
在互联网上盗版受版权保护的资料是一个贯穿所有媒体的持续问题。 在 Packt,我们非常重视版权和授权的保护。 如果您在互联网上发现任何形式的非法复制我们的作品,请立即提供我们的地址或网站名称,以便我们寻求补救。
请通过<[copyright@packtpub.com](mailto:copyright@packtpub.com)>与我们联系,并提供疑似盗版资料的链接。
我们感谢您保护我们的作者的帮助,以及我们为您带来有价值内容的能力。
问题
如果您对这本书的任何方面有任何问题,可以通过<[questions@packtpub.com](mailto:questions@packtpub.com)>与我们联系,我们将尽力解决它。**
一、理解 REST 服务
具象状态传输(REST)是一种架构风格,用于创建可扩展的服务。 基于 REST 的 Web 服务是符合 REST 架构约束的 Web 服务。 REST 架构风格在设计和架构能够通信的应用方面很快在世界范围内变得非常流行。 由于其简单性,它取代了基于 SOAP 和 wsdl 的 Web 服务,在世界范围内得到了广泛的接受。 它本质上是一个客户机-服务器架构,并使用无状态 HTTP 协议。 在本书中,我们将介绍使用 HTTP 协议的 REST。 我们掌握 REST 和 Web API 的旅程才刚刚开始!
在本章中,我们将涵盖以下主题:
- 休息
- 资源和 URI
- 休息和 RPC
- 在。net 4.5 中实现 RESTful 服务
- 创建 WCF 服务
- 使 WCF 服务 RESTful
- 指定绑定信息
- 托管服务
- 返回 JSON 数据
- 使用 RESTful 服务
理解 REST
其他是什么? 为什么随着时间的推移,它变得如此受欢迎? REST 是 Web 服务的替代品吗? 如何利用。net 框架来实现 RESTful 服务? 我们将在本章的章节中回答这些问题。
REST 是一种用于设计能够相互通信的分布式应用的架构风格。 请注意,REST 不是一种技术或一组标准。 相反,它是一组约束,可以用来定义一种新的架构风格。 本质上,它是一种客户机-服务器架构风格,其中连接是无状态的。
注意事项
请注意,REST 架构样式也可以应用于其他协议。 “无状态”一词意味着 HTTP/HTTPS 协议。 REST 架构风格在 HTTP 世界中很流行,当与 HTTP 协议结合使用时,可以得到更好的结果。
REST 不是标准; 相反,它是 RPC 和 Web 服务的架构替代方案。 在 REST 架构风格中,您可以使用 HTTP 协议(如果 HTTP 是正在使用的协议)在系统之间进行通信。 实际上,万维网(WWW)可以看作是一个基于 rest 的架构。 RESTful 架构基于可缓存和无状态的通信协议。
REST 是一种架构风格,它将应用的状态和功能划分为资源。 这些资源又可以通过 HTTP 上的 uri 进行寻址。 这些资源有一个公共接口,并且是唯一可寻址的。 基于 rest 的模型是无状态的、基于客户机-服务器的和可缓存的。
如前所述,在基于 rest 的模型中,资源用于表示状态和功能。 资源是通过逻辑 url 标识的。 在典型的基于 rest 的模型中,客户机和服务器使用请求和响应进行通信。 客户端向服务器发送资源请求,然后服务器将响应返回给客户端。
REST 架构风格的主要设计目标包括:
- 组件独立部署
- 减少延迟
- 服务交互的高安全性
- 可伸缩性
- 高性能
SOAP 和 REST 之间的基本区别在于前者强调动词,而后者强调资源。 在 REST 中,定义资源,然后使用统一的接口使用 HTTP 谓词对资源进行操作。 还应该注意的是,REST 使用起来更简单,因为它充分利用 HTTP 传输机制来格式化、缓存、路由和对给定资源执行操作。 相反,对于 SOAP,没有这样的约定。 基于 soap 的服务可以很容易地通过 TCP/IP、UDP、SMTP 或任何其他传输协议公开。 所以,它不必依赖于 HTTP 协议。
在基于 rest 的模型中,请求由端点 URL、开发人员 ID、参数和所需的操作组成。 端点 URL 用于表示完整的地址。 开发人员 ID 是唯一标识每个请求来源的键。 期望的动作用来表示要执行的动作。
REST 架构为CRUD(创建、读取、更新和删除)操作使用了一些常见的 HTTP 方法。 这些措施如下:
GET:用于请求资源的特定表示。HEAD:此用于只检索资源报头。PUT:是用于更新资源。DELETE:用于删除指定的资源。POST:用于提交将由标识的资源处理的数据。 理想情况下,POST应该仅用于创建资源,而PUT仅用于更新资源。
基于 rest 架构的资源
资源概念是 REST 中最重要的概念之一。 REST 的一些公共实现示例包括:
- 谷歌融合表
- Sones GraphDB:一个用 c#编写的面向图形的数据库
- Nuxeo:一个开源文档管理器
使用 URI 标识资源。 在 REST 风格的架构中,服务器和客户机之间的通信使用请求和响应进行。 客户端(也称为消费者)从服务器请求资源。 然后,服务器将响应发送回客户机。
在 REST 架构范例中,资源用于表示资源的状态和功能。 通过使用逻辑 uri 来标识它们,这样它们就可以被普遍寻址。 REST 架构本质上基于 http——一种无状态协议。 然而,资源可以在需要时进行缓存。 注意,因为 HTTP 提供了缓存机制,所以在 HTTP 协议上实现的 REST 提供了 HTTP 的特性和好处。 此外,还可以为缓存的数据设置缓存过期策略。
任何 REST 请求都包含以下组件:
- 端点 URL:这个表示脚本的完整地址。
- 开发人员 ID:这是一个与每个请求一起发送的键。 这用于标识请求的来源。 注意,开发人员 ID 不是所有 REST 服务都需要的。
- Parameters:这表示请求的参数。 这是可选的。
- 期望操作:这表示特定请求的操作。 操作基于 HTTP 动词。
让我们举个例子。 以下链接是一个典型的 REST 请求 URL:[http://localhost/payroll?devkey=1&action=search&type=department&keyword=DepartmentID](http://localhost/payroll?devkey=1&action=search&type=department& keyword=DepartmentID)。
在前面的请求中,端点是http://localhost/payroll,期望的操作是search,开发人员键是1。 您还可以在请求中提供type和keyword参数。 请参考下面的代码片段,它展示了 REST 请求和响应的样子:
<?xml version="1.0" encoding=" UTF-8"?>
<Request>
<RequestId>1R3ABC</RequestId>
<Parameters>
<Argument Name="devkey" Value="1" />
<Argument Name="action" Value="search" />
<Argument Name="type" Value="department" />
<Argument Name="keyword" Value="phone" />
</Parameters>
</Request>
<Response>
<ResultCount>2</ResultCount>
<Record>
<FirstName>Joe</FirstName>
<LastName>Stagner</LastName>
<DepartmentID>1</DepartmentID>
</Record>
<Record>
<FirstName>Stephen</FirstName>
<LastName>Smith</LastName>
<DepartmentID>1</DepartmentID>
</Record>
</Response>
REST 架构约束
REST 架构范例对架构定义了以下约束:
客户机-服务器
基于的 rest 实现基于客户机-服务器模型。 服务器和客户机是明显隔离的。 这意味着可以独立地修改服务器和客户机。 服务器完全不关心用户界面。 类似地,用户界面并不关心数据是如何持久化的。
无国籍
REST 架构基于无状态 HTTP 协议。 在 RESTful 架构中,客户机可以缓存服务器响应。 从客户机到服务器的任何请求都应该有足够的信息,以便能够理解和服务请求,但不会在服务器中存储客户机上下文。 这种类型的设计确保服务器对性能监视更加可见,并且具有可伸缩性。
可缓存
在典型的 REST 架构中,客户机应该能够缓存数据。 为了更好地管理缓存,该架构允许我们设置是否可以缓存响应。 该特性提高了可伸缩性和性能。
代码随需应变
REST 架构中的服务器可以(如果需要)扩展或定制特定客户机的功能。 这就是所谓的“随需应变代码”; 该特性允许 REST 架构实现中的服务器在需要时将逻辑传输到客户机。
统一接口
REST 架构风格在客户端和服务器之间定义了统一的接口; 因此,它只允许使用标准 HTTP 动词定义的一组有限的操作,例如GET、PUT、POST和DELETE。
资源管理
资源是 REST 风格架构中最重要的概念。 使用惟一的 uri 标识资源。 请注意,资源表示可以以任何数字格式(HTML、XML、JSON、RSS 等)的任何组合形式存在。
注意事项
这里应该注意的是,实际的资源在服务器上通常只有一种表示。 是客户端指定了它将以何种形式接受资源; 也就是说,它们应该如何被格式化。
SOAP、REST 和 XML-RPC——更仔细地看
简单对象访问协议(SOAP)是一个简单、轻量级、无状态、基于 xml 的协议,可用于分布式环境中异构系统之间的数据交换。 SOAP 可以用于传输数据,而不考虑所使用的平台和语言。 典型的 SOAP 消息格式如下:
<SOAP: Envelope>
<SOAP: Header>
</SOAP: Header>
<SOAP: Body>
</SOAP: Body>
</SOAP: Envelope>
下面的代码是一个 SOAP 请求的示例:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<ns1:RequestHeader
soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next"soapenv:mustUnderstand="0"xmlns:ns1="https://www.example.com/getData/P007">
<ns1:authentication xsi:type="ns1:ClientLogin" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><ns1:token>SuchALongToken</ns1:token>
</ns1:authentication>
<ns1:networkCode>ABC-XYZ-0012345</ns1:networkCode>
<ns1:applicationName>Sample</ns1:applicationName>
</ns1:RequestHeader>
</soapenv:Header>
<soapenv:Body>
<getProductData >
<filterData>
<query>WHERE productId IS NOT NULL</query>
</filterData>
</getProductData>
</soapenv:Body>
</soapenv:Envelope>
下面的代码片段演示了前一个请求的 SOAP 响应:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<ResponseHeader >
<requestId>Some Request Id</requestId>
<responseTime>26</responseTime>
</ResponseHeader>
</soap:Header>
<soap:Body>
<getProductDataResponse >
<rval>
<totalResultSetSize>1</totalResultSetSize>
<startIndex>0</startIndex>
<results>
<productId>7</productId>
<productName>CTV</productName>
<description>Samsung LED Color Television</description>
<status>Active</status>
<productCode>P007</productCode>
</results>
</rval>
</getProductDataResponse>
</soap:Body>
</soap:Envelope>
请注意,SOAP 可以在没有 HTTP 协议的情况下使用,并且 SOAP 总是使用POST操作。 SOAP 利用 XML 和无状态 HTTP 协议(如果与 HTTP 一起使用)来访问服务。 一个典型的 SOAP 请求看起来像以下代码:
GET /price HTTP/1.1
Host: http://localhost
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
xmlns:m="http://localhost/product">
<soap:Header>
<m:DeveloperKey>1</t>
</soap:Header>
<soap:Body>
<m:GetProductPrice>
<m:ProductCode>P001</m:ProductCode>
</m:GetProductPrice>
</soap:Body>
</soap:Envelope>
参考前面的代码片段,SOAP 请求的Body部分包含发送的实际 XML 请求对象。 下面的代码片段演示了一个典型的 SOAP 响应:
HTTP/1.1 200 OK
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
xmlns:m="http://localhost/product">
<soap:Body>
<m:GetProductPriceResponse>
<m:Price>1008.78</m:Price>
</m:GetProductPriceResponse>
</soap:Body>
</soap:Envelope>
REST 是一种架构范例,用于建模如何在 Web 上表示、访问和修改数据。 REST 使用无状态 HTTP 协议和标准 HTTP 操作(GET、PUT、POST和DELETE)来执行 CRUD 操作。 REST 允许您完成 SOAP 和 XML-RPC 所能完成的所有工作。 除此之外,您还可以使用防火墙来提高安全性,并使用缓存来增强性能。 相同请求的 REST 版本很简单,如下所示:
GET /product?ProductCode=P001 HTTP/1.1
Host: http://localhost
对前一个请求的 REST 响应也同样简单。 如下代码片段所示:
HTTP/1.1 200 OK
<?xml version="1.0"?><m:Price xmlns:m="http://localhost/product">1008.78</m:Price>
XML-RPC 是一个基于 xml 的远程过程调用协议。 下面的代码片段是一个典型的 XML-RPC POST 请求的例子:
POST /product HTTP/1.1
Host: http://localhost
<?xml version="1.0"?>
<methodCall>
<methodName>product.GetProductPrice</methodName>
<params>
<param>
<value><string>P001</string></value>
</param>
</params>
</methodCall>
为了响应前面的 XML-RPC 请求,下面的代码片段是典型的 XML-RPC 响应的样子:
HTTP/1.1 200 OK
<?xml version="1.0"?>
<methodCall>
<methodName>product.GetProductPrice</methodName>
<params>
<param>
<value><double>1008.78</double></value>
</param>
</params>
</methodCall>
了解 Windows 通信基础
Windows Communication Foundation(WCF)是微软的一个框架,它在单一的保护伞下提供了分布式技术(Web Services、Remoting、COM+等)的统一。 WCF 框架于 2006 年作为。net Framework 3.0 的一部分首次引入。 它是一个由许多技术组成的框架,为设计基于 SOA 并具有相互通信能力的应用提供了一个平台。 根据微软,在http://msdn.microsoft.com/en-us/library/bb907578.aspx,
Windows Communication Foundation (WCF)是一个统一的框架,用于创建安全、可靠、事务处理和可互操作的分布式应用。 在 Visual Studio 的早期版本中,有几种技术可以用于应用之间的通信。
与 WCF 架构相关的三个最重要的概念包括服务、客户机和消息。 下图分析了 WCF 架构的构建块。

WCF 和。net 框架
与 WCF 架构相关的三个最重要的概念是:服务、客户机和消息。 WCF 中的契约可以有三种类型:服务契约、数据契约和消息契约。
WCF 采用基于契约的方法。 一个 WCFService类至少实现一个服务契约。 服务契约是一个接口,用于定义由 WCFService类公开的操作。 WCFService类与任何其他. net 类一样,只是它被标记为ServiceContract属性。 消息契约可以定义为一种允许您更改消息格式的方法。 注意,ServiceContract、DataContract和其他相关属性是在System.ServiceModel名称空间中定义的。 WCF 中的绑定用于指定特定的服务如何与同类的其他服务和/或与其他客户端(也称为消费者)通信。
同样,任何在OperationContract属性之前的方法在外部对 soap 可调用操作的客户机可见。 如果您有一个没有此属性集的方法,则该方法将不包含在服务契约中,因此 WCF 客户端将无法访问 WCF 服务的该操作。
下面是 WCF 中预定义的内置绑定的列表:
- BasicHttpBinding
- MsmqIntergrationBinding
- WSHttpBinding
- WSDualHttpBinding
- WSFederationHttpBinding
- NetTcpBinding
- NetNamedPipeBinding
- NetMsmqBinding
- NetPeerTcpBinding
WCF 中的端点用于将服务契约与其地址关联起来。 通道实际上是服务与其客户机之间的桥梁。 WCF 中支持的通道类型如下:
- 单纯形输入
- 单纯形输出
- 请求-应答
- 双工
注意,WCF 服务基于三个概念:地址、绑定和契约。 另外,WCF 服务和 WCF 客户端使用消息进行通信。 下图展示了如何在 WCF 中使用消息进行通信:

WCF 中的通信
这些消息可以依次具有以下模式之一:
- 单纯形
- 请求-应答
- 双工
WCF 4.5 提供了对基于 rest 的特性的改进支持。 在本节中,我们将首先实现一个简单的 WCF 服务,然后对其进行必要的修改,使其成为 RESTful 服务。 WCF 的新版本对基于 rest 的特性提供了改进的支持。
REST 属性
现在,让我们仔细看看 WCF REST 属性及其用途。 顺便说一下,所有这些属性都可以在System.ServiceModel.Web.dll库中找到。 在本节中,我们将讨论在使用 RESTful 服务时经常使用的属性。
WebServiceHost
WebServiceHost属性的使用简化了基于 web 的服务的托管。 它派生于ServiceHost类并覆盖OnOpening方法,并自动将WebHttpBehavior类添加到端点。 下面的代码片段演示了如何使用WebServiceHost属性:
WebServiceHost host = new WebServiceHost(typeof(ClassName), baseAddress);
WebHttpBinding binding = new WebHttpBinding();
host.AddServiceEndpoint(typeof(ISomeContract), binding, "WebServiceHost");
host.Open();
WebHttpBinding
WebHttpBinding属性产生一个适当的基于 http 的传输通道。 在这里,安全性由WebHttpSecurity类处理。 通过使用WebGet属性或WebInvoke属性,可以使用WebHttpBinding绑定公开服务。
下面的代码片段演示了如何使用webHttpBinding属性:
<configuration>
<system.serviceModel>
<services>
<service name="PacktService">
<endpoint binding="webHttpBinding" contract="PacktService"
behaviorConfiguration="webHttp"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<configuration>
WebHttpBehavior
WebHttpBehavior属性定制基于 http 的调度逻辑,它覆盖操作选择、序列化和调用。 System.ServiceModel.Description命名空间中的WebHttpBehavior类如下所示:
public class WebHttpBehavior : IEndpointBehavior
{
// Properties
public virtual bool AutomaticFormatSelectionEnabled { get; set; }
public virtual WebMessageBodyStyle DefaultBodyStyle { get; set; }
public virtual WebMessageFormat DefaultOutgoingRequestFormat { get; set; }
public virtual WebMessageFormat DefaultOutgoingResponseFormat { get; set; }
public virtual bool FaultExceptionEnabled { get; set; }
public virtual bool HelpEnabled { get; set; }
protected internal string JavascriptCallbackParameterName { get; set; }
// Methods
public virtual void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters);
protected virtual void AddClientErrorInspector(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
protected virtual void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
public virtual void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
public virtual void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
protected virtual WebHttpDispatchOperationSelector GetOperationSelector(ServiceEndpoint endpoint);
protected virtual QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription);
protected virtual IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint);
protected virtual IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint);
protected virtual IClientMessageFormatter GetRequestClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint);
protected virtual IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint);
public virtual void Validate(ServiceEndpoint endpoint);
protected virtual void ValidateBinding(ServiceEndpoint endpoint);
}
WebOperationContext
WebOperationContext属性用于访问方法中的 HTTP 细节。 您可以使用WebOperationContext.Current属性检索当前上下文。 它为传入/传出的请求/响应上下文提供属性。
下面的代码片段演示了如何获取 HTTP 状态代码:
HttpStatusCode status = WebOperationContext.Current.IncomingResponse.StatusCode;
WebMessageFormat
此属性被用于控制服务中的消息格式。
注意事项
注意,WCF 支持两种主要的 web 格式:XML 和 JSON。
您可以使用RequestFormat和ResponseFormat属性控制消息的格式,如下代码所示:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public Employee GetData()
{
return new Employee
{
Firstname = "Joydip",
Lastname = "Kanjilal",
Email = "joydipkanjilal@yahoo.com";
};
}
WebGet
WebGet属性使用GET动词暴露操作。 换句话说,WebGet属性用于通过使用 URI 映射将传入的 HTTPGET请求映射到特定的 WCF 操作。 下面的代码片段显示了在System.ServiceModel.Web命名空间中如何定义该属性:
[AttributeUsageAttribute(AttributeTargets.Method)]
public sealed class WebGetAttribute : Attribute, IOperationBehavior
下面是一个示例,说明如何使用WebGet属性:
[OperationContract]
[WebGet(UriTemplate="/employee/{id}")]
public Employee GetEmployee(int id)
{
Employee empObj = null;
// Get employee object from the database
return empObj;
}
WebInvoke
WebInvoke属性暴露了使用其他 HTTP 动词的服务,例如,如POST、PUT和DELETE。 换句话说,WebInvoke属性用于GET请求之外的所有其他 HTTP 动词。 下面的代码片段显示了这个属性在System.ServiceModel.Web命名空间中是如何定义的:
[AttributeUsageAttribute(AttributeTargets.Method)]
public sealed class WebInvokeAttribute : Attribute, IOperationBehavior
Here is an example that illustrates the usage of the WebInvoke attribute:
[OperationContract]
[WebInvoke(Method = "DELETE", UriTemplate = "/employee/{id}")]
public void DeleteEmployee(int id)
{
// Code to delete an employee record in the database
}
尿酸板
UriTemplate类属于System.UriTemplate,实现了允许您在 URI 空间中指定变量的 URI 模板语法。 UriTemplate是一个表示 URI 模板的类。 UriTemplate是一个 URI 字符串,包含用大括号括起来的变量({,})。 请注意,UriTemplate属性是在WebGet和WebInvoke属性上指定的,我们在前面使用这些属性来标识一个员工资源。
下面的代码片段演示了如何使用UriTemplate:
[WebGet(UriTemplate = "RetrieveUserDetails/{userCode}/{projectCode}")]
public string RetrieveUserDetails(string userCode, string projectCode)
{
}
下表列出了重要的 HTTP 方法及其用法:
|方法
|
描述
|
| --- | --- |
| GET | 这用于请求特定资源的表示 |
| PUT | 这用于创建或更新具有特定表示形式的资源 |
| DELETE | 用于删除指定的资源 |
| POST | 这用于提交将由特定资源处理的数据 |
| HEAD | 这类似于 GET,但它只检索头信息 |
HTTP 协议还定义了一组标准状态码,用于指定特定请求的处理结果。 HTTP 的标准状态码及其用途如下表所示:
|状态码
|
描述
|
| --- | --- |
| 100 | 信息 |
| 200 | 成功的 |
| 201 | 创建 |
| 202 | 接受 |
| 300 | 重定向 |
| 304 | 不修改 |
| 400 | 客户端错误 |
| 402 | 付款要求 |
| 404 | 没有找到 |
| 405 | 方法不允许 |
| 500 | 服务器错误 |
| 501 | 没有实现 |
基于 rest 的 web 服务
RESTful web 服务(或 RESTful web API)是由一组资源组成的服务。 这些资源包括用于访问 web 服务的基本 URI、MIME 类型(即,JSON、XML 等)和一组定义的操作(即,POST、GET、PUT或DELETE)。 RESTful 服务与平台和语言无关。 然而,与 Web 服务不同的是,没有针对 RESTful 服务的任何官方标准设置。 REST 只是一种架构风格; 它没有任何标准。 使用 REST 的基本优点是传输中立性和使用高级WS-*协议的便利。 REST 是可互操作的,使用简单,并且具有统一的接口。
学习 RESTful web 服务
REST 式 web 服务是基于 REST 架构范例的服务。 本质上,这些(也称为 RESTful Web API)是由一组资源组成的 Web 服务。 这些资源提供如下:
- 用于访问 web 服务的基本 URI
- MIME 类型,它定义了 web 服务支持的数据格式,即 JSON、XML 等等
- web 服务使用 HTTP 方法支持的一组操作,这些方法包括
POST、GET、PUT或DELETE
与 web 服务类似,REST 服务是平台和语言独立的,基于 HTTP,甚至可以与防火墙一起使用。 请注意,与基于 SOAP 协议的 web 服务不同,RESTful 服务没有官方标准。 REST 只是一种架构风格,没有任何固定的标准。 下面的代码片段演示了一个 SOAP 请求的例子:
<?xml version = "1.0"?>
<soap:Envelope>
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:body emp="http://localhost/payroll">
<emp:GetEmployeeDetails>
<emp:EmployeeID>1</emp:EmployeeID>
</emp:GetEmployeeDetails>
</soap:Body>
</soap:Envelope>
下面的 url 显示了如何使用 REST 表示相同的内容:
http://localhost/payroll/EmployeeDetails/1
基于 rest 的 web 服务将 HTTP 方法映射到相应的 CRUD 操作。 前面的两个表显示了它们是如何映射的:
- HTTP 方法:CRUD 动作
- GET:检索资源
- POST:创建一个新的资源
- PUT:更新现有资源
- DELETE:删除已存在的资源
- HEAD:检索资源上的元数据信息
在。net 4.5 中实现 RESTful 服务
在本节中,我们将使用 WCF 实现 RESTful 服务。 WCF 是一个基于面向服务架构(SOA)的框架,用于设计分布式应用,这些分布式应用是具有相互通信能力的应用。 我们将在第三章,Working with rest 式服务中探讨更多关于 WCF 的内容。
UserNamePasswordValidator 类
在 WCF 的新版本中引入了UserNamePasswordValidator类。 您可以使用这个类来设计和实现您自己的自定义验证器,以验证用户的凭证。
在 WCF 4.5 中,System.IdentityModel.Selectors名称空间中的UserNamePasswordValidator类可用于验证用户凭证。 您可以创建自己的自定义验证器,只需扩展UserNamePasswordValidator类,然后重写Validate方法,如下面的代码片段所示:
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;
namespace Packt
{
public class PacktValidator : UserNamePasswordValidator
{
public override void Validate(String userName, String password)
{
if (!userName.Equals("joydip")) || !password.Equals("joydip1@3"))
{
throw new SecurityTokenException("User Name and/or Password incorrect...!");
}
}
}
}
然后,您可以配置您刚刚在配置文件中创建的验证器,如以下代码所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<bindings>
<wsHttpBinding>
<binding name="PacktAuthentication">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="PacktValidator.ServiceBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"customUserNamePasswordValidatorType="Packt.PacktValidator, Packt"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</services>
</system.serviceModel>
</configuration>
WCF 4.5 中的新增强包括以下内容:
- 简化的配置
- 标准的端点
- 发现
- 简化的 IIS 托管
- 其他改进
- 工作流服务
- 路由服务
- 自动帮助页面
简化配置
WCF 4.5 从默认的配置模型开始。 与之前的版本相比,WCF 4.5 中的配置要简单得多。 WCF 3。 X,您需要为服务主机指定端点、行为等。 在 WCF 4.5 中,提供了默认端点、绑定信息和行为。 从本质上说,当您实现特定的 WCF 服务时,WCF 4.0 消除了任何 WCF 配置的需要。
在 WCF 4.5 中,为任何 WCF 服务创建了一些标准端点和默认绑定/行为配置。 这使得开始使用 WCF 变得很容易,因为 WCF 3 繁琐的配置细节。 X 不再被要求。
考虑以下的 WCF 服务:
using System;
using System.ServiceModel;
namespace PacktService
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
String DisplayMessage();
}
public class TestService : ITestService
{
public String DisplayMessage()
{
return "Hello World!";
}
}
}
在 WCF 4.5 中,您可以使用ServiceHost来托管 WCF 服务,而不需要任何配置信息。 下面的代码是所有你需要宿主你的 WCF 服务和显示地址,绑定和契约信息:
using System.ServiceModel;
using System;
using System.ServiceModel.Description;
namespace PacktClient
{
class Program
{
static void Main(string[] args)
{
ServiceHost serviceHost = new ServiceHost(typeof(PacktService.TestService));
serviceHost.AddServiceEndpoint(typeof(PacktService.TestService), new BasicHttpBinding(),"http://localhost:1607/TestService.svc");
serviceHost.Open();
foreach (ServiceEndpoint serviceEndpoint in serviceHost.Description.Endpoints)
Console.WriteLine("Address: {0}, Binding: {1}, Contract: {2}", serviceEndpoint.Address, serviceEndpoint.Binding.Name, serviceEndpoint.Contract.Name);
Console.ReadLine();
serviceHost.Close();
}
}
}
以下代码是 WCF 4.5 中需要指定的所有配置信息的示例:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled ="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
注意,默认情况下使用的是BasicHttpBinding绑定。 如果您想选择更安全的绑定,例如WSHttpBinding,您可以使用以下代码片段更改绑定信息:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled ="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme ="http"/>
</protocolMapping>
</system.serviceModel>
</configuration>
标准端点
标准端点是 WCF Framework 4.5 中预定义的端点。 您总是可以重用它们,但它们通常不会更改。
您可以通过使用端点名称在<configuration>元素中引用以前的任何端点。 下面给出了一个相同的例子:
<configuration>
<system.serviceModel>
<services>
<service name="PacktService">
<endpoint kind="basicHttpBinding" contract="IMyService"/>
<endpoint kind="mexEndpoint" address="mex" />
</service>
</services>
</system.serviceModel>
</configuration>
发现
有两种操作模式。 它们如下:
- Ad-Hoc 模式:在此模式中,不存在集中式服务器,所有服务通知和客户端请求都以多播方式发送。
- 托管模式:拥有一台集中式服务器。 这样的服务器称为发现代理,其中集中发布服务,需要使用这种发布服务的客户端连接到该服务器以检索必要的信息。
您可以添加标准的udpDiscoveryEndpoint端点,并启用<serviceDiscovery>行为,以启用 Ad-hoc 模式下的服务发现。 下面的代码就是一个例子:
<configuration>
<system.serviceModel>
<services>
<service name="TestService">
<endpoint binding="wsHttpBinding" contract="ITestService" />
<!-- add a standard UDP discovery endpoint-->
<endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestService.MyServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to falsebefore deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceDiscovery />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
注意,在前面的代码片段中,添加了一个新端点来发现服务。 此外,还添加了ServiceDiscovery行为。 您可以使用DiscoveryClient类来发现您的服务并调用其中一个方法。
您必须创建DiscoveryClient类的实例,并将UdpDiscoveryEndPoint作为参数传递给该类的构造函数,以发现服务。 一旦发现了端点,就可以使用发现的端点地址来调用服务。 下面的代码片段说明了这一点:
using System;
using System.ServiceModel;
using System.ServiceModel.Discovery;
namespace PacktConsoleApplication
{
class Program
{
static void Main(string[] args)
{
DiscoveryClient discoverclient = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindResponse findResponse = discoverclient.Find(new FindCriteria(typeof(ITestService)));
EndpointAddress endpointAddress = findResponse.Endpoints[0].Address;
MyServiceClient serviceClient = new MyServiceClient(new WSHttpBinding(), endpointAddress);
Console.WriteLine(serviceClient.DisplayMessage());
}
}
}
WCF 4.5 还支持配置服务,以便在服务启动时立即宣布它们的端点。 下面的代码展示了如何配置你的服务在它开始时宣布端点:
<configuration>
<system.serviceModel>
<services>
<service name="TestService">
<endpoint binding="wsHttpBinding" contract="ITestService"/>
<endpoint kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDiscovery>
<announcementEndpoints>
<endpoint kind="udpAnnouncementEndpoint"/>
</announcementEndpoints>
</serviceDiscovery>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
简化 IIS 托管
在 IIS 上托管 WCF 4.5 应用现在变得容易多了。 下面给出一个简单的 WCF 服务示例:
<!-- PacktService.svc -->
<%@ ServiceHost Language="C#" Debug="true" Service=" PacktService
CodeBehind="~/App_Code/PacktService.cs" %>
[ServiceContract]
public class PacktService
{
[OperationContract]
public string GetMessage()
{
return "This is a test service.";
}
}
然后,您可以为应用的web.config配置文件中的服务启用服务元数据,如下面的代码片段所示:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
您还可以在应用的web.config配置文件中为您的 WCF 4.5 服务定义虚拟服务激活端点。 通过这样做,您可以激活您的 WCF 服务而不需要.svc文件。 您需要在您的应用的web.config配置文件中指定以下配置来激活您的服务,而不需要.svc文件:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="PacktService.svc" service="PacktService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
REST 的改进
WCF 4.5 提供了对基于 rest 的特性的改进的支持。 现在,您已经支持了一个自动帮助页面,该页面描述了服务使用者或客户可用的基于 rest 的服务。 这个特性默认是打开的,但是你也可以手动配置它,如下面的代码清单所示:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="PacktTestHelpBehavior">
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="PacktSampleWCFService">
<endpoint behaviorConfiguration="PacktTestHelpBehavior"binding="webHttpBinding"contract="PacktSampleWCFService" />
</service>
</services>
</system.serviceModel>
</configuration>
WCF 4.5 还支持 HTTP 缓存,这是通过使用AspNetCacheProfile属性实现的。 注意,AspNetCacheProfile支持实际上使用的是标准的 ASP.NET 输出缓存机制为您在 WCF 服务中提供缓存特性。
要使用此属性,您应该添加对System.ServiceModel.Web.Caching命名空间的引用。 您可以在WebGet操作中应用此属性,并指定您选择的缓存持续时间。 下面的代码片段可以在你的服务契约方法中使用这个特性:
using System.ServiceModel.Web.Caching;
[OperationContract]
[WebGet]
[AspNetCacheProfile("PacktCache")]
String GetProductName();
因此,你应该在你的应用的web.config文件中设置缓存配置文件,如下所示:
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="PacktCache" duration="60" varyByParam="format"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
使用 WCF 4.5 实现 RESTful 服务
在本节中,我们将使用 WCF 4.5 实现我们的第一个 RESTful 服务。 要做到这一点,我们需要遵循以下步骤:
- 创建 WCF 服务
- 使服务 RESTful
- 指定绑定信息
- 托管 RESTful 服务
- 使用 RESTful 服务
创建 WCF 服务
一个典型的 WCF 实现应该有一个 WCF 服务和一个 WCF 客户端。 WCF 客户机将使用 WCF 服务提供的服务。
注意,WCF 服务包含:
- 一个
Service班 - 一个托管环境
- 一个或多个端点
Service类是使用一种针对。net CLR 的托管环境的语言编写的。 本质上,Service类可以用任何你选择的。net 语言来编写(在本书中我们一直使用 c#)。 宿主环境是 WCF 服务将在其上下文中执行的环境。 端点使客户端或服务使用者能够访问 WCF 服务。
您可以从两个模板中选择创建 WCF 服务:Visual Studio 2013 WCF 服务库模板和 Visual Studio 服务应用模板。
让我们首先使用 Visual Studio WCF 服务库模板来创建一个 WCF 服务。 要做到这一点,请遵循以下步骤:
-
打开 Visual Studio 2013 IDE
-
导航到文件|新|项目
-
Select WCF Service Application from the list of templates displayed, as shown in the following screenshot:
![Creating a WCF service]()
创建 WCF 服务应用项目
-
为项目提供一个名称,然后单击OK保存。
创建一个 WCF 服务应用项目。 乍一看,Service类看起来像以下代码:
using System;
namespace MyDataService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change
// the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
}
前面的代码片段中的Service类实现了IService1接口,如下所示:
using System.Runtime.Serialization;
using System.ServiceModel;
namespace MyDataService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu
// to change the interface name "IService1" in both code
// and config file together.
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
}
// Use a data contract as illustrated in the sample below
// to add composite types to service operations.
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
}
考虑下面的 WCF 服务:
using System.ServiceModel;
namespace Test
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
String GetMessage();
}
public class TestService : ITestService
{
public string GetMessage()
{
return "Hello World!";
}
}
}
提示
注意在前面的代码片段中使用了OperationContract属性。 此属性用于指定向客户端调用公开特定操作。
要托管这个 WCF 服务,你可以编写以下代码:
using System;
using System.ServiceModel;
using Test;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost serviceHost = new ServiceHost(typeof(TestService)))
{
serviceHost.Open();
Console.WriteLine("WCF Service has started...");
Console.ReadLine();
serviceHost.Close();
}
Console.WriteLine("The WCF Service has stopped...");
}
}
}
使服务 RESTful
在设计一个 RESTful 服务时,您需要了解资源、用于映射这些资源的 uri,以及这些资源应该支持的 HTTP 谓词。
在典型的基于 WCF-REST 的服务中,除了用于公开服务操作的OperationContract属性外,还需要WebGet属性。 WebGet属性属于System.ServiceModel.Web名称空间。 HTTP-GET 操作的典型WebGet属性如下所示:
[WebGet(UriTemplate =
"/payroll/getemployees.xml",BodyStyle = WebMessageBodyStyle.Bare,RequestFormat = WebMessageFormat.Xml,ResponseFormat = WebMessageFormat.Xml)]
属性WebGet的UriTemplate参数用于定义访问服务操作的 URL 格式。 RequestFormat和ResponseFormat参数是WebMessageFormat枚举的一部分,可以有两个可能的值:Xml和Json之一。 下面的代码是 HTTP-POST 操作的典型WebGet属性的样子:
[GetOperationContract]
[WebInvoke(UriTemplate =
"/payroll/updateemployee.xml?
employeecode={code}",Method = "POST",BodyStyle = WebMessageBodyStyle.Bare,RequestFormat = WebMessageFormat.Xml,ResponseFormat = WebMessageFormat.Xml)]
要使我们在本章前面创建的服务是 RESTful 的,只需更改契约 ITest 并指定WebGet属性,如下面的代码片段所示:
[ServiceContract]
[WebGet()]
public interface ITestService
{
[OperationContract]
String GetMessage();
}
指定绑定信息
现在我们已经创建了服务契约和服务,以及服务将要公开的操作,我们需要指定服务的绑定信息,以便服务消费者或客户可以对其进行评估。 为了让客户端访问 WCF 服务,服务应该公开端点。 端点表示服务的地址、绑定和契约信息。 要指定服务的绑定信息,请打开App.Config文件,并在<system.serviceModel>标记中写入以下代码:
<system.serviceModel>
<bindings>
</bindings>
<services>
<service name ="Test.TestService" behaviorConfiguration="Default">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Test"/>
</baseAddresses>
</host>
<endpointaddress=""binding ="basicHttpBinding"contract="Test.ITestService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
在我们的示例中,我们使用的是 RESTful 服务。 因此,我们需要使用webHttpBinding类,如下所示:
<service name ="Test.TestService" behaviorConfiguration="Default">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Test"/>
</baseAddresses>
</host>
<endpointaddress=""binding ="webHttpBinding"contract="Test.TestService" />
</service>
托管 RESTful WCF 服务
托管 WCF 服务的方式有很多。 例如,您可以将 WCF 服务托管在 IIS 服务器中,或者使用Windows 激活服务(WAS)。 要在 IIS 中托管 WCF 服务,您必须创建一个虚拟目录,并使其指向您的服务所在的目录。 请注意,可以使用 HTTP 上的 SOAP 访问 IIS 中的 WCF 服务。
您可以在托管应用的App.Config文件中指定访问 IIS 托管的 WCF 服务如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled ="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme ="http"/>
</protocolMapping>
</system.serviceModel>
</configuration>
托管控制台应用中的服务
如果端点定义正确,您还可以以编程方式托管 WCF 服务。 要托管我们之前创建的 RESTful WCF 服务,你应该使用WebServiceHost,如下所示:
using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using Test;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
using (WebServiceHost serviceHost = new WebServiceHost(typeof(TestService)))
{
serviceHost.Open();
Console.WriteLine("WCF Service has started...");
Console.ReadLine();
serviceHost.Close();
}
Console.WriteLine("The WCF Service has stopped...");
}
}
}
返回 JSON 数据
您可以从基于 rest 的 WCF 服务中以JavaScript 对象标记(JSON)格式返回数据。 下面的代码片段演示了如何通过设置属性以 JSON 格式从 RESTful 服务返回数据:
using System.Xml;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
namespace Test
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
[WebGet(UriTemplate = "Test")]
Message GetMessage();
}
public class TestService : ITestService
{
public Message GetMessage()
{
StringBuilder stringBuilder = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
{
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("Message");
xmlWriter.WriteAttributeString("type", "Name");
xmlWriter.WriteString("Joydip");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
}
TextReader textReader = new StringReader(stringBuilder.ToString());
XmlReader xmlReader = XmlReader.Create(textReader);
return Message.CreateMessage(MessageVersion.None, "", xmlReader);
}
}
}
请注意,WCF 中的WebGet属性实际上是 WCF 的 HTTP 编程模型的一部分。 此属性用于使用 HTTP URI 调用 WCF 服务。 本质上,WebGet属性用于指定服务将响应 HTTPGET请求。
属性WebGet接受以下四个参数之一:
BodyStyle:这是,用于指定是否应该封装请求或响应RequestFormat:这是用于格式化请求消息ResponseFormat:这是用于格式化响应消息UriTemplate:用于指定服务操作的 HTTP 请求的 URI 模板
前面的代码片段使用了一个XmlWriter实例来创建 XML 格式的消息。 下面是返回的 JSON 数据的样子:
{
"Message": [{ "Name":"Joydip"},]
}
使用 RESTful 服务
要使用我们在本节前面创建的 RESTful 服务,您需要创建一个客户机应用(ASP.NET 或 WPF),将服务引用添加到我们在前面几节中创建的服务,然后使用服务引用实例来调用服务方法。 我们将在第 3 章、与 rest 式服务打交道和第 4 章、使用 rest 式服务中详细讨论。
总结
REST 现在已经成为设计和实现可伸缩服务的架构范例。 基于 rest 的 Web 服务通过 uri 公开资源,并使用 HTTP 方法执行 CRUD 操作。 REST 架构范例不仅打开了许多可能性,也带来了挑战。 我们将在本书各章中进一步探讨这些问题。 本章介绍了 REST,一种分布式超媒体系统的架构风格。 在下一章中,我们将详细探讨面向资源的架构。
二、理解资源和面向服务的架构
软件架构是指一个系统的整体结构以及组成系统的实体和组件之间的相互关系。 有各种各样的架构风格,如面向对象的架构、面向服务的架构、面向云的架构和面向资源的架构。
面向服务的****建筑(SOA)和【显示】面向资源架构(ROA)建筑设计模式,提供概念和必要的开发工具和技术来实现分布式应用的架构。 分布式架构由服务组成,客户机可以通过使用定义良好的接口通过网络使用这些服务。 客户端使用的这些组件是 ROA 中的命名资源和 SOA 中的服务。
**在本章中,我们将讨论面向资源架构的基础知识,以及它们与面向服务架构和面向对象架构的区别。 我们还将探讨设计和实现 ROAs 的最佳实践。
在本章中,我们将涵盖以下主题:
- SOA
- ROA
- 什么是资源导向?
- 资源定位的概念
- 可寻址能力
- 无国籍
- 表示
- 面向资源的服务和 REST
- 面向资源的服务和 web 服务
- 面向只读和读写资源的服务
- 指导方针和最佳实践
理解 SOA
SOA 是一种架构范例,在这种范例中,您拥有一组松散耦合和可扩展的服务,每个服务都能够独立于另一个服务进行修改,从而保持服务集成的完整性。 SOA 由一组称为服务的离散软件模块组成。 这些服务可以与其他服务交换数据和信息。
请注意,SOA 架构范例基于企业业务架构的功能分解。 在此过程中,它引入了两个不同的高级抽象,即企业的业务服务和企业的业务流程。 业务服务代表企业的业务功能,而业务流程定义企业业务的功能。
SOA 可以使用以下技术之一实现:
- Web 服务
- Windows Communication Foundation
- CORBA
- DCOM
- 我
- EJB
SOA 支持通过网络对松散耦合的分布式应用和服务进行出色的集成。 SOA 本质上是一组可以通信的服务。 请注意,web 服务、J2EE、CORBA 等实际上是 SOA 的实现。 面向服务的设计的最重要的好处包括以下几点:
- 平台和语言独立性
- 松散耦合
- 位置透明化,降低维护成本
- 随着时间的推移,支持无缝更新
- 更容易维护和无缝部署
- SOA 设计由许多元素组成,包括以下内容:
- 服务
- 服务提供者
- 服务消费者
- 服务注册中心
- 服务合同
让我们更详细地看看每一个。
服务
可以将服务定义为定义良好的、自包含的和独立的业务功能的实现,该业务功能具有接受一个或多个请求并使用定义良好的标准接口返回一个或多个响应的能力。 服务独立于其实现所依赖的技术; 因此,服务的接口应该是平台独立的。 服务还应该具有在运行时动态发现和调用的能力。 服务将业务功能作为服务操作提供给服务使用者。
服务是用于实现企业架构的设计、实现和部署构件的单元。 服务是使用谓词定义的。 例如,验证客户的凭证; 这描述了它实现的业务功能。 服务实现以 RPC 样式或消息传递样式定义服务接口。 虽然前者使用服务调用技术,但后者执行服务语义中定义的服务操作。
服务提供商
服务提供者是提供服务的可网络寻址实体。 注意,在 SOA 中,服务提供者也可以是服务使用者。
服务消费者
服务使用者是通过在服务注册中心定位服务、绑定到服务、然后执行服务方法来消费(或使用)服务提供者提供的服务的实体。 服务使用者也称为服务客户机或简称为客户机。
服务注册表
服务注册中心是发布服务的基于网络的存储库。 在运行时,服务使用者使用该注册中心定位服务并绑定到它。 使用服务注册表的优点包括:
- 可伸缩性
- 松散耦合
- 热更新
- 动态服务查找
服务合同
服务契约是一个规范,它表示服务使用者将如何与特定服务的服务提供者交互。 下图说明了服务契约及其实现之间的关系

服务契约与服务实现之间的关系
服务代理
服务代理是对服务使用者端服务的引用——它由服务提供者提供以方便服务方法调用。 服务使用者或服务客户机使用此代理来调用一个或多个服务方法。
服务租赁
服务租期是预定义的持续时间,表示服务的生命周期。 这个意味着在某个时间之后服务将不再有效。 注意,当这个时间周期结束时,服务使用者应该请求服务注册中心授予一个新的服务租约,以便服务使用者能够重新获得对服务的访问权并执行服务方法。
消息
服务提供者和服务使用者通过消息进行通信。 因此,消息是服务提供者(即服务的提供者)和服务使用者(即服务的使用者)之间通信的媒介。 注意,这类消息本质上是以预定义的 XML 格式提供的。 除了 XML 格式外,它还可以是 JSON 格式或服务提供者和使用者共同同意的任何其他格式。 下图显示了一个服务通过使用消息与另一个服务进行通信

服务之间使用消息交换进行通信
服务描述
服务描述是一个规范,它包含了调用服务所必需的信息。 这些信息可能包括参数、约束和定义如何调用服务的策略。
广告与发现
广告和发现是 SOA 中两个最基本的属性。 尽管前者关系到服务发布其描述以便服务使用者定位的能力,但后者关系到服务使用者从服务注册中心发现已发布的服务并在必要时调用它们的能力。
从面向对象到 SOA 到 ROA 再到 REST
基于调用的分布式系统具有以下架构风格之一:
- 面向对象的架构
- 你的声音听起来
- 罗阿斯
面向对象的架构(T0)处理对象实例,并且通信是隐式有状态的。 状态信息存储在服务器端。 对对象实例的每次访问都涉及一次往返通信。
soa 围绕服务及其暴露的端点展开。 由于 soa 的无状态特性,所以它是无状态且易于伸缩的。 REST 架构范例将世界上的所有实体视为连接的资源,并重用现有的 HTTP 基础设施。 缓存请求的能力、执行无状态交互的能力、可伸缩性、简单性、敏捷性和灵活性是该架构的一些优点。 然而,缺乏参考、缺乏工具支持以及缺乏适当的标准化是该架构的缺点。
服务确实有接口,并且可以在其生命周期内被引用。 它不一定有一个状态。 每个服务都有一个定义消息和有效负载格式的接口描述。 可以发现和动态绑定服务。 它是模块化的、自包含的、可互操作的、可寻址的和可通过网络定位的。 服务也可以由其他服务组成。 下图说明了服务使用者、服务提供者和服务代理之间的关系。

服务提供者、服务使用者和服务代理之间的关系
通过将服务发布到名为service Broker (Registry)的存储库中,服务对客户(服务使用者)可用。 服务使用者(服务客户端)定位服务,使用服务代理,然后使用服务代理实例调用一个或多个服务方法。下图显示了服务使用者如何与服务注册中心对话。

服务使用者使用服务代理与服务注册中心和服务提供者进行通信
ROAs 是无状态的,以资源为中心。 每个资源都使用一个 URI 来标识。 您总是可以拥有相同资源的多个副本。 在面向资源的架构中,请求通常是无状态的:在一个请求和下一个请求之间没有链接。 使用动词管理资源生命周期,即 HTTP、PUT、HTTP、DELETE 等。
REST 服务比基于 soap 的 SOA 更容易实现。 另外,REST 服务支持更好的缓存、轻量级的请求和响应以及减少网络流量。
REST 约束是应用于 REST 架构风格的设计规则。 我们将在下一章进一步探讨这些设计限制。
这些 REST 约束是:
- 客户机-服务器
- 无状态的
- 缓存
- 接口/统一合同
- 分层系统
- Code-On-Demand
SOA 和 ROA 是两个截然不同的架构范例。 在前者中,服务是被赋予重要性的。 然而,在后一种情况中,资源受到重视。 因此,在 SOA 中动词很重要,而在 ROA 中名词很重要。 在 ROA 中,用于资源生命周期管理的常用动词包括 PUT 和 DELETE。 我们将在本书的后面探讨这一点。
REST 的关键原则如下:
- 资源应该有一个 ID
- 链接相关资源
- 使用标准方法
- 资源可以有多种表示形式
- 无状态通信
一看 ROA
ROA 主要基于资源的概念。 资源是一种可分布的组件,可以通过标准的公共接口访问它。 每个资源都与包含 URL 的唯一标识符相关联。
ROA 的主要概念集中在资源上。 资源应该具有以下特点:
- 一个资源应该是唯一的,并且可能链接到其他相关的资源。
- 一个资源至少应该有一个表示。
- 资源应该有属性和模式,它应该是可访问的(通过它的地址),并且它应该提供上下文。
- 资源应该有名称; 这用于唯一地标识资源。 使用 uri 标识资源。
虽然资源链接用于表示同一资源或另一资源的另一种表示,但资源接口用于提供访问资源和操作其状态信息的接口。 资源使用 uri 表示。 注意,如果数据可以使用 URI 表示,那么它就是一种资源。
资源和 uri 的例子如下:
- http://www.mysoftware.com/software/releases/1.0.0.1.zip
- http://www.mysoftware.com/software/releases/1.0.0.2.zip
- http://www.mystore.com/search/Books/NewBook
没有两个资源可以是相同的,但是两个或更多的资源可以指向相同的数据。 下面是一个例子:
http://www.packtpub.com/sales/2012/Q4http://www.packtpub.com/sales/2012/Q3
下图显示了资源、它的表示和它的 URI 之间的关系:

资源、表示和 URI 之间的关系
ROAs 的基本性质
ROA 实现应该包含以下六个基本的属性:
- 可寻址性:这个表示通过 uri 共享数据和信息的能力。
- 无状态:这意味着基于 rest 的 web 服务上的每个请求都应该是自包含的。 为了实现这种无状态特性,对 RESTful 服务的所有调用都应该在每个请求中包含相关的应用状态位。
- 连通性:这意味着资源应该包含到相关资源的链接。
- 表示:一个资源可以有多个表示。 这些表示中的每一个都应该有类似的 uri。 实际上,URI 应该包含服务器生成所需表示的足够信息。 表示实际上是资源的描述。 资源的表示方式清楚地描述了它的状态信息。
- 资源链接:这个是用来表示同一资源或另一资源的另一种表示。
- 资源接口:使用来提供一个接口来访问资源并操作其状态信息。
ROAs 的基本概念
ROA 实现应该包含的四个基本概念包括:
- 可寻址性:资源的可寻址性是它通过格式良好的 uri 公开其数据的能力。
- 无状态:这意味着每个 HTTP(而且,因为 HTTP 是无状态协议)请求都是完全隔离的。
- 连通性:连通性是一种资源与另一资源连接的能力。 从本质上说,它是使用到同类数据的链接来建立的。
- 统一接口:RESTful 服务应该具有由 HTTP 的主要方法(即 GET、PUT、POST、DELETE 等)定义的统一接口。 特定资源的两个或多个表示形式使用 uri 明确标识。
HTTP 基本概念
在本节中,我们将讨论 HTTP 协议的基础知识。
下表显示了常见的 HTTP 方法及其目的:
|方法名称
|
目的
|
| --- | --- |
| DELETE | 用于删除资源 |
| GET | 这是用于请求资源的特定表示的 |
| HEAD | 这与GET相同,但是只检索头部而不检索正文 |
| OPTIONS | 这个用于检索资源支持的方法 |
| POST | 这个用于发布或提交资源要处理的数据 |
| PUT | 这是用于使用资源的特定表示创建或更新数据的 |
下表显示了 HTTP 状态码及其用途:
|状态码
|
描述
|
| --- | --- |
| 100 | 信息 |
| 200 | 成功的 |
| 201 | 创建 |
| 202 | 接受 |
| 300 | 重定向 |
| 304 | 不修改 |
| 400 | 客户端错误 |
| 402 | 付款要求 |
| 404 | 没有找到 |
| 405 | 方法不允许 |
| 500 | 服务器错误 |
| 501 | 没有实现 |
HTTP 重定向状态码:
|状态码
|
描述
|
| --- | --- |
| 300 | 多个选择 |
| 301 | 搬到永久 |
| 302 | 发现(临时重定向) |
HTTP 错误状态码如下表所示:
|状态码
|
描述
|
| --- | --- |
| 400 | 坏的请求 |
| 401 | 未经授权的 |
| 403 | 被禁止的 |
| 404 | 未找到资源 |
| 405 | 方法不允许 |
| 408 | 请求超时 |
| 409 | 冲突 |
| 413 | 请求实体太大 |
| 415 | 不支持的媒体类型 |
HTTP 服务器错误状态码如下表所示:
|状态码
|
描述
|
| --- | --- |
| 500 | 内部服务器错误 |
| 501 | 没有实现 |
| 503 | 服务不可用 |
| 505 | 不支持 HTTP 版本 |
下表列出了一些资源方法,以及如何使用 HTTP 协议实现它们:
|方法名称
|
描述
|
HTTP 操作
|
| --- | --- | --- |
| createResource | 此将创建一个新资源 | PUT |
| getResourceRepresentation | 这是用于检索特定资源表示的 | GET |
| deleteResource | 此删除资源 | DELETE |
| modifyResource | 此修改了资源 | POST |
| getMetaInformation | 此检索资源的元数据 | HEAD |
在下一节中,我们将探讨 ROA。 我们将讨论资源意味着什么、约束条件等等。
面向资源和面向服务的架构
SOA 和 ROA 架构设计范例提供了一种构建健壮的分布式架构的方法。 实质上,ROA 是针对 RESTful 架构的一组特定指导方针。 ROA 是一种为资源互连提供支持的结构设计。 资源是可以使用 URI 标识的实体。 服务器、计算机、计算机设备、网页、脚本等等都是 ROA 上下文中的资源。 SOA 是面向动词的,而 ROA 是面向名词的。
ROAs 涉及对特定资源实例的检索。 ROA 中的请求是无状态的。 资源生命周期管理动词包括PUT、DELETE、GET和POST。 在 ROA 中,您有一个维护资源集合的服务提供者。 该服务提供者公开了一些基本操作,如以下所示:
- 创造新资源
- 检索资源
- 修改的资源
- 删除的资源
下面是 RESTful 服务支持的核心操作列表:
- GET:这是一个返回已识别资源状态的操作
- POST:这是一个操作,用于更新特定的资源
- PUT:操作用于创建一个新资源
- DELETE:用于删除或销毁特定的资源
资源
roa 主要依靠资源发展。 资源是使用标准公共接口处理的分布式组件。 资源本质上是用名词来定义的。 雇员的雇佣合同就是资源的一个例子——它描述了资源所代表的数据。 请注意,一个资源可以与其他资源相关或链接。 ROA 基于这样一个原则:任何可以被分配统一资源标识符的实体都可以被称为资源。
注意事项
注意,没有两个资源可以是相同的,尽管它们可以指向相同的数据。 一个资源可以有一个或多个 uri。 例如,您可以在多个 uri 中使用相同的销售数据。
资源是通过以下方式识别的:
- 资源名称:这是标识资源的唯一名称
- 资源表示:此提供关于资源当前状态的元数据信息
- 资源链接:此是指向同一资源或其他资源的链接
- 资源接口:这是一个统一接口,用于评估资源和操作资源的状态
统一资源标识符
每个资源都有自己的 URI 来标识。 URI 是资源的名称和地址。 uri 应该是描述性的,如下所示:
http://www.packtpub.com/sales/2012/Q4
http://www.packtpub.com/sales/2012/Q3
注意事项
注意,一个资源可以有一个或多个 uri。 例如,2012 年第四季度销售数据的细节也可以通过不同的 URI 获得,如下所示:
http://www.packtpub.com/sales/2012/Q4
http://www.packtpub.com/sales/year/2012/Q4
在前面的示例中,两个 uri 都指向相同的资源。
可寻址性
可寻址性是每个 ROA 的一个有趣的方面。 如果应用将其数据作为资源公开,我们可以说它是可寻址的。 现在,ROA 中的资源使用 uri 公开。 因此,我们可以说,为了使应用具有可寻址性,它应该通过 uri 公开其数据。
无国籍
无状态性是 ROA 的另一个重要方面。 这意味着每个 HTTP 请求都是隔离的,即在完全隔离的情况下发生。
表象
表示被定义为描述资源当前状态的一些数据。 例如,当 web 服务器以一系列字节的形式发送数据时,它就是资源的表示。
三种建筑风格的比较
在选择适合您的业务需求的架构风格时,有很多地方需要考虑。 下表比较了不同的建筑风格:
|属性
|
面向对象的
|
面向资源的
|
面向服务的
|
| --- | --- | --- | --- |
| 粒度 | 对象实例 | 资源实例 | 服务实例 |
| 缓存响应 | 没有 | 是的 | 没有 |
| 有效载荷 | 是的,它通常是特定于中间件的 | 不,你没有任何链接到特定的地址或 URL | 是的,WSDL 模式 |
| 寻址或请求路由 | 独特的对象实例 | 特定资源的唯一地址 | 服务的端点地址 |
| 服务器与客户端之间的耦合 | 由于对象序列化和早期绑定到接口而产生的紧密耦合 | 由于延迟绑定到资源数据而导致的松散耦合 | 由于延迟绑定到服务接口而产生的松散耦合 |
当服务器和客户端组件之间的耦合或内聚非常紧密时,OOA 最适合,因此最适合于封闭系统。
面向服务的架构涉及客户端和服务器组件之间的松散耦合,这是由于后期绑定到服务接口。 这些系统非常灵活,而且由于它们的无状态特性,易于扩展。 这些架构最适合于可以跨组织边界工作的共享系统。 下图展示了面向服务架构和面向对象架构的比较:

SOA 和 OOA 的比较
面向资源的系统涉及服务器和客户机组件之间的松散耦合,它们最适合于需要资源数据的后期绑定和缓存能力的场景。 由于它们的无状态特性,这些系统是可伸缩的。
从本质上讲,ROA 是一种架构范例,它基于四个基本概念:资源、资源的名称、资源的表示以及资源之间的链接。 它还基于四个不同的属性:可寻址性、无状态性、连通性和统一接口。
选择正确的架构风格完全取决于您的业务需求。 从本质上讲,您可以设计一个 web 服务应用,它可以将架构风格与面向资源的方法相结合,用于简单的数据读取,并将面向服务的方法用于复杂的数据操作。
注意事项
你可以参考以下网址:
http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
总结
在 OOP 中,重点是创建同时包含状态和行为的对象。 相反,SOA 构建在 OOP 之上,并允许您创建可重用的服务。 OOP 侧重于应用所包含的内容,而 SOA 侧重于应用的功能。 ROA 基于资源的概念。 服务表示所请求操作的执行,而资源表示给定数据类型的特定实例的数据访问机制。 资源是通过标准的公共接口处理的分布式组件。 资源可以使用 uri 寻址。
本章描述了与 ROA、web 服务和 SOA 相关的基本概念。 它介绍了 ROA,以及它与其他当代架构风格(如 OOP 和 SOA)的不同之处。 我们讨论了这三种架构范例的不同之处,以及 ROA 的概念。
在下一章中,我们将把这些概念付诸实践,讨论 RESTful web 服务的概念和特征,并探索如何使用 WCF 设计和实现 RESTful 服务。**
三、创建 RESTful 服务
现在我们已经很好地掌握了 REST 和资源的概念,让我们来探索如何使用 WCF 创建 RESTful 服务。 在本章中,我们将深入讨论 WCF,然后创建 RESTful 服务。 注意,RESTful 服务以 uri 的形式公开资源,并使用 HTTP 方法执行 CRUD 操作。
在本章中,我们将涵盖以下几点:
- 探索 WCF
- WCF 绑定
- WCF 安全
- 创建 WCF 服务
- 使 WCF 服务 RESTful
- 指定绑定信息
- 托管服务
本章开始时,我们将深入讨论Windows Communication Foundation(WCF)——构建可扩展的安全服务的首选技术。
探索 Windows 通信基础(WCF)
Windows Communication Foundation (WCF)是一个基于面向服务架构(SOA)的框架。 WCF 可用于设计具有相互通信能力的应用。 WCF 最初被命名为“Indigo”,并作为.NET Framework 3.0 在 2006 年。
WCF 支持统一现有的。net 技术。 它为统一微软的分布式技术——web Services、Remoting、COM+等等——提供了一个伟大的平台。 WCF 还提供对跨平台互操作性、安全性、面向服务的开发和可靠性的支持。 它帮助您通过利用. net 的托管环境的优点来构建面向服务的应用。

基于。net 托管框架的 WCF
WCF 基于三个不同的概念:地址、绑定和契约。
地址表示服务的位置。 绑定指定要使用的通信协议,也就是说,它表示特定的服务如何与其他服务或其他客户机通信。 契约表示服务中公开的部分。 客户端通过服务公开的端点连接到服务。
下面是 WCF 中预定义的内置绑定列表:
- BasicHttpBinding
- MsmqIntergrationBinding
- WSHttpBinding
- WSDualHttpBinding
- WSFederationHttpBinding
- NetTcpBinding
- NetNamedPipeBinding
- NetMsmqBinding
- NetPeerTcpBinding
WCF 中的端点用于将服务契约与其地址关联起来。 通道是服务与其客户端之间的桥梁。 以下是 WCF 中支持的通道类型:
- 单纯形输入
- 单纯形输出
- 请求-应答
- 双工
WCF 消息可以是中的一种模式:
- 单纯形
- 请求-应答
- 双工

WCF 服务和 WCF 客户端使用消息相互通信
在 wcf 中可以有三个合同——一个服务合同,一个数据合同,以及消息合同。 任何 WCF 服务类都至少实现一个服务契约——一个用于定义 WCF 服务类公开的操作的接口。 此类操作还可以包括使用数据契约公开的数据操作。 服务契约是一个接口,用于定义由 WCF 服务类公开的操作。 实际上,WCF 服务类与任何其他类一样,只是它被标记为 ServiceContract 属性。 消息契约可以定义为允许您更改消息格式的应用。 注意 ServiceContract、DataContract 和其他相关属性是在System.ServiceModel命名空间中定义的。
同样,任何在 OperationContract 属性之前的方法对于 soap 可调用操作的客户机都是外部可见的。 如果您有一个没有此属性集的方法,则该方法将不包含在服务契约中,因此 WCF 客户端将无法访问 WCF 服务的该操作。
应用服务行为
您可以使用 servicemetadatbehavior 属性元素来配置应用于服务的行为。 这可以通过以下代码完成:
<behaviors>
<behavior>
<ServiceMetadata httpGetEnabled="true" />
</behavior>
</behaviors>
<services>
<service
name="DemoService"
<endpoint
address="http://Joydip-PC:8080/Demo"
contract="IDemoService"
binding="basicHttpBinding" />
</endpoint>
</service>
</services>
WCF 4.5 的新特性
在本节中,我们将回顾 WCF 4.5 中的新特性和增强。 WCF 4.5 中新的和增强的特性包括:
- 简化配置:WCF 4.5 为更简单的配置提供了支持。 它提供默认端点、绑定和行为。
- 标准端点:WCF 4.5 支持预先配置的标准端点。 WCF 4.5 中可用的标准端点包括 dynamicEndPoint、discoveryEndpoint、udpDiscoveryEndpoint、announcementEndpoint、udpAnnouncementEndpoint、mexEndPoint、webHttpEndpoint、webScriptEndpoint 和 workflowControlEndpoint。
- Discovery:WCF 4.5 提供了基于一些预定义的标准动态解析服务端点的能力。
- 简化 IIS 托管:WCF 4.5 通过易于使用的配置提供了对 IIS 中简化托管服务的支持。
- 对 REST 的更好支持:WCF 4.5 为基于 REST 的服务的设计和开发提供了增强的支持。
- 路由服务:WCF 4.5 提供路由支持。 您可以像托管 WCF 服务一样托管路由服务。 路由服务提供版本控制、协议桥接、事务和错误处理支持。
- Workflow services:WCF 4.5 支持 WCF 服务和 WF 服务的集成。 现在可以无缝地实现声明式服务。 在 IIS 中托管工作流服务的基础设施也得到了很大的改进。
WCF 框架的增强
WCF 框架是在 2006 年作为。net Framework 3.0 的一部分首次引入的。 它是一个由许多技术组成的框架,为设计基于 SOA 的应用提供了一个平台,这些应用可以具有相互通信的能力。
.NET Framework 3.5 中 WCF 的新增强包括:
- 支持支持 ajax 的 WCF 服务
- 改进了对 WCS 标准的支持
- 一个新的 WCF 设计器
- 新的 WCF 工具(WcfSvcHost 和 WcfTestClient)
- 支持基于 rest 的 WCF 服务
- 支持 WCF 和 WF 交互性
WCF 3.5 中另一个伟大的新特性是引入了UserNamePasswordValidator类。 您可以使用这个类来设计和实现您自己的自定义验证器,以验证用户的凭证。
在 WCF 3.5 中,System.IdentityModel.Selectors名称空间中的UserNamePasswordValidator类可用于验证用户凭证。 只需扩展UserNamePasswordValidator类,然后覆盖 Validate 方法,就可以创建自己的自定义验证器,如下中的所示:
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.ServiceModel;
namespace Packt
{
public class PacktValidator : UserNamePasswordValidator
{
public override void Validate(String userName, String password)
{
if (!userName.Equals("joydip")) || !password.Equals("joydip1@3"))
{
throw new SecurityTokenException("User Name and/or Password incorrect...!");
}
}
}
}
然后,您可以配置刚刚在配置文件中创建的验证器,如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<bindings>
<wsHttpBinding>
<binding name="PacktAuthentication">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="PacktValidator.ServiceBehavior">
<serviceCredentials>
<userNameAuthenticationuserNamePasswordValidationMode="Custom"customUserNamePasswordValidatorType="Packt.PacktValidator, Packt"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
WCF 4.5 中新的增强包括以下内容:
- 简化的配置
- 标准的端点
- 发现
- 简化的 IIS 托管
- 其他改进
- 工作流服务
- 路由服务
- 自动帮助页面
简化配置
WCF 4.5 使用默认的配置模型启动。 与之前的版本相比,WCF 4.5 中的配置要简单得多。 WCF 3。 x,您需要为服务主机指定端点、行为等。 在 WCF 4.5 中,默认情况下提供了默认端点、绑定信息和行为。 从本质上说,当您实现特定的 WCF 服务时,WCF 4.5 消除了任何 WCF 配置的需要。
在 WCF 4.5 中,有一些标准端点和默认绑定/行为配置是为任何 WCF 服务默认创建的。 这使得开始使用 WCF 变得很容易,因为 WCF 3 繁琐的配置细节。 x不再需要。
考虑以下的 WCF 服务:
using System;
using System.ServiceModel;
namespace PacktService
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
String DisplayMessage();
}
public class TestService : ITestService
{
public String DisplayMessage()
{
return "Hello World!";
}
}
}
在 WCF 4.5 中,您可以使用ServiceHost来托管 WCF 服务,而不需要任何配置信息。 下面是所有的代码,你需要宿主你的 WCF 服务和显示地址,绑定,和合同信息:
using System.ServiceModel;
using System;
using System.ServiceModel.Description;
namespace PacktClient
{
class Program
{
static void Main(string[] args)
{
ServiceHost serviceHost = new ServiceHost
(typeof(PacktService.TestService));
serviceHost.AddServiceEndpoint
(typeof(PacktService.TestService),
new BasicHttpBinding(),
"http://localhost:1607/
TestService.svc");
serviceHost.Open();
foreach (ServiceEndpoint serviceEndpoint
in serviceHost.Description.Endpoints)
Console.WriteLine("Address: {0}, Binding: {1},
Contract: {2}", serviceEndpoint.Address,
serviceEndpoint.Binding.Name,
serviceEndpoint.Contract.Name);
Console.ReadLine();
serviceHost.Close();
}
}
}
下面是在 WCF 4.5 中指定和使用服务所需的所有配置信息的一个示例:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled ="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
注意,默认使用的绑定是 BasicHttpBinding。 如果你想选择一个更安全的绑定(比如 WSHttpBinding),你可以改变绑定信息,如下代码片段所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled ="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme ="http"/>
</protocolMapping>
</system.serviceModel>
</configuration>
标准端点
标准端点是 WCFFramework 4.5 中预先配置的端点。 您总是可以重用它们,但它们通常不会更改。 下表列出了 WCF 4.5 中的标准端点及其用途。
通过使用端点名称在<configuration>元素中引用,您可以使用前面示例中显示的任何端点。 举例如下:
<configuration>
<system.serviceModel>
<services>
<service name="PacktService">
<endpoint kind="basicHttpBinding" contract="IMyService"/>
<endpoint kind="mexEndpoint" address="mex" />
</service>
</services>
</system.serviceModel>
</configuration>
发现
操作方式有两种:
- Ad-hoc 模式:不存在集中式服务器,所有服务通知和客户端请求都以组播方式发送。
- 托管模式:拥有一台集中式服务器。 这样的服务器称为发现代理,其中集中发布服务,需要使用这种发布服务的客户端连接到这种模式以检索必要的信息。
您可以添加标准的udpDiscoveryEndpoint端点,并启用<serviceDiscovery>行为,以启用 Ad-hoc 模式下的服务发现。 举例如下:
<configuration>
<system.serviceModel>
<services>
<service name="TestService">
<endpoint binding="wsHttpBinding" contract="ITestService" />
<!-- add a standard UDP discovery endpoint-->
<endpoint name="udpDiscovery" kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestService.MyServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true.Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceDiscovery />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
在前面的代码片段中,请注意如何添加一个新的端点来发现服务。 还添加了 ServiceDiscovery 行为。 您可以使用DiscoveryClient类来发现您的服务并调用其中一个方法。
您必须创建DiscoveryClient类的一个实例,并将UdpDiscoveryEndPoint作为参数传递给该类的构造函数以发现服务。 一旦发现了端点,就可以使用其地址来调用服务。 下面的代码片段说明了这一点:
using System;
using System.ServiceModel;
using System.ServiceModel.Discovery;
namespace PacktConsoleApplication
{
class Program
{
static void Main(string[] args)
{
DiscoveryClient discoverclient = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindResponse findResponse = discoverclient.Find(new FindCriteria(typeof(ITestService)));
EndpointAddress endpointAddress = findResponse.Endpoints[0].Address;
MyServiceClient serviceClient = new MyServiceClient(new WSHttpBinding(), endpointAddress);
Console.WriteLine(serviceClient.DisplayMessage());
}
}
}
WCF 4.5 还允许您配置服务,以便在服务启动时立即宣布它们的端点。 您可以配置您的服务在开始时使用以下代码宣布端点:
<configuration>
<system.serviceModel>
<services>
<service name="TestService">
<endpoint binding="wsHttpBinding" contract="ITestService"/>
<endpoint kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDiscovery>
<announcementEndpoints>
<endpoint kind="udpAnnouncementEndpoint"/>
</announcementEndpoints>
</serviceDiscovery>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
简化 IIS 托管
在 IIS 上托管 WCF 4.5 应用现在变得很容易。 下面是一个简单的 WCF 服务的例子:
<!-- PacktService.svc -->
<%@ ServiceHost Language="C#" Debug="true" Service=" PacktService
CodeBehind="~/App_Code/PacktService.cs" %>
[ServiceContract]
public class PacktService
{
[OperationContract]
public string GetMessage()
{
return "This is a test service.";
}
}
然后,您可以在应用的web.config配置文件中为服务启用服务元数据,如下面的代码片段所示:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
您还可以在应用的web.config配置文件中为您的 WCF 4.5 服务定义虚拟服务激活端点。 这样,您就可以在不需要任何.svc文件的情况下激活 WCF 服务。 下面是您需要在应用的web.config配置文件中指定的配置,以激活您的服务,而不需要.svc文件:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="PacktService.svc" service="PacktService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
REST 的改进
WCF 4.5 提供了对基于 rest 的特性的改进支持。 现在,您已经支持了一个自动帮助页面,该页面描述了服务使用者或客户可用的基于 rest 的服务。 这个特性在默认情况下是打开的,不过你也可以手动配置,如下面的代码清单所示:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="PacktTestHelpBehavior">
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="PacktSampleWCFService">
<endpoint behaviorConfiguration="PacktTestHelpBehavior"binding="webHttpBinding" contract="PacktSampleWCFService" />
</service>
</services>
</system.serviceModel>
</configuration>
WCF 4.5 也通过 AspNetCacheProfile 属性来支持 HTTP 缓存。 注意,AspNetCacheProfile 支持实际上使用标准的 ASP.NET 输出缓存机制为您在 WCF 服务中提供缓存特性。
要使用此属性,您应该添加对System.ServiceModel.Web.Caching命名空间的引用。 您可以在 WebGet 操作中应用此属性,并指定您所选择的缓存持续时间。 下面的代码片段可以在你的服务契约方法中使用这个特性:
using System.ServiceModel.Web.Caching;
[OperationContract]
[WebGet]
[AspNetCacheProfile("PacktCache")]
String GetProductName();
因此,你应该在你的应用的web.config文件中设置缓存配置文件,如下代码所示:
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="PacktCache" duration="60" varyByParam="format"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
路由服务
路由是 WCF 4.5 中的特性,用于确定如何转发消息以及何时出现来自客户机的请求。 筛选器确定路由服务如何将来自客户机的请求重定向到特定的 WCF 服务。 这些过滤器使用路由表映射到相应的 WCF 服务端点。 以下是可用的过滤类型:
- 行动
- 地址
- AddressPrefix
- 和
- 自定义
- 端点
- MatchAll
- XPath
WCF 4.5 中的 Routing 服务提供了对以下特性的支持:
- 消息路由
- 版本控制
- 错误处理
- 事务处理
- 协议桥接
在 WCF 4.5 中,您可以使用RoutingService类在应用中实现通用的 WCF 路由机制。 下面是RoutingService类的样子:
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,InstanceContextMode = InstanceContextMode.PerSession,UseSynchronizationContext = false, ValidateMustUnderstand = false)]
public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter,
IRequestReplyRouter, IDuplexSessionRouter
{
//Some code
}
托管 RoutingService 就像托管 WCF 服务一样简单。 您必须简单地创建一个 ServiceHost 实例,然后为服务类型指定 RoutingService。 举例如下:
public static void Main()
{
ServiceHost serviceHost = new ServiceHost(typeof(RoutingService));
try
{
serviceHost.Open();
Console.WriteLine("Routing Service started...");
Console.WriteLine("Press <ENTER> to stop the Routing Service.");
Console.ReadLine();
serviceHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine(ce.Message);
serviceHost.Abort();
}
}
路由部分由两个部分组成,过滤器和 filterTables。 为路由创建的所有筛选器都位于筛选器部分。 对于每个过滤器,我们必须指定名称和类型。 这里,filterData 是 EndpointName。 有不同种类的过滤器类型:
- EndpointName
- XPath
- 行动
- 和
- 自定义
通过调用 ServiceHost 实例上的Open()方法启动 RoutingService 之后,它可以根据需要路由消息。 下面是一个典型配置的例子,你可以用它来为你的路由服务指定路由信息:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="System.ServiceModel.Routing.RoutingService" behaviorConfiguration="TestBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:1809/TestService"/>
</baseAddresses>
</host>
<endpoint
address=""
binding="wsHttpBinding" name="TestRoutingEndpoint" contract="System.ServiceModel.Routing.IRequestReplyRouter"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="TestBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
<routing routingTableName="ServiceRouterTable"/>
<!--The Router Table Contains Entries for services-->
</behavior>
</serviceBehaviors>
</behaviors>
<!--Define Services Here-->
<client>
<endpoint
name="PacktService" binding="wsHttpBinding"
address="http://localhost:2709/Services/PacktService.svc"
contract="*">
</endpoint>
</client>
<!--Routing Defination-->
<routing>
<!--Filter For Detecting Messages Headers to redirect-->
<filters>
<filter name="TestFilter" filterType="MatchAll"/>
</filters>
<!--Define Routing Table, This will Map the service with Filter-->
<routingTables>
<table name="ServiceRouterTable">
<entries>
<add filterName="TestFilter" endpointName="PacktService"/>
</entries>
</table>
</routingTables>
</routing>
</system.serviceModel>
</configuration>
注意,前面代码片段中显示的路由服务托管在http://localhost:1809/TestService。 它使用 wsHttpBinding。
您还可以使用消息过滤器配置 RoutingService。 要做到这一点,你需要在 RoutingService 上启用 RoutingBehavior,然后指定配置信息,如下面的代码片段所示:
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="PacktServiceRoutingBehavior">
<serviceMetadata httpGetEnabled="True"/>
<routing filterTableName="myFilterTable" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
自动帮助页面
WCF 4.5 中的WebHttpBehavior类支持自动帮助页面。 该类包含一个名为HelpEnabled的属性,您可以根据需要打开或关闭该属性。 下面是如何配置这个自动帮助功能:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="PacktHelpBehavior">
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="PacktTestService">
<endpoint behaviorConfiguration="HelpBehavior"
binding="webHttpBinding"
contract="PacktTestService" />
</service>
</services>
</system.serviceModel>
</configuration>
在下一节中,我们将探讨 WCF 中的绑定,以及它们为什么有用。
WCF 中的绑定
绑定用于指定传输通道(HTTP、TCP、管道、消息队列)和协议(安全性、可靠性、事务流)。 一个绑定由绑定元素组成。 这些绑定元素表示端点如何与服务消费者通信。 WCF 支持 9 个内置绑定。 在 WCF 中,WCF 配置方案的三个主要部分是 serviceModel、bindings 和 services,如下所示:
<configuration>
<system.serviceModel>
<bindings>
</bindings>
<services>
</services>
<behaviors>
</behaviors>
</system.serviceModel>
</configuration>
下面是在配置文件中指定绑定信息的方法:
<service name="Demo">
<endpoint
address="/Test/"
contract="ITest "
binding="basicHttpBinding" />
</endpoint>
</service>
address 属性指定 URI(绝对路径或相对路径),其他端点将使用该 URI 与服务通信。 contract 属性表示此端点公开的合同,而 binding 属性用于选择一个预定义的或自定义的绑定来与端点一起使用。 在本节中,我们将探讨 WCF 中的绑定。
BasicHttpBinding
BasicHttpBinding 将 WCF 服务作为遗留的 ASMX web 服务公开,并且同时支持 HTTP 和安全 HTTP。 它同时支持 Text 和 MTOM 编码方法。 然而,这种类型的绑定不支持WS-*标准,如 WS-Addressing、WS-Security 和 WS-ReliableMessaging,如下所示:
<bindings>
<basicHttpBinding>
<binding name="Demo">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
WsHttpBinding
WsHttpBinding 默认加密 SOAP 消息,同时支持 HTTP 和 HTTPS。 它同时支持 Text 和 MTOM 编码方法。 它还支持WS-*标准,如 WS-Addressing、WS-Security 和 WS-ReliableMessaging。 这种类型的绑定默认情况下使用消息安全性。 您可以指定一个 HTTPS 端点来提供认证、完整性和机密性,如下所示:
<binding name="Demo">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"/>
<message clientCredentialType="IssuedToken"/>
</security>
</binding>
netttcpbinding
netttcpbinding 提供了对事务和安全性的支持。 它基于 TCP 协议,使用二进制作为编码方法。 它是 WCF 支持的所有绑定类型中最优化、最快的绑定。 它默认使用传输安全。 注意 IIS 6.0 不能承载 netttcpbinding 应用。
<client>
<endpoint name="Demo" address="net.tcp://localhost:8523/SecurityService"
binding="netTcpBinding" contract="ISecurityService" >
<identity>
<servicePrincipalName value="SecurityService/Joydip-PC" />
</identity>
</endpoint>
</client>
MsmqIntegrationBinding
这个绑定支持事务,使用传输安全性,并且为创建与非 WCF MSMQ 端点互操作的 WCF 客户端和服务进行了优化。 System.ServiceModel命名空间中的MsmqIntegrationBinding类将 MSMQ 消息映射到 WCF 消息。 MsmqIntegrationBinding 提供了与 MSMQ 通信的开箱即用绑定。
netMsmqBinding
netMsmqBinding 使用 MSMQ 作为传输通道,并在跨机环境中使用安全可靠的队列通信。 注意,WCF 支持两个绑定来与 MSMQ 通信; 即 MsmqIntegrationBinding 和 netMsmqBinding。 虽然前者可以用于 WCF 与其他 MSMQ 客户端和服务交换信息的异构架构中,但后者用于同质架构中,即服务和客户端都基于 WCF 的架构中。
netNamedPipeBinding
这通常用于跨进程通信,它使用传输安全性进行消息传输和身份验证,支持消息加密和签名,并使用命名管道进行消息传递。 这种绑定在同一个系统上的 WCF 服务和 WCF 客户端之间提供了安全可靠的基于命名管道的通信。 下面的代码片段演示了当使用 netNamedPipeBinding 时,一个典型的服务配置的样子:
<services>
<service name="DemoService" behaviorConfiguration="DemoServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/DemoService"/>
</baseAddresses>
</host>
<endpoint address="" binding="netNamedPipeBinding" contract="IDemoService"></endpoint>
</service>
</services>
And here is how the netNamedPipeBinding client configuration would look like:
<client>
<endpoint address="net.pipe://localhost/DemoService.svc" binding="netNamedPipeBinding" contract="IDemoService"></endpoint>
</client>
netPeerTcpBinding
它用于为点对点网络应用提供安全绑定。 您可以使用 WCF netPeerTCPBinding 来开发对等网络应用,这些应用利用了 tcp 级别的对等网格基础设施。 要使用这种类型的绑定,您的机器上应该安装对等体名称解析协议(PNRP)。 如果无法使用,您可以在控制面板中使用添加或删除程序手动安装。 您还应该确保 PNRP 及其相关服务在您的系统中运行。 下面的代码片段说明了如何配置 netPeerTcpBinding:
<endpoint
address="net.p2p://localhost/TestWCFService/"
binding="netPeerTcpBinding"
bindingConfiguration="netp2pBinding"
contract="ITestWCFService">
<bindings>
<netPeerTcpBinding>
<binding name="netP2P" >
<resolver mode="Pnrp" />
<security mode="None" />
</binding>
</netPeerTcpBinding>
</bindings>
WsDualHttpBinding
WsDualHttpBinding 提供 WsHttpBinding 的所有特性。 除此之外,它还支持双工消息交换模式。 在此模式中,服务可以使用回调与客户端通信。 下面的代码片段演示了如何连接到使用 WsDualHttpBinding 的 WCF 服务:
Uri serviceAddress = new Uri("http://localhost/DemoService");
WSDualHttpBinding wsd = new WSDualHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress(serviceAddress, EndpointIdentity.CreateDnsIdentity("localhost"));
client = new DemoServiceClient (new InstanceContext(this), wsd, endpointAddress);
以下是您将在客户端指定的配置:
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IDemoService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:00:05"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/DemoService/"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IDemoService"contract="IDemoService" name="WSDualHttpBinding_IDemoService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
WsFederationHttpBinding
WsFederationHttpBinding 是一种 WS Binding,它为联邦安全性提供了支持。 请注意,联合服务要求服务使用者使用安全令牌服务发出的安全令牌进行身份验证。 配置中的WSFederationHttpBinding类和wsFederationHttpBinding元素有助于公开联邦服务。 请注意,WSFederationHttpBinding 支持消息级安全性,并且在使用 WSFederationHttpBinding 时不需要选择客户机凭据类型,因为客户机凭据类型在默认情况下始终是发出的令牌。 您可以通过http://msdn.microsoft.com/en-IN/library/aa347982.aspx了解更多关于 WSFederationHttpBinding 的信息。
使用多个绑定
您还可以为同一个 WCF 服务使用多个绑定。 下面的配置显示了如何配置使用多个绑定的服务:
<service name="DemoService, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null">
<endpoint
address="http://Joydip-PC:8080/Demo1"
contract="IDemo, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
binding="basicHttpBinding"
bindingConfiguration="shortTimeout"
</endpoint>
<endpoint
address="http://Joydip-PC:8080/Demo2"
contract="IDemo, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
binding="basicHttpBinding"
bindingConfiguration="Secure"
</endpoint>
</service>
<bindings>
<basicHttpBinding
name="shortTimeout"
timeout="00:00:00:01"
/>
<basicHttpBinding
name="Secure" />
<Security mode="Transport" />
</bindings>
您也可以使用配置文件中的protocolMapping节实现相同的行为,如下所示:
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" bindingConfiguration="shortTimeout" />
<add scheme="https" binding="basicHttpBinding" bindingConfiguration="Secure" />
</protocolMapping>
<bindings>
<basicHttpBinding
name="shortTimeout"
timeout="00:00:00:01"
/>
<basicHttpBinding
name="Secure" />
<Security mode="Transport" />
</bindings>
下面的代码片段显示了服务侦听的端点:
ServiceHost host = new ServiceHost(typeof(DemoService), new Uri("http://localhost:9090/DemoService"));
host.Open();
Console.WriteLine("Service started...press any key to terminate");
ServiceEndpointCollection endpoints = host.Description.Endpoints;
foreach (ServiceEndpoint endpoint in endpoints)
{
Console.WriteLine("The service host is listening at {0}", endpoint.Address);
}
Console.WriteLine("Press any key to terminate the service.");
Console.ReadLine();
您还可以通过从System.ServiceModel.Channels.Binding类派生自定义绑定类来定义自定义绑定。 下表列出了 WCF 中的各种绑定,它们的传输模式、支持的消息编码类型、安全模式以及它们的事务支持:
绑定类
|
运输
|
信息编码
|
安全模式
|
可靠的消息传递
|
交易流
|
| --- | --- | --- | --- | --- | --- |
| BasicHttpBinding | HTTP | 文本 | 没有一个 | 不支持 | 不支持 |
| WSHttpBinding | HTTP | 文本 | 消息 | 禁用 | ws - atomictransaction |
| WSDualHttpBinding | HTTP | 文本 | 消息 | 启用 | ws - atomictransaction |
| WSFederationHttpBinding | HTTP | 文本 | 消息 | 禁用 | ws - atomictransaction |
| NetTcpBinding | TCP | 二进制 | 运输 | 禁用 | OleTransactions |
| NetPeerTcpBinding | P2P | 二进制 | 运输 | 不支持 | 不支持 |
| NetNamedPipesBinding | 命名管道 | 二进制 | 运输 | 不支持 | OleTransactions |
| NetMsmqBinding | MSMQ | 二进制 | 消息 | 不支持 | 不支持 |
| MsmqIntegrationBinding | MSMQ | 不支持 | 运输 | 不支持 | 不支持 |
下表列出了 WCF 中绑定的类型及其支持的模式:
|绑定类型
|
传输模式
|
消息模式
|
| --- | --- | --- |
| BasicHttpBinding | 是的 | 是的 |
| WSHttpBinding | 是的 | 是的 |
| WSDualHttpBinding | 没有 | 是的 |
| NetTcpBinding | 是的 | 是的 |
| NetNamedPipeBinding | 是的 | 没有 |
| NetMsmqBinding | 是的 | 是的 |
| MsmqIntegrationBinding | 是的 | 没有 |
| wsFederationHttpBinding | 没有 | 是的 |
选择正确的绑定
本质上,绑定是端点的一个属性,您可以使用它来配置服务的传输协议、编码和安全规范。 现在,我应该在什么时候使用哪个绑定? 以下是经验法则:
- WsHttpBinding:如果您需要在 Internet 上公开您的服务,您可以使用这种类型的绑定
- basicHttpBinding:如果您需要将 WCF 服务公开给旧客户端,比如 ASMX Web 服务,那么您应该选择这种类型的绑定
- NetTcpBinding:如果您需要在内部网中支持 WCF 客户端,那么可以使用这种类型的绑定
- netNamedPipeBinding:如果您需要在同一台机器上支持 WCF 客户端,那么这种类型的绑定是一个很好的选择
- netMsmqBinding:如果需要支持未连接的排队呼叫,可以选择该类型的绑定
- wsDualHttpBinding:如果您想为服务和客户端之间的双向通信提供支持,您可以选择这种类型的绑定
安全在 WCF -保护你的 WCF 服务
在本节中,我们将讨论如何保护我们的 WCF 服务。 要保护 WCF 服务并确保通过网络传输的数据的机密性,您可以依赖于身份验证、授权和消息或传输安全性的概念。 虽然身份验证表示用户(试图访问服务)凭证的身份,但授权表示经过身份验证的用户可以访问的资源。 要保持消息的完整性,可以在消息通过有线传输之前对其进行数字签名和加密。
传输级安全性
传输级安全性提供了两个端点之间的点对点安全性,并使用传输协议,如 TCP、HTTP 和 MSMQ。 注意,以这种安全模式传递的用户凭据依赖于协议。 下图显示了传输级安全的功能:

要启用传输安全性,请使用服务配置文件中的 security 属性,如下代码片段所示:
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
消息级安全性
消息级安全性是独立于安全协议的,在这里用户凭据在与消息一起通过网络传输之前是经过加密的。 尽管传输安全性比消息安全性更快,但后者要灵活得多。 下图显示了消息级安全的功能:

下面的代码片段演示了如何使用用户凭据实现消息级安全性:
<wsHttpBinding>
<binding name = "wsHttp">
<security mode = "Message">
<message clientCredentialType = "UserName"/>
</security>
</binding>
</wsHttpBinding>
下面是如何使用证书实现消息级安全性的方法:
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
我们已经有足够的关于 WCF 的讨论(这是必要的,因为我们将在本书中使用 WCF)。 在下一节中,我们将使用 WCF 实现 RESTful 服务。 我们还将创建贯穿本书的数据库。
利用 WCF 实现 RESTful 服务
在本节中,我们将探索如何使用 WCF 创建基于 rest 的服务。 要实现 RESTful Web 服务,首先需要创建一个 WCF 服务,然后使用适当的属性使服务 RESTful。
注意,您需要使用 WebHttpBinding 来启用 RESTful 行为。
WCF RESTful 服务的最简单表示如下所示:
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
public class Service : IService
{
public Employee[] GetEmployees()
{
return new Employee[]
{
new Employee() {EmpId=1,FirstName="Joydip",LastName="Kanjilal"},
new Employee() {EmpId=2,FirstName="Sabita",LastName="Kanjilal"}
};
}
}
ServiceContract 看起来如下所示:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate="/Employees",ResponseFormat=WebMessageFormat.Xml )]
Employee[] GetEmployees();
}
下面是数据合约:
[DataContract]
public class Employee
{
[DataMember]
public int EmpId { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
创建安全数据库
在本节中,我们将创建一个贯穿全书的数据库。 该数据库的名称为Packt_Security,包含以下表:
UserUserAuthenticationUserAuthenticationTypeUserLoginHistory
我已经使数据库设计尽可能的简单。 我们的Packt_Security数据库的数据库设计类似如下:

数据库设计
以下是Security数据库的完整脚本:
CREATE TABLE [dbo].[UserMaster](
[UserName] [nvarchar](max) NOT NULL,
[UserID] [int] IDENTITY(1,1) NOT NULL,
[UserEmail] [nvarchar](max) NULL,
[Password] [nvarchar](max) NOT NULL,
[LastLoginDate] [datetime] NULL,
[IsOnline] [bit] NULL,
[IsAdmin] [bit] NULL,
[IsActive] [bit] NULL,
[DateCreated] [datetime] NULL,
CONSTRAINT [pk_UserMaster] PRIMARY KEY CLUSTERED
(
[UserID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
CREATE TABLE [dbo].[UserLoginHistory](
[UserLoginID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NOT NULL,
[LoginDateTime] [datetime] NOT NULL,
CONSTRAINT [PK_UserLoginHistory] PRIMARY KEY CLUSTERED
(
[UserLoginID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[UserAuthentication](
[UserAuthenticationID] [int] IDENTITY(1,1) NOT NULL,
[UserAuthenticationTypeID] [int] NOT NULL,
[UserID] [int] NOT NULL,
[Password] [varchar](50) NOT NULL,
[SecurityQuestion] [varchar](50) NOT NULL,
[SecurityAnswer] [varchar](50) NOT NULL,
CONSTRAINT [PK_UserAuthentication] PRIMARY KEY CLUSTERED
(
[UserAuthenticationID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[UserAuthenticationType](
[UserAuthenticationTypeID] [int] IDENTITY(1,1) NOT NULL,
[UserAuthenticationTypeName] [varchar](50) NOT NULL,
CONSTRAINT [PK_UserAuthenticationType] PRIMARY KEY CLUSTERED
(
[UserAuthenticationTypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
现在我们将实现一个名为 SecurityService 的 WCF 服务,该服务将利用 Packt 数据库中的UserMaster表。
创建安全服务
要创建 WCF 服务,请遵循以下简单步骤:
- 打开 Visual Studio 2013 IDE。
- 进入文件|新|项目。
- 从显示的项目模板列表中选择WCF 服务应用。
- 指定 WCF 服务应用的名称。
- 点击OK保存。
请参考以下截图:

创建服务
一个 WCF 服务包括以下内容:
- 一个服务类
- 一个服务契约
- 托管环境
- 一个或多个端点
WCF 中的服务类是实现服务契约的服务类。 一个服务契约通常是一个接口,并使用[ServiceContract]属性进行装饰。 托管环境是指 WCF 服务执行的环境。 WCF 服务可以托管在 IIS 中,也可以是自托管服务。 客户端使用公开的端点连接到 WCF 服务。 在 WCF 服务中,可以使用[OperationContract]属性标记一个或多个方法。
当您创建一个新的 WCF 服务应用项目时,您将看到默认情况下创建的服务契约和服务类。 注意,服务契约是使用[ServiceContract]属性标记的,如下所示:
using System.Runtime.Serialization;
using System.ServiceModel;
namespace Packt.Services
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
}
服务类实现了前面定义的服务契约,如下所示:
using System;
namespace Packt.Services
{
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
}
服务契约是一个用[ServiceContract]属性标记的接口,并且包含一个或多个使用[OperationContract]属性公开的方法。 下一步是创建服务契约和服务类。 一个服务契约也可以有一个或多个数据契约。 数据契约是一个保存数据并用[DataContract]属性标记的类。
使服务 RESTful
要使安全服务 RESTful,您需要在服务契约中指定[WebGet]或[WebInvoke]属性。 虽然前者表明 WCF 服务可以响应 HTTP Get 请求,但后者用于表明 WCF 服务可以响应 HTTP Post 请求。 两者都属于System.ServiceModel.Web命名空间,实际上是 WCF 的 HTTP 编程模型的一部分。
下面的代码片段演示了一个典型的[WebGet]属性是如何定义的:
[WebGet(UriTemplate =
"/sales/getsales.xml",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml)]
可以定义[WebInvoke]属性,以便您的 WCF 服务可以响应 HTTP Post 操作:
[GetOperationContract]
[WebInvoke(UriTemplate =
"/sales/updatesales.xml?
productcode={code}",
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml)]
要使我们在本文前面创建的服务是 RESTful 的,只需更改 ISecurityService 契约,并指定WebGet属性,如下代码所示:
[ServiceContract]
public interface ISecurityService
{
[OperationContract]
[WebGet]
User GetUserData(Int32 userID);
[WebInvoke]
User PostUserData(Int32 userID);
}
启用服务在 ASP. exe 中运行.NET 兼容模式下,你应该用AspNetCompatibilityRequirements属性装饰你的服务类,如下代码所示:
[AspNetCompatibilityRequirements
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PackRESTSerivce : IRestSerivce
{
//Code implementation goes here
}
主机安全服务
您现在需要托管您的服务。 为此,您将使用从ServiceHost类派生的WebServiceHostfactory类。 如果服务使用 WebHttpBinding,则应该选择WebServiceHostFactory类。 如果您的服务使用其他类型的绑定,您可以简单地使用ServiceHostFactory来托管该服务。
要托管安全服务,请创建一个控制台应用,并添加对以下程序集的引用:
- 系统。 ServiceModel
- System.ServiceModel.Description
- System.ServiceModel.Web
接下来,创建WebServiceHostfactory类的实例,并将基址和服务类型名称作为参数传递:
Uri baseAddress = new Uri("http://localhost/SecurityService");
WebServiceHost host = new WebServiceHost(typeof(SecurityService), baseAddress);
现在需要为 RESTful 服务指定服务端点和服务调试行为。 下面是完整的源代码:
using System;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
using System.ServiceModel;
using Packt.Services.SecurityService;
namespace Packt.ServiceHost
{
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost/SecurityService");
using (WebServiceHost host = new WebServiceHost(typeof(SecurityService), baseAddress))
{
ServiceEndpoint serviceEndpoint = host.AddServiceEndpoint(typeof(ITestService), new WebHttpBinding(), "http://localhost/PacktServices/SecurityService.svc");
ServiceDebugBehavior serviceDebugBehavior = host.Description.Behaviors.Find<ServiceDebugBehavior>();
serviceDebugBehavior.HttpHelpPageEnabled = false;
host.Open();
Console.WriteLine("The SecurityService is ready...");
Console.WriteLine("Press enter to terminate...");
Console.ReadLine();
host.Close();
}
}
}
}
总结
在本章中,我们探讨了 WCF、WCF 绑定和 WCF 安全性。 我们还设计了安全数据库,并在创建的数据库之上创建了 RESTful 服务。 既然已经创建了 RESTful 服务,我们将在下一章探讨如何使用该服务。
四、使用 RESTful 服务
在本章中,我们将讨论如何使用不同的客户端使用 RESTful 服务来执行 CRUD 操作。
在本章中,我们将涵盖以下几点:
- 理解 Ajax
- JSON 和 jQuery 简介
- 语言集成查询(LINQ)概述
- 消费安全服务
- 使用一个 ASP。 网客户端
- 使用一个 ASP。 净 MVC 客户
- 使用 WPF 客户端
在讨论如何使用 WCF RESTful 服务之前,让我们先快速看一下 LINQ,因为在本书中我们将使用它来查询数据。
理解 AJAX
异步 JavaScript 和 XML(AJAX)是一种技术,用于构建具有快速响应用户界面的应用。 AJAX 可以用来显著减少网页回发,从而产生更好的响应时间。 你不仅可以使用 AJAX 来减少页面点击率,还可以将网页的一部分提交给 web 服务器,以减少网络流量。
注意事项
注意,不显眼的 AJAX 是 AJAX 的最新发展。 这个版本的 AJAX 清晰地分离了行为(JavaScript)、内容(HTML)和表示(CSS),甚至在浏览器中关闭 JavaScript 时也可以工作。 不显眼的 AJAX 帮助您的 web 应用工作,无论 JavaScript 是否关闭在您的 web 浏览器。 它甚至可以在手机、屏幕阅读器或网络上运行。
组成 AJAX 的技术如下:
- XMLHttpRequest:
XMLHttpRequest对象用于服务器和客户端之间的数据交换。 几乎所有的现代浏览器都有一个内置的XMLHttpRequest对象。 - JavaScript:这是一种解释性的、基于原型的脚本语言,它支持动态类型,允许客户端脚本与 web 浏览器中的控件交互。
- DHTML:这是一组技术,可用于创建交互式、直观和动态的用户界面。 它也被称为动态 HTML。
- DOM:文档对象模型(DOM)是一个跨平台的、独立于语言的标准 API,用于表示对象在 HTML、XHTML 和 XML 文档。****
******* XML:Extensible Markup Language(XML)是一种灵活的基于文本的标记语言,提供了定义文档编码规则的标准。******
****使用 AJAX 的优势是:
- 提高响应能力
- AJAX 帮助我们发送小的有效载荷
- 异步处理和减少网络流量
- 平台和架构中立
跨源资源共享(CORS)是一个的概念,它允许将 AJAX 请求发布到与客户端域不同的域。 现在的浏览器,如 Internet Explorer 8+、Firefox 3.5+、Safari 4+和 Chrome 都支持 CORS。 您可以通过http://www.bennadel.com/blog/2327-Cross-Origin-Resource-Sharing-CORS-AJAX-Requests-Between-jQuery-And-Node-js.htm了解更多关于 CORS 的内容。
AJAX 严重依赖于 JavaScript,因此为使用 AJAX 的应用提供多浏览器支持是一个挑战。 此外,由于大量使用 JavaScript,使用 AJAX 会使你的网页难以调试,并容易受到安全威胁。
介绍 JSON 和 jQuery
JavaScript 对象表示法(JSON)是一种基于开放标准的轻量级文本,用于数据交换。 您可以使用 JSON 数据格式在 Web 上序列化和传输数据。 注意,JSON 起源于 JavaScript,并使用两个数据结构表示——有序列表和名称/值对。 www.json.org提供了以下定义:
JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。 人类很容易读和写。 机器很容易解析和生成它。 它基于 JavaScript 编程语言的一个子集,标准 ECMA-262 第三版- 1999 年 12 月。 JSON 是一种完全独立于语言的文本格式,但它使用 C 族语言(包括 C、c++、c#、Java、JavaScript、Perl、Python 等)的程序员所熟悉的约定。 这些属性使 JSON 成为一种理想的数据交换语言。
下面的代码片段演示了如何调用toJSONString()方法将字符串转换为其等效的 JSON 表示:
var myObject = new Array();
myObject.push("Joydip Kanjilal");
myObject.push("Prakash Nagar");
myObject.push("Begumpet");
myObject.push("Hyderabad");
myObject.push("500016");
alert(myObject.toJSONString());
请注意,如果您的 web 浏览器不支持 JSON,您将从前面的代码片段中获得所需的输出。
jQuery 现在是一个成熟的 JavaScript 库。 它是一个开源的、跨浏览器的 JavaScript 库。 您可以使用 jQuery 来简化事件处理和动画。 需要指出的是,jQuery 是由 John Resig 在 2006 年发布的。 从那时起,这个 jQuery 库已经成熟了很多,现在在世界范围内广泛流行和接受。 jQuery 还支持扩展点——您可以通过附加一个插件来扩展这个库。 jQuery 官方网站声明如下:
jQuery 是一个快速而简洁的 JavaScript 库,它简化了 HTML 文档遍历、事件处理、动画和 AJAX 交互,用于快速 web 开发。 jQuery 旨在改变编写 JavaScript 的方式。
jQuery 的主要特点如下:
- 浏览器兼容性:这是一个特性,它允许应用的用户界面在多个浏览器中以相同的方式运行
- 简化事件处理模型:这是一个特性,它提供了基于 DOM 元素的统一和简化的事件处理模型,可以无缝地在每个常用和实现的浏览器事件上注册事件处理程序
理解语言集成查询(LINQ)
语言集成查询(LINQ)是作为 c# 3.0 库的一部分引入的查询转换管道。 它是一种融入语言本身的语言。 它是 c#的扩展,并提供了一个以强类型和面向对象的方式访问关系数据的简化框架。 您甚至可以使用 LINQ 从其他数据源(xml、对象和集合)查询数据。
业务线(LOB)应用是数据驱动的,它们主要依赖于数据上的 CRUD(创建、读取、更新和删除)操作。 构建 orm 时考虑到这一点,并通过提供数据一致性和数据完整性来提供一种简单的方法来访问数据库。 与一些了不起的特性,比如支持匿名方法,计数器和产量,lambda 表达式,扩展方法,和匿名类型,LINQ 基本上是一种领域特定语言(DSL【显示】)c#或者 VB.NET。 对于 IQueryable, IEnumerable, Func delegate,以及 lambda 表达式的支持在. net Framework 的新版本中都起到了很大的作用。****
LINQ 是 c#和 VB新版本的一部分.NET**编译器,并且它附带了一组强大的操作符来简化查询不同数据源的任务,例如 SQL Server 和 XML。
查询语言是用于查询应用中的数据的语言。 在 LINQ 出现之前,我们使用 PL-SQL 和 T-SQL 从数据库中查询数据。 然而,它们都不是类型安全的,而且它们也没有编译时检查来验证语句在编译时是否正确。 在 LINQ 中,我们有编译时检查和类型安全; 因此,您的查询将在编译时验证其准确性!
LINQ 是一个新的有用特性,作为 c# 3.0 的一部分可用,它允许您将查询集成到您的程序中。 它是 c#语言的一个扩展,并为以强类型和面向对象的方式访问关系数据提供了一个简化的框架。 除了类型安全和在编译时检查查询的能力之外,您还可以轻松调试 LINQ 查询—这确实是一个非常重要的特性。 应该注意的是,Visual Studio 对 LINQ 代码的调试支持有一些限制。 例如,不支持“编辑并继续”; 不允许在调试模式下进入谓词代码,并且被编译到表达式树的代码不在调试器的控制范围内。
LINQ 提供了对延迟加载、编译查询和扩展方法的支持。 扩展方法,顾名思义,就是那些允许您为现有类型提供扩展的方法。 这使您能够向现有类型添加新方法,而不需要创建新的派生类型。 一种可拓方法的实例如下:
public static class EmployeeExtensions
{
public IQueryable<T> IsActive<T>(this IQueryable<T> source)
where T : Employee
{
return source.Where(e => (e.JoiningDate < DateTime.Now)&& (e.LeavingDate == DateTime.Now)&& e.IsActive == true);
}
}
注意事项
不过,有一种方法可以调试谓词代码。 您可以做的是用对包含谓词代码的方法的调用替换谓词代码,也就是说,通过创建包装器方法。
LINQ 库包含以下重要的命名空间:
System.Linq:这个名称空间提供了一组类和接口来支持 LINQ 查询System.Data.Linq:这个名称空间提供了一组用于与关系数据库交互的类和接口
数据源控件
数据源控件的作用类似于数据源和数据绑定控件之间的一个层。 数据绑定控件可以是在使用数据源控件所绑定到的数据源控件所提供的数据服务时实际与最终用户交互的任何控件。 它定义了某些方法和属性,用于执行特定于数据的操作,例如在提取数据源时对数据源上的数据进行插入、删除、更新和选择。 下面是随 ASP 附带的各种数据源控件.NET 4.0。
ObjectDataSource
ObjectDataSource 控件适用于内存中的集合。 它定义了属性,如InsertMethod、DeleteMethod、UpdateMethod和SelectMethod,这些属性执行基本的数据存储和检索操作。 必须创建适当的方法并映射到这些属性以执行所需的任务。 当使用这些属性之一时,ObjectDataSource 控件实际上创建实例并调用适当的方法,并且在完成执行阶段后立即销毁该实例。 ObjectDataSource 通常用于应用的业务层,它帮助您直接绑定到表示层上的数据绑定控件。
SqlDataSource
SqlDataSource 控件允许您对关系数据库中持久化的数据执行标准的数据操作,例如插入、更新、删除和选择。 SqlDataSource 控件不仅适用于 SQL Server 数据库,而且可以用于任何托管 ADO.NET 提供程序,这意味着您可以对不同的关系数据源使用 SqlDataSource 控件。 SqlDataSource 控件定义了一些属性,如InsertCommand、DeleteCommand、UpdateCommand和SelectCommand,用于对数据执行标准的数据操作,如插入、删除、更新和选择。 在使用命令属性之前,需要设置适当的查询。 当连接到 SqlDataSource 控件的数据控件被更新时,SqlDataSource 控件将为所有列创建更新参数,尽管只更新了少数列。 该控件还支持缓存功能,这有助于提高应用的性能。
SiteMapDataSource
SiteMapDataSource 控件允许您绑定网站的站点地图。 站点地图可以代表一个层次结构。 SiteMapDataSource 控件需要在给定的层次结构中指定适当的根节点。 SiteMapDataSource 控件包含允许您指定节点位置的属性。 SiteMapDataSource 控件主要用于数据导航,这意味着您不能执行标准的数据操作,例如数据的插入、更新、删除、排序和分页。
XMLDataSource
XmlDataSource 控件是另一种数据源控制。 基本上,它表示 XML 形式的数据。 通过将控件连接到 XML 文件或 XML 数据,您可以从 XmlDataSource 控件访问 XML 数据,该 XML 文件或 XML 数据作为字符串嵌入在数据源控件中。 默认情况下,XmlDataSource 控件中的缓存是启用的,以提高性能。 您可以对 XmlDataSource 控件表示的 XML 数据执行标准的数据操作,例如插入、删除、更新和选择。 但是,XmlDataSource 控件不支持排序和分页等操作。 该控件还支持通过 XML 样式表应用 XML 转换。
LinqDataSource
LinqDataSource 控件是在 ASP 中引入的一个新的控件.NET 3.5。 它扩展了 DataSourceControl 并驻留在System.Web.UI.WebControls命名空间中。 它提供了一种将 LINQ 模型绑定到 ASP 中的 web 控件上的新方法。 网络应用。 LinqDataSource 控件提供属性和事件,您可以使用这些属性和事件执行操作,例如选择、筛选、分组和排序 LINQ 数据源。
LinqDataSource 数据控件提供了一种灵活的机制来使用基于向导的工作流构建数据控件。 它允许您在 LINQ 模型上对数据执行 CRUD 操作,而不需要编写 SQL 查询。
无论您使用什么数据源,语法都是相同的。 不需要为选择、删除、更新和插入操作定义查询。
LINQ 提供了统一数据模型的概念; 您所要做的就是专注于您的逻辑,因为 LinqDataSource 控件会根据您的需要自动创建必要的命令。
下面的代码示例展示了使用 LinqDataSource 控件的语法:
<asp:LinqDataSource ID="ldsPurchaseOrderDetails" runat="server" ContextTypeName=" AdventureWorksDataContext" TableName="PurchaseOrderDetails" Select="new (ProductID, UnitPrice, StockedQty)">
</asp:LinqDataSource>
在前面的代码片段中,ContextTypeName表示DataContext类。 注意,在 Visual Studio 2013 IDE 中使用 LINQ to SQL 设计器创建数据模型时,会自动创建DataContext类。 属性指的是PurchaseOrderDetail类型的集合。 Select属性提取出一个新的匿名类型,其中包含ProductID、UnitPrice和StockedQty属性。 与前面的数据源控件结合使用,可以使用诸如DetailsView、GridView或ListView等数据控件来绑定数据。 一个表示 GridView 数据源到 LinqDataSource 控件绑定机制的简单语法如下:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ldsPurchaseOrderDetails">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" ReadOnly="True" SortExpression="UnitPrice" />
<asp:BoundField DataField="StockedQty" HeaderText="StockedQty" ReadOnly="True" SortExpression="StockedQty" />
</Columns>
</asp:GridView>
下面的例子展示了如何使用 LinqDataSource 控件将内存中的对象绑定到 DropDownList 控件:
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="Packt.Customer" TableName="FirstNames"></asp:LinqDataSource>
<asp:DropDownList DataSourceID="LinqDataSource1" runat="server" ID="DropDownList1"></asp:DropDownList>
在Default.aspx.cs文件中,我们将创建一个名为Customer的类。 类表示如下:
public class Customer
{
List<string> names = new List<string>();
public Customer()
{
names.Add("Joydip");
names.Add("Sriram");
names.Add("Sandeep");
names.Add("Ramesh");
names.Add("Sandy");
names.Add("John");
}
public List<string> FirstNames { get { return names; } }
}
下面的图说明了 LINQ 的架构:

LINQ 到 XML
“LINQ to XML”将您的 LINQ 查询或 LINQ 语句映射到相应的 XML 数据源。 它帮助您使用 LINQ 标准查询操作符来检索 XML 数据。 LINQ to XML 通常被称为 XLINQ。 您还可以使用 LINQ 无缝地查询内存中的集合和业务实体(包含与特定实体相关的数据的内存对象)。
System.XML.Linq命名空间提供了对 LINQ to XML 的支持。 下面是一个例子,说明如何使用 LINQ to XML 来创建一个数据文档:
public static void CreateEmployeeDataSheet()
{
XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),new XComment("Employee Data Sheet"),new XElement("employees",new XElement("Employee",new XAttribute("ID", 1),
new XAttribute("Salaried", "false"),new XElement("First Name", "Joydip"),new XElement("Last Name", "Kanjilal"),new XElement("Joining Date", "02/01/2013")),new XElement("Employee",new XAttribute("ID", 1),new XAttribute("Salaried", "false"),new XElement("First Name", "Peter"),new XElement("Last Name", "Ward"),new XElement("Joining Date", "07/01/2013"))
)
);
}
LINQ 到 SQL
与 XLINQ(用于查询 XML 文档)类似,还有 DLINQ,它是 LINQ 的一个实现,允许您查询数据库。 LINQ to SQL,或者 DLINQ,实际上是一个非常简单的 ORM 工具。 它不是一个完整的 ORM 工具,因为它缺乏 ORM 所具有的一些特性。 它不支持状态管理和数据生成。
注意事项
要在程序中使用 LINQ,必须添加对System.Core.dll的引用,并在using语句中指定System.Linq命名空间。
LINQ 到对象
LINQ to Objects 是 LINQ 的另一种风格,用于查询内存中的对象集合。 注意,LINQ to Objects 与内存中的T:System.Collections.IEnumerable或T:System.Collections.Generic对象或一组对象一起工作。 注意,LINQ to Objects 是隐含在 LINQ 中的一部分; 它是。net 框架新版本的一部分。 将 LINQ 写入对象查询时,不需要指定任何单独的名称空间。
LINQ 到实体
ADO.NET 实体框架是一种类型的 ORM。 它是一个在关系或逻辑模型之上提供抽象层的开发平台。 这样做,它将应用的对象模型与数据在关系存储中的实际存储方式隔离开来。 开发人员可以使用 ADO.NET 实体框架来针对对象模型编程,而不是逻辑或关系模型。
这个抽象级别是使用实体数据模型(EDM)——一个扩展的实体关系模型来实现的。 EDM 减少了域对象模型对正在使用的数据存储的数据库模式的依赖。 开发人员可以使用 ADO.NET Entity Framework 来处理特定于领域的属性,例如员工姓名、员工地址和联系方式,而不必关心实际数据如何在底层数据存储中存储和表示。 框架可以处理从数据存储中检索数据或执行插入、更新和删除所需的转换。
LINQ to Entities 用于查询 EDM 公开的数据。 LINQ to Entities 允许您以强类型的方式查询业务对象。 您可以使用它从概念数据模型(即 EDM)查询业务对象或业务对象集合。 LINQ to Entities 使用 ObjectServices 从 EDM 查询数据。
实体使用对象服务基础设施从概念模型中查询数据。 ObjectContext和ObjectQuery类是使用 LINQ to Entities 时使用的两个最重要的类。 类用于组成一个ObjectQuery实例。 泛型ObjectQuery类实际上表示一个实体或类型化实体实例的集合。 应该注意的是,LINQ 到 Entities 的查询在内部被转换为规范查询树。 然后,底层数据库在内部以预定义的形式将这些查询转换为相应的 SQL 查询。
LINQ 与实体和实体框架之间的关系如下图所示:

使用 LINQ 中的服务操作
服务操作是可以通过数据服务调用的方法,这些方法与实体集具有相同的可见性。 类支持通过数据服务公开的用户定义方法。 为此,我们需要为该函数设置一个WebGet属性,并在数据服务的数据服务配置中设置访问规则。
下面的代码片段演示了一个DataService类:
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class GenericCollections : DataService<AddressSet>
{
[WebGet]
public IQueryable<Address> GetAddresssByCity(string City)
{
var addressquery = from addr in this.CurrentDataSource.Addresses
where addr.City.Equals(City)
select addr;
return addressquery;
}
public static void InitializeService(IDataServiceConfiguration config)
{
config.UseVerboseErrors = true;
config.SetEntitySetAccessRule("Addresses", EntitySetRights.AllRead);
config.SetServiceOperationAccessRule("GetAddresssByCity", ServiceOperationRights.All);
}
}
这里,我们有使用IQueryable<T>接口,以便该方法可以返回类型为 T 的IQueryable集合,其中 T 是一个类。 [WebGet]属性允许在HTTP GET操作中访问该方法。 此外,GenericCollections 类上的类属性[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]将显示堆栈跟踪,以防在执行时遇到任何异常。
下面的代码片段展示了如何查询数据服务公开的数据:
protected void Page_Load(object sender, EventArgs e)
{
System.Data.Services.Client.DataServiceContext dataServiceContext = new DataServiceContext(new Uri("http://localhost:2490/GenericCollections.svc"));
IEnumerable<Address> addresses =dataServiceContext.Execute<Address>(new Uri("http://localhost:2490/GenericCollections.svc/Addresses"));
var addressquery =from address in addresses
where address.City.StartsWith("S")
select address;
foreach (var address in addressquery)
{
Response.Write(string.Format("{0}<BR/>{1}<BR/>{2}<BR/><BR/>", address.AddressID, address.AddressLine,address.City));
}
}
LINQ to SQL 允许您创建映射到关系数据库中的表的对象模型。 LINQ 到 SQL 的对象关系映射实现处理 SQL 查询的执行策略。 数据库标记语言文件,也称为.dbml文件,是由 Visual Studio IDE 在从 LINQ 设计界面上的解决方案资源管理器拖放数据库表到 SQL 设计界面时生成的。 将每个表拖到设计图面上时,将为每个表创建一个类。 这些类称为实体类,是部分类。 它们包含一组允许添加自定义实现的分部方法。 实体类的对象称为实体。 关联由 LINQ to SQL 设计器根据底层表关系自动创建。
主键和外键之间的实体关系由 LINQ to SQL 组件自动表示为对象关系。 当关系数据库中的表和列发生更改时,LINQ 提供的映射到 SQL 的方案提供了较少的管理任务。 只需更新映射规则,而无需更改应用中的代码。
AdventureWorksDataContext类(在 Visual Studio 2012 中使用 LINQ to SQL 设计器创建)看起来像以下代码:
[System.Data.Linq.Mapping.DatabaseAttribute(Name="AdventureWorks")]
public partial class AdventureWorksDataContext : System.Data.Linq.DataContext
注意事项
注意,它使用一个指定数据库名称的DatabaseAttribute类。 该类还定义了几个重载的构造函数,可用于适当的原因。
LINQ 对 SQL 的优势
与其他 ORM 工具相比,LINQ to SQL 基本的优势包括:
- 开发非 linq -to- sql 的以数据为中心的应用可能要花费大量的时间和精力来构建将与数据源交互的自定义组件。 LINQ to SQL 映射表到类; 这有助于架构师设计更好的 n 层架构,从而提高生产力。
- 实体类中的属性通过适当的数据类型映射方案映射到表中的列。 因此,执行编译时检查,减少运行时错误。
- 对于开发人员来说,另一个额外的好处是 Visual Studio IDE 在使用 LINQ 到 SQL 应用时提供的智能感知。
安全服务
下面是我们将要使用的安全服务的完整代码。
下面的代码片段演示了ISecurityService接口。 这是服务合同。
[ServiceContract]
public interface ISecurityService
{
/// <summary>
/// GetAllUsers operation contract
/// </summary>
/// <returns></returns>
[OperationContract]
List<UserAuthentication> GetAllUsers();
/// <summary>
/// GetUserByID operation contract
/// </summary>
/// <param name="userID"></param>
/// <returns></returns>
[OperationContract]
List<UserAuthentication> GetUserByID(Int32 userID);
}
下面的SecurityService类实现了ISecurityService接口:
public class SecurityService : ISecurityService
{
/// <summary>
/// GetAllUsers service method
/// </summary>
/// <returns>An instance of List<UserAuthentication></returns>
public List<UserAuthentication> GetAllUsers()
{
using (RepositoryBase<SecurityEntities> repository = new RepositoryBase<SecurityEntities>("SecurityEntities"))
{
return repository.Select<UserAuthentication>().ToList<UserAuthentication>();
}
}
/// <summary>
/// GetUserByID service method
/// </summary>
/// <param name="userID">userID as Int32</param>
/// <returns>An instance of List<UserAuthentication></returns>
public List<UserAuthentication> GetUserByID(Int32 userID)
{
using (RepositoryBase<SecurityEntities> repository = new RepositoryBase<SecurityEntities>("SecurityEntities"))
{
return repository.Select<UserAuthentication>().Where( x => x.UserID == userID).ToList<UserAuthentication>();
}
}
}
使用安全服务
在本节中,我们将探索如何使用 ASP 使用SecurityService类。 净和 ASP。 净 MVC。
净
微软的 ASP.NET 4.5 是最近最流行的 web 技术之一。 ASP.NET 是建立在公共语言运行时(CLR)之上的 web 应用开发框架,您可以使用它在托管平台上构建和部署 web 应用和动态网站。
使用 ASP 实现安全服务的消费.NET 4.5
下面的代码片段演示了如何从 ASP 中消费SecurityService类.NET 客户端:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindUserDropDownList();
BindGrid();
}
}
protected void BindGrid()
{
SecurityService serviceObj = new SecurityService();
var userData = serviceObj.GetAllUsers();
if (userData.Count > 0)
{
grdUser.DataSource = userData;
grdUser.DataBind();
}
}
protected void BindGrid(Int32 userId)
{
SecurityService serviceObj = new SecurityService();
var userData = serviceObj.GetUserByID(userId);
if (userData.Count > 0)
{
grdUser.DataSource = userData;
grdUser.DataBind();
}
}
protected void BindUserDropDownList()
{
SecurityService serviceObj = new SecurityService();
var userData = serviceObj.GetAllUsers();
if (userData.Count > 0)
{
ddlUser.DataSource = userData;
ddlUser.DataTextField = "UserName";
ddlUser.DataValueField = "UserID";
ddlUser.DataBind();
}
ListItem li = new ListItem("All", "0");
ddlUser.Items.Insert(0, li);
}
protected void ddlUser_SelectedIndexChanged(object sender, EventArgs e)
{
if (ddlUser.SelectedValue == "0")
{
BindGrid();
}
else
{
BindGrid(Convert.ToInt32(ddlUser.SelectedValue));
}
}
}
当你执行 ASP。 在。NET 客户端应用中,的输出如下截图所示:

ASP。 净 MVC 框架
模型视图控制器(MVC)设计模式由 Trygve Reenskaug 发明,并由 Ruby on Rails 框架推广。 微软的 Scott Guthrie 实际上设计了 ASP.NET MVC 框架 2007 年。 ASP.NET MVC 框架是基于流行的模型视图控制器设计模式的应用框架。 通过隔离应用中的关注点,它有助于减少组件之间的内聚性。
使用 MVC 设计模式有以下好处:
- 使您的代码更容易测试、维护和部署
- 促进代码重用、可维护性和可测试性
MVC 设计模式由以下几个主要组件组成:
- 模型:它是数据访问层,代表业务逻辑组件和应用的数据
- 视图:它是用户界面或应用
- 控制器:它是业务逻辑层,它处理用户交互并在需要时更新模型
MVC 设计模式最重要的好处是它能够促进关注点的清晰分离。 这样,基于 MVC 模式设计的应用就更容易测试和维护。
您可以使用 MVC 设计模式来促进代码重用,降低应用组件之间的内聚性,并简化应用组件的维护和测试。 ASP.NET MVC 框架是在 MVC 框架的基础上设计的,有望成为用 ASP 设计 web 应用的首选技术。 这主要是由于它对传统 asp.net 的特性进行了改进。 网运行时。 你可以了解更多关于 ASP。 asp.net MVC 框架和 MVC 设计模式来自我的书《ASP。 Mc-Graw Hill Publishingathttp://www.amazon.com/ASP-NET-4-0-Programming-Joydip-Kanjilal/dp/0071604103. NET 4.0 编程 byMc-Graw Hill Publishing
使用 ASP 实现安全服务的消费.NET MVC
HomeController类扩展了 ASP 的控制器类。 净 MVC 框架。 它包含一组操作方法。
我们在HomeController类中创建了SecurityService类的实例。 在Index()操作方法中,GetAllUsers()方法在UserAuthenticationModel实例上调用。 userList()方法以Json类型返回用户列表。
下面的代码演示了 asp.net 的控制器类.NET MVC 的客户:
public class HomeController : Controller
{
SecurityService serviceObj = new SecurityService();
public ActionResult Index()
{
UserAuthenticationModel userModel = new UserAuthenticationModel();
ViewBag.ListUser = new SelectList(serviceObj.GetAllUsers().ToList(), "UserID", "UserName");
return View(userModel);
}
private IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder)
{
if (string.IsNullOrWhiteSpace(fieldName)) return data;
if (string.IsNullOrWhiteSpace(sortOrder)) return data;
var param = Expression.Parameter(typeof(T), "i");
Expression conversion = Expression.Convert(Expression.Property(param, fieldName), typeof(object));
var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param);
return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression)
: data.OrderBy(mySortExpression);
}
public JsonResult UserList(string id, string sidx = "UserId", string sord = "asc", int page = 1, int rows = 10)
{
var userData = serviceObj.GetAllUsers().AsQueryable();
if (id != null)
{
userData = serviceObj.GetUserByID(Convert.ToInt32(id)).AsQueryable();
}
var sortedDept = SortIQueryable<DataAccess.UserAuthentication>(userData, sidx, sord);
var totalRecords = userData.Count();
var totalPages = (int)Math.Ceiling((double)totalRecords / (double)rows);
var data = (from s in userDataselect new
{
id = s.UserID,cell = new object[] { s.UserID, s.UserName, s.UserEmail, }
}).ToArray();
var jsonData = new
{
total = totalPages,page = page,records = totalRecords,rows = data.Skip((page - 1) * rows).Take(rows)
};
return Json(jsonData);
}
}
当 ASP.NET MVC 客户端应用被执行,输出将如下截图所示:

异步操作
异步操作帮助异步地执行操作,因此利用了当今并行处理器的灵活性。 异步操作在。net 4.5 中使用。net Framework 4.5 和 MVC 4 中的Task对象来执行。 .NET 4.5 的异步编程模型是建立在现有的 NET 4.0 异步编程模型之上的,它允许您编写返回Task类型对象的方法。 本质上,await和async关键字以及Task对象使得在。net 4.5 中编写异步代码更加容易。 这个模型也被称为任务异步模式(TAP)。 该模式的一个示例如下:
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadData));
}
public async Task LoadSomeData()
{
var employees = Client.DownloadStringTaskAsync("api/employees");
var departments = Client.DownloadStringTaskAsync("api/departments");
var cities = Client.DownloadStringTaskAsync("api/cities");
await Task.WhenAll(employees, departments, cities);
var employeeData = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await employees);
var departmentData = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await departments);
var cityData = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await cities);
listEmployees.DataSource = employees;
listEmployees.DataBind();
}
您也可以在 ASP 中实现异步操作。 asp.net MVC 框架使用异步控制器。 为此,您应该从抽象AsyncController类扩展您的控制器。
下面的代码显示了AsyncController类的外观:
public abstract class AsyncController : Controller, IAsyncManagerContainer, IAsyncController, IController
{
protected AsyncController();
public AsyncManager AsyncManager { get; }
protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state);
protected virtual IAsyncResult BeginExecuteCore(AsyncCallback callback, object state);
protected override IActionInvoker CreateActionInvoker();
protected virtual void EndExecute(IAsyncResult asyncResult);
protected virtual void EndExecuteCore(IAsyncResult asyncResult);
}
注意事项
注意,AsyncManager类属于System.Web.Mvc.Async名称空间,并且为AsyncController类提供了必要的操作。
你可以通过从AsyncController类派生你的自定义控制器类来编写你的控制器,如下代码所示:
public class HomeController : AsyncController
{
//Usual code
}
这里需要注意的重要的点是,异步控制器类的名称应该带有“controller”后缀。 因此,Home controller类可以命名为HomeController,但不能命名为“Home”或“ControllerHome”。 这里要注意的另一个有趣的点是,您不能将同一方法的同步和异步版本驻留在同一个控制器中。
因此,您不能让Index()和IndexAsync()方法同时驻留在 Index 控制器类中。 如果这样做,将抛出一个AmbiguousMatchException异常。
下面的代码片段演示了一个同步控制器及其动作方法:
public class ProductsController: Controller
{
public ActionResult GetProducts(int productCode)
{
//Usual code
}
}
下面的代码片段演示了一个异步控制器及其动作方法:
public class ProductsController: AsyncController
{
public ActionResult GetProducts(int productCode)
{
//Usual code
}
}
一个异步操作由一对方法组成,它们应该分别具有“async”和“Completed”后缀。 下面的代码片段说明了这一点:
public class HomeController : AsyncController
{
public void GetProductsAsync()
{
//Some code
}
public ActionResult GetProductsCompleted(IList<Product> items)
{
//Some code
}
}
注意事项
注意,虽然这些 api 仍然受到支持,但使用新的“async/await”关键字和Task对象是在您的 ASP 中实现异步行为的推荐方法.NET 4.5 的应用。
当你定义异步处理请求的路由时,你应该使用AsyncMvcRouteHandler而不是通常的MvcRouteHandler,如下代码片段所示:
routes.Add(new Route("Default.aspx", new AsyncMvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
});
了解 Windows 演示基础
Windows Presentation Foundation (WPF),原代码——名叫“阿瓦隆”,是最广受欢迎的组件添加到新版本的 Microsoft . net 框架设计和开发 Windows 应用,它可以提供具有极强的视觉冲击力和丰富的用户界面。****
**下面的代码片段演示了 WPF TextBox 控件的典型 XAML 代码:
<TextBox SpellCheck.IsEnabled="True" Language="en-US" />
下面的代码片段可以用于验证用户输入,并根据我们指定的地区(即US)检查拼写。
protected override void OnTextInput(TextCompositionEventArgs e)
{
string data = Text.Remove(SelectionStart, SelectionLength) + e.Text;
if (_regex != null && !_regex.IsMatch(data))
{
e.Handled = true;
}
else
{
base.OnTextInput(e);
}
}
WPF 是一个图形子系统,是。net Framework 最新版本的一部分。 顺便提一下,WPF 是在。net Framework 3.0 中引入的。 WPF 使您能够创建富 UI 外观的应用,并设计富用户界面、媒体、矢量图形等的应用。 XAML 提供了对 WPF 的声明性触摸。 但是,应该注意的是,XAML 并不是 WPF 或. net 特有的,而且该标准也被许多其他技术所使用。
使用 WPF 使用安全服务
下面的代码演示了将使用SecurityService类的 WPF 客户机的 XAML 标记。 我尽可能地使它简单——只用一个 Grid 控件来显示用户数据。
<Grid>
<DataGrid Name="dataGrid1" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding UserID}" Header="User ID" IsReadOnly="True" x:Name="dgrUserID">
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding UserName}" Header="User Name" IsReadOnly="True" x:Name="dgrUserName">
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding UserEmail}" Header="User Email" IsReadOnly="True" x:Name="dgrUserEmail">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
请参考以下代码片段中给出的MainWindow类。 满足方法的BindData()将用于使用 SecurityService 将数据绑定到 WPFDataGrid类。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
BindGrid();
}
protected void BindGrid()
{
SecurityService serviceObj = new SecurityService();
var userData = serviceObj.GetAllUsers();
if (userData.Count > 0)
{
dataGrid1.ItemsSource = userData.ToList();
}
}
}
下图展示了上述程序的输出结果:

参考文献
- http://www.json.org/
- http://json.codeplex.com/
- http://weblogs.asp.net/scottgu/archive/2007/10/14/aspnet-mvc-framework.aspx
总结
在本章中,我们探讨了如何使用不同的客户机(即 ASP. net)来使用SecurityService类。 净,ASP.NET MVC 和 WPF 客户端。 在下一章中,我们将探讨 ASP 的新特性。 并使用 asp.net 4.5 构建应用。 净 Web API。********
五、使用 ASP.NET 4.5
在本章中,我们将讨论 asp.net 的新特性.NET 4.5,并探索我们如何使用 asp.net 4.5。 净 Web API。 ASP.NET Web API 是一种轻量级的替代方法,就像 WCF 一样,它使用 HTTP 作为应用协议。
在本章中,我们将涵盖以下几点:
- 使用 OData 协议
- 微软。net Framework 4.5 的新特性
- ASP 的新特性和增强.NET 4.5
- 使用 ASP。 净 Web API
使用 OData 协议
开放数据协议(OData)是一个协议,它建立在 HTTP、Atom 和 JSON 等 web 标准之上,规范了数据的公开和消费方式。 它是一种数据访问协议,提供了对数据执行 CRUD 操作的统一方式。 它用于暴露和访问来自不同数据源的信息; 也就是说,关系数据库、文件系统、内容管理系统等等。 OData 是建立在核心协议(如 HTTP)和架构范例(如 REST)之上的标准化协议。 与 RSS 一样,Atom 也是一种公开提要的方法。 请注意,AtomPub 使用了 GET、POST、PUT 和 DELETE 等 HTTP 动词来促进数据的发布。
使用 ASP.NET Web API 和 OData
在本节中,我们将探索如何使用 ASP.NET Web API 和 OData。 要安装 Web API OData Controller 模板,右键单击解决方案资源管理器窗口中的Controllers文件夹,然后选择新建 scaffold 项目。 接下来,选择Web API 2 OData Controller与使用实体框架的动作。
使用 ASP.NET Web API 和 OData 遵循以下步骤:
- 打开 Visual Studio 2013 IDE。
- 创建一个新项目并以名称保存它。
- 在解决方案资源管理器中,右键单击并选择新项目。
- 创建一个实体数据模型。
- 配置 OData 路由。
- 实现 OData 控制器。
注意事项
注意,如果您想公开一个符合 OData 协议的端点,您应该从ODataController扩展您的Controller类。 相反,如果您希望有一个 REST 端点,则应该从ApiController扩展您的Controller类。 此外,还可以在非 OData 端点之间宿主多个 OData 端点。
下面的代码片段演示了EmployeeController类的样子:
public class EmployeeController : ODataController
{
List<Employee> _employees = DataStore.Employees;
[Queryable]
public IQueryable<Employee> GetEmployees()
{
return _employees.AsQueryable();
}
public Employee GetEmployee([FromODataUri] int employeeID)
{
return _employees[employeeID];
}
}
[Queryable]属性简化了特定操作上的 OData 查询语法。 你也可以从EntitySetController派生你的控制器类——一个用于公开实体集的基类。
.NET Framework 4.x 的新特性
在本节中,我们将用来看看 Microsoft . net Framework 4 中引人注目的特性。 x。
支持。net Framework 4.x 中的异步编程
异步编程是 Microsoft . net Framework 4.5 中的一个特性,它可以增强应用的整体响应能力。 Visual Studio 2012 内置了对异步编程的支持。 异步任务有助于编写响应性更好的应用,并提供更好的用户体验。
方法调用可以是同步的,也可以是异步的。 在同步方法调用中,方法由当前执行的线程完整地完成。 另一方面,在异步方法调用中,当前执行的线程开始执行方法并立即返回—它不会以任何方式阻塞用户界面。 您可以使用System.Threading.Thread命名空间在 Microsoft . net Framework 中执行同步线程。 同步线程是那些按顺序依次执行的线程。 在同步操作中,两个或多个线程在同一个上下文中运行,因此其中一个线程的执行可能会阻塞另一个线程。
通过关键字async和await可以获得对异步编程的支持。 关键字async和await的使用使您能够无缝地实现异步编程——没有回调、IAsyncResult 等等。 您可以使用这两个关键字来创建异步方法。 注意,异步方法可以有三种可能的返回类型。 这些都是:
Task<TResult>Taskvoid
当针对该特定任务调用await关键字时,该任务的方法将立即挂起,并在任务执行完成后继续执行该方法。
下面是一个代码片段,演示了异步编程如何在 Microsoft .NET Framework 4.5 中实现:
async Task<int> CallWebPagesAsynchronously()
{
HttpClient client = new HttpClient();
Task<string> strTask = client.GetStringAsync("http://joydipkanjilal.com");
DoSomeWork();
string content = await strTask;
return content.Length;
}
介绍 asp.net 的新特性.NET 4.5
ASP.NET 是一种运行在。NET 框架管理环境之上的服务器端技术。 你可以使用 ASP.NET 来构建和部署 web 应用和开发动态网站。 Microsoft . net Framework 是一个托管平台,用于设计和开发可移植、可伸缩和健壮的应用。 微软的 ASP.NET 作为有史以来最成功的 web 应用开发框架之一脱颖而出。 多年来,它已经足够成熟,成为 web 开发人员的首选框架,您可以使用它来开发高度可伸缩的、高性能的 web 应用,利用托管环境的特性。 ASP.NET 4.5 是作为 Visual Studio 2012 的一部分发布的,它包含了许多有趣的新特性。
增强的状态管理特性
ASP.NET 4.5 提供了对改进状态管理特性的支持。 ViewStateMode属性可以更好地控制 ViewState。 注意,该属性可以有三个值之一:Enabled、Disabled 或 Inherit。 您还引入了另一个名为ClientIDMode的新属性。 您可以使用此属性设置服务器控件的 ClientID,并从客户端使用它。 此属性可以具有以下四个值之一:Static、Predictable、Legacy 或 Inherit。
下面的脚本代码演示了如何使用 JavaScript 显示控件的ClientID:
<script type="text/javascript">
function DisplayClientID()
{
alert('<%= myButtonControl.ClientID %>');
}
</script>
下面是一个示例,展示了如何使用ClientIDMode属性:
<asp:Panel ID="pnlFirst" runat="server" ClientIDMode="Static">
下面的代码片段演示了如何使用Predictable模式:
<asp:Content ID="contentObj" ContentPlaceHolderID="contentPlaceHolderObject" Runat="server">
<asp:Panel ID="ParentPanel" runat="server" ClientIDMode="Static">
<asp:Panel ID="ChildPanel" runat="server" ClientIDMode="Predictable">
<asp:Button ID="btnSubmit" runat="server"/>
</asp:Panel>
</asp:Panel>
</asp:Content>
如果控件的ClientIDMode设置为Inherit,则控件继承其父控件的ClientIDMode设置。 下面是一个例子:
<asp:Content ID="contentObj" ContentPlaceHolderID="contentPlaceHolderObj"
Runat="Server">
<asp:Panel ID="PanelParent" runat="server">
<asp:Panel ID="PanelChild" runat="server" ClientIDMode="Static">
<asp:Button ID="btnSubmit" runat="server" ClientIDMode="Inherit" />
</asp:Panel>
</asp:Panel>
</asp:Content>
性能监控
ASP.NET 4.5 使您能够监视资源利用。 要启用这种资源监控,你只需要在aspnet.config文件中使用以下配置:
<configuration>
<runtime>
<appDomainResourceMonitoring enabled="true"/>
</runtime>
</configuration>
可扩展输出缓存
ASP。 净 4。 x,输出缓存已经改进了很多。 输出缓存是一个特性,它允许您存储您的 ASP 的输出.NET 网页缓存,以便后续对同一网页的请求可以从内存缓存中获取。 通过这样做,对于包含相对陈旧数据的 web 页面,应用的性能可以在很大程度上得到改善。
ASP。 净 4。 x,您有一个名为可扩展输出缓存的特性,您可以使用它向输出缓存添加扩展点。 您现在还可以管理和配置一个或多个自定义输出缓存提供程序。 这里是缓存存储的 ASP。 净 4。 xCache API 支持:
- 基于磁盘的输出缓存
- 自定义对象缓存
- 分布式对象缓存
- 基于云计算的对象缓存
要配置自定义的输出缓存提供程序,你需要做的就是在应用的web.config文件中指定以下内容:
<caching>
<outputCache defaultProvider="Packt.CustomCacheProvider">
<providers>
<add name="DiskCache"
type="Packt.CustomCacheProvider, Packt"/>
</providers>
</outputCache>
</caching>
搜索引擎优化
ASP。 净 4。 x为 SEO 提供支持 命名空间提供了通过使用RouteTable和PageRouteHandler类进行路由的支持。 您也可以使用 ASP 中可用的Page Meta Keyword和Description特性来实现 SEO.NET 4.5,如下代码片段所示:
protected void Page_Load(object sender, EventArgs e)
{
this.Page.Title = "Packt";
this.Page.MetaKeywords = "Books";
this.Page.MetaDescription = "Packt Books";
}
其他显著增强
在本节中,我们将重点介绍 ASP 中其他一些显著的增强.NET 4.5:
- Web Sockets:Web Sockets; NET 4.5 包括对 Web Sockets 的全面支持。 HTML5 标准可用 ASP.NET 4.5 通过 SignalR 库在 IIS 8.0 上运行。 这让你可以轻松地将实时网络功能添加到应用中。
- 认证:与 ASP. php NET 4.5,您现在有了一个通用提供者(
DefaultMembershipProvider)。 另外,OAuth 协议也在那里。 OAuth 是一种开放标准,用于授权客户机能够代表资源所有者访问服务器资源。 - Web 发布:InASP. net NET 4.5, Web 发布特性得到了增强——您现在可以比较本地和远程文件,并且只发布您需要的文件。
- Web API:这个 API 包含在 ASP 中.NET 4.5 及其基于 rest 的特性,用于开发和构建 RESTful 应用。 此外,Web API 现在包含了广泛的 OData 支持。
- 利用 IIS 特性: NET 4.5 使您能够利用Internet Information Server(IIS)8.0 中可用的新特性。 这包括预取和应用初始化,比如在启动时 ping 应用。
使用 ASP。 净 Web API
ASP.NET Web API 是一个框架,您可以利用它来构建使用 HTTP 作为协议的 Web 服务。 您可以使用 ASP.NET Web API 根据客户端请求的数据返回数据; 也就是说,您可以返回 JSON 或 XML 作为数据格式。

应用的层
ASP.NET Framework 运行在。NET Framework 的托管环境之上。

模型、视图和控制器(MVC)架构模式是用于分离的担忧一个应用便于检测,减轻维护应用的代码的过程,并提供更好的支持变化。 模型表示应用的数据和业务对象; 视图是表示层组件,控制器将模型和视图绑定在一起。 下图说明了模型视图架构的组成部分:

MVC 架构
ASP.NET Web API 架构
ASP.NET Web API 是一个轻量级的基于 Web 的架构,它使用 HTTP 作为应用协议。 在 ASP 中的路由.NET Web API 的工作方式与它在 ASP 中工作的方式有点不同。 净 MVC。 MVC 中的路由和 Web API 中的路由之间的基本区别是,Web API 使用 HTTP 方法而不是 URI 路径来选择操作。 Web API 框架使用一个路由表来确定针对特定请求调用哪个操作。 您需要在App_Start目录下的WebApiConfig.cs文件中指定路由参数。
下面是一个示例,展示了如何配置路由:
routes.MapHttpRoute(
name: "Packt API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
下面的代码片段演示了如何通过操作名配置路由:
routes.MapHttpRoute(
name: "PacktActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
ASP.NET Web API 生成结构化数据,如 JSON 和 XML 作为响应。 它可以根据 HTTP 谓词(而不仅仅是操作名称)将传入请求路由到操作。 同时,ASP.NET Web API 可以托管在 asp.net 之外.NET 运行时环境和 IIS Web 服务器上下文。
asp.net 中的路由 净 Web API
ASP. net 中的路由 asp.net Web API 与中的 asp.net Web API 非常相似。 净 MVC。 ASP.NET Web API 将 url 路由到控制器。 然后,将控件交给与请求消息的 HTTP 谓词对应的操作。 注意,asp.net 的默认路由模板.NET Web API 项目是{controller}/{id}——这里的{id}参数是可选的。 同时,ASP.NET Web API 路由模板可以选择包含一个{action}参数。 应该注意的是,不像 ASP。 asp.net MVC, url 在 ASP.NET Web API 不能包含复杂类型。 还应该注意,复杂类型必须出现在 HTTP 消息体中,而且 HTTP 消息体中可以有且只能有一种复杂类型。
注意事项
注意,ASP。 asp.net MVC 和 asp.net.NET Web API 是两个截然不同的框架,它们遵循一些常见的架构模式。
在 ASP.NET Web API 框架,控制器处理所有 HTTP 请求。 控制器包含一组操作方法—Web API 框架的传入请求,请求被路由到适当的操作。 现在,框架使用路由表来确定在接收请求时调用的动作方法。
下面是一个例子:
routes.MapHttpRoute(
name: "Packt Web API",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
参考下面的UserController类。 注意,它扩展了我们在本章前面设计的BaseApiController类:
public class UserController <UserAuthentication>: BaseApiController<UserAuthentication>
{
public void GetAllUsers() { }
public IEnumerable<User> GetUserById(int id) { }
public HttpResponseMessage DeleteUser(int id){ }
}
下面的表展示了 HTTP 方法和相应的 URI, action,等等:
|HTTP 方法
|
尤里
|
行动
|
参数
|
| --- | --- | --- | --- |
| GET | api/users | GetAllUsers | 没有一个 |
| GET | api/users/1 | GetUserByID | 1 |
| POST | api/users | | |
| DELETE | api/users/3 | DeleteUser | 3 |
Web API 框架匹配模板的 URI 路径中的片段。 执行以下步骤:
- URI 与路由模板匹配。
- 选择相应的控制器。
- 选择相应的操作。
方法选择控制器,接受一个HttpRequestMessage实例,并返回HttpControllerDescriptor。 在选定控制器之后,Web API 框架通过调用IHttpActionSelector.SelectAction方法来选择操作。 该方法依次接受HttpControllerContext并返回HttpActionDescriptor。 还可以通过使用HttpGet、HttpPut、HttpPost或HttpDelete属性装饰动作方法,显式地为动作指定 HTTP 方法。 下面是一个例子:
public class UsersController : ApiController
{
[HttpGet]
public User FindUser(id) {}
}
您还可以使用AcceptVerbs属性启用除GET、PUT、POST和DELETE之外的 HTTP 方法。 下面是一个例子:
public class UsersController : ApiController
{
[AcceptVerbs("GET", "HEAD")]
public User FindUser(id) { }
}
您还可以通过操作名称来定义路由。 下面是一个例子:
routes.MapHttpRoute(
name: "PacktActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
您还可以通过使用ActionName属性覆盖操作名称。 下面的代码片段演示了两个操作:一个支持GET,另一个支持POST:
public class UsersController : ApiController
{
[HttpGet]
[ActionName("Token")]
public HttpResponseMessage GetToken(int userId);
[HttpPost]
[ActionName("Token")]
public void AddNewToken(int userId);
}
实现 ASP.NET Web API 用于安全数据库
实现 ASP。 您需要创建一个派生自ApiController类的类。 现在,Web API 控制器中定义的方法映射到相应的 HTTP 方法。 您应该确保希望在 Web API Controller 类中实现的操作以正确的请求类型(GET、POST、PUT和DELETE)作为前缀。
要创建一个 ASP。 . NET Web API 为我们的Security数据库,遵循以下步骤:
-
右键单击解决方案资源管理器窗口。
-
Select Add New Project.
![Implementing the ASP.NET Web API for the Security database]()
创建一个新的 ASP.NET Web API 项目
-
选择 NET MVC 4 Web 应用从列表的模板下的Web类别如上图所示。
-
为项目指定一个名称,然后单击OK。
-
Select Web API as the Project Template, as shown in the following screenshot:
![Implementing the ASP.NET Web API for the Security database]()
选择项目模板
-
确保选择的视图引擎为Razor。 完成后点击OK。
下面是HomeController类的样子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ASP.NET.MVC.WebAPI.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
这是ValuesController类的样子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace ASP.NET.MVC.WebAPI.Controllers
{
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
}
现在,当你执行应用时,输出是这样的:

在 web 浏览器中输出
让我们创建一个名为Employee的实体类,并在ValuesController类中使用。 我已经使Employee类尽可能简单:
public class Employee
{
public Int32 ID { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
}
现在我们将创建一个Employee类的数组,并使用构造函数在其中存储一些数据。 注意:ASP.NET Web API 控制器源于ApiController。 下面是更新ValuesController类的样子:
public class ValuesController : ApiController
{
Employee[] employeeArray = null;
public ValuesController()
{
employeeArray = new Employee[] {
new Employee {ID = 1, FirstName = "Joydip", LastName = "Kanjilal"},
new Employee {ID = 2, FirstName = "Steve", LastName = "Smith"},
new Employee {ID = 3, FirstName = "Michael", LastName = "Stevens"}
};
}
public IEnumerable<Employee> Get()
{
return employeeArray;
}
public string GetFullName(int id)
{
return employeeArray[id].FirstName + " " + employeeArray[id].LastName;
}
}
现在让我们看看执行应用和调用 Web API 时的输出。

执行中的 ValuesController 类
现在,让我们调用 Web API 控制器,并传递 Employee ID 作为参数。 下面是输出的样子:

检索特定记录
现在我们将设计一个BaseApiController类——一个可以作为所有控制器类的基类。 下面是这个类的初始版本:
public class BaseApiController<T> : ApiController where T : class
{
BaseRepository<SecurityEntities> repository = null;
public BaseApiController()
{
repository = new BaseRepository<SecurityEntities>("SecurityEntities");
}
}
下面是BaseRepository类的初始版本:
public class BaseRepository<TContext> : IDisposablewhere TContext : DbContext, IObjectContextAdapter, new()
{
private TContext context;
private BaseRepository()
{
}
public BaseRepository(string connectionStringName)
{
context = new TContext();
context.Database.Connection.ConnectionString = "data source=Joydip;initial catalog=SecurityDB;integrated security=True;";
}
}
下面是BaseRepository类的完整的实现:
using System;
using System.Linq;
using System.Data.Entity;
using System.Linq.Expressions;
using System.Reflection;
using System.Data.Entity.Infrastructure;
using System.Data;
namespace DataAccess
{
public class BaseRepository<TContext> : IDisposablewhere TContext : DbContext, IObjectContextAdapter, new()
{
private TContext dataContext;
private BaseRepository()
{
}
public BaseRepository(string connectionStringName)
{
dataContext = new TContext();
dataContext.Database.Connection.ConnectionString = "datasource=Joydip;initial catalog=SecurityDB;integrated security=True;";
}
public virtual Int32 CreateData<T>(T TObject) where T : class
{
var dbSetInstance = dataContext.Set<T>().Add(TObject);
return SaveChanges();
}
public virtual Int32 RemoveData<T>(T instance) where T : class
{
dataContext.Set<T>().Remove(instance);
return SaveChanges();
}
public virtual Int32 EditData<T>(T instance) where T : class
{
var dbEntityEntry = dataContext.Entry(instance);
dataContext.Set<T>().Attach(instance);
dbEntityEntry.State = EntityState.Modified;
return SaveChanges();
}
private Int32 SaveChanges()
{
return dataContext.SaveChanges();
}
public void Dispose()
{
if (dataContext != null)
{
dataContext.Dispose();
dataContext = null;
}
}
}
}
下面是IBaseApiController接口的外观:
using System;
namespace ASP.NET.MVC.WebAPI.Models
{
/// <summary>
/// IBaseApiController interface
/// </summary>
public interface IBaseApiController : IDisposable
{
int ID { get; set; }
}
}
BaseApiController类继承了ApiController类并实现了IBaseApiController接口:
using System;
using System.Collections.Generic;
using System.Web.Http;
using ASP.NET.MVC.WebAPI.Models;
using DataAccess;
namespace ASP.NET.MVC.WebAPI.Helpers
{
public class BaseApiController<T> : ApiController where T : class, IBaseApiController
{
BaseRepository<SecurityEntities> repository = null;
protected string[] includesArray { get; set; }
/// <summary>
/// Default Contructor that initializes the instance of BaseRepository
/// </summary>
public BaseApiController()
{
repository = new BaseRepository<SecurityEntities>("SecurityEntities");
}
/// <summary>
/// Get method to retrieve entity data based on the generic type supplied
/// </summary>
/// <returns></returns>
public virtual IEnumerable<T> Get()
{
return repository.GetData<T>(includesArray);
}
/// <summary>
/// Get method to retrieve entity data based on the id of the entity
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public virtual T Get(Int32 id)
{
return repository.SearchData<T>(t => t.ID == id, includesArray);
}
/// <summary>
/// Post method - edits data
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Int32 Post([FromBody]T value)
{
return repository.EditData<T>(value);
}
/// <summary>
/// Put method - creates / inserts new entity
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Int32 Put([FromBody]T value)
{
return repository.CreateData<T>(value);
}
/// <summary>
/// Delete method - deletes an existing entity
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Int32 Delete([FromBody]T value)
{
return repository.RemoveData<T>(value);
}
}
}
标准 ASP.NET MVC 项目中,路由配置在Global.asx.cs文件中定义。 相反,在一个标准的 ASP.NET Web API 项目中,在Application_Start文件夹中有一个RouteConfig类和一个WebApiConfig类。

RouteConfig and WebApiConfig in ASP.NET Web API
请注意,RouteConfig.cs文件类似于标准的 ASP.NET MVC 项目,用于为 MVC 框架设置路由。 WebApiConfig.cs文件实际上是 ASP.NET Web API 路由配置被指定。 WebApiConfig类是这样的:
using System;
using System.Collections.Generic;
using System.Linq;
uswing System.Web.Http;
namespace ASP.NET.MVC.WebAPI
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
注意事项
以下是有关此主题的进一步参考资料的连结:
- http://msdn.microsoft.com/en-us/library/ms171868.aspx
- http://www.asp.net/web-api
- http://idesign.net/articles/asp_net_web_api_vs_wcf.htm
总结
在本章中,我们探讨了 ASP 的新特性.NET 4.5。 我们还探讨了 ASP。 并实现了一个 asp.net Web API.NET MVC 4 应用,使用 asp.net.NET Web API 框架。 我们探索了 ASP.NET Web API,特别关注如何在 asp.net 中处理路由和安全性。 净 Web API。 在下一章中,我们将讨论如何使用 Silverlight 使用 WCF 的 RIA 和 RESTful 服务。
六、使用 Silverlight 处理 RESTful 数据
这是本书的倒数第二章,在这一章中,我们将探讨如何使用 Silverlight 5 使用 WCF 4.5 的 RIA 和 RESTful 服务。
在本章中,我们将涵盖以下几点:
- Silverlight 5 简介
- Silverlight 5 中的新特性
- 理解 WCF 4.5 RIA 服务
- 实现一个使用 WCF 4.5 RIA 服务的示例应用
- 使用 Silverlight 5 客户端使用 WCF 4.5 RIA 服务
Silverlight 5 简介
Silverlight(代号为 Windows Presentation Foundation/Everywhere 或 WPF/E)是一个浏览器插件。 Silverlight 是一种提供 RIA 支持的客户端技术。 它可以用来增强基于 web 的应用的外观和感觉。 Silverlight 的新版本包含了构建基于 ria 的业务应用和富媒体应用的增强功能。 跨浏览器和跨平台的兼容性以及对富图形和动画的强大支持是 Silverlight 的一些显著特性。 而且,它运行在沙箱环境中——WPF 框架的一个子集。
Silverlight 的新版本提供了对打印(包括虚拟打印预览)、COM 自动化、Web cam 和麦克风、MEF(托管扩展框架)和 WCF 4.5 RIA 服务的强大支持。 另一方面,Silverlight 5 应用的性能在很大程度上得到了优化。
WCF 4.5 RIA Services 提供了一个框架,帮助您使用 WCF 4.5 连接。net 客户端对象和。net 服务器对象。 Silverlight 的新版本提供了对 WCF 4.5 RIA Services 的支持。 请注意,WCF 4.5 RIA Services(以前称为。net RIA 服务)以优化的。net 二进制格式或 ATOM、JSON 或 OData 格式向 Silverlight 应用公开数据。 WCF 4.5 RIA Services 简化了 RIA 应用的开发,即使用 Silverlight 5 等技术设计的应用。 RIA 服务为您提供了一个无需复制中间层组件的框架。
Silverlight 为开发下一代跨浏览器、跨平台的富互联网应用(ria)提供了极好的支持。 它有助于设计和开发 web 和移动应用的引人入胜的、交互式的用户体验。 然而,Silverlight 5 看起来像微软的 Silverlight 的最新版本,HTML 5 将是未来的选择。
选择 Silverlight 5 还是 HTML 5 取决于很多因素。 如果你正在创建一个Line of Business Application(LOB),你可以选择 Silverlight 5 并利用它的数据绑定特性。 相反,如果您需要需要图像、链接和文本框、动画和交互性的应用,HTML 5 是一个更好的选择。 然而,Silverlight 5 更适合于内部网应用,而不是基于 web 的应用。 另外,请注意,Silverlight 5 只支持 Windows phone。
Silverlight 5 的新特性
以下是 Silverlight 4 和 5 新增的新功能:
-
控件的增强:在 Silverlight 5 中添加到控件的新特性包括:文本溢出、支持多点点击、提前输入文本搜索、合并
DataContextChanged事件、文本跟踪、文本呈现、布局、清晰度等方面的改进。 在 Silverlight 5 中,当使用SaveFileDialog框时,你可以使用DefaultFileName属性设置默认文件名。 下面是如何使用它:SaveFileDialog fileDialog = new SaveFileDialog(); fileDialog.DefaultFileName = "Demo.txt"; fileDialog.ShowDialog(); -
数据绑定的改进。
-
XAML changes: In the XAML stack, the features that have been added in Silverlight 5 include: XAML debugging, markup extensions, implicit data templates, binding in styles, and so on. Extensible Application Markup Language or XAML is an XML-based declarative markup language from Microsoft that enables you to design stunning user interfaces for your WPF or Silverlight applications. The XAML content is stored in an
.xamlfile, and you can use XAML to separate the user interface definition of your applications from the runtime logic by using code-behind files.注意事项
注意,XAML 调试只在 Internet Explorer 9 及以上版本中工作。
-
Implicit data template is a great new feature that enables you to set a data type using the
DataTypeproperty to the data template, instead of attaching the data template to every control in your page. Here's an example of a code snippet that illustrates this:<ListBox x:Name="users"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding FirstName}" FontWeight="Bold" /> <TextBlock Text="{Binding LastName}" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>标记扩展是一种允许您在 XAML 解析时执行代码的特性。 其中包括
{Binding}、{StaticResource}、{RelativeSource}等等。 您还可以创建自己的自定义标记扩展。 -
更新/更改用户界面,图形和媒体。
-
对网络摄像头和麦克风的支持:Silverlight 4 和 Silverlight 5 使您能够构建具有共享视频和音频能力的应用。
-
优化的性能:使用 Silverlight 4 和 Silverlight 5 构建的应用与早期版本的 Silverlight 相比速度快得惊人。 此外,Silverlight 5 应用启动得更快。 Silverlight 5 支持 64 位操作系统,允许受信任的应用不受任何限制地访问本地文件系统。
-
增强对 COM 互操作性的支持:Silverlight 4 和 Silverlight 5 可以与 COM 接口进行互操作。 下面的代码片段展示了如何从 Silverlight 与 Microsoft Office 应用通信:
-
要让你的 Silverlight 4 和 Silverlight 5 应用与 Microsoft Word 进行通信,你可以编写以下代码:
-
改进了对 RIA 服务的支持:在 Silverlight 5 中,对 WCF 4.5 RIA 服务的支持得到了改进。 现在您已经支持复杂类型、更好的 MVVM 支持,还支持对生成的代码进行更好的自定义。
-
增强对浏览器外应用的支持:Silverlight 4 和 Silverlight 5 提供了对 RIA 应用的支持,而且这种支持无需下载和安装任何额外的代码或运行时。 现在您已经支持跨域网络访问、访问用户文件夹、COM Interop 和 HTML 托管。
-
请注意,在
ApplicationManifest.xaml文件中包含以下配置,以便在安装和使用浏览器外应用时可以利用提高的权限。<OutOfBrowserSettings.SecuritySettings> <SecuritySettings ElevatedPermissions="Required" /> </OutOfBrowserSettings.SecuritySettings>
WCF 4.5 RIA 服务
注意,在以数据为中心的系统中,即严重依赖数据的系统中,数据可能来自不同的系统。 现在,您的应用需要将业务逻辑对象和其他服务器对象驻留在客户端,以便能够访问数据。
这种方法的主要问题是代码的重复,以及客户端对内存资源的高消耗。 这就是 WCF 4.5 RIA Services 可以发挥作用的地方。 顺便提一下,WCF 4.5 RIA 服务是在。net Framework 4 和 Silverlight 4 中引入的。 它允许开发人员设计和实现应用,而不需要服务管道代码。
下图展示了一个典型的 WCF 4.5 RIA Services 应用的架构组件:

WCF 4.5 RIA Services(构建在 WCF 4.5 服务之上)简化了 n 层应用开发(尤其是使用 Silverlight 的应用),而无需编写服务管道代码。 实际上,如果您使用 WCF 4.5 RIA Services,您的应用逻辑可以驻留在服务器上。 客户端无需在客户端(即服务使用者端)复制应用的逻辑组件就可以使用这一功能。 RIA 服务构建在 WCF 4.5 之上,简化了客户端编程模型。 然而,RIA 服务也有一些潜在的缺点。 最重要的是,处理元数据是一件痛苦的事情,特别是当您需要经常更新您的模型时。 如果您有一个包含许多实体的数据库,那么当您使用 RIA 服务时,您将花费更多的时间来更新您的模型。
注意事项
如果你使用 WCF 4.5 RIA Services,服务消费者可以在服务器端的业务逻辑组件发生变化时获得最新的更新。
下面是 WCF 4.5 RIA Services 提供的一些特性:
- 当您使用 WCF 4.5 RIA Services 时,客户端实例是通过依赖于服务器端对象的反射来创建的,而不是由服务器上执行的服务公开的服务契约。
- WCF 4.5 RIA 服务提供了对 LINQ 查询序列化的支持; 所以,你可以在客户端编写 LINQ 查询,并在服务器端执行它。
实现示例应用
在本节中,我们将实现一个样例应用,演示如何设计和实现一个 WCF 4.5 RIA 服务,然后使用 Silverlight 5 使用它。 当你创建一个 Silverlight 应用时,你可以选中启用 WCF RIA Services复选框。 这将确保创建 RIA 服务链接,当您最终构建完整的解决方案时,将为域服务和共享代码生成客户端代码。
要开始在 Silverlight 5 中使用 WCF 4.5 RIA Services,请遵循以下简单步骤:
-
打开 Visual Studio 2013 IDE。
-
点击文件,再点击新建项目。
-
Select Silverlight from the templates displayed, and save it with a Name:, as shown in the following screenshot:
![Implementing a sample application]()
-
接下来,删除Solution Explorer窗口中的服务器和客户端项目中的
Class1.cs文件。 -
After you delete the
Class1.csfile in both the Server and Client projects, the Solution Explorer window would look like this:![Implementing a sample application]()
-
Next, right-click on References in the Demo.Web project, and select Manage NuGet Packages... from the menu that is displayed, as shown in the following screenshot:
![Implementing a sample application]()
-
From the list of packages Online | All, you can see EntityFramework listed on the next page. Click on Install, as shown in the following screenshot:
![Implementing a sample application]()
当你点击安装,实体框架的安装将开始。
注意事项
请注意,您也可以通过在包管理器控制台中执行命令来安装实体框架。 您可以在 NuGet 网站http://www.nuget.org/packages/entityframework了解更多关于实体框架版本的详细信息。
实体框架安装成功后,您可以看到如下截图所示的绿色标记:
![Implementing a sample application]()
-
Next, create a solution folder named
Models, and a new entity data model using theAdventureWorksdatabase.![Implementing a sample application]()
-
接下来,在您的 web 项目中创建两个文件夹,一个名为
App-Code,另一个名为Services。 -
Now, create a
DomainServiceclass. To do this, navigate to Add | New Item on theServicessolution folder, and select Web from the list of the installed templates. Then select Domain Service Class. Name this classDepartmentDomainService.csand, click on Add.
### 注意事项
如果你想在 WCF 4.5 RIA Services 中利用实体框架实体数据模型,你应该将其转换为基于“ObjectContext”的模型,否则你在创建域服务时将看不到列出的实体。 您将观察到这样一条消息:**一些实体框架上下文类可能已经被排除**。
要解决此问题,请在设计器模式中打开实体数据模型,并将**代码生成策略**从**无**更改为**默认**。 接下来,删除与模型相邻的两个`.tt`文件,然后重新构建项目。
- The next step is to add a domain service class. Refer to the following screenshot:

- 当您点击OK时,框架将自动创建Department实体的域服务类。
注意事项
需要注意的是,如果你将一个类库项目添加到一个 Silverlight 业务应用项目中,你将不能向服务器项目添加身份验证服务。 这是因为 Silverlight 业务应用模板中的用户对象不能从类库项目中访问。
需要注意的是,Silverlight 无法与服务器端共享程序集。 为了弥补这个差距,我们使用了。net RIA Services。 如果使用。net RIA Services,则在客户端生成的代码几乎是域类的副本。 这确保了您可以在服务器端和客户端之间来回移动对象。 下图说明了RIA 链接****Silverlight 应用之间建立和【显示】的 Web 应用,当您使用 WCF RIA 服务****使用 Silverlight 和使用它们:

现在让我们看一下自动生成的Domain Service类。 下面是DepartmentDomainService类的样子:
namespace Demo.Web.Services
{
using System.Data;
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
using Demo.Web.Models;
[EnableClientAccess()]
public class DepartmentDomainService : LinqToEntitiesDomainService<AdventureWorks2008R2Entities>
{
public IQueryable<Department> GetDepartments()
{
return this.ObjectContext.Departments;
}
public void InsertDepartment(Department department)
{
if ((department.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(department, EntityState.Added);
}
else
{
this.ObjectContext.Departments.AddObject(department);
}
}
public void UpdateDepartment(Department currentDepartment)
{
this.ObjectContext.Departments.AttachAsModified(currentDepartment, this.ChangeSet.GetOriginal(currentDepartment));
}
public void DeleteDepartment(Department department)
{
if ((department.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(department, EntityState.Deleted);
}
else
{
this.ObjectContext.Departments.Attach(department);
this.ObjectContext.Departments.DeleteObject(department);
}
}
}
}
请参考前面的代码片段。 在构建 LOB 应用时,常见的特性是对数据进行创建、更新、读取和删除操作。 System.Web.Ria名称空间中的EnableClientAccessAttribute属性允许在编译时生成客户端代码。
现在,您可以指定必要的配置来使用这个 WCF 4.5 RIA 服务公开的数据。
现在,让我们基于本书前面创建的SecurityDB快速创建一个域服务类。
遵循以下步骤:
-
创建一个名为
DomainServices的新项目。 -
Create an entity data model based on the Control and ControlType tables of
SecurityDBas shown in the following screenshot:![Implementing a sample application]()
-
选择新创建的项目,然后右键单击并导航到Add|New Item。
-
Select Domain Service Class from the templates displayed as shown in the following screenshot:
![Implementing a sample application]()
-
Now, name the Domain Service Class as
SecurityDomainService.csand click on Add. You will see a page that looks like the following screenshot:![Implementing a sample application]()
如您所见,列出了两个实体Control和ControlType。 选择两者,然后点击OK。 现在将生成域服务类。 乍一看,SecurityDomainService类是这样的:
namespace DomainServices
{
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
[EnableClientAccess()]
public class SecurityDomainService : LinqToEntitiesDomainService<SecurityDBEntities>
{
public IQueryable<Control> GetControls()
{
return this.ObjectContext.Controls;
}
public IQueryable<ControlType> GetControlTypes()
{
return this.ObjectContext.ControlTypes;
}
}
}
CRUD 操作
下一步是将必要的 CRUD 方法添加到 Domain Service 中,用于创建新记录、更新现有记录、删除现有记录以及检索属于Control或ControlType表的一个或多个记录。
以下是SecurityDomainService类添加了必要的 CRUD 方法后的完整代码:
namespace DomainServices
{
using System.Data;
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
[EnableClientAccess()]
public class SecurityDomainService : LinqToEntitiesDomainService<SecurityDBEntities>
{
public IQueryable<Control> GetControls()
{
return this.ObjectContext.Controls;
}
public IQueryable<ControlType> GetControlTypes()
{
return this.ObjectContext.ControlTypes;
}
public IQueryable<Control> GetControls()
{
return this.ObjectContext.Controls;
}
public IQueryable<ControlType> GetControlTypes()
{
return this.ObjectContext.ControlTypes;
}
public void InsertControl(Control control)
{
if ((control.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(control, EntityState.Added);
}
else
{
this.ObjectContext.Controls.AddObject(control);
}
}
public void InsertControlType(ControlType controlType)
{
if ((controlType.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(controlType, EntityState.Added);
}
else
{
this.ObjectContext.ControlTypes.AddObject(controlType);
}
}
public void UpdateControls(Control controlObj)
{
this.ObjectContext.Controls.AttachAsModified(controlObj, this.ChangeSet.GetOriginal(controlObj));
}
public void UpdateControlTypes(ControlType controlTypeObj)
{
this.ObjectContext.ControlTypes.AttachAsModified(controlTypeObj, this.ChangeSet.GetOriginal(controlTypeObj));
}
public void DeleteControls(Control controlObj)
{
if ((controlObj.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(controlObj, EntityState.Deleted);
}
else
{
this.ObjectContext.Controls.Attach(controlObj);
this.ObjectContext.Controls.DeleteObject(controlObj);
}
}
public void DeleteControlTypes(ControlType controlTypeObj)
{
if ((controlTypeObj.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(controlTypeObj, EntityState.Deleted);
}
else
{
this.ObjectContext.ControlTypes.Attach(controlTypeObj);
this.ObjectContext.ControlTypes.DeleteObject(controlTypeObj);
}
}
}
}
要使用 Silverlight 5 中的域服务,您需要遵循本章前面讨论的相同步骤。
注意事项
这里有一些链接,以进一步参考这个主题:
- http://msdn.microsoft.com/en-us/library/gg986857%28v=vs.95%29.aspx
- http://www.silverlightshow.net/items/WCF-RIA-Services-Part-1-Getting-Started.aspx
- http://www.johnpapa.net/silverlight5features/
- http://msdn.microsoft.com/en-us/library/ee707336%28v=vs.91%29.aspx
- http://code.msdn.microsoft.com/silverlight/Getting-Started-WCF-RIA-1469cbe2
- http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2010/05/04/silverlight-and-wcf-ria-services-1-overview.aspx
总结
您可以使用 WCF 4.5 RIA Services 编写从小型业务应用到非常复杂的应用的应用。 在本章中,我们已经讨论了 WCF 4.5 RIA 服务,以及如何在 Silverlight 5 应用中使用它们。 在下一章中,我们将讨论一些高级特性,包括使用 WCF 服务和 ASP 的最佳实践。 净 Web API。
七、高级功能
这是本书的最后一章,在这一章中我们将探索 WCF 和 Web API 中的一些高级概念。
在本章中,我们将涵盖以下几点:
- 使用 WCF 服务的最佳实践
- 使用 ASP 的最佳实践。 净 Web API
WCF 的最佳实践
Windows Communication Foundation(WCF)是统一的编程模型,用于构建面向服务的应用。 WCF 提供了一个强大的框架来设计、构建、配置和部署基于SOA的应用,其中 SOA 代表面向服务的架构。
微软在 2006 年发布了 WCF,最初的代号为Indigo,作为。net Framework 3.0 的一部分。
WCF 使开发人员能够构建安全、可靠和事务性的解决方案,这些解决方案可以跨不同平台集成,并与现有投资提供高度的互操作性。
WCF 的核心理念可以归结为以下三个关键概念,即 ABC:
- 地址
- 绑定
- 合同
在本节中,我们将探索使用 WCF 创建应用时需要考虑的最佳实践。
WCF 安全问题
在本节中,我们将探索如何为我们的 WCF 服务实现健壮的安全性。 我们将从对 WCF 绑定的简要介绍开始讨论。
绑定
绑定用于指定传输通道(HTTP、TCP、管道和消息队列)和协议(安全性、可靠性和事务流)。 绑定由绑定元素组成,还包括消息编码元素(文本/XML、MTOM 和二进制)。 这些绑定元素表示端点如何与服务消费者通信。 WCF 支持 9 个内置绑定。 一个绑定必须包含至少一个传输绑定元素、一个编码绑定元素和一个或多个其他传输协议绑定,例如安全性和可靠性。 注意,需要在服务器和客户端中指定的绑定信息是不同的; 也就是说,您必须在 WCF 服务的配置文件中以及在 WCF 服务客户端的配置文件中指定绑定信息。
在 WCF 中,WCF 配置方案的三个主要部分是 ServiceModel、bindings 和 services。
本质上,绑定是端点的一个属性,您可以使用它来配置服务的传输协议、编码和安全规范。 现在,我应该在什么时候使用哪个绑定? 以下是经验法则:
WsHttpBinding:如果您需要通过 Internet 公开您的服务,您可以使用这种类型的绑定。basicHttpBinding:如果您需要向旧客户端(如 ASMX web 服务)公开 WCF 服务,您应该选择这种类型的绑定。WsHttpBinding和basicHttpBinding之间的主要区别之一是消息安全性。WsFederationHttpBinding:这是一种特殊类型的 WS 绑定,它提供了对联邦安全性的支持。NetTcpBinding:如果需要在内部网中支持 WCF 客户端,您可以使用这种类型的绑定。 这是可用的最优化和最快的绑定,并支持可靠性、事务和安全性。NetTcpBinding提供对 TCP 协议和二进制以及编码方法的支持。NetPeerTcpBinding:这个绑定提供了对netTcpBinding特性的支持,并且对于使用 WCF 服务的点对点环境来说更加安全。netNamedPipeBinding:如果您需要在同一台机器上支持 WCF 客户端,那么这种类型的绑定是一个很好的选择。netMsmqBinding:需要支持未连接排队呼叫时,可以选择该绑定类型。wsDualHttpBinding:如果您想为服务和客户端之间的双向通信提供支持,您可以选择这种类型的绑定。 这种结合具有WsHttpBinding的所有特征; 此外,它还支持双工消息交换模式(MEP)。
下表提供了 WCF 中绑定的比较:
|绑定
|
配置
|
Protocol /运输
|
安全
|
事务
|
双工
|
| --- | --- | --- | --- | --- | --- |
| BasicHttpBinding | 基本概要 1.1 | 使用 HTTP / HTTPS | 没有一个 | … | … |
| WSHttpBinding | WS | HTTP、HTTPS、TCP | 消息 | 是的 | … |
| WSDualHttpBinding | WS | HTTP, HTTPS | 消息 | 是的 | 是的 |
| netttcpbinding | net | 命名管道 | 运输 | 是的 | 是的 |
| NetNamedPipeBinding | net | 命名管道 | 运输 | 是的 | 是的 |
| NetMsmqBinding | net | MSMQ | 运输 | 是的 | 没有 |
| WSFederationHttpBinding | ws - federation | HTTP, HTTPS | 消息 | 是的 | 没有 |
| NetPeerTcpBinding | 同行 | TCP | 运输 | … | 是的 |
| MsmqIntegrationBinding | MSMQ | MSMQ | 运输 | 是的 | … |
注意事项
您还可以使用Custom绑定,它允许使用不同绑定元素的组合创建自定义绑定。
WCF 安全性
当您使用 WCF 服务时,数据和信息的机密性和完整性至关重要。 您创建服务操作,然后将它们公开给外部世界。 有多种方法可以保护你的 WCF 服务,如下:
- 使用身份验证
- 使用授权
- 使用证书
- 使用传输级别安全性
- 使用消息级安全性
- 使用的口令安全
此外,您可以在两个级别上在 WCF 中提供安全性。 您可以在传输级别或消息级别提供安全性。 这两种级别各有利弊。
传输安全性依赖于传输。 它提供互操作性和改进的性能,当您发送的消息通过中间系统路由,并且服务和客户机都位于内部网中时,应该使用它。 然而,与消息安全性相比,传输安全性提供的凭证支持最少。
消息级安全性
在消息级安全性中,用户的凭据被封装在服务器和客户机之间传递的消息中。 消息安全性适用于需要将消息转发到其他 WCF 服务或通过中间系统路由的情况。 但是,由于加密和签名每条消息所需的开销,消息安全性与传输安全性相比要慢一些。 另外,消息安全性不支持与旧 ASMX 客户机的互操作性。 消息安全支持的证书类型为 Windows、无、证书、用户名和令牌。
下面的代码片段演示了如何通过使用wsHttpBinding绑定保护消息来实现消息级安全性:
<wsHttpBinding>
<binding name = "wsHttp">
<security mode = "Message">
<message clientCredentialType = "UserToken"/>
</security>
</binding>
</wsHttpBinding>
如果你在消息安全模式下使用证书安全,下面是如何保护你的 WCF 服务:
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
注意事项
要在接口或操作级别上指定消息安全保护级别,必须使用[ServiceContract(ProtectionLevel)]属性并设置保护级别。 您可以从任何支持的保护级别中进行选择,即None、Sign和EncryptAndSign。
通过以下步骤在 WCF 4.5 中实现消息级安全:
-
使用
makecert.exe工具为服务器和客户机(服务提供者和服务使用者)创建证书。 -
使用 Visual Studio 2013 IDE 创建一个 WCF 应用。
-
在服务器的配置文件中指定必要的绑定行为,如下所示:
<bindings> <wsHttpBinding> <binding name="wsHttpEndpointBinding"> <security> <message clientCredentialType="Certificate" /> </security> </binding> </wsHttpBinding> </bindings> <serviceCredentials> <clientCertificate> <authentication certificateValidationMode="PeerTrust"/> </clientCertificate> <serviceCertificate findValue="DemoWCFServer"storeLocation="CurrentUser"storeName="My"x509FindType="FindBySubjectName" /> </serviceCredentials> -
创建 WCF 客户端应用,并配置客户端证书凭据,代码如下:
<behaviors> <endpointBehaviors> <behavior name="CustomBehavior"> <clientCredentials> <clientCertificate findValue="DemoWCFClient" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" /> <serviceCertificate> <authentication certificateValidationMode="PeerTrust"/> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint address="http://localhost:1234/DemoService.svc" binding="wsHttpBinding" bindingConfiguration="WSEndpoint" contract="Packt.Services.IDemoService" name="WSEndpoint" behaviorConfiguration="CustomBehavior"> <identity> <dns value="DemoWCFServer"/> </identity> </endpoint> </client>
你完成了!
使用 FaultContract 属性
下面的代码片段创建了一个将保护级别设置为Sign的接口:
[ServiceContract(ProtectionLevel=ProtectionLevel.Sign]
public interface ISecurityService
{
[OperationContract]
[FaultContract(typeof(FaultDetails))]
UserLoginHistory GetUserLoginHistory(Int32 userID);
}
类用于指定一个或多个 SOAP 默认值,当对服务方法的调用在运行时遇到错误时返回这些默认值。 下面的代码片段指定了一个将保护级别设置为Sign的操作:
[OperationContract(ProtectionLevel=ProtectionLevel.Sign]
服务方法返回用户的登录历史详细信息,将其用户 ID 作为参数传递。
类实现了ISecurityService接口(服务契约),并定义了getUserLoginInformation方法(操作契约)。 下面的代码片段展示了SecurityService类的外观:
public class SecurityService : ISecurityService
{
public UserLoginHistory GetUserLoginHistory(Int32 userID)
{
try
{
return new UserLoginHistory { UserID = userID };
}
catch
{
FaultDetails faultObject = new FaultDetails();
faultObject.FaultID = 1;
faultObject.FaultMessage = "The User ID you entered is invalid...";
throw new FaultException<FaultDetails> (faultObject, new FaultReason(faultObject.FaultMessage));
}
}
}
正如您可以在前面的代码片段中看到的,GetUserLoginHistory操作契约返回一个UserLoginHistory的实例。 我跳过了检索作为参数传递的用户 ID 的用户登录历史的代码。
我们需要两个消息契约,一个用于存储用户的登录历史,另一个用于错误异常发生时的错误详细信息。 MessageBodyMemberAttribute类属于。net Framework 4.5,用于指定将一个成员序列化为 SOAP 主体中的一个元素。
下面的代码片段是我们需要使用的两个消息契约的代码:
[MessageContract]
public class UserLoginHistory
{
[MessageBodyMemberAttribute(Order = 1, ProtectionLevel = ProtectionLevel.None)]
public Int32 UserID { get; set; }
[MessageBodyMemberAttribute(Order = 2, ProtectionLevel = ProtectionLevel.Sign)]
public DateTime LoginTime { get; set; }
[MessageBodyMemberAttribute(Order = 2, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public DateTime Password { get; set; }
}
[MessageContract]
public class FaultDetails
{
[MessageBodyMemberAttribute(Order = 1, ProtectionLevel = ProtectionLevel.None)]
public Int32 FaultID
{
get;
set;
}
[MessageBodyMemberAttribute(Order = 2, ProtectionLevel = ProtectionLevel.None)]
public string FaultMessage
{
get;
set;
}
}
添加服务引用后,您可以使用以下代码从客户端应用中使用该服务:
try
{
ChannelFactory<ISecurityService> factory =
new ChannelFactory<ISecurityService>("WSHttpBinding_ISecurityService",
new EndpointAddress("http://localhost/Packt/SecurityService.svc"));
ISecurityService proxy = factory.CreateChannel();
UserLoginHistory userLoginHistoryObj = proxy.GetUserLoginHistory(3);
}
catch (FaultException<FaultDetails> faultExceptionInstance)
{
//Some code
}
注意事项
您可以通过编程方式关闭 WCF 中的安全性。 一个例子如下:
bindingObject.Security.Mode = SecurityMode.None;
传输级安全性
与消息安全性相比,传输安全性的工作速度要快得多,而且传输级别的安全性是协议独立的。
在传输安全模式下实现basicHttpBinding或WsHttpBinding绑定时,可用的客户端凭据类型包括:
- 无:无安全性; 安全性被关闭
- Basic:基本认证只适用于 HTTP 协议。 在这里,根据活动目录对客户机进行身份验证
- 摘要:这种类型的身份验证类似于 Basic,但在此选项中,凭据以散列形式发送,而不是以明文形式发送
- NTLM:这也只适用于 HTTP 协议,并且客户端使用 Windows 帐户进行身份验证
- Windows:在此选项中,使用 Windows 令牌对活动目录进行身份验证
- Certificate:使用服务证书进行认证,使用 HTTP 协议时使用 SSL 证书进行认证
实现传输级安全性
下面的代码片段演示了如何使用以下代码实现传输安全性:
NetTcpBinding netTcpBinding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
netTcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
Uri adddress = new Uri("net.tcp://Tcp");
ServiceHost serviceHost = new ServiceHost(typeof(SecurityService), adddress);
serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My,X509FindType.FindByIssuerName, "Contoso.com");
serviceHost.AddServiceEndpoint(typeof(ISecurityService), b, "SecurityService");
serviceHost.Open();
Console.WriteLine("Service Started..........");
Console.Read0Line();
注意事项
注意,在默认情况下,netTcpBinding使用传输安全性。 这意味着您应该将客户端凭据配置为使用证书安全性。
要通过配置实现传输级安全性,需要在配置文件中指定安全模式,如下代码片段所示:
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
提示
要在 Windows 中使用netTcpBinding以提高传输安全性,您可以使用以下代码:
<bindings>
<netTcpBinding>
<binding name="PacktTcpBinding">
<security mode="TransportWithMessageCredential" >
<transport clientCredentialType="Windows" />
<message clientCredentialType="Certificate" />
</security>
</binding>
</netTcpBinding>
</bindings>
如果您使用 HTTPS 协议,您应该将服务行为上的httpGetEnabled更改为httpsGetEnabled,如下代码片段所示:
<behaviors>
<serviceBehaviors>
<behavior name="Packt.SecureService.SecurityServiceBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
下一个步骤是指定支持安全通信的端点。 请参考以下代码:
<services>
<service name="Packt.SecureService.SecurityService" behaviorConfiguration="Packt.SecureService.SecurityServiceBehavior" >
<!-- Service Endpoints -->
<endpoint address="http://localhost/Packt/SecurityService.svc" binding="wsHttpBinding" bindingConfiguration="TransportSecurity" contract="Packt.SecureService.ISecurityService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
现在您应该在 IIS 中托管您的服务。 要做到这一点,右键单击解决方案资源管理器窗口中的服务项目,在Web选项卡中,选择使用本地 IIS Web 服务器单选按钮,如下图所示:

你还应该通过点击create virtual directory按钮来创建一个虚拟目录,如上面的截图所示。 下一个屏幕是这样的:

注意事项
注意,为了从 Visual Studio IDE 在 IIS 中托管一个服务,你应该在管理员模式下打开 Visual Studio 2012 IDE。
您可以进入“Internet Services Manager”窗口,将 SSL 证书关联到网站。 您还应该为您的网站启用 SSL 绑定。
使用 WCF 服务的最佳实践
在使用 WCF 服务时,你应该记住以下几点:
- 不要在
using语句中放置代理。 - 使用
FaultExceptions类来处理服务异常。 您应该使用FaultContracts类向服务使用者返回错误信息。 - 使用消息日志记录服务操作。
- 使用每个调用实例模型总是更好的。
- 使用 WCF 工具,如
SvcUtil.exe、SvcConfigEditor.exe、SvcTraceViewer.exe。 - 您应该保护日志文件不受未经授权的访问,并且日志文件不应该包含敏感信息。
- 使用适当的身份验证机制对服务使用者进行身份验证。
- 使用字符串密码,并保护对凭据存储区的访问。
- 使用 IIS 来托管您的服务,除非您想使用 IIS 不支持的传输协议。
- 在服务器端验证输入参数,不要只依赖于客户端验证。
- 定义可维护的服务和数据契约版本控制。
- 明确定义名称空间以避免冲突。
- 加密包含敏感数据的配置部分。
- 您应该通过配置管理绑定和端点信息,而不是通过代码。
- 在类库中定义服务,而不是直接在宿主项目中定义服务。
- 在服务契约定义中包含
FaultContract属性。 - 使用静态代理类代替
ChannelFactory类。 - 如果必须频繁调用服务方法,请使用缓存来存储客户端代理。
- 使用 X509 证书而不是 NTLM 证书。
- 只有在使用传输或消息级安全保护元数据交换端点之后,才应该发布元数据。
- 您应该更喜欢数据契约而不是可序列化类型。
- 尽可能使用 WAS 托管和 IIS 托管外部仅 http 服务。
- 您可以使用协议缓冲区 WCF 服务来获得更好的性能。 您可以通过http://www.developer.com/net/net/working-with-protobuf-services-in-.net.html了解更多关于协议缓冲区的信息,以及如何在 WCF 服务中使用它们。
使用 ASP 的最佳实践。 净 Web API
ASP.NET Web API 是在。NET 框架上构建 RESTful 应用的理想平台。 ASP.NET Web API 是一个可以用来构建Http服务的框架,无论REST还是RPC——它是微软对 RFC 的最好实现。 它允许 IIS 和自托管,并且是异步的。 Web API 是灵活的,并提供了对关注点分离的支持。 它使您能够直接通过 HTTP 协议向 Web 公开应用、数据和服务。 ASP.NET Web API 依赖于基本的协议和格式,如 HTTP、WebSockets、SSL、JQuery、JSON 和 XML。 不支持更高级别的协议,如可靠消息传递或事务。
下面快速浏览一下使用 Web API 时可以遵循的最佳实践和技巧:
- 你应该使用一个自定义的基础 WebApiController,在那里你可以抽象控制器的特性和行为
- 使用 URL 帮助器来过滤所有的图像 URL
- 总是安装MvcRoutingShim插件以避免多个 HTTP 模块的微妙和混乱行为
- 建议为每个资源创建一个单独的控制器
下面的代码是对我们在本书前面创建的 Web API 的 Base API 控制器的快速查看。 BaseApiController类扩展ApiController类,实现IBaseApiController接口。
public interface IBaseApiController : IDisposable
{
Int32 ID { get; set; }
}
public class BaseApiController<T> : ApiController where T : class, IBaseApiController
{
BaseRepository<SecurityEntities> repository = null;
protected string[] includesArray { get; set; }
public BaseApiController()
{
repository = new BaseRepository<SecurityEntities>("SecurityEntities");
}
public virtual IEnumerable<T> Get()
{
return repository.GetData<T>(includesArray);
}
public virtual T Get(Int32 id)
{
return repository.SearchData<T>(t => t.ID == id, includesArray);
}
public virtual Int32 Post([FromBody]T value)
{
return repository.EditData<T>(value);
}
public virtual Int32 Put([FromBody]T value)
{
return repository.CreateData<T>(value);
}
public virtual Int32 Delete([FromBody]T value)
{
return repository.RemoveData<T>(value);
}
}
参考文献
http://msdn.microsoft.com/en-us/magazine/cc163394.aspx
http://msdn.microsoft.com/en-us/library/ms732362.aspx
http://msdn.microsoft.com/en-us/library/ms733099.aspx
http://msdn.microsoft.com/en-us/magazine/cc163382.aspx
http://msdn.microsoft.com/en-us/library/ff405740.aspx
http://www.codemag.com/article/0611051
http://wcf.codeplex.com/wikipage?title=WCF%20HTTP
总结
WCF 为在一个保护伞下统一许多技术提供了一个平台。 它可以用于设计和实现独立于平台的、可扩展的和可伸缩的服务。 ASP.NET Web API 是一个轻量级的基于 Web 的框架,它使用 HTTP 作为应用协议。 在本章中,我们讨论了 WCF 服务和 Web API 可以采用的最佳实践,以增强安全性、可伸缩性和性能。
八、附录 A:参考文献
本附录分为A 节和B 节两部分。
在Section A中,我们将探讨以下内容:
- 流行的基于 rest 的服务框架/ api:
- Ruby on Rails
- Restlet
- Django
- Flickr
- 谷歌
- 雅虎
- 使用 Visual Studio 2013 IDE
在B中,我们将讨论以下几点:
- HTTP 响应代码
- ASP.NET Web API 类库
【课文讲解
这是附录的 A 部分。 在本节中,我们将从流行的基于 rest 的服务框架开始讨论。
流行的基于 rest 的服务框架
具象的状态转移是一种架构范式。 REST 的主要目标包括以下几点:
- 可伸缩性
- 与其他技术和平台的兼容性
- 一般性的接口
- 可发现性; 即资源之间的互联互通
- 组件之间可以独立部署
- 减少延迟
- 更好的安全性
- 可扩展性
RESTful Web API 是指遵循 REST 原则的 Web API。 REST 的主要原则包括:
- 识别的资源
- 无状态通信
- 通过表示操作资源
- 自描述信息
下面的部分将解释流行的基于 rest 的服务框架或 api。
Ruby on Rails
Ruby on Rails 是一个优化的开源 web 应用框架,它运行在 Ruby 编程语言之上。 Ruby on Rails 遵循基本的软件工程模式和原则。 Rails Web API 是一个基于模型-视图-控制器(MVC)框架的 Web 应用创建框架。 视图层由模板组成,大多数模板都是基于 html 的,并嵌入了 Ruby 代码。 模型层表示域模型、业务逻辑类和数据访问类。 控制器层处理传入的 HTTP 请求。 请注意,Rails 控制器可以生成 XML、JSON、pdf 以及特定于移动设备的视图。 您可以从http://api.rubyonrails.org/获得更多关于此框架的信息。
Restlet
Restlet 提供了对扩展列表的支持,扩展列表包括以下内容:
- 春天
- WADL
- XML
- JSON
- jax - rs API
Restlet 的好处包括以下几点:
- 支持完全对称的客户端/服务器 API
- 支持 HTTP 以外的连接器协议
- 通过 Restlet API 支持完整的 URI 路由控制
- 它是快速和可扩展的
- 强大的过滤支持
- 支持一致的客户机/服务器 API
您可以从http://restlet.org/discover/features中了解更多关于这个 API 的信息。
Django REST
Django REST 框架提供了一个强大而灵活的 API,你可以使用它无缝地构建 Web API。 这个 API 提供了广泛的文档和出色的社区支持。 您可以从这个链接http://django-rest-framework.org/了解更多关于这个框架的信息。
Flickr REST API
Flickr REST API 简单易用。 Flickr 也有一些 JSON API,您可以使用它们通过 JavaScript 调用 API。 您可以从http://www.flickr.com/services/api/request.rest.html中获得更多关于的信息。
谷歌 API
谷歌的自定义搜索 JSON/Atom API 使开发人员能够编写能够利用该 API 并在应用中检索和显示自定义搜索的应用。 这个 API 允许您使用 RESTful 调用进行 web 搜索,并获得 JSON 或 Atom 格式的结果。 您可以从这个https://developers.google.com/custom-search/json-api/v1/overview了解更多关于此 API 的信息。
雅虎! 社会 REST api
Yahoo ! RESTapi 提供了一组 URI 资源,可以提供以下访问:
- 用户的配置文件
- 状态信息
- 状态更新
这些 uri 实际上根据它们返回的信息分组到 api 中。 更多信息,您可以参考以下网站:http://developer.yahoo.com/social/rest_api_guide/web-services-intro.html。
【课文讲解
在B中,我们将探讨 Visual Studio 2013 IDE 的使用。
使用 Visual Studio 2013 IDE
在本节中,我们将探索如何使用 Visual Studio 2013 IDE。 本节首先讨论如何在系统中安装和设置 Visual Studio 2013 IDE。
安装 Visual Studio 2013
在本节中,我们将学习如何安装 Visual Studio 2013。 Visual Studio 2013 RC 现在可以下载了。 链接如下:http://www.microsoft.com/visualstudio/eng/2013-downloads。
下载安装文件后,双击该文件开始安装。

接下来,同意许可条款和隐私政策,继续的安装,如下截图所示:

当安装开始时,屏幕将会是这样的:

安装完成后,屏幕会是这样的:

点击Restart Now按钮重启系统,完成 Visual Studio 2013 的安装。
这是 Visual Studio 2013 的打开屏幕的样子:

一旦您调用 Visual Studio 2013,您将观察到它询问您是否想要登录,如下面的截图所示。 我选择了选项now Not, maybe later。

接下来,选择您的开发设置:,如下图所示。 我在系统中选择了通用选项。

然后,点击Start Visual Studio按钮。 Visual Studio 2013 现在将开始在你的系统中第一次使用时进行必要的准备/配置检查,如下截图所示:

一旦这个过程完成,下面是你的 Visual Studio 2013 IDE 在第一眼看到的样子:

Visual Studio 2013 IDE 的新特性
Visual Studio 2013 IDE 中新增的特性包括:
- 支持异步调试
- 支持图形诊断
- 增强的代码编辑器特性
- 支持从代码窗口创建代码映射
- 支持在调试模式下映射调用堆栈
- ALM 扩展功能
- JavaScript 的新 IDE 特性
- 支持创建 Office 365 的现代商业应用
- 支持 Windows 8.1 应用开发
- 增强的 Windows Azure 支持,包括 Windows Azure 移动服务
HTTP 请求和响应代码
下表列出了 HTTP 的标准状态码及其用法。 如欲获得完整资料,请浏览以下连结:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|状态码
|
描述
|
| --- | --- |
| 100 | 信息 |
| 200 | 成功的 |
| 201 | 创建 |
| 202 | 接受 |
| 204 | 没有内容 |
| 300 | 重定向 |
| 304 | 不修改 |
| 400 | 客户端错误 |
| 401 | 未经授权的 |
| 402 | 付款要求 |
| 403 | 被禁止的 |
| 404 | 没有找到 |
| 405 | 方法不允许 |
| 409 | 冲突 |
| 500 | 服务器错误 |
| 501 | 没有实现 |
缩略语
- HTTP:超文本传输协议
- ROA:面向资源的架构
- SOA:面向服务的架构
- SOAP:简单对象访问协议
- REST:具象状态传输
- RPC:远程过程调用
- URL:统一资源定位器
- W3C:万维网联盟
- WSDL:Web 服务描述语言
- XML- rpc:XML 远程过程调用
ASP.NET Web API 库参考(基于。NET Framework Version 4.5)
ASP.NET Web API 包含以下命名空间:
|名称空间
|
目的
|
| --- | --- |
| System.Net.Http | 这个名称空间由 HTTP 属性的类组成。 此命名空间为HttpRequestMessage类提供扩展方法。 |
| System.Net.Http.Formatting | 此包含可用于序列化和反序列化 HTTP 消息体的类。 |
| System.Net.Http.Handlers | 此包含一组事件处理程序。 |
| System.Net.Http.Headers | 这个名称空间包含与HttpHeaders相关的类。 |
| System.Web.Http | 这个名称空间由 HTTP 属性的类组成。 此命名空间包含HttpConfiguration类的扩展方法。 |
| System.Web.Http.Controllers | 这个名称空间由一组类组成,这些类可以控制服务如何在 HTTP 协议之上工作。 |
| System.Web.Http.Dependencies | 这个名称空间由一组类组成,这些类具有一组依赖属性。 |
| System.Web.Http.Description | 这个命名空间由一组用于 web API 描述的类组成。 |
| System.Web.Http.Dispatcher | 这个名称空间由一组与操作分派相关的类组成。 |
| System.Web.Http.Filters | 这个名称空间由一组与动作筛选器属性相关的类组成。 |
| System.Web.Http.Hosting | 这个名称空间由一组在 HTTP 托管中使用的类组成。 |
| System.Web.Http.Metadata | 这个名称空间由一组类组成,这些类与数据模型的公共元数据相关。 |
| System.Web.Http.Metadata.Providers | 这个名称空间由与元数据提供程序相关的类集合组成。 |
| System.Web.Http.ModelBinding | 这个名称空间由一组与模型绑定相关的类组成。 |
| System.Web.Http.ModelBinding.Binders | 这个名称空间由一组模型绑定的类组成。 |
| System.Web.Http.Routing | 这个命名空间由一个或多个指定路由属性的类组成。 |
| System.Web.Http.SelfHost | 这个名称空间由一个或多个类组成,这些类与 HTTP 自托管服务相关。 |
| System.Web.Http.SelfHost.Channels | 这个名称空间由一个或多个类组成,这些类与用于 HTTP 绑定和安全性的类相关。 |
| System.Web.Http.Services | 这个名称空间由一个或多个与默认服务相关的类组成。 |
| System.Web.Http.Tracing | 这个名称空间由一个或多个与跟踪相关的类组成。 |
| System.Web.Http.Validation | 这个名称空间由一个或多个与模型验证相关的类组成。 |
| System.Web.Http.Validation.Providers | 这个名称空间由一个或多个与模型验证相关的提供者类和工厂类组成。 |
| System.Web.Http.Validation.Validators | 这个名称空间由一个或多个与模型验证相关的类组成。 |
| System.Web.Http.ValueProviders | 这个名称空间由一个或多个与值提供程序相关的类组成。 |
| System.Web.Http.ValueProviders.Providers | 这个名称空间由一个或多个与提供者抽象相关的类组成。 |
| System.Web.Http.WebHost | 这个命名空间包含一个或多个类的集合,这些类与 web 主机有关。 |
参考文献
以下是参考网站:














浙公网安备 33010602011771号