基于轻量型Web服务器Raspkate的RESTful API的实现

在上一篇文章中,咱们已经了解了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节点下,例如:app

<?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服务。ide

案例:计算器

最简单的不过就是计算器运算:加、减、乘、除。那么最最简单的就是计算两个整数的和,好吧,就以这个为例,开始咱们的RESTful API开发之旅。测试

首先,打开Visual Studio 2013,新建一个C#类库(Class Library)项目,项目命名为RaspkateCalculatorModule,注意.NET Framework至少选择4.5.2以上(老版本的Framework除了2.0之外,Microsoft都再也不官方支持了)。成功建立项目后,添加对Raspkate.dll的引用。日志

而后,在这个项目中新建一个名为CalculatorController的类,代码以下:xml

[RoutePrefix("calc")]
public class CalculatorController : RaspkateController
{
    [HttpGet]
    [Route("add/{a}/{b}")]
    public int Add(int a, int b)
    {
        return a + b;
    }
}

接着,在这个项目中新建一个名为Module的类,代码以下:blog

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请求的服务了:

image

请打开你的浏览器,在地址栏中输入:

http://127.0.0.1:9023/calc/add/12/30

那么,你应该看到的是:

image

看来Raspkate服务已经将计算结果返回给你了。怎么样?使用Raspkate开发RESTful API是否是很是快捷?接下来让咱们看看更加有意思的特性。

案例:计算器(进阶)

刚才咱们的计算器仍是太简单,接下来我打算让这个计算器可以计算复数(包括虚数部分)的乘法。同窗们是否还记得复数相乘的计算公式?

image

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),看看咱们的程序是否能够正确执行:

image

测试成功,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编程更为简单快捷。从此若是这部分的确有应用的话,能够对整个结构做进一步完善。

相关文章
相关标签/搜索