[原]RESTful Web Service之以HTTP PUT方式调用WCF服务

时间:2022-06-26 13:21:31
昨天突然想到一个问题,在RESTful Web Service中,如何修改一个对象呢,怎么看都不像是通过把一个复杂对象分解为Uri的参数的形式来上传到服务器上的。又看了微软提供的WCF的示例代码《 高级 Web 编程》,其中倒有一段代码貌似和我的需求一致:

 

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务[原]RESTful Web Service之以HTTP PUT方式调用WCF服务代码
    [OperationContract]
    [WebInvoke(Method 
=   " PUT " , UriTemplate  =   " {id} " )]
    Customer UpdateCustomer(
string  id, Customer newCustomer);

 

这里从客户端传上来一个Customer类型的对象newCustomer,而不是完全把Customer分解成简单类型传上来。但是还是感觉这不是我想要的代码,因为这个Customer类型还是太“具体”,为每一个PUT动作都设计一个方法并不是我想要的。而且,如果离开了.NET平台,离开了DataContract,DataMember调用是不是会变的复杂呢(这个我现在也没有去研究,希望知道的兄弟指教一二),我心中希望的这种调用,最好就像Google Data API中的AtomEntry一样,使用一个AtomEntry.Update(),就可以把自已更新到服务器上去,而不是为每一个类型都去做自已的更新方法。既然Google能做到,那一定是实现的办法。

通过反复的查询MSDN,终于找到了一个可以被WCF当然数据契约接收的“通用”类型:

 

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务[原]RESTful Web Service之以HTTP PUT方式调用WCF服务代码
[DataContractAttribute]
public   abstract   class  SyndicationItemFormatter

 

很显然,这是一个抽象类,它的继承层次如下:

System.Object
    System.ServiceModel.Syndication.SyndicationItemFormatter
    System.ServiceModel.Syndication.Atom10ItemFormatter
    System.ServiceModel.Syndication.Rss20ItemFormatter

再进一步,又发现了下面的这个类型:

 

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务[原]RESTful Web Service之以HTTP PUT方式调用WCF服务代码
public   class  Atom10ItemFormatter < TSyndicationItem >  : Atom10ItemFormatter
where  TSyndicationItem :  new (), SyndicationItem

MSDN解释如下:

一个用于在 SyndicationItem派生类与 Atom 1.0 格式之间来回序列化的类。

备注:

使用此类可以序列化SyndicationItem 派生类的实例,以及从包含 Atom 1.0 项的 XML 文档创建SyndicationFeed 派生类的实例。如果必须序列化SyndicationItem实例,请改用Atom10ItemFormatter格式化程序。

如果把Atom10ItemFormatter<TSyndicationItem>做为WCF服务方法的参数类型,再使用HTTP 的PUT方式把数据推到WCF服务的方法上,这个Atom10ItemFormatter<TSyndicationItem>应该会将推进来的XML数据自动转换成SyndicationItem对象吧,试试看:

随例建一个Syndication Service项目,然后将IFeed1.cs修改为如下代码所示:

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务[原]RESTful Web Service之以HTTP PUT方式调用WCF服务代码
    [ServiceContract]
    [ServiceKnownType(
typeof (Atom10FeedFormatter))]
    [ServiceKnownType(
typeof (Rss20FeedFormatter))]
    
public   interface  IFeed1
    {

        [OperationContract]
        [WebGet(UriTemplate 
=   " get " , BodyStyle  =  WebMessageBodyStyle.Bare)]
        SyndicationFeedFormatter CreateFeed();

        [OperationContract]
        [WebInvoke(Method 
=   " PUT " , RequestFormat  =  WebMessageFormat.Xml, UriTemplate  =   " up " )]
        
void  Update(Atom10ItemFormatter < SyndicationItem >  item);
    }

接下来再修改Feed1.cs,为其添加Update方法:

 

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务[原]RESTful Web Service之以HTTP PUT方式调用WCF服务代码
         public   void  Update(Atom10ItemFormatter < SyndicationItem >  item)
        {
            
using  (System.IO.StreamWriter file  =   new  System.IO.StreamWriter( @" C:\a.txt " true ))
            {
                file.WriteLine(item.Item.Title.Text);
            } 
        }

 

为了观察是否得到了客户端PUT来的数据,我做了一个简单的Log,把PUT来的SyndicationItem的Title写入到一个文本文件。

有了服务端,还得有个客户端,新建一个控制台应用程序,将main.cs修改为如下所示:

 

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务[原]RESTful Web Service之以HTTP PUT方式调用WCF服务代码
         static   void  Main( string [] args)
        {
            HttpWebRequest req 
=  (HttpWebRequest)WebRequest.Create( " http://localhost:8731/Design_Time_Addresses/RESTfulTest/Feed1/up " );
            req.Method 
=   " PUT " ;
            SyndicationItem item 
=   new  SyndicationItem( " think8848 " " Item Content " new  Uri( " http://Item/Alternate/Link " ),  " itemID " , DateTimeOffset.Now);
            MemoryStream ms 
=   new  MemoryStream();
            XmlWriter writer 
=  XmlWriter.Create(ms);
            item.SaveAsAtom10(writer);
            writer.Close();
            req.ContentLength 
=  ms.Length;
            req.ContentType 
=   " text/html " ;
            Stream sw 
=  req.GetRequestStream();
            sw.Write(ms.ToArray(), 
0 , ( int )ms.Length);
            WebResponse resp 
=  req.GetResponse();
            Stream s 
=  resp.GetResponseStream();
            StreamReader sr 
=   new  StreamReader(s);
            Console.WriteLine(sr.ReadToEnd());
            resp.Close();
            Console.ReadLine();
        

Go!Go!Go! Start new instance

 

观察下c:\a.txt中有没有东西:

 

[原]RESTful Web Service之以HTTP PUT方式调用WCF服务

 

示例代码下载

 

参考文章:http://social.msdn.microsoft.com/Forums/en/wcf/thread/c2f7a08e-3af8-4ea6-8eab-03eb07951de4

推荐博客:http://www.robbagby.com/blog