使用ServiceStack構建Web服務

提到構建WebService服務,你們確定第一個想到的是使用WCF,由於簡單快捷嘛。首先要說明的是,本人對WCF不太瞭解,可是想快速創建一個WebService,因而看到了MSDN上的這一篇文章 Building Cross-Platform Web Services with ServiceStack,因此這裏簡要介紹一下如何使用ServiceStack快速創建一個WebService服務。html

固然,在開始以前,首先要說明一下ServiceStack是個什麼東西。 在國內用ServiceStack的彷佛不多,大部分都是WCF或者ASP.NET WebAPI,惟一接觸ServiceStack的多是在C# 中調用Redis的時候,有個ServiceStack.Redis,以前還寫過一篇 .NET中使用Redis 的拙文。這個ServiceStack.Redis其實就是ServiceStack的一個組件,專門用來跟Redis進行交互的。git

一 關於WebService

在談論ServiceStack以前,先看看構成一個WebService的基本框架:github

Print

服務層就是定義WebService接口的地方,這一層也是客戶端使用WebService惟一須要與之交互的一層。web

業務層一般包含有大量的業務邏輯。他也是實現接口層定義的接口的地方,也是保持服務層的輕量以及關注服務端客戶端的契約以及通信的地方。瀏覽器

數據層一般就是封裝數據訪問方法並給業務層提供抽象數據模型。架構

如今咱們來看Service這一層。一些WebService使用遠程過程調用的方法來實現(RPC),好比會定義以下函數調用:app

public interface IService
{
    string DoSomething(int input);
}

這種RPC的方式使得服務不能很好的應對變化。好比,在上面的代碼中,若是後續版本的接口須要接受兩個參數來執行DoSomething方法,或者說除了返回一個string外還須要返回其餘信息。若是在原接口上修改的話,就會使得老版本的客戶端沒法使用。固然,咱們能夠建立一個平行的DoSomething_v2來接受兩個參數。可是隨着時間的遷移,咱們的接口中會充斥着愈來愈多這樣的定義,不論是新用戶仍是老用戶都會感到困惑。框架

面對這種狀況,可使用數據傳輸對象(DTO) 來定義前面的接口中的相關參數。上面的RPC方式轉換爲對應的DTO模型以下:異步

public class DoSomethingRequest
{
    public int Input { get; set; }
}
public class DoSomethingResponse
{
    public string Result { get; set; }
}
public interface IService
{
    DoSomethingResponse DoSomething(DoSomethingRequest request);
}

每一個服務接受一個DTO請求參數,返回一個DTO響應。在請求和相應的DTO對象中添加字段,不會破壞舊的客戶端。ide

在WCF中RPC和DTO風格的WebService均支持,可是在ServiceStack中僅支持DTO風格。ServiceStack爲了減小繁瑣和注重接口設計從而僅擁抱的DTO風格的遠程 WebService接口。 這是瞭解 ServiceStack的關鍵,也是ServiceStack框架的設計原則。

瞭解了ServiceStack的設計理念後,來看看ServiceStack是什麼。

二 ServiceStack是什麼

ServiceStack是一個開源的十分流行的WebService框架,引用其官網的介紹:

「Service Stack is a high-performance .NET web services platform that simplifies the development of high-performance REST (JSON, XML, JSV, HTML, MsgPack, ProtoBuf, CSV) and WCF SOAP Web Services.」

「ServiceStack是一個高性能的.NET Web Service 平臺,他可以簡化開發高性能的REST (支持JSON,XML,JSV,HTML,MsgPack,ProtoBuf,CSV等消息格式)以及WCF SOAP風格的WebService」。

在其主頁上也有一篇名爲What is the ServiceStack的介紹。建議您直接看,這裏從裏面截取了幾張圖:

more than service

能夠看到ServiceStack除了在其底層是一個精簡的WebService框架以外,在其上還有與之相關的一些組件,好比號稱.NET 上最快的JSON序列化工具,.NET中流行的Redis訪問模塊,輕量級快速Orm框架OrmLite等諸多功能。

what is service stack

能夠看到這些組件基本提供了一個WebService框架必需的一些功能。

Visualizing ServiceStack

在內部實現上ServiceStack創建在原生的ASP.NET IHttpHandler之上,他可以容許在.NET Framework和Mono之上。

下面來看如何使用ServiceStack創建一個WebService:

三 使用ServiceStack

要建立服務,首先要定義接口。這裏以一個售票系統爲例來講明如何使用ServiceStack來建立服務:

建立服務接口層

首先新建一個TicketSystem.ServiceContract的類庫,咱們定義DTO對象。必須要有一個Ticket實體類:

public class Ticket
{
    public int TicketId { get; set; }
    public int TableNumber { get; set; }
    public int ServerId { get; set; }
    public List<Order> Orders { get; set; }
    public DateTime Timestamp { get; set; }
}

在WCF中須要在實體類和字段上面添加DataContract和DataMember來表示序列化時須要的字段,若是沒有添加這些標籤,在序列化的時候就會忽略。

而在ServiceStack中,這些標記都不須要,ServiceStack會序列化全部的Plain Old CLR Objects(POCOs),而且這些對象對客戶端均可見。

而後開始定義Service中須要用到的對外提供服務的接口:

public interface ITicketService
{
    List<Ticket> Any(GetAllTicketsInQueueRequest request);

    void Any(QueueTicketRequest request);

    Ticket Any(PullTicketRequest request);
}

在ITickertService中,咱們定義了三個操做,第一次看到這樣的操做可能有些奇怪,由於方法名稱都同樣。這是ServiceStack和WCF不同的地方。在WCF中以上接口多是這樣的:

[ServiceContract]
public interface ITicketService
{
    [OperationContract]
    List<Ticket> GetAllTicketsInQueue(GetAllTicketsInQueueRequest request);
    [OperationContract]
    void QueueTicket(QueueTicketRequest request);
    [OperationContract]
    Ticket PullTicket(PullTicketRequest request);
}

WCF中接口須要使用ServiceContract來代表,其中的方法須要使用OperationContract來標記。方法的名稱就是服務的名稱。

ServiceStack中的服務方法名爲Any,Get以及Post,這也是ServiceStack支持的請求類型,Any表示服務能夠經過HTTP Get和HTTP Post兩種方式調用。這強化和簡化了RESTFull風格的WebService的實現。只須要在這些方法上添加愛[Route(…)]屬性便可。在ServiceStack中,方法和方法之間的區別是經過服務的參數及請求對象Request DTO來區分的,而不是像WCF中經過方法名稱來區分。這就表示一個請求DTO對象不能在ServiceStack的多個Service中複用。

建立服務端

有了服務接口層以後,須要編寫服務端以實現這些邏輯,也就是前面定義的ITicketService接口。首先建立名爲ServiceStackServer的空的ASP.NET 應用程序,而後新建TicketService類,是該類實現ITicketService接口並繼承自Service類。Service類是ServiceStack中的,能夠經過NuGet來安裝和引用ServiceStack相關類庫:

Managet NuGet Packages

實現後TicketService類以下:

public class TicketService : Service, ITicketService
{
    private static readonly TicketSystem.TicketProcessor.TicketProcessor
        _ticketProcessor = new TicketSystem.TicketProcessor.TicketProcessor();

    public List<Ticket> Any(GetAllTicketsInQueueRequest request)
    {
        return _ticketProcessor.GetTicketsInQueue()
            .Select(TicketTranslator.TranslateTicket).ToList();
    }

    public void Any(QueueTicketRequest request)
    {
        _ticketProcessor.QueueTicket(
            TicketTranslator.TranslateTicket(request.Ticket));
    }

    public Ticket Any(PullTicketRequest request)
    {
        TicketSystem.TicketProcessor.Ticket nextTicket =
            _ticketProcessor.PullTicket();

        if (nextTicket != null)
        {
            return TicketTranslator.TranslateTicket(nextTicket);
        }

        return null;
    }
}

這裏面咱們定義了一個私有了TicketProcessor 變量,接口中的全部方法都經過該類實現,在接口對象到該方法的調用中,咱們對實體進行了轉換。該對象在其餘程序集中定義,這樣能保證服務端代碼簡潔。

有了服務端以後,須要把服務端Host起來對外提供服務,ServiceStack提供了經過IIS,Self-Host等多種形式。由於咱們以前建立的ASP.NET程序,因此,只須要再添加一個Global.asax文件,而後在啓動的事件Application_Start中初始化便可。

protected void Application_Start(object sender, EventArgs e)
{
    //Initialize your web service on startup.
    new TicketServiceHost().Init();
}

 

public class TicketServiceHost : AppHostBase
{
    //Register your web service with ServiceStack.
    public TicketServiceHost() 
        : base("Ticket Service", typeof(TicketService).Assembly) 
    { }

    public override void Configure(Funq.Container container)
    {
        //Register any dependencies your services use here.
    }
}

只須要實現ApphostBase基類,提供服務顯示名稱,以及實現了Service接口的服務所在的程序集便可。

固然也能夠經過控制檯應用程序來Host咱們的WebService,這時TicketServiceHost須要實現AppSelfHostBase,實現以下:

public class TicketServiceHost : AppSelfHostBase
{
    /// <summary>
    /// Default constructor.
    /// Base constructor requires a name and assembly to locate web service classes. 
    /// </summary>
    public TicketServiceHost()
        : base("WebApplication1", typeof(TicketService).Assembly)
    {

    }

    /// <summary>
    /// Application specific configuration
    /// This method should initialize any IoC resources utilized by your web service classes.
    /// </summary>
    /// <param name="container"></param>
    public override void Configure(Container container)
    {
        //Config examples
        //this.AddPlugin(new PostmanFeature());
        //this.AddPlugin(new CorsFeature());
    }
}

而後在Main函數中,啓動便可:

static void Main(string[] args)
{
    var listeningOn = args.Length == 0 ? "http://*:1337/" : args[0];
    var appHost = new TicketServiceHost()
        .Init()
        .Start(listeningOn);

    Console.WriteLine("AppHost Created at {0}, listening on {1}",
        DateTime.Now, listeningOn);

    Console.ReadKey();
}

如今,咱們運行前面建立的ASP.NET或者運行Console託管的TicketServiceHost, 在瀏覽器中訪問http://localhost:1337/便可看到咱們定義好的服務:

AppSelfHost

service page 

服務客戶端

服務端建立和託管好以後, 服務使用者就能夠直接編寫HttpWebRequest對象對這些服務經過Get或者Post方式進行直接訪問了。

除此以外,ServiceStack也內置了一些便捷訪問的客戶端,這些對象位於ServiceStack.ServiceClient.Web命名空間中。全部的內置的客戶端都實現了ServiceStack.Service.IServiceClient 放,這些支持REST的客戶端都實現了ServiceStack.Service.IRestClient.這些客戶端對象包括:

  • JsonServiceClient
  • JsvServiceClient
  • XmlServiceClient
  • MsgPackServiceClient
  • ProtoBufServiceClient
  • Soap11ServiceClient
  • Soap12ServiceClient

從名稱能夠看出,這幾種不一樣之處在於支持的序列化和反序列化格式不一樣。由於他們實現的是一系列相同的接口,因此他們的用法相同,也能夠相互替換。

這裏咱們不演示如何經過HttpWebRequest像請求普通的網頁那樣請求咱們以前託管好的WebService,如今假設咱們有一個Console程序須要使用WebService程序。只須要新建一個ServiceStack的Service,而後將Host的地址傳入便可。這些方法在內部會爲咱們將代碼轉化爲傳統的使用HttpWebRequest的方式請求,目前這些方法還都是同步的。

好比,若是咱們想使用WCF中使用的Soap11來請求,只需以下代碼:

static void Main(string[] args)
{
    Console.Title = "ServiceStack Console Client";

    using (var client = new Soap11ServiceClient("http://localhost:1337"))
    {
        List<Ticket> queuedTickets = client.Send<List<Ticket>>(
            new GetAllTicketsInQueueRequest()) ;
        if (queuedTickets != null)
        {
            foreach (Ticket ticket in queuedTickets)
            {
                PrintTicket(ticket);
            }
        }
    }
            
    Console.ReadKey();
}

這裏的Soap11ServiceClient 對象能夠換成ServiceStack支持的其餘數據序列化格式。

四 結語

本文介紹了開源的比較流行的WebService框架ServiceStack,並經過一個簡單的例子展示瞭如何使用ServiceStack建立出一個WebService。

它可以比較方便快捷的搭建高效的具備RESTFull風格的WebService應用程序。其框架的設計思路也很是值得學習,經過相似「約定大於配置」的方式,減小了WCF中建立WebService須要的各類標記,強制用戶使用DTO的方式來創建服務接口。ServiceStack也提供了名爲ServiceStackVS的VisualStudio插件可以幫助您方便的建立ServiceStack模板。

ServiceStack Template

WCF能夠實現ServiceStack全部的功能。可是ServiceStack爲您快速建立一個高效WebService提供了另一種選擇,他能夠運行於不一樣的平臺。ServiceStack也是開源社區比較活躍的一個WebService框架,經過研究其代碼也能夠借鑑其思路,提升本身的編碼和架構水平。好比能夠修改Client以支持異步方法調用等等,能夠本身動手添加本身想要的功能。

但願本文對您瞭解ServiceStack有所幫助。

相關文章
相關標籤/搜索