背景


由于公司积极推动各业务产品服务化,得益于容器化技术的不断发展及普及,项目组的服务也更多地基于Mono,Jexus,Docker,Kubernetes等类库、容器、管理工具运行于Linux系统上。业务服务中基于WebApi方式的服务必不可少,本文主要记录在ms的Webapi2框架下,以mono+jexus作为编译、运行框架在linux环境下提供服务这个过程中存在的一些坑。

mono版本的选择


截止写本文之前,Mono的最新版本是4.6.0.125,除此版本之外,主要使用、测试的版本还包括,Mono-4.4(小版本记不清了),Mono-4.2.2。

这3个版本以4.2,4.4,4.6三个版本指代,并且这3个版本都是官方的stable版本。

其中未完成的功能本文略过不提,可参考 这个链接

(注:下文所述所有产生问题的后端代码,在.net framework+windows平台部署测试均无任何问题,仅针对Mono+Jexus+linux环境而言)

Mono-4.6版本支持c#6.0语法,但是,MVC 4,5中的某些Asyn方法未实现(后边的测试会看到),这个对Webapi2框架是一样的,然而这些都不是最重要的,Mono4.6(亲测),4.4(同事测试反映)这两个大版本存在一个无法搞定的问题:

Webapi部署后测试,由其发起的对外的Http请求工作正常,但是在一段时间后(不定,一般一小时内吧),不会再发出Http请求,但是response并不为空仅仅是Content为空。

这个问题就类似于一票否决,虽然Mono4.6版本修复了之前(4.2)版本存在的一些问题,并且还支持了C#6.0语法等等,但是这个莫名其妙的缺陷如此致命以至于在实际开发工作中无法使用这两个版本(4.4,4.6)。如有解决方案请不吝指出。

因此,虽然存在很多缺陷,但是Mono-4.2版本是目前(4.6.0版本及之前)唯一的选择。

Mono-4.2版本使用过程遇到的一些问题


这里并没有说这些问题是Mono-4.2版本的Bug,因为有些问题是官方明确了还未实现的,所以并不能说是Bug。

在我的实际工作场景中(Webapi服务),主要的问题还是集中于请求中Content解析上,再次强调一下,下文所有代码在.net framework下都没有任何问题,仅在Mono-4.2版本编译运行环境下存在缺陷。

请求均以Content-Type:application/json发送。

示例一:

[ActionName("GetStatusTimeDist")]
[HttpPost]
public IHttpActionResult GetStatusTimeDist([FromBody]ParamClass param)
{
  ...
}

正常情况下下最常见的写法,ParamClass是自定义的参数类型,FromBody属性加或者不加都不会影响结果:HttpStatusCode:500,路由匹配时抛出的异常。

2016-11-9补充:

通过errorfilter捕获服务器内部异常包装后返回可以看到详细信息:

400错误信息:
["Method 'HttpRequestBase.GetBufferlessInputStream' not found."]

mono的开发记录中可以查询这个方法的实现:在4.2.2版本中,这个方法应该还未实现,因此出现以上错误。

示例二:

[ActionName("GetStatusTimeDist")]
[HttpPost]
public IHttpActionResult GetStatusTimeDist([FromBody]dynamic param)
{
  ...
}

也是一种好用的写法,不用预先定义参数类型,以动态类型获取content内的参数,但结果仍然一样:HttpStatusCode:500

示例三:

经过以上两种示例尝试,可见在api声明中加入请求体中的参数获取是无法正确匹配路由的,但是对querystring的传参方式是没有问题的,具体的测试就略过,如果改为querystring的方式传参,是可以看到200返回的。

要解决请求content传递参数,只能从Request中主动获取Content内容:

[ActionName("GetStatusTimeDist")]
[HttpPost]
public IHttpActionResult GetStatusTimeDist()
{
    HttpContent bodyContent = Request.Content;
    Task<string> task = bodyContent.ReadAsStringAsync();
    task.Wait();
    content = task.Result;
}

这种获取Content的方式,可以正确匹配路由,结合querystring传参方式的测试结果可证明Mono4.2并不支持在API声明中包含content传参的任何形式。但是会收到另一个HttpStatusCode:405,异常点:task.Wait(),猜测是Mono-4.2版本中部分Asyn方法未实现造成。

示例四:

一种不太常见的stream获取方式

[ActionName("GetStatusTimeDist")]
[HttpPost]
public IHttpActionResult GetStatusTimeDist()
{
    string content;
    Stream stream = new MemoryStream();
    var action = Request.Content.CopyToAsync(stream);
    action.Wait();
    stream.Position = ;
    using (StreamReader sr = new StreamReader(stream))
    {
     content = sr.ReadToEnd();
    }
    stream.Dispose();
}

以这种方式获取content内容,mono会明确告诉你错误信息:CopyToAsync(Stream stream)这个方法不存在。应该是还未实现。

以上的四种方式均为.net framework中可以正常工作的获取content内容的方式,但是在mono-4.2版本中都不可行。

以下是目前测试出的唯一可行的方式:

示例五:

[ActionName("GetStatusTimeDist")]
[HttpPost]
public IHttpActionResult GetStatusTimeDist()
{
    string content;
    using (StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream))
    {
        content = reader.ReadToEnd();
    }
}

获取到的content为body中传递的json字符串,需要主动进行反序列化,得到所需要的参数对象。

总结


Mono截止目前(4.6.0.125)版本为止,功能已经越来越完善,比如在4.6版本中已经修复了4.2版本中存在的请求Content参数获取的各种缺陷,可以以.net framework环境下各种可用的(如示例一,二等)方式来获取请求的content参数,但却引入了一些新的缺陷(一段时间后无法主动发出http请求),并且直接导致该版本不可用于生产环境。这些问题都需要全面的测试及评估,Mono的版本更迭也需要更加谨慎。

以上内容均基于本人对现阶段各版本(截止 Mono-4.6.0.125)亲自测试,如有错误请不吝指出。

现阶段Mono版本下的WebAPI开发中存在的一些问题的更多相关文章

  1. 【WebApi系列】浅谈HTTP在WebApi开发中的运用

    WebApi系列文章 [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi参数的传递 [04]详解WebApi测试和PostMan [05]浅谈W ...

  2. MVC4 WebApi开发中如果想支持Session请做好如下几个方面的问题

    1.在WebApiConfig中建立建立HttpControllerHandler和HttpControllerRouteHandler 并覆写它 public class SessionRouteH ...

  3. idea下的jsp开发中cannot resolve taglib with uri的解决方法

    写jsp难免会用到<c:foreach>标签,于是我在idea上的jsp顶头写下了 <%@ taglib prefix="c" uri= 'http://java ...

  4. WebAPI开发中的定时处理

    https://blog.csdn.net/lordwish/article/details/77931897

  5. android开发中的5种存储数据方式

    数据存储在开发中是使用最频繁的,根据不同的情况选择不同的存储数据方式对于提高开发效率很有帮助.下面笔者在主要介绍Android平台中实现数据存储的5种方式. 1.使用SharedPreferences ...

  6. 在Android 开发中使用 SQLite 数据库笔记

    SQLite 介绍   SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且只利用很少的内存就有很好的性能.此外它还是开源的,任何人都可以使用它.许多开源项目((Mozilla, PH ...

  7. 开发中解决Access-Control-Allow-Origin跨域问题的Chrome神器插件,安装及使用

    背景: 笔者在用cordova开发安卓程序的时候在安卓设备上不存在跨域问题,但是在浏览器端模拟调试的时候却出现了Access-Control-Allow-Origin跨域问题,报错如下 No 'Acc ...

  8. 团队开发中Git冲突解决

    正常来说我们团队协作开发过程中,冲突是常有的事,下面介绍下本人在开发中的解决办法. 冲突的主要原因就是由于我们开发人员在分支的同一位置写入了不一样的代码,然后合并到主干上导致我们冲突. 方法: 当冲突 ...

  9. 【原】webapp开发中兼容Android4.0以下版本的css hack

    话说现在的手机型号越来越多,主要还是android和ios这2个巨头称霸了江湖,而他们自带的浏览器内核是webkit,那对于做移动网页开发的同事来说,一般只要做好webkit内核浏览器的展现效果就行了 ...

随机推荐

  1. GitHub 实现多人协同提交代码并且权限分组管理

    转载请标明出处: http://www.cnblogs.com/zhaoyanjun/p/5882784.html 出自[赵彦军博客] 2016-09-19 前言: 在上一篇文章中Android gi ...

  2. 在 CentOS7 上安装 MongoDB

    在 CentOS7 上安装 MongoDB 1 通过 SecureCRT 连接至 CentOS7 服务器: 2 进入到 /usr/local/ 目录: cd /usr/local 3 在当前目录下创建 ...

  3. 小心SQL SERVER 2014新特性——基数评估引起一些性能问题

    在前阵子写的一篇博文"SQL SERVER 2014 下IF EXITS 居然引起执行计划变更的案例分享"里介绍了数据库从SQL SERVER 2005升级到 SQL SERVER ...

  4. mysql 单表排序,相同值排序

    两种方式: 第一种是利用笛卡尔积,两对比排序 -- 学校类型数据 SELECT t.examid,'-' AS unitcode,t.schooltype,'-' AS classname,t.bkr ...

  5. 实时事件统计项目:优化flume:用file channel代替mem channel

    背景:利用kafka+flume+morphline+solr做实时统计. solr从12月23号开始一直没有数据.查看日志发现,因为有一个同事加了一条格式错误的埋点数据,导致大量error. 据推断 ...

  6. Windows驱动——虚拟机 虚拟串口 双机调试

    =================================版权声明================================= 版权声明:原创文章 谢绝转载  请通过右侧公告中的“联系邮 ...

  7. 使用Sqoop从MySQL导入数据到Hive和HBase 及近期感悟

    使用Sqoop从MySQL导入数据到Hive和HBase 及近期感悟 Sqoop 大数据 Hive HBase ETL 使用Sqoop从MySQL导入数据到Hive和HBase 及近期感悟 基础环境 ...

  8. python基础(八)面向对象的基本概念

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 谢谢逆水寒龙,topmad和Liqing纠错 Python使用类(class)和对 ...

  9. 搭建 OpenStack 实验环境 - 每天5分钟玩转 OpenStack(16)

    在学习 OpenStack 各服务之前,让我们先搭建起一个实验环境. 毋庸置疑,一个看得到摸得着而且允许我们随便折腾的 OpenStack 能够提高我们的学习效率. 因为是我们自己学习用的实验环境,C ...

  10. 【小白的CFD之旅】01 引子

    小白的CFD之旅 写在前面 CFD是计算流体力学的英文简称,是计算机辅助工程(CAE)的主要分支,目前广泛应用与科学研究.工程设计中.这是一门综合了数学.计算机及流体力学的综合学科,涉及到众多的专业理 ...