在上一篇文章中,我們已經了解了Raspkate這一輕量型Web服務器,今天,我們再一起了解下如何基於Raspkate實現簡單的RESTful API。
模塊
首先讓我們了解一下“模塊”的概念。Raspkate的模塊包含了一組能夠提供完整業務功能的HTTP處理器(Handler),例如,在Raspkate的源代碼庫中,默認提供了兩個模塊:Default和RaspberryPi,它們分別位於兩個不同的C#項目中:
- Raspkate.Modules.Default
- Raspkate.Modules.RaspberryPi
Default模塊包含了一個標准的靜態文件訪問服務/處理器,以及一個能夠讀取並返回服務器信息的RESTful API控制器;而RaspberryPi模塊則提供了一個訪問樹莓派信息頁靜態文件的處理器,以及一個讀取樹莓派信息的RESTful API控制器。當然,在這里靜態文件訪問處理都是由FileHandler負責,而RESTful API的處理則由ControllerHandler完成。雖然這兩個模塊使用了相同類型的Handler,但它們所專注的業務功能完全不同,而且它們是相互隔離,獨立執行的。
Raspkate中每個模塊都被存放於modules目錄下的某個子目錄中,在Raspkate服務啟動時,會掃描modules目錄下的所有程序集,定位所有繼承於RaspkateModule類的子類,並根據類型定義對Handler進行初始化然后注冊到Raspkate服務中,以便這些Handler能夠為HTTP請求提供服務。當然,這些模塊也可以放在其它目錄下,但這就需要修改Raspkate服務的配置文件RaspkateService.exe.config,把模塊所在的目錄添加到modules節點下,例如:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="raspkateConfiguration" type="Raspkate.Config.RaspkateConfiguration, Raspkate"/> </configSections> <raspkateConfiguration xmlns="urn:Raspkate.Config" prefix="http://127.0.0.1:9023/"> <modules> <add path="modules"/> <add path="d:\\test" relative="false" /> </modules> </raspkateConfiguration> </configuration>
在模塊的注冊類型中(也就是繼承於RaspkateModule類的子類中),只需要返回該模塊能夠提供的Handler實例即可。接下來,讓我們一起看看,如何開發一個自己的模塊,並通過注冊ControllerHandler,向調用者提供RESTful API服務。
案例:計算器
最簡單的不過就是計算器運算:加、減、乘、除。那么最最簡單的就是計算兩個整數的和,好吧,就以這個為例,開始我們的RESTful API開發之旅。
首先,打開Visual Studio 2013,新建一個C#類庫(Class Library)項目,項目命名為RaspkateCalculatorModule,注意.NET Framework至少選擇4.5.2以上(老版本的Framework除了2.0以外,Microsoft都不再官方支持了)。成功創建項目后,添加對Raspkate.dll的引用。
然后,在這個項目中新建一個名為CalculatorController的類,代碼如下:
[RoutePrefix("calc")] public class CalculatorController : RaspkateController { [HttpGet] [Route("add/{a}/{b}")] public int Add(int a, int b) { return a + b; } }
接着,在這個項目中新建一個名為Module的類,代碼如下:
internal sealed class Module : RaspkateModule { public Module(ModuleContext context) : base(context) { } protected override IEnumerable<IRaspkateHandler> CreateHandlers() { yield return new ControllerHandler("CalculatorController", new [] { typeof(CalculatorController) }); } }
OK,萬事俱備,只欠東風啦!回到Raspkate中,將RaspkateService.exe.config稍微改動一下,將該模塊的輸出目錄添加到modules節點中,即可直接啟動RaspkateService.exe程序了:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="raspkateConfiguration" type="Raspkate.Config.RaspkateConfiguration, Raspkate"/> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <raspkateConfiguration xmlns="urn:Raspkate.Config" prefix="http://127.0.0.1:9023/"> <modules> <add path="modules"/> <add path="C:\Users\chenqn\Documents\visual studio 2013\Projects\RaspkateCalculatorModule\RaspkateCalculatorModule\bin\Debug" relative="false"/> </modules> </raspkateConfiguration> <log4net> <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%utcdate{DATE} [%thread] %level %logger - %message%newline"/> </layout> </appender> <appender name="FileAppender" type="log4net.Appender.FileAppender"> <file value="logs/raspkate.log" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %level %logger - %message%newline" /> </layout> </appender> <root> <level value="INFO"/> <appender-ref ref="ConsoleAppender"/> <appender-ref ref="FileAppender" /> </root> </log4net> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> </configuration>
啟動程序后,你可以在輸出的日志中注意到,CalculatorController已經被注冊到ControllerHandler當中,進而可以開始提供HTTP請求的服務了:
請打開你的瀏覽器,在地址欄中輸入:
http://127.0.0.1:9023/calc/add/12/30
那么,你應該看到的是:
看來Raspkate服務已經將計算結果返回給你了。怎么樣?使用Raspkate開發RESTful API是不是非常快捷?接下來讓我們看看更加有意思的特性。
案例:計算器(進階)
剛才我們的計算器還是太簡單,接下來我打算讓這個計算器能夠計算復數(包括虛數部分)的乘法。同學們是否還記得復數相乘的計算公式?
OK,也就是我們的RESTful API需要接收兩個復數,每個復數都要包含實數 r 和虛數 i 兩個部分,返回值也應該包含實數和虛數兩個部分。那么,我們的CalculatorController就可以寫成這樣:
[RoutePrefix("calc")] public class CalculatorController : RaspkateController { [HttpGet] [Route("add/{a}/{b}")] public int Add(int a, int b) { return a + b; } [HttpPost] [Route("mul")] public dynamic Multiplicity([FromBody] dynamic input) { var a = input.x.r; // 第一個數的實數部分 var b = input.x.i; // 第一個數的虛數部分 var c = input.y.r; // 第二個數的實數部分 var d = input.y.i; // 第二個數的虛數部分 return new { z = new { r = a * c - b * d, i = b * c + a * d } }; } }
重新運行Raspkate服務,打開能夠發出HttpPost請求的測試客戶端(我用的是Fiddler),看看我們的程序是否可以正確執行:
測試成功,RESTful API已經以JSON格式返回了我們需要的計算結果。
總結
從上面的演示可以看到,Raspkate服務中RESTful API的實現,沿用了類似微軟ASP.NET Web API的編程習慣,包括:
- Controller的編程模型(ASP.NET Web API中使用ApiController作為基類,此處使用RaspkateController作為基類)
- Attribute Routing
- HttpGet和HttpPost兩種HTTP方法(其它的暫未實現)
- FromBody特性修飾符,使得方法的某些參數可以直接從HTTP Post Body中取值
- 對dynamic類型、匿名類型的支持
相比之下,Raspkate服務所提供的RESTful API編程更為簡單快捷。今后如果這部分的確有應用的話,可以對整個結構作進一步完善。