每周源代码32– Atom, AtomPub和BlogSvc(WCF中的AtomPub服务器)


[原文发表地址]  The Weekly Source Code 32- Atom, AtomPub and BlogSvc, an AtomPub Server in WCF

[原文发表时间]  2008-08-20 10:21 AM

亲爱的读者,在我的新的请求阅读源代码以成为更杰出的开发人员中,现在我在"每周源代码”一系列帖子中向您展示每周源代码32。

BlogSvc 

更新:BlogSvc.NET 代码已经被大范围地重构了,可以考虑查看最近的CheckIns,看看到底有哪些变化。

BlogSvc.NET—WCF和.NET的AtomPub服务器

非常敬佩那些不仅发布了Open Source Software,还特意花时间为BlogSvc.NET方案设计了一个非常漂亮又整洁的logo的人。这个代码是Jarrett Vance编写的,此代码发布在CodePlex了。详细文档和具体细节请参见BlogSvc.NET主网站

http://www.blogsvc.net网站似乎是BlogSvc自己的演示网站。其实,如果你下载该资源,那么完整的实现BlogSvc.net的网站也同时会被下载。Booyachaka. 非常令人敬佩。

因为该方案用到了Atom和AtomPub,针对这一情况,他用到了Windows Live Writer. 你可以通过阅读Joe Cheng的一系列帖子来了解WLW中意Atom的原因。Joe Cheng是Live Writer团队的精英人才。他们在帖子上告诉了大家是怎样完全实现这些的。

已经做到这一步了,但是Atom究竟是什么呢?这一次,我们可以参考Wikipedia给出的大致精准的定义。

Atom这个名字适用于相关的标准。Atom Syndication Forma是一种用于Web种子的XML语言。但Atom Publishing Protocol(简称AtomPub或APP)是一种简单的为创建和更新Web资源,基于HTTP的协议。

从一个方面来看,RSS作为一种联合格式,类似于XML,但它打心底里并不尊重XML.但Atom却是尊重XML的。对于发布博客或内容网站,Blogger/MetaWeblog APIs基于XML/RPC(一个协议,它要么让你喜欢的不得了,要么让你感到十分头疼。或者两种情况兼之)。而AtomPub则基于RESTmodel和Atom,并经过了一个更标准的采纳过程。但根本上来说,使用Atom和/或AtomPub是安全的选择。大家都非常安全了。今年的早些时候,微软就采用了这两种格式。我的偶像Pablo Castro(他是ADO Data Services的首席设计师)在他的项目中支持AtomPub。

据说,BlogSvc是:

“…Atom Publishing Protocol的一个开放的源代码实现。它创建于提供程序模型的顶端。也有文件系统和数据库的提供程序。该服务和Live Writer是兼容的。”

先介绍到这了。我们再来看看一些代码。虽然是0.3,但它一直在进步发展。当Jarrett开始使用NET 3.5 SP1时,他可能会做一些“通过减法运算来编写代码”,并通过System.ServiceModel.Syndication交换出许多令人乏味的Atom Object Model代码,并使用ServiceDocument。Jarreyy可能会删掉他的大部分"BlogService.Core"项目。新的3.5 SP1包括Atom和AtomPub对象模型,以及Rss20模型。如果这些新的对象模型能与Argotic.相抗衡,这将会非常有趣。

他已经写了一个非常全面的IAtomPub的命名空间。并附带了从他遵循的RFC 4151 上获得的"tag" URI Scheme相对应的Uri模板。

   1: [ServiceContract]
   2: public interface IAtomPub
   3: {
   4:     [OperationContract]
   5:     [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{workspaceName}/{collectionName}")]
   6:     Stream CreateResource(string workspaceName, string collectionName, Stream stream);
   7:  
   8:     [OperationContract]
   9:     [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{workspaceName}/{collectionName}/*")]
  10:     Stream Annotate(string workspaceName, string collectionName, Stream stream);
  11:  
  12:     [OperationContract]
  13:     [WebGet(UriTemplate = "{workspaceName}/{collectionName}/*")]
  14:     Stream RetrieveResource(string workspaceName, string collectionName);
  15:  
  16:     [OperationContract]
  17:     [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "{workspaceName}/{collectionName}/*", Method = "PUT")]
  18:     Stream UpdateResource(string workspaceName, string collectionName, Stream stream);
  19:  
  20:     [OperationContract]
  21:     [WebInvoke(UriTemplate = "{workspaceName}/{collectionName}/*", Method = "DELETE")]
  22:     void DeleteResource(string workspaceName, string collectionName);
  23:  
  24:     [OperationContract]
  25:     [WebInvoke(UriTemplate = "{workspaceName}/{collectionName}/*", Method = "HEAD")]
  26:     void HeadResource(string workspaceName, string collectionName);
  27:  
  28:     [OperationContract]
  29:     [WebGet(UriTemplate = "service")]
  30:     AppService RetrieveService();
  31:  
  32:     [OperationContract]
  33:     [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "service", Method = "PUT")]
  34:     AppService UpdateService(AppService serviceDoc);
  35:  
  36:     [OperationContract]
  37:     [WebGet(UriTemplate = "{workspaceName}/{collectionName}/category?scheme={scheme}")]
  38:     AppCategories RetrieveCategories(string workspaceName, string collectionName, string scheme);
  39:  
  40:     [OperationContract]
  41:     [WebGet(UriTemplate = "{workspaceName}/{collectionName}")]
  42:     AtomFeed RetrieveFeed(string workspaceName, string collectionName);
  43: }

现在,让我们看看CreateMedia.,对于任意一种数据类型(并非Atom内容类型),它是CreateResource的一部分。 如果你想把图片或视频附在博文上,CreateMedia恰恰就能帮您实现。

   1: public AtomEntry CreateMedia(string workspace, string collection, Stream stream)
   2: {
   3:     try
   4:     {
   5:         if (!Authenticate(true)) return null;
   6:         string slug = WebOperationContext.Current.IncomingRequest.Headers["Slug"];
   7:         string contentType = WebOperationContext.Current.IncomingRequest.ContentType;
   8:         string etag;
   9:         AtomEntry entry = Atom.Provider.GetService().GetCollection(workspace, collection).CreateMedia(stream, slug, contentType, out etag);
  10:         WebOperationContext.Current.OutgoingResponse.ContentType = Atom.ContentTypeEntry;
  11:         WebOperationContext.Current.OutgoingResponse.Headers["Content-Location"] = entry.Location.AbsoluteUri;
  12:         WebOperationContext.Current.OutgoingResponse.ETag = etag;
  13:         WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated(entry.Location);
  14:         return entry;
  15:     }
  16:     catch (ResourceNotFoundException rnfe)
  17:     {
  18:         WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(rnfe.Message);
  19:     }
  20:     catch (InvalidContentTypeException icte)
  21:     {
  22:         WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotAcceptable;
  23:         WebOperationContext.Current.OutgoingResponse.StatusDescription = icte.Message;
  24:     }
  25:     catch (Exception ex)
  26:     {
  27:         WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.InternalServerError;
  28:         WebOperationContext.Current.OutgoingResponse.StatusDescription = ex.Message;
  29:     }
  30:     return null;
  31: }

我个人做了一些重构并退出WebOperationContext.Current.OutgoingResponse到一个变量中。因为该方法和其他大多数方法差不多,我认为可以进行更大规模和更深入的重构。CRUD(创建,阅读,更新,删除)代码确实一直处于这样的循环模式。

我认为 Jarrett有能力调动所有的 try/catch,eTags的缓存工作行以及一些辅助工具中没有涵盖到的东西。这个项目网站上提到下一步是添加身份验证,并把它重构成一个模块。他已通过大量的 TODO注释来证实了。

真的非常喜欢阅读诸如Jarrett等人的代码。他们真的花了大量时间在 TODO:注释上。如果你知道编程人员的下一个步骤要做什么,那就很容易猜到他们的做法。 同时,TODOs也会告诉你他们的进度。我可以判断,当我在读代码时,项目主管肯定知道哪些是好的,哪些不好。并根据这些来评估该项目的发展轨迹。

image

真是个好东西!我希望在 Atom和 AtomPub的.NET Open Source space上也能看到这样的东西。为什么要关注这个?也许你所在的公司拥有内容管理系统,或销售目录系统,销售人员想要在该系统上编辑项目web页面。为什么不把 BlogSvc置于它之前呢?这样那些销售人员就可以使用 Windows Live Writer或 其他AtomPub的兼容性编辑器了。真的有无限的可能性啊!

奇怪的旁注:当我打开他的"Web.csproj"时,会出现一个很怪异的 COM Interop错误-"System.Runtime.InteropServices.COMException."我在记事本中打开 csproj,发现两件事。第一,IISUrl被 设置为了他的计算机名http://rocket,因此我把它改成了http://localhost.第二, UseIIS显示的是 ‘True",所以我怀疑lame 错误信息正试图告诉我,我的Vista系统中没有 IIS 6.0兼容扩展项。我把它设置为 UseIIS="False",这样一来就可以正常加载了。

证实:在连接的过程中出现了bug, 我在心里已经暗骂它了。

看到BlogSvc和 3.5 SP1中的ADO Data相交的过程将会非常有趣。顺便说一下:你可以通过观看MSDN上的How Do I视频来了解更多关于ADO Data Services 的东西。(确实,视频播放器是有够烂的,但你可以下载 WMV)

Comments (0)

Skip to main content