作为测试新的Weblog-ZBlog的功能,发些简单的代码(不过这些也花费了我三四个小时的时间),主要是有关WCF 进行REST编程的,网上很多有关使用ASP.NET Extensions,Javascript,甚至成熟的第三方组件:jQueryExtJs 2
像[url=]jQuery AJAX calls to a WCF REST Service[/url]中已经详尽的阐述了用jQuery调用WCF REST Service的完整细节,而我在学习REST in WCF系列 的时候,也发现作者也在使用ASP.NET Extensions中的AJAX功能来消费WCF REST Service。

其实这也是我思考的一个问题,虽然目前ASP.NET AJAX Client Library for ADO.NET还没有正式发布,但我想终究它会发布,从而它将一统目前消费 ADO.NET Data Service的AJAX 客户端。

而我们研究WCF REST Service的目的也正是为了今后真正的用好 ADO.NET Data Service,其一: ADO.NET Data Service是基于WCF REST框架,两者是同源的,理解WCF REST Service可以让能够更底层的理解ADO.NET Data Service编程模型,同时在架构上你也必须做这种储备和打算,即当ADO.NET Data Service在某些地方束缚你的手脚时(比如现在ADO.NET Data Service v1不支持 UriTemplate parameter,不支持返回实体的自定义格式化,也不支持 MEST 实体模型等等),你可以使用更原始的WCF REST Service来进行补充和扩展。比如让ADO.NET Data Service完成对外的数据查询部分,而控制和性能要求更高或业务相对复杂的CUR的操作可以封装在一个自定义的WCF REST Service中。

掌握WCF REST Service的编程模型非常必要,除了出于ADO.NET Data Service功能的限制外,很可能是在架构上的要求,比如需要使用更定制化或灵活的方式来定义和实现你的应用。

所以,下面的问题就是一个问题,如何用.NET的类库来消费一个WCF REST Service?.NET的类库至少有两个好处,第一.NET类库是胖客户端,方便你做测试和真正的单元测试,其二,有些方式下,.NET类库是必须的,比如WCF REST Service返回一个流格式,或者二进制格式,甚至你自定义的格式比如PDF文件,同时研究.NET Client Library for WCF REST Service对你开发Silverlight的客户端有技术积累和加分,比如最新的3.5 SP1内置的NET Client Library for ADO.NET Data Service就使用的非常方便,现实中存在另外一个方向,就是其他的应用有需要集成WCF REST Service产生更复杂的服务,而此时AJAX,Javascript这样的消费型的方式就不能满足聚合的要求了。

查了一下资料,不像NET Client Library for ADO.NET Data Service提供了原生的System.Data.Services.Client可以让你使用,WCF REST Service可以很灵活,似乎毫无规律,非常灵活,那么客户端则难以固定。

How to consume REST services with WCFWCF and interoperability - Consuming REST Services的描述中,发现存在使用.NET类库的方式,而不是简单的使用WebRequest。

即通过ChannelFactory 构造一个客户端和服务器端的Channel来进行通信,从而不需要产生一个代理。这也是我们消费或调用一个普通WCF Service两种方式之一。

比如

BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost/EchoService/");

ChannelFactory<IEcho> myChannelFactory =
new ChannelFactory<IEcho>(myBinding, myEndpoint);

// Create a channel.
IEcho wcfClient1 = myChannelFactory.CreateChannel();
string s = wcfClient1.Echo("Hello Wrold");
Console.WriteLine(s.ToString());

通过ChannelFactory.CreateChannel,你可以创建 multiple endpoint listeners,这也是它比Proxy方式的强大优点之一。

因为WCF REST Services基于WCF,所以理论上可以的。查了半天没有完整的资料,创建一个WCF REST Services很快,但真正能调用成功发现还是有些困难的,最后才发现要使用WebChannelFactory才行。(唉,这时Google比不上MSDN Library)

下面是一个最简单的代码,可以作为一个框架

服务端:

namespace HelloWorldREST
{

    [ServiceContract]
    public interface IPingService
    {
      [OperationContract]
      [WebGet(UriTemplate = "Ping/{name}")]
      string Ping(string name);
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    class ServiceImp : IPingService
    {
        #region IService Members

        public string Ping(string name)
        {
            Console.WriteLine("SERVER - Processing Ping('{0}')", name);
            return "Hello, " + name;
        }

        #endregion

    }

    class Host
    {
        WebServiceHost _host = null; 

        public void Start(string args)
        {
            ServiceImp service = new ServiceImp(); 

            WebHttpBinding binding = new WebHttpBinding();
            WebHttpBehavior behavior = new WebHttpBehavior();

            _host = new WebServiceHost(service, new Uri(args));
            _host.AddServiceEndpoint(typeof(IPingService), binding, "");
            
            ServiceMetadataBehavior metadataBehavior =new ServiceMetadataBehavior();
            metadataBehavior.HttpGetEnabled = true;
            _host.Description.Behaviors.Add(metadataBehavior);

            try
            {
                _host.Open();

                Console.WriteLine("Service is running at {0}", _host.Description.Endpoints[0].ListenUri);
            }
            catch (Exception cex)
            {
                Console.WriteLine("An exception occurred: {0}", cex.Message);
                _host.Abort();
            }

        }

        public void Stop()
        {
            if (_host != null)
            {
                if (_host.State != CommunicationState.Closed)
                {
                    _host.Close();

                    Console.WriteLine("Service is stopped.");
                }
            }
        }

    }
}


Hosting 到一个控制台应用中

static void Main(string[] args)
{
    string url = "http://localhost.:8009/echo";
    Host svc = new Host();
    svc.Start(url);

    Console.WriteLine("Press Enter to exit");
    Console.ReadLine();

    svc.Stop(); 
}


客户端:

namespace Client
{
    [ServiceContract]
    public interface IPingService
    {
        
        [OperationContract]
        [WebGet(UriTemplate = "Ping/{name}")]
        string Ping(string name);
    }

    class Program
    {
        static void Main(string[] args)
        {
            string url = "http://localhost.:8009/echo";
            WebChannelFactory<IPingService> scf;
           
            scf = new WebChannelFactory<IPingService>(new Uri(url));
            IPingService svc = scf.CreateChannel();
            
            string myname = "";
            while (myname != "exit")
            {
                Console.WriteLine("Client-Name:--input");
                myname = Console.ReadLine();
                if (myname == "exit" || myname =="") break;

                string name = svc.Ping(myname);
                Console.WriteLine("Client: response from service:" + name);
                myname = string.Empty; 
            }

            (svc as ICommunicationObject).Close(); 
        }
    }
}


运行结果:


除了.NET Client的方式,你一样还是可以通过浏览器的方式进行测试。


Fiddler2同样可以大发神威,无论通过Web浏览器的方式还是.NET Client的方式,都可以在Fiddler2中获得重要的信息,所以我说,单元测试和专项测试的应用可以极大的显现.NET Client for WCF REST Service的强大之处。


除了使用WebChannelFactory inside ,另外客户端和服务器端需要共享一个一致的Contract---IPingService 也是非常关键的。


下一步阅读和练习
Web Programming ModelWeb Programming Model Samples

慢慢地我们会发现WCF REST框架可以很快的开发出 WCF REST Singleton Service,WCF REST Collection Service,WCF ATOM Feed Service和WCF HTTP Plain XML Service等形态的REST服务,从而有效的支持ADO.NET Data Service的不足和增加多样性。

版权声明
本文原创,版权所有,未经作者同意请勿转载或基于文章进行摘录,截取片段以及进行任何打破完整性的演绎和传播,否则保留追究法律责任的权利。本文所披露和展示的信息、观点及推测反映作者于最初发表文章日期当日的判断,可随时更改;其代码仅仅用于学习和示范,不构成对任何人的使用建议或任何使用后的责任承诺。