超媒体(平日号称应用程序状态的引擎
(HATEOAS))是有血有肉状态传输 (REST) 的重中之重范围之一。有一种守旧认为超媒体项目(如链接或表单)可用于申明客户端怎么样与一组
HTTP 服务交互。那一点也不慢成为1个诙谐的定义,在支付可演化的 API
设计时会用到它。那与大家常常与 Web 交互的措施未有任何例外。大家平时记住网址主页的贰个入口点或
U昂科威L,然后使用链接浏览网址的次第差异区域。大家还利用表单,它附带预约义的操作或 ULANDL
以提交网址实施有些操作所需的数目。

开发人士倾向在劳务中提供具有扶助的形式的静态描述,从正规预订(如
SOAP 服务中的 Web 服务描述语言 (WSDL))到非超媒体 Web API
中的简单文书档案都以如此。那样做的显要难点是静态 API
描述将客户端与服务器紧凑关联。一言以蔽之,它阻挡了可演化性,因为 API
描述中的任何变更都或许半上落下全数现有客户端。

那在能够优先控制和掌握客户端应用程序数目标合营社中近来不会挑起难点。然而,当潜在客户端数呈指数级增进时(就像是当前,数以千计的第三方应用程序在八个装备上运营),那样做就不适当了。不难地从
SOAP 迁移到 HTTP 服务并不可能保险化解此难题。例如,假若在要计算 U宝马7系L
的客户端上提供部分学问,难点仍会设有,甚至没有 WSDL
之类的其余显式约定。超媒体能够帮助客户端屏蔽任何服务器更改。

应用程序状态工作流也应放在服务器端,它规定客户端接下来能够做什么样。假定财富中的一个操作仅对点名状态可用,该逻辑是或不是应驻留在任意恐怕的
API 客户端?肯定特别。服务器应始终控制能够对财富执行怎么样操作。例如,如若撤除购买销售订单
(PO),就不应允许客户端应用程序提交该
PO,这象征在发送到客户端的响应中应不大概利用提交该 PO
的链接或表单。

超媒体应运而生

链接始终是 REST 类别布局的基本点器件。当然,链接在诸如浏览器的用户界面上下文中很常见;例如,挂念使用“参见详细音信”链接来取得目录中钦定产品的详细新闻。不过尚未用户界面或用户交互的微机到电脑境况如何做吧?大家觉得,您也足以在那么些情况中央银行使超媒体项目。

利用那几个新格局后,服务器不仅重回数据。它回到数据和超媒体项目。超媒体项目为客户端提供了1种方法,使它能够依据服务器应用程序工作流的处境来明确能够在钦定时间点执行的操作集合。

那是一般区分常规 Web API 和支撑 REST 的 API
的1处,可是还设有适用的别样限制,因此在大部景况下探究 API 是还是不是支持REST 也许未有意义。我们要关切的是 API 能或不能够正确将 HTTP
作为应用程序协议并尽量使用超媒体。通过启用超媒体,您能够成立可自小编发现的
API。那并未有为不提供文书档案找借口,可是 API
在可更新性方面更灵敏了。

能够行使什么超媒体项目重点由所选的媒体类型决定。大家当下用来塑造 Web API 的很多媒体类型(如 JSON 或
XML)和 HTML 一样,不提供表示链接或表单的放权概念。您能够经过定义表示超媒体的诀窍来行使这么些媒体类型,不过那须求客户端询问超媒体语义在其上是何等定义的。相比较之下,诸如 XHTML (application/xhtml+xml) 或 ATOM
(application/atom+xml)
的传媒类型已辅助个中的1对超媒体项目(如链接或表单)。


HTML 中,一个链接由多少个部分组成: 叁个对准 ULacrosseL
的“href”属性,三个表达链接与当下财富事关的“rel”属性和多个可选的“type”属性(用于内定供给的媒体类型)。例如,假使要利用 XHTML
公开目录中的产品列表,财富负载可能类似于图 1 中所示的载荷。

图 1使用 XHTML 公开产品列表

  1. <div id=”products”>
  2. <ul class=”all”>
  3. <li>
  4. <span class=”product-id”>1</span>
  5. <span class=”product-name”>Product 1</span>
  6. <span class=”product-price”>5.34</span>
  7. <a rel=”add-cart” href=”/cart” type=”application/xml”/>
  8. </li>
  9. <li>
  10. <span class=”product-id”>2</span>
  11. <span class=”product-name”>Product 2</span>
  12. <span class=”product-price”>10</span>
  13. <a rel=”add-cart” href=”/cart” type=”application/xml”/>
  14. </li>
  15. </ul>
  16. </div>

在此示例中,使用专业 HTML
成分表示产品目录,可是笔者动用了 XHTML,因为那样1来使用任意现有 XML
库分析会不难很多。而且作为负载的壹有的,包罗了二个锚点 (a)
成分,表示用于将该项添加到当下用户购物车的链接。通过查阅该链接,客户端能够从 rel
属性预计其用法(添加新项),并将 href 用于对该能源 (/cart)
执行叁个操作。请留意,链接由服务器依照其业务工作流来变化,由此客户端不供给对此外ULX570L 实行硬编码或推断任何规则。那也提供了在运行时修改工作流的新机会而不影响现有客户端。借使目录中的任意产品缺货,服务器只供给忽略用于将该产品丰硕到购物车的链接即可。从客户端角度看,该链接不可用,由此不能订购该产品。服务器端只怕采用了与该工作流有关的更复杂的规则,然则客户端根本察觉不到那点,因为它唯壹关怀的作业是该链接不存在。由于超媒体和链接,客户端与劳动器端的事务工作流已收回关联。

还要,能够采用超媒体和链接创新 API
设计的可衍变性。随着服务器上中国人民解放军海军事工业程大学业作工作流的不断完善,它能够提供用于新功用的别的链接。在大家的产品目录示例中,服务器只怕包蕴三个新链接用于将成品标志为收藏项,如下所示:

  1. <li>
  2. <span class=”product-id”>1</span>
  3. <span class=”product-name”>Product 1</span>
  4. <span class=”product-price”>5.34</span>
  5. <a rel=”add-cart” href=”/cart/1″ type=”application/xml”/>
  6. <a rel=”favorite” href=”/product_favorite/1″
  7. type=”application/xml”/>
  8. </li>

就算现有客户端只怕忽略该链接并不受这么些新成效的震慑,可是较新的客户端能够马上发轫使用该意义。那样,思索为您的 Web API 提供单个入口点或根 UPRADOL
也就相差为奇了,该入口点或根 U汉兰达L 包蕴发现任何功用的链接。例如,您能够有所2个 U翼虎L“/shopping_cart”,它回到以下
HTML 表示情势:

  1. <div class=”root”>
  2. <a rel=”products” href=”/products”/>
  3. <a rel=”cart” href=”/cart”/>
  4. <a rel=”favorites” href=”/product_favorite”/>
  5. </div>


OData 服务中也提供类似成效,该作用在根 U哈弗L
中公然一个服务文书档案,该文书档案包括全体援助的能源集和用于获取与其关系的多少的链接。

链接是连连服务器和客户端的好格局,可是它存在贰个显明的题材。在关于产品目录的在此以前示例中,HTML 中的贰个链接只提供
rel、href 和 type 属性,那暗含部分关于怎么着处理用 href 属性表示的该 URubiconL
的带外知识。客户端应使用 HTTP POST 照旧 HTTP GET?如若它选拔POST,应在伸手主体中带有哪些数据?就算拥有知识或然记录在某处,然则假使客户端能够实际发现该意义不更可以吗?对于具有那些难题,使用 HTML
表单能够解决,它有许多意义。

操作中的表单

动用浏览器与 Web
交互时,日常选用表单表示操作。在产品目录示例中,按“添加到购物车”链接暗示将 HTTP GET
发送到服务器,它将回来二个可用于将产品增加到购物车的 HTML
表单。该表单能够涵盖3个带 U兰德本田UR-VL 的“action”属性、1个代表 HTTP
方法的“method”属性和一部分恐怕要求用户输入的输入字段,还蕴藏可读的存在延续操作的求证。

你能够在处理器到电脑情况中做同样的业务。假设不想透过人工与表单交互,您大概必要周转 JavaScript
或 C# 的应用程序。在产品目录中,用于访问第2个产品的“add-cart”链接的 HTTP
GET 将寻找用 XHTML 表示的以下表单:

  1. <form action=”/cart” method=”POST”>
  2. <input type=”hidden” id=”product-id”>1</input>
  3. <input type=”hidden” id=”product-price”>5.34</input>
  4. <input type=”hidden” id=”product-quantity” class=”required”>1</input>
  5. <input type=”hidden” id=”___forgeryToken”>XXXXXXXX</input>
  6. </form>

客户端应用程序现在已与涉及将成品充分到购物车的一点详细新闻撤销关联。它只须求动用
HTTP POST 将此表单提交到 action 属性中钦命的 UHighlanderL。服务器还足以在表单中包罗别的新闻,例如,包括二个假冒标记以制止跨站点请求伪造
(CSENVISIONF) 攻击或对先行为服务器填充的数量开始展览签订契约。

此模型允许私下 Web API
通过依据分歧因素(如用户权限或客户端要使用的版本)提供新表单来随便演变。

用以 XML 和 JSON 的超媒体?

如本人在前文中所述,XML (application/­xml) 和 JSON
(application/json)
的通用媒体类型未有对超媒体链接或表单的放到协助。即便可以使用域特定的概念(如“application/vnd-shoppingcart+xml”)扩张这个媒体类型,不过那须求新客户端询问在新类型中定义的装有语义(并还可能衍生媒体类型),因而1般不这么做。

正因为这么,有人提议了动用链接语义扩充 XML 和 JSON
的新媒体类型建议,它名叫超文本应用程序语言 (HAL)。该草案在
stateless.co/hal_specification.html 上颁发,它回顾定义四个利用 XML 和
JSON 表示超链接和松手财富(数据)的正规方法。HAL
媒体类型定义包涵一组属性、1组链接和一组嵌入能源的能源,如图 2
中所示。

图片 1.png) 图 二 HAL
媒体类型


3
呈现1个演示,它表达产品目录在同时使用 XML 和 JSON 表示方式的 HAL
中是何等体统。图 4 是示例财富的 JSON 表示格局。

图 3HAL 中的产品目录

  1. <resource href=”/products”>
  2. <link rel=”next” href=”/products?page=2″ />
  3. <link rel=”find” href=”/products{?id}” templated=”true” />
  4. <resource rel=”product” href=”/products/1″>
  5. <link rel=”add-cart” href=”/cart/” />
  6. <name>Product 1</name>
  7. <price>5.34</price>
  8. </resource>
  9. <resource rel=”product” href=”/products/2″>
  10. <link rel=”add-cart” href=”/cart/” />
  11. <name>Product 2</name>
  12. <price>10</price>
  13. </resource>
  14. </resource>

图 肆示例资源的 JSON 表示方式

  1. {
  2. “_links”: {
  3. “self”: { “href”:
    “/products” },
  4. “next”: { “href”:
    “/products?page=2” },
  5. “find”: { “href”:
    “/products{?id}”, “templated”: true }
  6. },
  7. “_embedded”: {
  8. “products”: [{
  9. “_links”: {
  10. “self”: { “href”:
    “/products/1” },
  11. “add-cart”: { “href”:
    “/cart/” },
  12. },
  13. “name”: “Product 1”,
  14. “price”: 5.34,
  15. },{
  16. “_links”: {
  17. “self”: { “href”:
    “/products/2” },
  18. “add-cart”: { “href”:
    “/cart/” }
  19. },
  20. “name”: “Product 2”,
  21. “price”: 10
  22. }]
  23. }
  24. }

在 ASP.NET Web API 中支持超媒体

在前文中,大家研商了在布署 Web API
时要依据的一对超媒体原理。以后大家来领会一下怎么在接纳 ASP.NET Web API
的生育环境中其实履行这一个原理,并应用此框架提供的保有可扩充性和机能。

在基础级别,ASP.NET Web API
协理格式化程序的定义。格式化程序完成方式知道怎么着处理特定媒体类型,以及怎样将它体系化或反系列化为实际的
.NET 类型。过去在 ASP.NET MVC
中对新媒体类型的支撑特别星星。只有 HTML 和
JSON 被视为有效成员并在整整堆栈中收获完全扶助。其它,未有用于扶助内容协商的同等模型。您能够因而提供自定义 ActionResult
完毕来帮衬响应音讯的不如媒体类型格式,可是它不知道什么引入新媒体类型来反体系化请求音信。利用具有新的模子绑定程序或值提供程序的模型绑定基础结构常常能够消除此难点。幸运的是,那种不一致性在 ASP.NET Web API
中已透过引入格式化程序得到缓解。

各类格式化程序从基类
System.Net.Http.Formatting.MediaTypeFormatter 派生天公地道写方法
CanReadType/ReadFromStreamAsync 以协理反类别化,重写方法
CanWriteType/WriteToStreamAsync 以支撑将 .NET
类型系列化为钦命的传播媒介类型格式。


5
突显 MediaTypeFormatter 类的概念。


5 MediaTypeFormatter 类

  1. public abstract class MediaTypeFormatter
  2. {
  3. public Collection<Encoding>
    SupportedEncodings { get; }
  4. public
    Collection<MediaTypeHeaderValue> SupportedMediaTypes { get; }
  5. public abstract bool CanReadType(Type type);
  6. public abstract bool CanWriteType(Type type);
  7. public virtual Task<object> ReadFromStreamAsync(Type type,
  8. Stream readStream,
  9. HttpContent content, IFormatterLogger formatterLogger);
  10. public virtual Task WriteToStreamAsync(Type
    type, object value,
  11. Stream writeStream, HttpContent content,
  12. TransportContext transportContext);
  13. }

格式化程序在 ASP.NET Web API
中对此支撑内容协商起着首要成效,因为框架以往能够依据在伸手音信的“Accept”和“Content-Type”标头中吸收的值选取正确的格式化程序。

ReadFromStreamAsync 和 WriteToStreamAsync
方法正视职分并行库 (TPL) 来实行异步操作,由此它们重回 Task
实例。假如你要显式使格式化程序达成同步工作,基类
BufferedMediaTypeFormatter 将在中间为你执行此操作。此基类提供你可以在贯彻中重写的五个点子 SaveToStream 和
ReadFromStream,它们是 SaveToStreamAsync 和 ReadFromStreamAsync
的协同版本。

付出用于 HAL 的 MediaTypeFormatter

HAL
使用一定语义来表示财富和链接,因而你不可能只是利用 Web API
达成中的任何模型。为此,大家利用三个用以表示财富的基类和另3个用于表示财富聚合的基类来使格式化程序的贯彻更简明:

  1. public abstract class LinkedResource
  2. {
  3. public List<Link> Links {
    get; set; }
  4. public string HRef { get; set; }
  5. }
  6. public abstract class LinkedResourceCollection<T> :
    LinkedResource,
  7. ICollection<T> where T : LinkedResource
  8. {
  9. // Rest of the collection
    implementation
  10. }

Web
API 控制器将选取的实际模型类可以从那七个基类派生。例如,一个出品或产品汇聚能够按以下办法贯彻:

  1. public class Product : LinkedResource
  2. {
  3. public int Id { get; set; }
  4. public string Name { get; set; }
  5. public decimal UnitPrice { get; set; }
  6. }
  7. public class Products :
    LinkedResourceCollection<Product>
  8. {
  9. }

今昔,有了概念 HAL
模型的专业措施,由此得以达成格式化程序了。生成新的格式化程序实现的最简单易行方法是从
MediaTypeFormatter 基类或 BufferedMediaTypeFormatter
基类派生。图 6 中的示例使用了第2个基类。


6 BufferedMediaTypeFormatter 基类

  1. public class HalXmlMediaTypeFormatter :
    BufferedMediaTypeFormatter
  2. {
  3. public HalXmlMediaTypeFormatter()
  4. : base()
  5. {
  6. this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(
  7. “application/hal+xml”));
  8. }
  9. public override bool CanReadType(Type type)
  10. {
  11. return type.BaseType == typeof(LinkedResource) ||
  12. type.BaseType.GetGenericTypeDefinition() ==
  13. typeof(LinkedResourceCollection<>);
  14. }
  15. public override bool CanWriteType(Type type)
  16. {
  17. return type.BaseType == typeof(LinkedResource) ||
  18. type.BaseType.GetGenericTypeDefinition() ==
  19. typeof(LinkedResourceCollection<>);
  20. }
  21. }

该代码首先在构造函数中定义扶助的此达成的媒体类型(“application/hal+xml”),然后重写
CanReadType 和 CanWriteType 方法以内定帮衬的 .NET 类型,这几个项目必须从
Linked­Resource 或 LinkedResourceCollection 派生。因为已在构造函数中定义,此实现只帮衬 HAL 的 XML
变体。还能落成另一个格式化程序来支撑 JSON
变体(可选)。

实质上中国人民解放军海军事工业程高校业作在 WriteToStream 和 ReadFromStream
方法中完毕(如图 7 中所示),那个点子将分别采取 XmlWriter 和
XmlReader 来将对象写入流或从流中读取对象。


7 WriteToStream 和 ReadFromStream 方法

  1. public override void WriteToStream(Type type, object value,
  2. System.IO.Stream writeStream, System.Net.Http.HttpContent content)
  3. {
  4. var encoding = base.SelectCharacterEncoding(content.Headers);
  5. var settings = new
    XmlWriterSettings();
  6. settings.Encoding = encoding;
  7. var writer = XmlWriter.Create(writeStream, settings);
  8. var resource = (LinkedResource)value;
  9. if (resource is IEnumerable)
  10. {
  11. writer.WriteStartElement(“resource”);
  12. writer.WriteAttributeString(“href”,
    resource.HRef);
  13. foreach (LinkedResource
    innerResource in
    (IEnumerable)resource)
  14. {
  15. // Serializes the resource state and links
    recursively
  16. SerializeInnerResource(writer, innerResource);
  17. }
  18. writer.WriteEndElement();
  19. }
  20. else
  21. {
  22. // Serializes a single linked resource
  23. SerializeInnerResource(writer, resource);
  24. }
  25. writer.Flush();
  26. writer.Close();
  27. }
  28. public override object ReadFromStream(Type type,
  29. System.IO.Stream readStream, System.Net.Http.HttpContent content,
  30. IFormatterLogger formatterLogger)
  31. {
  32. if (type != typeof(LinkedResource))
  33. throw new ArgumentException(
  34. “Only the LinkedResource type is
    supported”, “type”);
  35. var value = (LinkedResource)Activator.CreateInstance(type);
  36. var reader = XmlReader.Create(readStream);
  37. if (value is IEnumerable)
  38. {
  39. var collection = (ILinkedResourceCollection)value;
  40. reader.ReadStartElement(“resource”);
  41. value.HRef = reader.GetAttribute(“href”);
  42. var innerType = type.BaseType.GetGenericArguments().First();
  43. while (reader.Read() &&
    reader.LocalName == “resource”)
  44. {
  45. // Deserializes a linked resource
    recursively
  46. var innerResource = DeserializeInnerResource(reader, innerType);
  47. collection.Add(innerResource);
  48. }
  49. }
  50. else
  51. {
  52. // Deserializes a linked resource
    recursively
  53. value = DeserializeInnerResource(reader, type);
  54. }
  55. reader.Close();
  56. return value;
  57. }

最终一步是将格式化程序实现作为 Web API
宿主的1有个别布署。此步骤差不多能够用与在 ASP.NET 或 ASP.NET Web API
自托管中平等的艺术来落实,只是所需的 HttpConfiguration
实现分裂。固然自托管使用 HttpSelfHostConfiguration 实例,ASP.NET
经常选用在 System.Web.Http.GlobalConfiguration.Configuration
中全局可用的 HttpConfiguration 实例。HttpConfiguration 类提供3个 Formatters
集合,您能够将它注入本身的格式化程序完毕。以下是何等对 ASP.NET 执行此操作:

  1. protected void Application_Start()
  2. {
  3. Register(GlobalConfiguration.Configuration);
  4. }
  5. public static void Register(HttpConfiguration config)
  6. {
  7. config.Formatters.Add(new
    HalXmlMediaTypeFormatter());
  8. }


ASP.NET Web API 管道中布局格式化程序后,任何控制器选用 HAL
都能够省略地回来一个模子类,该模型类从格式化程序要体系化的
LinkedResource 派生。对于产品目录实例,产品和代表目录的产品汇集能够分别从
LinkedResource 和 LinkedResourceCollection 派生:

  1. public class Product : LinkedResource
  2. {
  3. public int Id { get; set; }
  4. public string Name { get; set; }
  5. public decimal UnitPrice { get; set; }
  6. }
  7. public class Products :
    LinkedResourceCollection<Product>
  8. {
  9. }

用以拍卖产品目录财富的富有请求的控制器
ProductCatalogController 以往能够为 Get 方法重临 Product 和 Products
的实例(如图 8 中所示)。


8 ProductCatalogController 类

  1. public class ProductCatalogController :
    ApiController
  2. {
  3. public static Products Products = new Products
  4. {
  5. new Product
  6. {
  7. Id = 1,
  8. Name = “Product 1”,
  9. UnitPrice = 5.34M,
  10. Links = new List<Link>
  11. {
  12. new Link { Rel = “add-cart”, HRef = “/api/cart” },
  13. new Link { Rel = “self”, HRef = “/api/products/1” }
  14. }
  15. },
  16. new Product
  17. {
  18. Id = 2,
  19. Name = “Product 2”,
  20. UnitPrice = 10,
  21. Links = new List<Link>
  22. {
  23. new Link { Rel = “add-cart”, HRef = “/cart” },
  24. new Link { Rel = “self”, HRef = “/api/products/2” }
  25. }
  26. }
  27. };
  28. public Products Get()
  29. {
  30. return Products;
  31. }
  32. }

此示例使用 HAL 格式,不过你还可以够应用类似措施来营造利用
Razor 的格式化程序和将模型种类化为 XHTML 的模版。您在
RestBugs 中得以找到用于 Razor 的 MediaTypeFormatter
的求实贯彻,该示例应用程序由 霍华德 Dierking 创造,演示怎样利用 ASP.NET
Web API 来创立超媒体 Web API,网站为
github.com/howarddierking/RestBugs

格式化程序使您能够轻松使用新媒体类型扩张 Web API。   

在 Web API 控制器中提供更好的链接匡助

以前的 ProductCatalog­Controller
示例肯定有不妥之处。在那之中的持有链接都硬编码了,要是路由平常变化,会令人脑仁疼不已。幸而框架提供了名叫 System.Web.Http.Routing.UrlHelper
的扶助器类来机关从路由表测度链接。通过 Url
属性在 ApiController
基类中提供此类的实例,因而得以在别的控制器方法中轻松使用它。UrlHelper
类定义类似于:

  1. public class UrlHelper
  2. {
  3. public string Link(string routeName,
  4. IDictionary<string, object> routeValues);
  5. public string Link(string routeName, object routeValues);
  6. public string Route(string routeName,
  7. IDictionary<string, object> routeValues);
  8. public string Route(string routeName, object routeValues);
  9. }

Route
方法再次来到钦点路由的相持 UXC90L(例如 /products/一),Link 方法重返相对U帕杰罗L(能够在模型中应用该 UMuranoL 来防止硬编码)。Link
方法接收七个变量: 路由名称和要整合 U本田CR-VL 的值。


9
显示对于在此之前的产品目录示例,怎么着在 Get 方法中使用 UrlHelper
类。


9 如何在 Get 方法中选拔 UrlHelper 类

  1. public Products Get()
  2. {
  3. var products = GetProducts();
  4. foreach (var product in products)
  5. {
  6. var selfLink = new Link
  7. {
  8. Rel = “self”,
  9. HRef = Url.Route(“API Default”,
  10. new
  11. {
  12. controller = “ProductCatalog”,
  13. id = product.Id
  14. })
  15. };
  16. product.Links.Add(selfLink);
  17. if(product.IsAvailable)
  18. {
  19. var addCart = new Link
  20. {
  21. Rel = “add-cart”,
  22. HRef = Url.Route(“API Default”,
  23. new
  24. {
  25. controller = “Cart”
  26. })
  27. };
  28. product.Links.Add(addCart);
  29. }
  30. }
  31. return Products;
  32. }

已运用控制器名称 ProductCatalog 和制品 ID
从默许路由生成了产品的链接“self”。还从暗中认可路由中生成了用来将成品丰裕到购物车的链接,只是选用的控制器名字为Cart。如图 9
中所示,用于将成品丰富到购物车的链接依据产品可用性 (product.IsAvailable)
与响应关联。向客户端提供链接的逻辑重要依赖于壹般在控制器中推行的作业规则。

总结

超媒体的功力很强大,允许客户端和服务器独立演变。通过在不相同阶段接纳服务器提供的链接或任曹紫珩媒体项目(如表单),客户端能够成功与驱动交互的服务器业务工作流撤消关联。

 

Pablo Cibraro 是国际上公认的学者,在应用 Microsoft
技术安插和完成大型分布式系统方面负有超过 1二 年的增进经历。 他是团结系统
MVP。 方今 九 年中,Cibraro 扶助众多 Microsoft
共青团和少先队开发了一些工具和框架,以便于采纳 Web 服务、Windows Communication
Foundation、ASP.NET 和 Windows Azure 营造面向服务的应用程序。
他的博客地址是
weblogs.asp.net/cibrax,您能够在
脸书 twitter.com/cibrax
上关切她。

原文:
http://msdn.microsoft.com/zh-cn/magazine/jj883957.aspx 

相关文章

网站地图xml地图