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

在上一篇文章《Raspkate - 基于.NET的可运行于树莓派的轻量型Web服务器中,我们已经了解了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节点下,例如:

1
2
3
4
5
6
7
8
9
10
11
12
1 14
<? 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的类,代码如下:

1
2
3
4
5
6
7
8
9
1
[RoutePrefix( "calc" )]
public  class  CalculatorController : RaspkateController
{
     [HttpGet]
     [Route( "add/{a}/{b}" )]
     public  int  Add( int  a, int  b)
     {
         return  a + b;
     }
}

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

1
2
3
4
5
6
7
8
9
10
1
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程序了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2 30
31
32
33
34
35
36
37
38
<? 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请求的服务了:

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

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

那么,你应该看到的是:

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

案例:计算器(进阶)

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

OK,也就是我们的RESTful API需要接收两个复数,每个复数都要包含实数 和虚数 两个部分,返回值也应该包含实数和虚数两个部分。那么,我们的CalculatorController就可以写成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[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编程更为简单快捷。今后如果这部分的确有应用的话,可以对整个结构作进一步完善。


相关文章: 

  • Raspkate - 基于.NET的可运行于树莓派的轻量型Web服务器

  • 在树莓派下安装Mono环境

  • 树莓派上安装mono和jexus运行ASP.NET程序

  • 树莓派2发布:四核 CPU+1G RAM 硬件升级不加价,支持Windows 10


陈晴阳(Sunny Chen),2003年毕业于中南大学铁道校区。高级程序员,系统分析员,微软MVP(Visual C#)。cnblogs网名daxnet,并打算以该名闯荡IT江湖。MicrosoftDynamics AX、Microsoft .NET/C#以及领域驱动设计(DDD)的狂热爱好者。

原文地址:http://www.cnblogs.com/daxnet/p/5326992.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329787.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python股票自动买卖视频教程_十分钟学会用Python交易股票

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼本文通过讲述 [单股票均线策略] 在 Ricequant 量化平台的实现&#xff0c;熟悉平台并快速入门、创建自己的量化策略代码 。难易度&#xff1a;入门级.从一下几点说起&#xff1b;1 确定框架&#xff1a;[单股票均线策略] 的主要策略…

前端面试常考系列二

转载自 前端面试常考系列二 一、外部引用CSS有几种方式&#xff0c;有何区别 外部引用CSS的方式有两种分别是link和import。 区别如下&#xff1a; 1、link是XHTML标签&#xff0c;除了加载CSS外&#xff0c;还可以定义RSS等其它事务&#xff1b;import属于CSS范畴&#xff0c;…

3分钟看完Build2016 Day 1 Keynote

Build 2016 Day 1 Keynote 直播结束&#xff0c;M姐不得不说&#xff0c;没看直播的真心错过了一大波黑科技和充值我软信仰的大好时机&#xff0c;不过别后悔&#xff0c;M姐精选了干货&#xff0c;一次性让你补充信仰。没看的真心会被甩开八条街&#xff01;&#xff01; 言归…

js动态给按钮赋id_如何给SHOPIFY店铺添加“立即购买”动态结账按钮

动态结账按钮会根据店铺后台所支持的第三方快速结账付款方式和顾客设备浏览器的记录动态展示快速结帐按钮&#xff0c;比如PayPal Express Checkout、Apple Pay等。当然如果浏览器没有记录或者店铺后台没有支持的快速结帐付款方式&#xff0c;按钮则会显示为“buy it now”。Dy…

java序列化与深度拷贝

【README】 1&#xff0c; 为啥要序列化或序列化的意义&#xff1f;2&#xff0c;系统间调用的报文格式&#xff0c;大多数是Json字符串&#xff08;或字节数组&#xff09;&#xff1b;接收方接收json&#xff1b;3&#xff0c;但当系统调用如RMI&#xff0c;客户端请求服务器…

微软Build 2016开发者大会--兑换承诺

微软的Build开发者大会已经成为它向我们宣布其在未来一年里的战略方向的一个最大平台。不像苹果的发布大会&#xff0c;微软之所以要召开这个会议并不是要发布什么产品&#xff0c;而是像众多业内人士所分析的那样&#xff0c;希望通过介绍公司的努力来说服它最重要的听众——开…

前端面试常考系列三

转载自 前端面试常考系列三 一、简述一下src与href的区别 href 表示超文本引用&#xff0c;在 link和a 等元素上使用。src 表示来源地址&#xff0c;指向外部资源所在位置&#xff0c;在 img、script、iframe 等元素上。src 的内容&#xff0c;是页面的一部分&#xff0c;是引入…

java内部类小结

【README】 1&#xff0c;本文总结了java4种内部类&#xff0c;包括 成员内部类&#xff1a;在外部类内部定义的非静态类&#xff1b;成员内部类不能独立存在&#xff0c;如 UML中类间的组合关联关系&#xff1b;静态内部类&#xff1a;在外部类内部定义的静态类&#xff1b;…

python内置模块有哪些_python中那些小众但有用的内置模块

今天带来的是python里一些小众但是却比较实用的python库&#xff0c;一起来看看吧&#xff01;pprint&#xff1a;更清晰的打印pprint 是 pretty printer 的缩写&#xff0c;用来打印 Python 数据结构&#xff0c;与 print 相比&#xff0c;它打印出来的结构更加整齐&#xff0…

微软想让你跟机器人说句话就把事办了

也别猜错&#xff0c;微软可没有像 Google 一样打算让四只脚能跑 60 迈和两只脚能穿行森林的机器人大军占领你的家。他们家的机器人不是 Robot&#xff0c;而叫 Bot&#xff0c;可能是 chatbot 的简称&#xff0c;也就是聊天机器人。 具体来说&#xff0c;微软在自然语言处理的…

转:Spring Boot 获取 HttpServletRequest 的方法

转自&#xff1a; Spring Boot 获取 HttpServletRequest 的方法 - 简书本文介绍 Spring Boot 2 获取 HttpServletRequest 的方法。 目录 概述 方法Controller 方法参数属性自动注入手动方法调用借助 Mo...https://www.jianshu.com/p/b7a7d66c4ef2 本文介绍 Spring Boot 2 获取…

前端面试常考系列四

转载自 前端面试常考系列四 一、CSS盒子模型有哪些用处 css中的盒子模型是为了理解divcss模型的定位功能&#xff0c;它利用盒子模型这样的布局方式代替了传统的表格布局方式。盒子模型是在学习divcss布局方式中必须要学习的一个模型&#xff0c;通过这个模型可以明白网页中di…

python线性加权模型_局部加权之线性回归(1) - Python实现

1 #局部加权线性回归2 #交叉验证计算泛化误差最小点345 importnumpy6 from matplotlib importpyplot as plt789 #待拟合不含噪声之目标函数10 deforiFunc(x):11 y numpy.exp(-x) * numpy.sin(10*x)12 returny13 #待拟合包含噪声之目标函数14 def traFunc(x, sigma0.03):15 y …

3分钟看完 Day2 Keynote

hey~ M姐又给大家带来了满满惊喜的 Build2016 Day 2 Keynote 干货汇总了。 如果你连昨天的都还不知道&#xff0c;那真心就 out 了。如果说信仰在昨天充值爆棚&#xff0c;今天就要充值信仰到掀翻房顶的节奏了&#xff01;&#xff01;&#xff01; 红衣主教今天妥妥变身成为新…

latex 数学公式_技能分享——LaTeX篇I

公众号文章系列二——“小袁技能分享”上线啦&#xff0c;第一篇推文我们聊一聊LaTeX(音译 “拉泰赫”)Question 1什么是LaTeX&#xff1f;要解释LaTeX是什么&#xff0c;我们先要了解另外一个事物&#xff1a;TeX。1968年&#xff0c;美国著名计算机科学家、现代计算机科学的先…

转:springboot servlet使用配置

转自&#xff1a; springboot servlet使用配置_奔跑的蜗牛的博客-CSDN博客在spring boot中添加自己的Servlet有两种方法&#xff0c;代码注册Servlet和注解自动注册&#xff08;Filter和Listener也是如此&#xff09;。 一、代码注册通过ServletRegistrationBean 获得控制。 也…

前端面试常考系列五

转载自 前端面试常考五 一、DIV元素是什么 DIV元素是用来为HTML文档内大块&#xff08;block-level&#xff09;的内容提供结构和背景的元素。DIV的起始标签和结束标签之间的所有内容都是用来构成这个块的&#xff0c;其中所包含元素的特性由DIV标签的属性来控制&#xff0c;或…

从业十余年谈谈对dotnet看法与坚持

前言 园子经常在讨论关于.Net发展的问题&#xff0c;我也这些年在工作乃至创业过程中使用.Net碰到的一些问题和看法。个人擅长的技术面&#xff0c;C/C/MFC/STL、ASM、JAVA、VB、Javascript/Typescript、C#/WebForm/MVC、Android/MonoDroid,Linux/Windows&#xff0c;还有没有可…

kali安装python3.7_Debian服务器之安装Python3.7

1、系统环境介绍1.1 系统版本debian-9.6.0-amd64-netinst1.2 系统内核Linux lnnkee 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux2、下载安装包https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz3、配置安装环境apt install libffi-dev …

org.apache.kafka.common.errors.TimeoutException: Topic not present in metadata 解决方法

【README】 本文po出了 topic not present in metadata 的解决方法&#xff1b; 很多博文说是 因为 jackson-databind 没有引入&#xff0c;但是我重新引入后&#xff0c;还是没有解决问题&#xff1b; 最后&#xff0c;原因在于我要发送消息的分区&#xff0c;topic 没有对…