服务站

创建和使用 Web 源

Jon Flanders

代码下载可从 MSDN 代码库
浏览代码联机

内容

Web 源
WCF 和源
馈送结构
公开一个源
实现该订阅源
AtomPub
使用源

在中,1 月 2009 问题MSDN 杂志 》我讨论了为体系结构使用 Representational 状态传输 (REST),用于构建客户端-服务器应用程序的基本知识。我还启动看可能在如何构建这样的应用程序使用 Microsoft.NET Framework 3.5 中的 Windows Communication Foundation (WCF) 功能。

本月,我将讨论源 WCF 的功能,启用只因为的基本支持的一些其他 Web。读取上时服务站列将帮助您了解此,您可以安全地读取此项,而无需向您自己进行任何损害,(尽管一些知识库的 WCF REST 等基础是很有帮助)。

Web 源已几乎是要从 World Wide Web 中提取信息的应用程序的一种在十年周围。传统上用于提供文章和博客中的信息,源现在通常用于公开其他类型的数据以及因体系结构的简单性。

源是只是通过一个 HTTP URI 公开的 XML 数据。源读取器负责某些时间间隔轮询 URI,然后处理检索到的数据。读者旨在提供一个的人将源的数据的应用程序时将通知用户新的数据可用。情况的无人参与源阅读器可以是任何应用程序代码) 通常将通过新的数据获取触发某些应用程序操作。

考虑多个源都公开网络日志的数据原因有关生成服务的一列的主题?公开数据源的简单性格式以及无处不在订阅源的读取器 (和库分析源) 的已导致许多其他类型数据作为源公开。ADO.NET 数据服务,是例如是启用服务的数据层完全使用源的技术 (特别使用标准之上调用子组件的子组件发布我将讨论本文稍后介绍的协议 (AtomPub),)。服务由许多其他公司与在 Microsoft Windows Azure 平台将公开更其数据功能),以这种方式。

成功的源的一个原因是使用已知和主要标准的 XML 格式。而不是使用每个数据提供程序自定义格式,行业有了两个常见的源的架构: 真正简单的整合 (RSS) 和 Atom。RSS 是在两种的格式旧并虽然子组件已成为广泛采用的标准,那么多个源将仍然公开 RSS 和子组件版本。如果要生成一个服务,特别是在 RESTful 服务您将和提供需要考虑构建使用源,使用 RSS 或 Atom,如果该服务是只读文件,或使用 AtomPub,如果该服务未读 / 写。

WCF 和源

上用于构建 RESTful 终结点的基本支持的顶部.NET Framework 3.5 中的 WCF 还支持公开源。可以创建基于 WCF HTTP 的终结点,并提供使用常见源的格式的源。在.NET Framework 3.5 SP 1 中的 WCF 添加对源的其他支持,从而可以轻松实现支持 AtomPub 规范的终结点。

在我看来,源支持在 WCF 中的很好的功能之一就是它离开提取,子组件或 RSS 格式的需要知道深入详细信息。WCF 提供用于生成一般的对象 (在对象模型是更类似于子组件,因为子组件有些更丰富模型比 RSS) 的图形的一个对象模型。您就可以然后此对象关系图的顶层以及它传递给称为格式化程序的另一个提供 Framework 的对象。格式化程序负责对象图表数据序列化传递到正确的源格式。这是如何您可以轻松地公开 RSS 和 Atom 从相同的端点和它还阻止您将来更改源的格式由于所有需要是新的格式化程序。您的工作是填充对象图表的数据。基础结构,负责将数据转换为正确的源格式。

馈送结构

我进一步之前,因此应我有点讨论源和及其与 WCF 对象模型的关系的结构。源是一个相当简单的公开的数据 (请参见 图 1 ) 的集合的方法。源 (通常包括标题、 说明、 发布的日期、 最后更新日期 / 时间,以及项的集合。其中的每一项也是相当简单的一条带发布的日期、 一个的标题和内容的数据。内容通常会包含重要的数据的是网络日志项、 了报纸文章还是一些其他信息片段。每个项可以有可以链接到单个项目或项目 (如它的数据而不是仅摘要完整 HTML 页) 的其他表示的超链接。请参阅 图 1 。 直观源

fig01.gif

图 1 一个源体系结构

假设我想要公开 MSDN Magazine 文章通过新闻复制的信息。首先,我需要确定哪些数据通过此订阅源公开。尽管有几个选项,我决定实现本示例为所有问题和 MSDN Magazine 中发布的文章的源。当源读取器获取更新时, 它将显示发布为一个小的一个单独项目每篇文章文章的摘要与内容。

例如,我将能从我的最后一个专栏扩展该代码,我构建泛型的 RESTful 服务端点提供 MSDN Magazine 来自。再次,不一定必须返回并阅读该文章可了解这一,但没有我如我选择此特定情形的某种用途并且它实际上适用于 RESTful 和基于 SOAP 的 Web 服务。通常,源是一个良好的实施详细信息将添加到现有的服务。WCF 将好就是它是直接将源的终结点添加到几乎任何服务您曾构建使用 WCF 无论整个服务是 RESTful。

公开一个源

首先我要执行的是扩展我的服务合同和定义来包括可以提供新闻复制的操作。为此,我已经添加一个名为我 IMSDNMagazineService 的 GetIssuesFeed 的新方法接口 (参见 图 2 )。

图 2 添加 GetIssuesFeed 方法

[ServiceContract]
public interface IMSDNMagazineService {
  [OperationContract]
  [WebGet(UriTemplate="/")]
  IssuesCollection GetAllIssues();

  [OperationContract]
  [WebGet(UriTemplate = "/feed?format={format}")]
  [ServiceKnownType(typeof(Atom10FeedFormatter))] 
  [ServiceKnownType(typeof(Rss20FeedFormatter))]
  SyndicationFeedFormatter GetIssuesFeed(string format);  

  [OperationContract]
  [WebGet(UriTemplate = "/{year}")]
  IssuesData GetIssuesByYear(string year);

  //remainder of interface commented for clarity
  ...
}

有几注意有关此方法。首先,返回类型 SyndicationFeedFormatter,WCF 的一部分源我引用前面通常为格式化程序的支持。它将引用我已填充的数据的基础对象,并且它将生成正确的 XML 源根据源对象的类型的格式。

要注意事是 WebGetAttribute 的 UriTemplate 属性。这表明 WCF 哪些每种方法应响应的 URI 或句柄。在本例中是感兴趣的是,GetIssuesFeed 方法有文本 URI 模板:"/ 送纸"。GetIssuesByYear (这是泛型 RESTful 方法具有与源) 有一个变量的路径段 ("/ {年份}") 的 URI 中。由于 URI 分析和路由机制请将所有内容将转换为字符串,它将显示以下两个 UriTemplates 应在冲突。

UriTemplate 分析在 WCF 中的规则要求文本匹配项将变量的匹配项之前一致。因此,如果在传入 URI 结尾"/ 送纸",它将路由到 GetIssuesFeed,但带只是该路径段的任何其他 URI 将被路由到 GetIssuesByYear。请注意我还使用查询字符串来指示源格式客户端正在请求。(只有请求具体来说,我将返回 RSS,否则我将返回子组件)。

在第三个 GetIssuesFeed 方法感兴趣的是 ServiceKnownTypeAttribute。此属性由 WCF 用来通知可能会作为实际返回值它需要要正确执行序列化) 传递的返回任何的值派生类的序列化层。在这种情况下我可能希望返回这两种格式,并使我都两个 ServiceKnownTypeAttribute 声明,每个引用相应派生类 SyndicationFeedFormatter: AtomFeedFormatter 和 Rss20FeedFormatter。它是相当明显从此类名称 AtomFeedFormatter 返回源使用子组件格式但 Rss20FeedFormatter 返回源使用 RSS 2.0 格式。这是只是普通 WCF 结构,但您可能不已经了解此功能除非您已尝试处理 WCF 之前的返回值的多态性。

实现该订阅源

哇,这是所有没有获取到实现。由于只需要将我的数据问题和文章,并将数据转移到 WCF 对象模型,实现是实际上相当简单。对象模型不基于 SyndicationFeedFormatter 请记住的格式设置的对象。对象模型中心,围绕一个名为 SyndicationFeed 的类型 (请参见 图 3 )。一个 SyndicationFeed 对象可用于获取一个有效的 SyndicationFeedFormatter 并且保存到每个源项目的对象。项目是 SyndicationFeed.items 集合的一部分。

fig03.gif

图 3 SyndicationFeed 对象模型

SyndicationFeed 对象模型遵循一个泛型的源的理念,虽然向子组件 (与作者和链接集合,以及 SyndicationItem 内容和汇总属性) 稍有适合其模型。图 4 显示了我的服务上实现 GetIssuesFeed 方法的代码。

图 4 GetIssuesFeed

public SyndicationFeedFormatter GetIssuesFeed(string format) {
  SyndicationFeedFormatter ret = null;
  SyndicationFeed myFeedData = new SyndicationFeed();
  myFeedData.Title = new TextSyndicationContent(
    "MSDN Magazine feed");
  Articles articles = GetAllArticles();

  SyndicationItem sitem = null;
  List<SyndicationItem> list = new List<SyndicationItem>();
  myFeedData.Items = list;
  SyndicationLink altLink = null;
  foreach (var item in articles) {
    sitem = new SyndicationItem {
      Title = new TextSyndicationContent(
        "MSDN Magazine Article: " + item.Title),
      Content = new XmlSyndicationContent(GenerateContent(item)),
      PublishDate = GetPublished(item),
      LastUpdatedTime = GetUpdated(item)
    };
    altLink = MakeLinkForArticle(item);
    sitem.Links.Add(altLink);
    list.Add(sitem);
  }
  ret = new Atom10FeedFormatter(myFeedData);
  return ret;
}

这是 uncomplicated 的代码和遵循相同的基本模式为所有源在是创建一个 SyndicationFeed 对象,,根据,设置其属性的 WCF 中的代码创建列表 SyndicationItems,和后关联 SyndicationFeed 对象 (这并不执行自动),与 SyndicationItems 包含您的数据填充该列表的列表。(可以从 MSDN Magazine 网站中下载完整的代码以便为简便起见,我没有显示所有帮助器方法此处,)

填写 SyndicationItem 属性不会引入的根据是否计划在公开 RSS 或 Atom (或两者) 的复杂性。但实质上它的设置标题、 PublishedDate、 LastUpdatedDate 和内容属性。

注意有关此代码的另一点是 LastUpdatedTime 和 PublishDate 属于类型 DateTimeOffset,.NET Framework 3.5 来简化使用确切的日期和时间以及时区中添加的新类型。

标题和内容是有点不同比您预期的。标题类型 TextSyndicationContent,并且内容是文章 SyndicationContent 类型。这些类型 (和其他主要派生的类型,XmlSyndicationContent) 用来管理不同部分的内容,但它们有时会不同它们所包含的内容的源。例如,纯文本、 XML (甚至 XHTML 或 HTML) 的某种形式或某种内容 (因此在 UrlSyndicationContent 类型) 的二进制文件的链接,可以具有 SyndicationItem.content 属性。SyndicationContent 是所需的层的支持所有这些不同类型的数据源的项目的间接寻址。

一旦我拥有此源设置和运行,我可以用户代理请求为其,并且 Internet Explorer 是快乐源并允许用户订阅它 (如将任何源的读取器用户代理)。

向子组件移动多个站点和服务的另一个原因是由于的子组件发布协议 (AtomPub)。其中,子组件是源格式,AtomPub 将是用于检索、 创建,和更新资源的一个规范。很之上的 REST,限制因此一旦您理解 REST 等,使用它是简单的规格。因为与子组件的实例完成大部分交互,格式是也已知和理解。

大多数子组件周围的 AtomPub 中心源,但有两个新的文档类型: 服务文档和类别。NET Framework 3.5 SP 1 添加了对 AtomPub 的支持,通过支持这些新的文档类型的两个新对象。(可以实现与只是.NET Framework 3.5,AtomPub 但 SP 1 中添加功能,使工作更容易)。

一个 AtomPub 服务文档是元数据文档,特定的 AtomPub 终结点支持有关哪个工作区中通知用户代理。工作区是确实是指向特定的子组件的源的超链接的成员资源的集合。服务文档还可以指定操作,如何种媒体类型每个源支持 (如图像或其他二进制文件) 时, 所有源都应支持标准的子组件的项。

AtomPub 规范还指定如何使用统一的接口,对每个源 (成员资源)。您可以看到在 图 5 中的此映射。

图 5 AtomPub 应用程序的统一的接口
资源 统一的接口方法 说明
服务文档 GET 一旦该 URI 已知用户代理,可以通过 GET 检索服务文档
类别的文档 GET 用于获取该类别的表示形式
集合 GET 获取表示形式源的子组件
集合 POST 创建一个新的子组件条目
成员 GET 获取可以是一个单独的子组件条目或二进制文件的单个成员
成员 PUT 修改成员
成员 删除 删除成员

添加的 SP 1 的类型是 ServiceDocument (类似于 SyndicationItem) 和 AtomPub10ServiceDocumentFormatter 提供 SyndicationFeedFormatter 相同)。同样,将一个名为 ResourceCollectionInfo 来表示服务文档中的每个集合的类型。因为 ServiceDocument 保存到 ResourceCollectionInfos 以生成服务文档本身的主要的内容的列表,此类型将具有到 ServiceDocument 有点类似于 SyndicationFeed 和 SyndicationItem,之间关系的关系。

若要支持我的终结点上的 AtomPub,首先我需要向我的合同的另一种方法:

[OperationContract]
  [WebGet(UriTemplate = "/servicedoc")]
  AtomPub10ServiceDocumentFormatter GetServiceDoc();

然后我可以提供实现,如 图 6 所示。 这将产生服务文档 图 7 所示。

图 6 AtomPub 服务文档实现

public AtomPub10ServiceDocumentFormatter GetServiceDoc() {
  OutgoingWebResponseContext ctx =
    WebOperationContext.Current.OutgoingResponse;
  ctx.ContentType = "application/atomsvc+xml";
  AtomPub10ServiceDocumentFormatter ret = null;

  //create the ServiceDocument type
  ServiceDocument doc = new ServiceDocument();
  IncomingWebRequestContext ictx =
    WebOperationContext.Current.IncomingRequest;

  //set the BaseUri to the current request URI
  doc.BaseUri = ictx.UriTemplateMatch.RequestUri;

  //create a Collection of resources   
  List<ResourceCollectionInfo> resources =
     new List<ResourceCollectionInfo>();

  //create the Blog resource
  ResourceCollectionInfo mainBlog =
    new ResourceCollectionInfo("MSDNMagazine",
      new Uri("feed", UriKind.Relative));

  //add the Accepts for this resource
  //remember this is the default if no accepts if present
  mainBlog.Accepts.Add("application/atom+xml;type=entry");
  resources.Add(mainBlog);

  //create the Pictures resource
  ResourceCollectionInfo mainPictures =
    new ResourceCollectionInfo("Pictures",
      new Uri("pictures", UriKind.Relative));

  //add the Accepts for this resource
  mainPictures.Accepts.Add("image/png");
  mainPictures.Accepts.Add("image/jpeg");
  mainPictures.Accepts.Add("image/gif");
  resources.Add(mainPictures);

  //create the Workspace
  Workspace main = new Workspace("Main", resources);

  //add the Workspace to the Service Document
  doc.Workspaces.Add(main);

  //get the formatter
  ret = doc.GetFormatter()
    as AtomPub10ServiceDocumentFormatter;
  return ret;
}

图 7 定义服务

<?xml version="1.0" encoding="utf-8"?>
<service xml:base="http://localhost:1355/Issues.svc/servicedoc" 
  xmlns="http://www.w3.org/2007/app" 
  xmlns:a10="http://www.w3.org/2005/Atom">
  <app:workspace xmlns:app="http://www.w3.org/2007/app">
    <a10:title type="text">Main</a10:title>
    <app:collection href="feed">
      <a10:title type="text">MSDNMagazine</a10:title>
      <app:accept>application/atom+xml;type=entry</app:accept>
    </app:collection>
    <app:collection href="pictures">
      <a10:title type="text">Pictures</a10:title>
      <app:accept>image/png</app:accept>
      <app:accept>image/jpeg</app:accept>
      <app:accept>image/gif</app:accept>
    </app:collection>
  </app:workspace>
</service>

此服务文档通信没有具有两个集合的一个工作区命名的主。 一个的集合具有"源"和使用默认媒体类型作为其输入 (子组件项媒体类型) 的相对 URI。 其他集合包含二进制文件,专门列出的媒体类型限制的图像文件和具有的"图片"的 URI。 给定此文档,用户代理可以轻松地与交互我 AtomPub 端点遵循着手 图 5 中的规则。

AtomPub 是一有用的标准,可应用于许多不同情形而不仅仅是博客和 (如图像) 关联的文件。

使用源

SyndicationFeed API 还可在客户端使用新闻复制。 各种当前源格式 (并且可能会有多个在以后) 设使用自定义的代码,因此这是在.NET Framework 基库的非常好除了一个重要任务。 下面是一些简单的代码演示使用源的:

string uri = "http://localhost:1355/Issues.svc/feed";
XmlReader xr = XmlReader.Create(uri);
SyndicationFeed feed = SyndicationFeed.Load(xr);
Console.WriteLine("Feed title:{0}",feed.Title.Text);
foreach (var item in feed.Items) {
  Console.WriteLine("Item {0}",item.Title.Text);
} 

标准很多公司化尽可能 AtomPub 围绕用于构建服务和框架。 ADO.NET 数据服务使用 AtomPub 公开数据实体。 反过来,ADO.NET 数据服务用于所有表、 日志和 Microsoft Azure 队列功能。 Windows Live 服务的大部分其公开的服务使用 AtomPub。 这里在点是即使您从任何要生成的应用程序不公开子组件或 AtomPub,可能性是很高您需要知道如何进行交互并使用 AtomPub 服务,现在或某一时间在不久的将来。 希望我所示您将帮助您入门。

ADO.NET 数据服务或 WCF?

ADO.NET 数据服务和.NET Framework 3.5 都提供如何轻松地公开 RESTful 的服务,可生成符合标准的 Web 源中的 WCF。 因此何时使用 ADO.NET 数据服务,以及当您应在 WCF 中使用内置的支持?

WCF 提供功能公开和调用服务终结点。 使用 WCF 3.5,服务终结点可能是标准基于 SOAP 的或执行简单的 RESTful 服务界面样式。 若要公开 RESTful 终结点,注释与该 UriTemplate 您服务类中的该方法用于定义资源标识符。 URI 匹配从模板参数中传递的在方法调用该模板导致。 在您的类中的批注方法集组成您的服务合同。

作为 RSS 或 Atom 兼容源,请从 WCF 服务返回结果,您在方法内创建 SyndicationFeed 对象包含 SyndicationItems 表示返回的内容的列表。 您然后传递该 SyndicationFeed 适当的类型的一个 SyndicationFeedFormatter 创建,并返回该 SyndicationFeedFormatter 从您的方法。

ADO.NET 数据 Services 基于 WCF,并通过一个实体模型如由 Microsoft 实体框架或其他 IQueryable 的数据源提供的模型提供 queryable 的基于 REST 的终结点。 使用 ADO.NET 数据服务,模型成为服务合同。 该模型可以查询通过标准的 URI 包含,除了服务根和资源路径查询选项 (如筛选、 排序、 分页和图形扩展。 此外,ADO.NET 数据服务提供的功能控制的访问权限、 公开自定义服务操作和自定义资源访问的方式 (是例如对于实施基于用户的安全) 通过查询) 被窃取。

ADO.NET 数据服务支持 JSON 和 AtomPub 规范,包括如何插入,更新,并删除对服务 (如允许) 通过标准的 HTTP 谓词。 因此,ADO.NET 数据服务从任何 HTTP 客户端访问。

此外,Microsoft 提供 ADO.NET 数据服务客户端.NET 客户端框架、 Silverlight 和为查询和更新对 ADO.NET 数据服务兼容终结点的数据提供了强类型化的、 基于 LINQ 的体验的 Ajax (是否该终结点是使用 ADO.NET 数据服务或自定义实现如 Azure 表实现)。

因此如果想要通过一个数据源 (如一个 ADO.NET 数据提供程序或 IQueryable 源 (包括内存中的集合) 和 JSON 或 AtomPub 兼容的格式可通过简单的 HTTP 客户端或强类型的客户端使用的返回结果中公开一个 REST 基于 queryable 模型,ADO.NET 数据服务将提供大多数功能工作的最低金额。

而在另一方面,如果希望实现一组方法的手工艺品源基于自定义应用程序的逻辑然后 WCF 中内置的功能更易于将方法公开为 RESTful 服务能够返回源 RSS 或 Atom 兼容的格式。

—Michael Pizzo,主体级结构设计版数据可编程性

将您的问题和提出的意见发送至 sstation@Microsoft.com.

Jon Flanders 是一独立技术顾问、 扬声器,和的 Pluralsight 培训师。 他专门研究 BizTalk Server、 Windows Workflow Foundation 和 Windows Communication Foundation。 您可以访问在 Jon masteringbiztalk.com/blogs/jon.