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的框架,此时正好也可以用上
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPI.Http.Net
7 *文件名: ServerSocket
8 *版本号: V1.0.0.0
9 *唯一标识:ab912b9a-c7ed-44d9-8e48-eef0b6ff86a2
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/8 17:11:15
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/8 17:11:15
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using SAEA.Sockets.Core;
25 using SAEA.Sockets.Interface;
26 using System;
27 using System.Collections.Generic;
28 using System.Net;
29 using System.Text;
30
31 namespace SAEA.WebAPI.Http.Net
32 {
33 class ServerSocket : BaseServerSocket
34 {
35 public event Action<IUserToken, string> OnRequested;
36
37 public ServerSocket(int bufferSize = 1024 * 100, int count = 10000) : base(new HContext(), bufferSize, true, count)
38 {
39
40 }
41
42 protected override void OnReceiveBytes(IUserToken userToken, byte[] data)
43 {
44 HCoder coder = (HCoder)userToken.Coder;
45
46 coder.GetRequest(data, (result) =>
47 {
48 OnRequested?.Invoke(userToken, result);
49 });
50 }
51
52 public void Reply(IUserToken userToken, byte[] data)
53 {
54 base.Send(userToken, data);
55 base.Disconnected(userToken);
56 }
57 }
58 }
二、Http:这个是个应用协议,本人了解下来至少有3个版本,完全熟悉的话估计没个半年都搞不定;但是只需要关键,比如说http1.1的工作模式、传输格式、常见异常code、常见mime类型、js跨域支持等,这些基本能覆盖绝大部分日常场景,至于更多的那些细枝末节的理它作甚,本人的做法就是用Chrome的开发人员工具来查看相关network详情,这样的话就可以清楚http这个协议的具体编码解码了。
1 public void GetRequest(byte[] data, Action<string> onUnpackage)
2 {
3 lock (_locker)
4 {
5 var str = Encoding.UTF8.GetString(data);
6
7 var index = str.IndexOf(ENDSTR);
8
9 if (index > -1)
10 {
11 var s = str.Substring(0, index);
12
13 _result.Append(s);
14
15 onUnpackage.Invoke(_result.ToString());
16
17 _result.Clear();
18
19 if (str.Length > index + 4)
20 {
21 _result.Append(str.Substring(index + 4));
22 }
23 }
24 else
25 {
26 _result.Append(str);
27 }
28 }
29 }
经过分析后http的内容格式其实就是字符回车分隔,再加上一些约定生成的分隔符bound完成的。
1 public HttpRequest(Stream stream)
2 {
3 this._dataStream = stream;
4 var data = GetRequestData(_dataStream);
5 var rows = Regex.Split(data, Environment.NewLine);
6
7 //Request URL & Method & Version
8 var first = Regex.Split(rows[0], @"(\s+)")
9 .Where(e => e.Trim() != string.Empty)
10 .ToArray();
11 if (first.Length > 0) this.Method = first[0];
12 if (first.Length > 1)
13 {
14 this.Query = first[1];
15
16 if (this.Query.Contains("?"))
17 {
18 var qarr = this.Query.Split("?");
19 this.URL = qarr[0];
20 this.Params = GetRequestParameters(qarr[1]);
21 }
22 else
23 {
24 this.URL = this.Query;
25 }
26
27 var uarr = this.URL.Split("/");
28
29 if (long.TryParse(uarr[uarr.Length - 1], out long id))
30 {
31 this.URL = this.URL.Substring(0, this.URL.LastIndexOf("/"));
32 this.Params.Set("id", id.ToString());
33 }
34 }
35 if (first.Length > 2) this.Protocols = first[2];
36
37 //Request Headers
38 this.Headers = GetRequestHeaders(rows);
39
40 //Request "GET"
41 if (this.Method == "GET")
42 {
43 this.Body = GetRequestBody(rows);
44 }
45
46 //Request "POST"
47 if (this.Method == "POST")
48 {
49 this.Body = GetRequestBody(rows);
50 var contentType = GetHeader(RequestHeaderType.ContentType);
51 var isUrlencoded = contentType == @"application/x-www-form-urlencoded";
52 if (isUrlencoded) this.Params = GetRequestParameters(this.Body);
53 }
54 }
看到上面,有人肯定会说你这个传文件咋办?一个呢本人这个是针对webapi;另外一个,如真有这个场景,可以用Chrome的开发人员工具来查看相关network详情,也可以使用httpanalyzerstd、httpwatch等众多工具分析下,其实也就是使用了一些约定的分隔符bound完成,每个浏览器还不一样,有兴趣的完全可以自行扩展一个。
三、Reponse这个是webapi服务端相当重要的一个组件,本人也是尽可能方便并且按尽量按asp.net mvc的命名来实现,另外这里加入支持js跨域所需大部分场景heads,如果还有特殊的heads,完全可以自已添加。


1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPI.Http
7 *文件名: HttpResponse
8 *版本号: V1.0.0.0
9 *唯一标识:2e43075f-a43d-4b60-bee1-1f9107e2d133
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/8 16:46:40
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/8 16:46:40
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using SAEA.Commom;
25 using SAEA.Sockets.Interface;
26 using SAEA.WebAPI.Http.Base;
27 using SAEA.WebAPI.Mvc;
28 using System.Collections.Generic;
29 using System.Net;
30 using System.Text;
31
32 namespace SAEA.WebAPI.Http
33 {
34 public class HttpResponse : BaseHeader
35 {
36 public HttpStatusCode Status { get; set; } = HttpStatusCode.OK;
37
38 public byte[] Content { get; private set; }
39
40
41
42 internal HttpServer HttpServer { get; set; }
43
44 internal IUserToken UserToken { get; set; }
45 /// <summary>
46 /// 创建一个HttpRequest实例
47 /// </summary>
48 /// <param name="httpServer"></param>
49 /// <param name="userToken"></param>
50 /// <param name="stream"></param>
51 /// <returns></returns>
52 internal static HttpResponse CreateInstance(HttpServer httpServer, IUserToken userToken)
53 {
54 HttpResponse httpResponse = new HttpResponse("");
55 httpResponse.HttpServer = httpServer;
56 httpResponse.UserToken = userToken;
57 return httpResponse;
58 }
59
60 /// <summary>
61 /// 设置回复内容
62 /// </summary>
63 /// <param name="httpResponse"></param>
64 /// <param name="result"></param>
65 internal static void SetResult(HttpResponse httpResponse, ActionResult result)
66 {
67 httpResponse.Content_Encoding = result.ContentEncoding.EncodingName;
68 httpResponse.Content_Type = result.ContentType;
69 httpResponse.Status = result.Status;
70
71 if (result is EmptyResult)
72 {
73 return;
74 }
75
76 if (result is FileResult)
77 {
78 var f = result as FileResult;
79
80 httpResponse.SetContent(f.Content);
81
82 return;
83 }
84
85 httpResponse.SetContent(result.Content);
86 }
87
88
89 public HttpResponse(string content) : this(content, "UTF-8", "application/json; charset=utf-8", HttpStatusCode.OK)
90 {
91
92 }
93
94 public HttpResponse(string content, string encoding, string contentType, HttpStatusCode status)
95 {
96 this.Content_Encoding = encoding;
97 this.Content_Type = contentType;
98 this.Status = status;
99 this.SetContent(content);
100 }
101
102 internal HttpResponse SetContent(byte[] content, Encoding encoding = null)
103 {
104 this.Content = content;
105 this.Encoding = encoding != null ? encoding : Encoding.UTF8;
106 this.Content_Length = content.Length.ToString();
107 return this;
108 }
109
110 internal HttpResponse SetContent(string content, Encoding encoding = null)
111 {
112 //初始化内容
113 encoding = encoding != null ? encoding : Encoding.UTF8;
114 return SetContent(encoding.GetBytes(content), encoding);
115 }
116
117
118 public string GetHeader(ResponseHeaderType header)
119 {
120 return base.GetHeader(header);
121 }
122
123 public void SetHeader(ResponseHeaderType header, string value)
124 {
125 base.SetHeader(header, value);
126 }
127
128 /// <summary>
129 /// 构建响应头部
130 /// </summary>
131 /// <returns></returns>
132 protected string BuildHeader()
133 {
134 StringBuilder builder = new StringBuilder();
135 builder.Append(Protocols + SPACE + Status.ToNVString() + ENTER);
136 builder.AppendLine("Server: Wenli's Server");
137 builder.AppendLine("Keep-Alive: timeout=20");
138 builder.AppendLine("Date: " + DateTimeHelper.Now.ToFString("r"));
139
140 if (!string.IsNullOrEmpty(this.Content_Type))
141 builder.AppendLine("Content-Type:" + this.Content_Type);
142
143 //支持跨域
144 builder.AppendLine("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
145 builder.AppendLine("Access-Control-Allow-Origin: *");
146 builder.AppendLine("Access-Control-Allow-Headers: Content-Type,X-Requested-With,Accept,yswenli");//可自行增加额外的header
147 builder.AppendLine("Access-Control-Request-Methods: GET, POST, PUT, DELETE, OPTIONS");
148
149 if (this.Headers != null && this.Headers.Count > 0)
150 {
151 foreach (var key in Headers.Names)
152 {
153 builder.AppendLine($"{key}: {Headers[key]}");
154 }
155 }
156
157 return builder.ToString();
158 }
159
160 /// <summary>
161 /// 生成数据
162 /// </summary>
163 private byte[] ToBytes()
164 {
165 List<byte> list = new List<byte>();
166 //发送响应头
167 var header = BuildHeader();
168 byte[] headerBytes = this.Encoding.GetBytes(header);
169 list.AddRange(headerBytes);
170
171 //发送空行
172 byte[] lineBytes = this.Encoding.GetBytes(System.Environment.NewLine);
173 list.AddRange(lineBytes);
174
175 //发送内容
176 list.AddRange(Content);
177
178 return list.ToArray();
179 }
180
181
182 public void Write(string str)
183 {
184 SetContent(str);
185 }
186
187 public void BinaryWrite(byte[] data)
188 {
189 SetContent(data);
190 }
191
192 public void Clear()
193 {
194 this.Write("");
195 }
196
197 public void End()
198 {
199 HttpServer.Replay(UserToken, this.ToBytes());
200 HttpServer.Close(UserToken);
201 }
202
203
204
205 }
206 }
View Code
四、HttpServer:这个就是承载webapi的容器;有人说不是有IIS和Apache么?本人想说的是:有self-host方便么?有无需安装,无需配置、随便高性能开跑好么?asp.net core里面都有了这个,没这个就没有逼格....(此处省略一万字),前面还研究tcp、http这个当然不能少了
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPI.Http
7 *文件名: HttpServer
8 *版本号: V1.0.0.0
9 *唯一标识:914acb72-d4c4-4fa1-8e80-ce2f83bd06f0
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/10 13:51:50
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/10 13:51:50
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using SAEA.Sockets.Interface;
25 using SAEA.WebAPI.Common;
26 using SAEA.WebAPI.Http.Net;
27 using System;
28 using System.Collections.Generic;
29 using System.IO;
30 using System.Text;
31
32 namespace SAEA.WebAPI.Http
33 {
34 class HttpServer
35 {
36 ServerSocket _serverSocket;
37
38 public HttpServer()
39 {
40 _serverSocket = new ServerSocket();
41 _serverSocket.OnRequested += _serverSocket_OnRequested;
42 }
43
44 public void Start(int port = 39654)
45 {
46 _serverSocket.Start(port);
47 }
48
49
50 private void _serverSocket_OnRequested(IUserToken userToken, string htmlStr)
51 {
52 var httpContext = HttpContext.CreateInstance(this, userToken, htmlStr);
53
54 var response = httpContext.Response;
55
56 response.End();
57 }
58
59 internal void Replay(IUserToken userToken, byte[] data)
60 {
61 _serverSocket.Reply(userToken, data);
62 }
63
64 internal void Close(IUserToken userToken)
65 {
66 _serverSocket.Disconnected(userToken);
67 }
68
69
70 }
71 }
五、Controller:为了实现类似于mvc的效果Controller这个大名鼎鼎的当然不能少了,其在C#中使用非常少量的代码即可实现
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPI.Mvc
7 *文件名: Controller
8 *版本号: V1.0.0.0
9 *唯一标识:a303db7d-f83c-4c49-9804-032ec2236232
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/10 13:58:08
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/10 13:58:08
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24
25 using SAEA.WebAPI.Http;
26
27 namespace SAEA.WebAPI.Mvc
28 {
29 /// <summary>
30 /// WebApi控制器
31 /// </summary>
32 public abstract class Controller
33 {
34 public HttpContext HttpContext { get; set; }
35
36 /// <summary>
37 /// 返回Json
38 /// </summary>
39 /// <param name="data"></param>
40 /// <returns></returns>
41 protected JsonResult Json(object data)
42 {
43 return new JsonResult(data);
44 }
45 /// <summary>
46 /// 自定义内容
47 /// </summary>
48 /// <param name="data"></param>
49 /// <returns></returns>
50 protected ContentResult Content(string data)
51 {
52 return new ContentResult(data);
53 }
54
55
56 /// <summary>
57 /// 小文件
58 /// </summary>
59 /// <param name="filePath"></param>
60 /// <returns></returns>
61 protected FileResult File(string filePath)
62 {
63 return new FileResult(filePath);
64 }
65
66 /// <summary>
67 /// 空结果
68 /// </summary>
69 /// <returns></returns>
70 protected EmptyResult Empty()
71 {
72 return new EmptyResult();
73 }
74 }
75 }
六、ActionResult:是mvc里面针对reponse结果进行了一个http格式的封装,本人主要实现了ContentResult、JsonResult、FileResult三个,至于其他的在WebAPI里基本上用不到。
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPI.Mvc
7 *文件名: JsonResult
8 *版本号: V1.0.0.0
9 *唯一标识:340c3ef0-2e98-4f25-998f-2bb369fa2794
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/10 16:48:06
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/10 16:48:06
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using SAEA.WebAPI.Common;
25 using System;
26 using System.Collections.Generic;
27 using System.Net;
28 using System.Text;
29
30 namespace SAEA.WebAPI.Mvc
31 {
32 public class JsonResult : ActionResult
33 {
34 public JsonResult(object model) : this(SerializeHelper.Serialize(model))
35 {
36
37 }
38 public JsonResult(string json) : this(json, Encoding.UTF8)
39 {
40
41 }
42
43 public JsonResult(string json, HttpStatusCode status)
44 {
45 this.Content = json;
46 this.ContentEncoding = Encoding.UTF8;
47 this.ContentType = "application/json; charset=utf-8";
48 this.Status = status;
49 }
50
51 public JsonResult(string json, Encoding encoding, string contentType = "application/json; charset=utf-8")
52 {
53 this.Content = json;
54 this.ContentEncoding = encoding;
55 this.ContentType = contentType;
56 }
57 }
58 }
七、RouteTable:MVC里面有一个相当重要的概念叫约定优先,即为Controller、Action的名称是按某种规则来写编码的,其中将URL与自定义Controller对应起来的缓存映射就是RouteTable,并且作为缓存,也能极大的提升访问性能。当然这里并没有严格按照asp.net mvc里面的routetable来设计,而是根据只是实现webapi,并使用缓存反射结构能来实现的,并且只有约定,没有配置。
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPI.Mvc
7 *文件名: RouteTable
8 *版本号: V1.0.0.0
9 *唯一标识:1ed5d381-d7ce-4ea3-b8b5-c32f581ad49f
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/12 10:55:31
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/12 10:55:31
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using System;
25 using System.Collections.Generic;
26 using System.Linq;
27 using System.Reflection;
28 using System.Text;
29
30 namespace SAEA.WebAPI.Mvc
31 {
32 /// <summary>
33 /// SAEA.WebAPI路由表
34 /// </summary>
35 public static class RouteTable
36 {
37 static object _locker = new object();
38
39 static List<Routing> _list = new List<Routing>();
40
41
42 /// <summary>
43 /// 获取routing中的缓存
44 /// 若不存在则创建
45 /// </summary>
46 /// <param name="controllerType"></param>
47 /// <param name="controllerName"></param>
48 /// <param name="actionName"></param>
49 /// <param name="isPost"></param>
50 /// <returns></returns>
51 public static Routing TryGet(Type controllerType, string controllerName, string actionName, bool isPost)
52 {
53 lock (_locker)
54 {
55 var list = _list.Where(b => b.ControllerName.ToLower() == controllerName.ToLower() && b.ActionName.ToLower() == actionName.ToLower() && b.IsPost == isPost).ToList();
56
57 if (list == null || list.Count == 0)
58 {
59 var routing = new Routing()
60 {
61 ControllerName = controllerName,
62 ActionName = actionName,
63 IsPost = isPost
64 };
65
66 var actions = controllerType.GetMethods().Where(b => b.Name.ToLower() == actionName.ToLower()).ToList();
67
68 if (actions == null || actions.Count == 0)
69 {
70 throw new Exception($"{controllerName}/{actionName}找不到此action!");
71 }
72 else if (actions.Count > 2)
73 {
74 throw new Exception($"{controllerName}/{actionName}有多个重复的的action!");
75 }
76 else
77 {
78 routing.Instance = System.Activator.CreateInstance(controllerType);
79
80 //类上面的过滤
81 var attrs = controllerType.GetCustomAttributes(true);
82
83 if (attrs != null)
84 {
85 var attr = attrs.Where(b => b.GetType().BaseType.Name == "ActionFilterAttribute").FirstOrDefault();
86
87 routing.Atrr = attr;
88
89 }
90 else
91 {
92 routing.Atrr = null;
93 }
94
95 routing.Action = actions[0];
96
97 //action上面的过滤
98 if (routing.Atrr == null)
99 {
100 attrs = actions[0].GetCustomAttributes(true);
101
102 if (attrs != null)
103 {
104 var attr = attrs.Where(b => b.GetType().BaseType.Name == "ActionFilterAttribute").FirstOrDefault();
105
106 routing.Atrr = attr;
107
108 }
109 else
110 {
111 routing.Atrr = null;
112 }
113 }
114 }
115 _list.Add(routing);
116 return routing;
117 }
118 else if (list.Count > 1)
119 {
120 throw new Exception("500");
121 }
122 return list.FirstOrDefault();
123 }
124 }
125 }
126
127 }
在MVC的思想里面ActionFilterAtrribute的这个AOP设计也一直伴随左右,比如记日志、黑名单、权限、验证、限流等等功能,所以路由的时候也会缓存这个。至此一些关键性的地方都已经弄的差不多了,为了更好的了解上面说的这些,下面是vs2017中项目的结构截图:

纯粹干净单码,无任何晦涩内容,如果对mvc有一定了解的,这个差不多可以NoNotes,接下来就是按asp.net mvc命名方式,写个测试webapi看看情况,首先还是测试项目结构图:
HomeController里面按asp.net mvc的习惯来编写代码:
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPITest.Controllers
7 *文件名: HomeController
8 *版本号: V1.0.0.0
9 *唯一标识:e00bb57f-e3ee-4efe-a7cf-f23db767c1d0
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/10 16:43:26
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/10 16:43:26
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using SAEA.WebAPI.Mvc;
25 using SAEA.WebAPITest.Attrubutes;
26 using SAEA.WebAPITest.Model;
27
28 namespace SAEA.WebAPITest.Controllers
29 {
30 /// <summary>
31 /// 测试实例代码
32 /// </summary>
33 //[LogAtrribute]
34 public class HomeController : Controller
35 {
36 /// <summary>
37 /// 日志拦截
38 /// 内容输出
39 /// </summary>
40 /// <returns></returns>
41 //[Log2Atrribute]
42 public ActionResult Index()
43 {
44 return Content("Hello,I'm SAEA.WebAPI!");
45 }
46 /// <summary>
47 /// 支持基本类型参数
48 /// json序列化
49 /// </summary>
50 /// <param name="id"></param>
51 /// <returns></returns>
52 public ActionResult Get(int id)
53 {
54 return Json(new { Name = "yswenli", Sex = "男" });
55 }
56 /// <summary>
57 /// 底层对象调用
58 /// </summary>
59 /// <returns></returns>
60 public ActionResult Show()
61 {
62 var response = HttpContext.Response;
63
64 response.Content_Type = "text/html; charset=utf-8";
65
66 response.Write("<h3>测试一下那个response对象使用情况!</h3>参考消息网4月12日报道外媒称,法国一架“幻影-2000”战机意外地对本国一家工厂投下了...");
67
68 response.End();
69
70 return Empty();
71 }
72
73 [HttpGet]
74 public ActionResult Update(int id)
75 {
76 return Content($"HttpGet Update id:{id}");
77 }
78 /// <summary>
79 /// 基本类型参数、实体混合填充
80 /// </summary>
81 /// <param name="isFemale"></param>
82 /// <param name="userInfo"></param>
83 /// <returns></returns>
84 [HttpPost]
85 public ActionResult Update(bool isFemale, UserInfo userInfo = null)
86 {
87 return Json(userInfo);
88 }
89 [HttpPost]
90 public ActionResult Test()
91 {
92 return Content("httppost test");
93 }
94 /// <summary>
95 /// 文件输出
96 /// </summary>
97 /// <returns></returns>
98 public ActionResult Download()
99 {
100 return File(HttpContext.Server.MapPath("/Content/Image/c984b2fb80aeca7b15eda8c004f2e0d4.jpg"));
101 }
102 }
103 }
增加一个LogAtrribute打印一些内容:
1 /****************************************************************************
2 *Copyright (c) 2018 Microsoft All Rights Reserved.
3 *CLR版本: 4.0.30319.42000
4 *机器名称:WENLI-PC
5 *公司名称:Microsoft
6 *命名空间:SAEA.WebAPITest.Common
7 *文件名: LogAtrribute
8 *版本号: V1.0.0.0
9 *唯一标识:2a261731-b8f6-47de-b2e4-aecf2e0e0c0f
10 *当前的用户域:WENLI-PC
11 *创建人: yswenli
12 *电子邮箱:wenguoli_520@qq.com
13 *创建时间:2018/4/11 13:46:42
14 *描述:
15 *
16 *=====================================================================
17 *修改标记
18 *修改时间:2018/4/11 13:46:42
19 *修改人: yswenli
20 *版本号: V1.0.0.0
21 *描述:
22 *
23 *****************************************************************************/
24 using SAEA.Commom;
25 using SAEA.WebAPI.Http;
26 using SAEA.WebAPI.Mvc;
27
28 namespace SAEA.WebAPITest.Attrubutes
29 {
30 public class LogAtrribute : ActionFilterAttribute
31 {
32 /// <summary>
33 /// 执行前
34 /// </summary>
35 /// <param name="httpContext"></param>
36 /// <returns>返回值true为继续,false为终止</returns>
37 public override bool OnActionExecuting(HttpContext httpContext)
38 {
39 return true;
40 }
41
42 /// <summary>
43 /// 执行后
44 /// </summary>
45 /// <param name="httpContext"></param>
46 /// <param name="result"></param>
47 public override void OnActionExecuted(HttpContext httpContext, ActionResult result)
48 {
49 ConsoleHelper.WriteLine($"请求地址:{httpContext.Request.Query},回复内容:{result.Content}");
50 }
51 }
52 }
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
如果发现本文有什么问题和任何建议,也随时欢迎交流~
感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是yswenli 。