自行实现高性能MVC WebAPI

转载 2018年04月16日 23:43:04

wcf虽然功能多、扩展性强但是也面临配置忒多,而且restful的功能相当怪异,并且目前没法移植。asp.net core虽然支持webapi,但是功能也相对繁多、配置复杂。就没有一个能让码农们安安心心的写webapi,无需考虑性能、配置、甚至根据问题场景自行设计、改造等问题的方案么?当然不是,特别是在dnc2.0已经相当强大的此时,完全可以自行设计一套简洁、高效的webapi框架!说到自行写一套框架,很多码农们就可能会想到开发工作量难以想像,事实真的如此么?面对日益强大的dnc,本人就不是很信这个邪,所以就亲自编了一个试试。

      设计的编码思路就是仿asp.net mvc,原因就是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 
27 namespace SAEA.WebAPITest.Controllers
28 {
29     [LogAtrribute]
30     public class HomeController : Controller
31     {
32         public ActionResult Index()
33         {
34             return Content("Hello,I'm SAEA.WebAPI!");
35         }
36 
37         public ActionResult Get(int id)
38         {
39             return Json(new { Name = "yswenli", Sex = "" });
40         }
41 
42         public ActionResult Show()
43         {
44             var response = HttpContext.Response;
45 
46             response.Content_Type = "text/html; charset=utf-8";
47 
48             response.Write("<h3>测试一下那个response对象使用情况!</h3>参考消息网4月12日报道外媒称,法国一架“幻影-2000”");            
49 
50             response.End();
51 
52             return Empty();
53         }
54 
55         public ActionResult Download()
56         {
57             return File(HttpContext.Server.MapPath("/Content/Image/c984b2fb80aeca7b15eda8c004f2e0d4.jpg"));
58         }
59     }
60 }
复制代码

  从上面的代码风格出发,那么需要考虑的问题有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:这个只需要了解一下相关的传输就行,本人的做法就是用Chrome的开发人员工具来查看相关network详情,这样的话就可以实现tcp传输的解码问题了

复制代码
 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         }
复制代码

  解决了tcp的问题,还得简单分析http的解码,http的内容其实就是字符回车分隔。

复制代码
 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等众多工具分析下,然后自行扩展~

  三、Reponse这个是webapi服务端相当重要的一个组件,本人也是尽可能方便并且按asp.net的命名来实现

 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这个大名鼎鼎的当然不能少了

复制代码
 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里基本上用不到,所以还是以JsonResult为主

复制代码
 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中项目的结构截图:

  接下来就是按asp.net mvc命名方式,写个测试webapi看看情况,首先还是测试项目结构图:

  program里面启动一下服务:

1 MvcApplication mvcApplication = new MvcApplication();
2 
3 mvcApplication.Start();

  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 
27 namespace SAEA.WebAPITest.Controllers
28 {
29     [LogAtrribute]
30     public class HomeController : Controller
31     {
32         public ActionResult Index()
33         {
34             return Content("Hello,I'm SAEA.WebAPI!");
35         }
36 
37         public ActionResult Get(int id)
38         {
39             return Json(new { Name = "yswenli", Sex = "" });
40         }
41 
42         public ActionResult Show()
43         {
44             var response = HttpContext.Response;
45 
46             response.Content_Type = "text/html; charset=utf-8";
47 
48             response.Write("<h3>测试一下那个response对象使用情况!</h3>参考消息网4月12日报道外媒称,法国一架“幻影-2000”");            
49 
50             response.End();
51 
52             return Empty();
53         }
54 
55         public ActionResult Download()
56         {
57             return File(HttpContext.Server.MapPath("/Content/Image/c984b2fb80aeca7b15eda8c004f2e0d4.jpg"));
58         }
59     }
60 }
复制代码

  增加一个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 }
复制代码

  最后F5跑起来看看效果:

  使用Apache ab.exe压测一下性能如何:

  至此,一个简洁、高效的WebApi就初步完成了!

 http://www.mjg4415.cn/

http://www.dkk2480.cn/
http://www.qru6126.cn/
http://www.ocs5821.cn/
http://www.wne9476.cn/
http://www.xuh4863.cn/
http://www.icb3050.cn/
http://www.tfe0886.cn/
http://www.xgs5975.cn/
http://www.umx9976.cn/
http://www.eyf3292.cn/
http://www.wxm6819.cn/
http://www.ewv7964.cn/
http://www.wdr5566.cn/
http://www.qdn5355.cn/
http://www.kpp1176.cn/
http://www.rxi1689.cn/
http://www.vja2045.cn/
http://www.qry8357.cn/
http://www.pck8038.cn/
http://www.hiv8337.cn/
http://www.bjl7141.cn/
http://www.qou5361.cn/
http://www.kgs1242.cn/
http://www.zri8413.cn/
http://www.vpk8803.cn/
http://www.kwx0094.cn/
http://www.kft8401.cn/
http://www.bbe1708.cn/
http://www.nne0088.cn/
http://www.wph2022.cn/
http://www.uvr1927.cn/
http://www.qfg6726.cn/
http://www.ffr2858.cn/
http://www.rlp0976.cn/
http://www.qsa5453.cn/
http://www.rgj9684.cn/
http://www.xrr9518.cn/
http://www.dwm8256.cn/
http://www.yhb3879.cn/
http://www.evv5980.cn/
http://www.nat5354.cn/
http://www.nkc4539.cn/
http://www.jal3249.cn/
http://www.ppr6189.cn/
http://www.xnw9449.cn/
http://www.jwv1856.cn/
http://www.ddh4684.cn/
http://www.ymu2666.cn/
http://www.kdz0246.cn/
http://www.sph9900.cn/
http://www.fmh8265.cn/
http://www.igf1400.cn/
http://www.toy2618.cn/
http://www.xjh6427.cn/
http://www.cce2139.cn/
http://www.vzx2078.cn/
http://www.fhw1039.cn/

MVC WebAPI跨平台开发例子

  • 2015年11月12日 12:11
  • 63.94MB
  • 下载

MVC WebApi 用户权限及授权DEMO

  • 2017年10月24日 09:19
  • 102KB
  • 下载

MVC中的webApi

webapi
  • lv17774848392
  • lv17774848392
  • 2017-02-23 22:32:06
  • 188

使用Autofac实现MVC、WebApi的注入

http://www.cnblogs.com/yinrq/p/5383396.html
  • YangangwuWuyangang
  • YangangwuWuyangang
  • 2017-04-27 10:06:59
  • 1738

MVC WebApi 用户权限验证及授权DEMO

  • 2016年07月19日 18:44
  • 22.36MB
  • 下载

ASP.NET MVC WebAPI请求

ASP.NET MVC WebAPI请求
  • hezheqiang
  • hezheqiang
  • 2016-12-06 17:43:23
  • 1914

ASP.NET MVC同时支持web与webapi模式

我们在创建 web mvc项目时是不支持web api的接口方式访问的,所以我们需要添加额外的组件来支持实现双模式。 首先我们需要准备三个web api依赖的组件(目前在.net 4/4.5版本下面...
  • laymat
  • laymat
  • 2017-03-23 16:19:16
  • 2384

MVC WebApi 图片上传和显示

1 MVC中显示 内存流 中的图片。(不是图片文件) 创建一个Index用来显示 Action: public ActionResult Index() { r...
  • hanjun0612
  • hanjun0612
  • 2016-12-08 15:20:17
  • 2805

MVC和Web API 过滤器Filter

MVC和Web API Filter(过滤器) ASP.NET MVC 支持以下类型的操作筛选器: ·        授权筛选器。这些筛选器用于实现IAuthorizationFilter 和做出关于...
  • yfz19890410
  • yfz19890410
  • 2014-11-18 11:00:40
  • 4466
收藏助手
不良信息举报
您举报文章:自行实现高性能MVC WebAPI
举报原因:
原因补充:

(最多只允许输入30个字)