提到構建WebService服務,大家肯定第一個想到的是使用WCF,因為簡單快捷嘛。首先要說明的是,本人對WCF不太了解,但是想快速建立一個WebService,於是看到了MSDN上的這一篇文章 Building Cross-Platform Web Services with ServiceStack,所以這裡簡要介紹一下如何使用ServiceStack快速建立一個WebService服務。
當然,在開始之前,首先要說明一下ServiceStack是個什麼東西。 在國內用ServiceStack的似乎很少,大部分都是WCF或者ASP.NET WebAPI,唯一接觸ServiceStack的可能是在C# 中調用Redis的時候,有個ServiceStack.Redis,之前還寫個一篇 .NET中使用Redis 的拙文。這個ServiceStack.Redis其實就是ServiceStack的一個組件,專門用來跟ServiceStack進行交互的。
在談論ServiceStack之前,先看看構成一個WebService的基本框架:
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對象中添加字段,不會破壞舊的客戶端。
在WCF中RPC和DTO風格的WebService均支持,但是在ServiceStack中僅支持DTO風格。ServiceStack為了減少繁瑣和注重接口設計從而僅擁抱的DTO風格的遠程 WebService接口。 這是了解 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的介紹。建議您直接看,這裡從裡面截取了幾張圖:
三 使用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相關類庫:
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/即可看到我們定義好的服務:
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模板。
WCF可以實現ServiceStack所有的功能。但是ServiceStack為您快速創建一個高效WebService提供了另外一種選擇,他可以運行於不同的平台。ServiceStack也是開源社區比較活躍的一個WebService框架,通過研究其代碼也可以借鑒其思路,提高自己的編碼和架構水平。比如可以修改Client以支持異步方法調用等等,可以自己動手添加自己想要的功能。
希望本文對您了解ServiceStack有所幫助。
得看你用什麼系統了,一般用微軟的windows 系統的話,建議用iis ,插上系統盤之後,在控制面板--添加刪除程序裡面--添加刪除組件裡面就可以安裝iis ,設置根目錄之後,把網頁文件放到根目錄就行了。
如果需要發布的話,需要有一個固定的外圍ip的,如果沒有的話,那就用一些軟件做一個動態域名解析也行。
你還是在作一次web引用,因為你在第一個解決方案中可以引用login
,在第二個解決方案就一定可以.否則你第一個是怎麼用的.
再其次你看看login WebService 是否還是存在,運行第一個解決方案測試看看.
如果服務不提供了,當然也引用不到了
補充問題:
development server 就是你右下角的東東,是一個輕量的服務器,用於本地調試用的.
你前人開發完成的Web Service可能發布到IIS(真正的服務器上),所以你看不到右下角的圖標
啟動WebService不用2個vs的.在一個vs中你右鍵點你的WebService項目文件,右鍵菜單有個Debug.你可以先啟動WS.然後再用同樣的方法啟動你的客戶端。一個vs就可以了