自行实现高性能MVC
wcf虽然功能多、扩展性强但是也面临配置忒多,而且restful的功能相当怪异,并且目前没法移植。asp.net core虽然支持webapi,但是功能也相对繁多、配置复杂。就没有一个能让码农们安安心心的写webapi,无需考虑性能、配置、甚至根据问题场景自行设计、改造等问题的方案么?
当然不是,特别是在dnc2.0已经相当强大的此时,完全可以自行设计一套简洁、高效的webapi框架!说到自行写一套框架,很多码农们就可能会想到开发工作量难以想像,事实真的如此么?java因为开源众多,很多对mvc稍有了解的都可以拿这个拿那个拼出一个自已的mvc框架;而面对日益强大的dnc,本人觉得C#根本无需东拼西凑这么麻烦,完全可以根据自已的需求简单快速的写出一个来,不服就开干!
设计的编码思路就是仿asp.net mvc,原因就是asp.net mvc成功发展了这么多年,有着大量的C#码农习惯了这套优良的编码方式;至于spring mvc、spring boot那些,站在使用者的角度来说,光配置和注解都能敲死人,如要要说简洁快速,asp.net mvc比他强多了,更别提ruby on rails。不扯远了,下面就按C#经典来。那么需要考虑的问题有tcp、http、request、response、server、controller、actionresult、routetable等,下面就一一来解决这个问题。
一、Tcp:这个是实现传输通信的底层,当然采用IOCP来提高吞吐量和性能,本人之前在做Redis Client等的时候就使用这个IOCP Socket的框架,此时正好也可以用上
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPI.Http.Net
*文件名: ServerSocket
*版本号: V1.0.0.0
*唯一标识:ab912b9a-c7ed-44d9-8e48-eef0b6ff86a2
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/8 17:11:15
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/8 17:11:15
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using SAEA.Sockets.Core;
using SAEA.Sockets.Interface;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text; namespace SAEA.WebAPI.Http.Net
{
class ServerSocket : BaseServerSocket
{
public event Action<IUserToken, string> OnRequested; public ServerSocket(int bufferSize = * , int count = ) : base(new HContext(), bufferSize, true, count)
{ } protected override void OnReceiveBytes(IUserToken userToken, byte[] data)
{
HCoder coder = (HCoder)userToken.Coder; coder.GetRequest(data, (result) =>
{
OnRequested?.Invoke(userToken, result);
});
} public void Reply(IUserToken userToken, byte[] data)
{
base.Send(userToken, data);
base.Disconnected(userToken);
}
}
}
二、Http:这个是个应用协议,本人了解下来至少有3个版本,完全熟悉的话估计没个半年都搞不定;但是只需要关键,比如说http1.1的工作模式、传输格式、常见异常code、常见mime类型、js跨域支持等,这些基本能覆盖绝大部分日常场景,至于更多的那些细枝末节的理它作甚,本人的做法就是用Chrome的开发人员工具来查看相关network详情,这样的话就可以清楚http这个协议的具体编码解码了。
public void GetRequest(byte[] data, Action<string> onUnpackage)
{
lock (_locker)
{
var str = Encoding.UTF8.GetString(data); var index = str.IndexOf(ENDSTR); if (index > -)
{
var s = str.Substring(, index); _result.Append(s); onUnpackage.Invoke(_result.ToString()); _result.Clear(); if (str.Length > index + )
{
_result.Append(str.Substring(index + ));
}
}
else
{
_result.Append(str);
}
}
}
经过分析后http的内容格式其实就是字符回车分隔,再加上一些约定生成的分隔符bound完成的。
public HttpRequest(Stream stream)
{
this._dataStream = stream;
var data = GetRequestData(_dataStream);
var rows = Regex.Split(data, Environment.NewLine); //Request URL & Method & Version
var first = Regex.Split(rows[], @"(\s+)")
.Where(e => e.Trim() != string.Empty)
.ToArray();
if (first.Length > ) this.Method = first[];
if (first.Length > )
{
this.Query = first[]; if (this.Query.Contains("?"))
{
var qarr = this.Query.Split("?");
this.URL = qarr[];
this.Params = GetRequestParameters(qarr[]);
}
else
{
this.URL = this.Query;
} var uarr = this.URL.Split("/"); if (long.TryParse(uarr[uarr.Length - ], out long id))
{
this.URL = this.URL.Substring(, this.URL.LastIndexOf("/"));
this.Params.Set("id", id.ToString());
}
}
if (first.Length > ) this.Protocols = first[]; //Request Headers
this.Headers = GetRequestHeaders(rows); //Request "GET"
if (this.Method == "GET")
{
this.Body = GetRequestBody(rows);
} //Request "POST"
if (this.Method == "POST")
{
this.Body = GetRequestBody(rows);
var contentType = GetHeader(RequestHeaderType.ContentType);
var isUrlencoded = contentType == @"application/x-www-form-urlencoded";
if (isUrlencoded) this.Params = GetRequestParameters(this.Body);
}
}
看到上面,有人肯定会说你这个传文件咋办?一个呢本人这个是针对webapi;另外一个,如真有这个场景,可以用Chrome的开发人员工具来查看相关network详情,也可以使用httpanalyzerstd、httpwatch等众多工具分析下,其实也就是使用了一些约定的分隔符bound完成,每个浏览器还不一样,有兴趣的完全可以自行扩展一个。
三、Reponse这个是webapi服务端相当重要的一个组件,本人也是尽可能方便并且按尽量按asp.net mvc的命名来实现,另外这里加入支持js跨域所需大部分场景heads,如果还有特殊的heads,完全可以自已添加。
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPI.Http
*文件名: HttpResponse
*版本号: V1.0.0.0
*唯一标识:2e43075f-a43d-4b60-bee1-1f9107e2d133
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/8 16:46:40
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/8 16:46:40
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using SAEA.Commom;
using SAEA.Sockets.Interface;
using SAEA.WebAPI.Http.Base;
using SAEA.WebAPI.Mvc;
using System.Collections.Generic;
using System.Net;
using System.Text; namespace SAEA.WebAPI.Http
{
public class HttpResponse : BaseHeader
{
public HttpStatusCode Status { get; set; } = HttpStatusCode.OK; public byte[] Content { get; private set; } internal HttpServer HttpServer { get; set; } internal IUserToken UserToken { get; set; }
/// <summary>
/// 创建一个HttpRequest实例
/// </summary>
/// <param name="httpServer"></param>
/// <param name="userToken"></param>
/// <param name="stream"></param>
/// <returns></returns>
internal static HttpResponse CreateInstance(HttpServer httpServer, IUserToken userToken)
{
HttpResponse httpResponse = new HttpResponse("");
httpResponse.HttpServer = httpServer;
httpResponse.UserToken = userToken;
return httpResponse;
} /// <summary>
/// 设置回复内容
/// </summary>
/// <param name="httpResponse"></param>
/// <param name="result"></param>
internal static void SetResult(HttpResponse httpResponse, ActionResult result)
{
httpResponse.Content_Encoding = result.ContentEncoding.EncodingName;
httpResponse.Content_Type = result.ContentType;
httpResponse.Status = result.Status; if (result is EmptyResult)
{
return;
} if (result is FileResult)
{
var f = result as FileResult; httpResponse.SetContent(f.Content); return;
} httpResponse.SetContent(result.Content);
} public HttpResponse(string content) : this(content, "UTF-8", "application/json; charset=utf-8", HttpStatusCode.OK)
{ } public HttpResponse(string content, string encoding, string contentType, HttpStatusCode status)
{
this.Content_Encoding = encoding;
this.Content_Type = contentType;
this.Status = status;
this.SetContent(content);
} internal HttpResponse SetContent(byte[] content, Encoding encoding = null)
{
this.Content = content;
this.Encoding = encoding != null ? encoding : Encoding.UTF8;
this.Content_Length = content.Length.ToString();
return this;
} internal HttpResponse SetContent(string content, Encoding encoding = null)
{
//初始化内容
encoding = encoding != null ? encoding : Encoding.UTF8;
return SetContent(encoding.GetBytes(content), encoding);
} public string GetHeader(ResponseHeaderType header)
{
return base.GetHeader(header);
} public void SetHeader(ResponseHeaderType header, string value)
{
base.SetHeader(header, value);
} /// <summary>
/// 构建响应头部
/// </summary>
/// <returns></returns>
protected string BuildHeader()
{
StringBuilder builder = new StringBuilder();
builder.Append(Protocols + SPACE + Status.ToNVString() + ENTER);
builder.AppendLine("Server: Wenli's Server");
builder.AppendLine("Keep-Alive: timeout=20");
builder.AppendLine("Date: " + DateTimeHelper.Now.ToFString("r")); if (!string.IsNullOrEmpty(this.Content_Type))
builder.AppendLine("Content-Type:" + this.Content_Type); //支持跨域
builder.AppendLine("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
builder.AppendLine("Access-Control-Allow-Origin: *");
builder.AppendLine("Access-Control-Allow-Headers: Content-Type,X-Requested-With,Accept,yswenli");//可自行增加额外的header
builder.AppendLine("Access-Control-Request-Methods: GET, POST, PUT, DELETE, OPTIONS"); if (this.Headers != null && this.Headers.Count > )
{
foreach (var key in Headers.Names)
{
builder.AppendLine($"{key}: {Headers[key]}");
}
} return builder.ToString();
} /// <summary>
/// 生成数据
/// </summary>
private byte[] ToBytes()
{
List<byte> list = new List<byte>();
//发送响应头
var header = BuildHeader();
byte[] headerBytes = this.Encoding.GetBytes(header);
list.AddRange(headerBytes); //发送空行
byte[] lineBytes = this.Encoding.GetBytes(System.Environment.NewLine);
list.AddRange(lineBytes); //发送内容
list.AddRange(Content); return list.ToArray();
} public void Write(string str)
{
SetContent(str);
} public void BinaryWrite(byte[] data)
{
SetContent(data);
} public void Clear()
{
this.Write("");
} public void End()
{
HttpServer.Replay(UserToken, this.ToBytes());
HttpServer.Close(UserToken);
} }
}
四、HttpServer:这个就是承载webapi的容器;有人说不是有IIS和Apache么?本人想说的是:有self-host方便么?有无需安装,无需配置、随便高性能开跑好么?asp.net core里面都有了这个,没这个就没有逼格....(此处省略一万字),前面还研究tcp、http这个当然不能少了
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPI.Http
*文件名: HttpServer
*版本号: V1.0.0.0
*唯一标识:914acb72-d4c4-4fa1-8e80-ce2f83bd06f0
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/10 13:51:50
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/10 13:51:50
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using SAEA.Sockets.Interface;
using SAEA.WebAPI.Common;
using SAEA.WebAPI.Http.Net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text; namespace SAEA.WebAPI.Http
{
class HttpServer
{
ServerSocket _serverSocket; public HttpServer()
{
_serverSocket = new ServerSocket();
_serverSocket.OnRequested += _serverSocket_OnRequested;
} public void Start(int port = )
{
_serverSocket.Start(port);
} private void _serverSocket_OnRequested(IUserToken userToken, string htmlStr)
{
var httpContext = HttpContext.CreateInstance(this, userToken, htmlStr); var response = httpContext.Response; response.End();
} internal void Replay(IUserToken userToken, byte[] data)
{
_serverSocket.Reply(userToken, data);
} internal void Close(IUserToken userToken)
{
_serverSocket.Disconnected(userToken);
} }
}
五、Controller:为了实现类似于mvc的效果Controller这个大名鼎鼎的当然不能少了,其在C#中使用非常少量的代码即可实现
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPI.Mvc
*文件名: Controller
*版本号: V1.0.0.0
*唯一标识:a303db7d-f83c-4c49-9804-032ec2236232
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/10 13:58:08
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/10 13:58:08
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/ using SAEA.WebAPI.Http; namespace SAEA.WebAPI.Mvc
{
/// <summary>
/// WebApi控制器
/// </summary>
public abstract class Controller
{
public HttpContext HttpContext { get; set; } /// <summary>
/// 返回Json
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
protected JsonResult Json(object data)
{
return new JsonResult(data);
}
/// <summary>
/// 自定义内容
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
protected ContentResult Content(string data)
{
return new ContentResult(data);
} /// <summary>
/// 小文件
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
protected FileResult File(string filePath)
{
return new FileResult(filePath);
} /// <summary>
/// 空结果
/// </summary>
/// <returns></returns>
protected EmptyResult Empty()
{
return new EmptyResult();
}
}
}
六、ActionResult:是mvc里面针对reponse结果进行了一个http格式的封装,本人主要实现了ContentResult、JsonResult、FileResult三个,至于其他的在WebAPI里基本上用不到。
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPI.Mvc
*文件名: JsonResult
*版本号: V1.0.0.0
*唯一标识:340c3ef0-2e98-4f25-998f-2bb369fa2794
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/10 16:48:06
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/10 16:48:06
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using SAEA.WebAPI.Common;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text; namespace SAEA.WebAPI.Mvc
{
public class JsonResult : ActionResult
{
public JsonResult(object model) : this(SerializeHelper.Serialize(model))
{ }
public JsonResult(string json) : this(json, Encoding.UTF8)
{ } public JsonResult(string json, HttpStatusCode status)
{
this.Content = json;
this.ContentEncoding = Encoding.UTF8;
this.ContentType = "application/json; charset=utf-8";
this.Status = status;
} public JsonResult(string json, Encoding encoding, string contentType = "application/json; charset=utf-8")
{
this.Content = json;
this.ContentEncoding = encoding;
this.ContentType = contentType;
}
}
}
七、RouteTable:MVC里面有一个相当重要的概念叫约定优先,即为Controller、Action的名称是按某种规则来写编码的,其中将URL与自定义Controller对应起来的缓存映射就是RouteTable,并且作为缓存,也能极大的提升访问性能。当然这里并没有严格按照asp.net mvc里面的routetable来设计,而是根据只是实现webapi,并使用缓存反射结构能来实现的,并且只有约定,没有配置。
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPI.Mvc
*文件名: RouteTable
*版本号: V1.0.0.0
*唯一标识:1ed5d381-d7ce-4ea3-b8b5-c32f581ad49f
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/12 10:55:31
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/12 10:55:31
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text; namespace SAEA.WebAPI.Mvc
{
/// <summary>
/// SAEA.WebAPI路由表
/// </summary>
public static class RouteTable
{
static object _locker = new object(); static List<Routing> _list = new List<Routing>(); /// <summary>
/// 获取routing中的缓存
/// 若不存在则创建
/// </summary>
/// <param name="controllerType"></param>
/// <param name="controllerName"></param>
/// <param name="actionName"></param>
/// <param name="isPost"></param>
/// <returns></returns>
public static Routing TryGet(Type controllerType, string controllerName, string actionName, bool isPost)
{
lock (_locker)
{
var list = _list.Where(b => b.ControllerName.ToLower() == controllerName.ToLower() && b.ActionName.ToLower() == actionName.ToLower() && b.IsPost == isPost).ToList(); if (list == null || list.Count == )
{
var routing = new Routing()
{
ControllerName = controllerName,
ActionName = actionName,
IsPost = isPost
}; var actions = controllerType.GetMethods().Where(b => b.Name.ToLower() == actionName.ToLower()).ToList(); if (actions == null || actions.Count == )
{
throw new Exception($"{controllerName}/{actionName}找不到此action!");
}
else if (actions.Count > )
{
throw new Exception($"{controllerName}/{actionName}有多个重复的的action!");
}
else
{
routing.Instance = System.Activator.CreateInstance(controllerType); //类上面的过滤
var attrs = controllerType.GetCustomAttributes(true); if (attrs != null)
{
var attr = attrs.Where(b => b.GetType().BaseType.Name == "ActionFilterAttribute").FirstOrDefault(); routing.Atrr = attr; }
else
{
routing.Atrr = null;
} routing.Action = actions[]; //action上面的过滤
if (routing.Atrr == null)
{
attrs = actions[].GetCustomAttributes(true); if (attrs != null)
{
var attr = attrs.Where(b => b.GetType().BaseType.Name == "ActionFilterAttribute").FirstOrDefault(); routing.Atrr = attr; }
else
{
routing.Atrr = null;
}
}
}
_list.Add(routing);
return routing;
}
else if (list.Count > )
{
throw new Exception("");
}
return list.FirstOrDefault();
}
}
} }
在MVC的思想里面ActionFilterAtrribute的这个AOP设计也一直伴随左右,比如记日志、黑名单、权限、验证、限流等等功能,所以路由的时候也会缓存这个。至此一些关键性的地方都已经弄的差不多了,为了更好的了解上面说的这些,下面是vs2017中项目的结构截图:
纯粹干净单码,无任何晦涩内容,如果对mvc有一定了解的,这个差不多可以NoNotes,接下来就是按asp.net mvc命名方式,写个测试webapi看看情况,首先还是测试项目结构图:
HomeController里面按asp.net mvc的习惯来编写代码:
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPITest.Controllers
*文件名: HomeController
*版本号: V1.0.0.0
*唯一标识:e00bb57f-e3ee-4efe-a7cf-f23db767c1d0
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/10 16:43:26
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/10 16:43:26
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using SAEA.WebAPI.Mvc;
using SAEA.WebAPITest.Attrubutes;
using SAEA.WebAPITest.Model; namespace SAEA.WebAPITest.Controllers
{
/// <summary>
/// 测试实例代码
/// </summary>
//[LogAtrribute]
public class HomeController : Controller
{
/// <summary>
/// 日志拦截
/// 内容输出
/// </summary>
/// <returns></returns>
//[Log2Atrribute]
public ActionResult Index()
{
return Content("Hello,I'm SAEA.WebAPI!");
}
/// <summary>
/// 支持基本类型参数
/// json序列化
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public ActionResult Get(int id)
{
return Json(new { Name = "yswenli", Sex = "男" });
}
/// <summary>
/// 底层对象调用
/// </summary>
/// <returns></returns>
public ActionResult Show()
{
var response = HttpContext.Response; response.Content_Type = "text/html; charset=utf-8"; response.Write("<h3>测试一下那个response对象使用情况!</h3>参考消息网4月12日报道外媒称,法国一架“幻影-2000”战机意外地对本国一家工厂投下了..."); response.End(); return Empty();
} [HttpGet]
public ActionResult Update(int id)
{
return Content($"HttpGet Update id:{id}");
}
/// <summary>
/// 基本类型参数、实体混合填充
/// </summary>
/// <param name="isFemale"></param>
/// <param name="userInfo"></param>
/// <returns></returns>
[HttpPost]
public ActionResult Update(bool isFemale, UserInfo userInfo = null)
{
return Json(userInfo);
}
[HttpPost]
public ActionResult Test()
{
return Content("httppost test");
}
/// <summary>
/// 文件输出
/// </summary>
/// <returns></returns>
public ActionResult Download()
{
return File(HttpContext.Server.MapPath("/Content/Image/c984b2fb80aeca7b15eda8c004f2e0d4.jpg"));
}
}
}
增加一个LogAtrribute打印一些内容:
/****************************************************************************
*Copyright (c) 2018 Microsoft All Rights Reserved.
*CLR版本: 4.0.30319.42000
*机器名称:WENLI-PC
*公司名称:Microsoft
*命名空间:SAEA.WebAPITest.Common
*文件名: LogAtrribute
*版本号: V1.0.0.0
*唯一标识:2a261731-b8f6-47de-b2e4-aecf2e0e0c0f
*当前的用户域:WENLI-PC
*创建人: yswenli
*电子邮箱:wenguoli_520@qq.com
*创建时间:2018/4/11 13:46:42
*描述:
*
*=====================================================================
*修改标记
*修改时间:2018/4/11 13:46:42
*修改人: yswenli
*版本号: V1.0.0.0
*描述:
*
*****************************************************************************/
using SAEA.Commom;
using SAEA.WebAPI.Http;
using SAEA.WebAPI.Mvc; namespace SAEA.WebAPITest.Attrubutes
{
public class LogAtrribute : ActionFilterAttribute
{
/// <summary>
/// 执行前
/// </summary>
/// <param name="httpContext"></param>
/// <returns>返回值true为继续,false为终止</returns>
public override bool OnActionExecuting(HttpContext httpContext)
{
return true;
} /// <summary>
/// 执行后
/// </summary>
/// <param name="httpContext"></param>
/// <param name="result"></param>
public override void OnActionExecuted(HttpContext httpContext, ActionResult result)
{
ConsoleHelper.WriteLine($"请求地址:{httpContext.Request.Query},回复内容:{result.Content}");
}
}
}
program.cs Main中启动一下服务:
1 MvcApplication mvcApplication = new MvcApplication();
2
3 mvcApplication.Start();
最后F5跑起来看看效果:
使用Apache ab.exe压测一下性能如何:
至此,一个简洁、高效的WebApi就初步完成了!
转载请标明本文来源:http://www.cnblogs.com/yswenli/p/8858669.html
更多内容欢迎star作者的github:https://github.com/yswenli/SAEA
如果发现本文有什么问题和任何建议,也随时欢迎交流~
自行实现高性能MVC的更多相关文章
- 线程安全使用(四) [.NET] 简单接入微信公众号开发:实现自动回复 [C#]C#中字符串的操作 自行实现比dotcore/dotnet更方便更高性能的对象二进制序列化 自已动手做高性能消息队列 自行实现高性能MVC WebAPI 面试题随笔 字符串反转
线程安全使用(四) 这是时隔多年第四篇,主要是因为身在东软受内网限制,好多文章就只好发到东软内部网站,懒的发到外面,现在一点点把在东软写的文章给转移出来. 这里主要讲解下CancellationT ...
- 自行实现高性能MVC WebAPI
wcf虽然功能多.扩展性强但是也面临配置忒多,而且restful的功能相当怪异,并且目前没法移植.asp.net core虽然支持webapi,但是功能也相对繁多.配置复杂.就没有一个能让码农们安安心 ...
- 基于Node的高性能MVC框架
赶上公司去Windows化,有一大波.net站点需要转成Node.js,于是自己就顺便琢磨一个通用的Node版MVC框架. 经过几天的努力,beta版终于面世了!因为其高性能的特点,特地命名node- ...
- 高性能.NET MVC之QMVC!
ASP.NET!这个词代表者一个单词Fat!因为他总是捆绑着太多的太多的类,太多太多的各种功能!你也许会用到,如果你反编译或阅读他们开源的源码,你会不会犹如在大海中找不到方向?不管是Web form ...
- 简介 – ASP.NET MVC 4 系列
正所谓好记性不如烂笔头,尤其是技术类书籍在阅读后,时间久了一定会忘记.而重新翻阅整本书也较为低效,遂以博客记录阅读摘要以供日后查阅.本系列文章均摘要自 Wrox 红皮书[ASP.NET ...
- swoolefy PHP的异步、并行、高性能网络通信引擎内置了Http/WebSocket服务器端/客户端
近半年来努力付出,项目终于要正式结项了,团队4人经历了很多困难,加班加点,最终完成了!剩下的时间将总结一下在该项目中用到知识和遇到问题.今天就从swoole说起!项目中实现异步大文件传输的功能,在服务 ...
- 2014年5月份第3周51Aspx源码发布详情
HGM简单连连看游戏源码 2014-5-19 [VS2010]源码描述:这是一款基于WinForm窗体程序的简单水果连连看的小游戏.界面比较美观, 功能如下:该游戏可以显示当前关卡,还有剩余时间.重 ...
- 16Aspx.com源码2014年7月详细
Web电子商务网(三层)V2.0源码 2014-07-31 [VS2010] 源码介绍: Web电子商务网(三层)V2.0源码 源码描述: 一.源码特点 采用三层架构开发, ...
- [Node.js框架] 为什么要开发 Codekart 框架
两年前,在被php的$符号和字符串处理折磨得半夜骂娘之后,我义无反顾地决定:珍爱生命,远离php. 之后一直在寻找一门“完美的语言”,先后接触了Lisp.python.java.Ruby.Lisp几乎 ...
随机推荐
- layui 数据表格+分页+搜索+checkbox+缓存选中项数据
在做数据表格的时候遇到了很多坑, 今天整理一下方便以后使用. 主要功能是使用数据表格, 做分页,做搜索, 还有checkbox, 支持全选. 当选中一些数据的时候, 数据切换页面数据在切换回来后, ...
- 使用过AsyncTask、EventBus、Volley以及Retrofit,必须好好了解handler运行机制
我们都知道在UI线程中不能进行耗时操作,例如数据读写.网络请求.Android 4.0开始,在主线程中进行网络请求甚至会抛出Android.os.NetworkOnMainThreadExceptio ...
- 前端路由简介以及vue-router实现原理
后端路由简介 路由这个概念最先是后端出现的.在以前用模板引擎开发页面时,经常会看到这样 http://www.xxx.com/login 大致流程可以看成这样: 浏览器发出请求 服务器监听到80端口( ...
- android recovery 升级时间与速度研究
从android4.4到现在android7.1升级,现在的升级包越来越大,一个system分区大小都分配了2G,整个升级包达到了接近500M, 升级包解压之后1G+,奇怪的是,发现了两个不同批次的板 ...
- matlab练习程序(FAST特征点检测)
算法思想:如果一个像素与它邻域的像素差别较大(过亮或过暗) , 那它更可能是角点. 算法步骤: 1.上图所示,一个以像素p为中心,半径为3的圆上,有16个像素点(p1.p2.....p16). 2.定 ...
- 【Python】keras使用Lenet5识别mnist
原始论文中的网络结构如下图: keras生成的网络结构如下图: 代码如下: import numpy as np from keras.preprocessing import image from ...
- [20180413]热备模式相关问题2.txt
[20180413]热备模式相关问题2.txt --//上午测试热备模式相关问题,就是如果打开热备模式,如果中间的归档丢失,oracle在alter database end backup ;时并 ...
- 对Spring的理解(简单)!
1.Spring是对j2EE诸多功能进行封装了的一个工具集:它的核心就是提供了一种新的机制来管理业务对象及依赖关系:具体就是控制反转.依赖注入,Aop(面向切面). Spring的底层实现机制是用De ...
- 修改sqlserver2008数据库的排序规则 (转)
修改sqlserver2008数据库的排序规则 (转) 修改SQL server 2008服务器排序规则 SQL Server 2008安装好后,发现服务器排序规则不对,又不想重装SQL S ...
- windows下编写shell脚本执行错误
在 windows 下,换行符是 \r\n,在linux下,换行符是 \n.如果你在IDEA里写sh脚本,可以手动设置脚本的换行符为 \n,如果你用notepad++写脚本,可以显示所有字符,以便明确 ...