netcore mvc 的简单实现
-
实现的功能
- 简单的路由系统
- 支持中间件
- 简单Filter支持
- 只支持HttpPost、HttpGet
- 使用Dotliquid做为视图渲染引擎
-
核心实现
-
HttpChannel
- 复制监听Tcp请求,并按照Http协议将tcp数据传输解析为HttpRequest数据实例,解析完调用HttpHandler继续下一步处理
-
HttpRequest
- 单次Http请求信息,包含 HttpMethod、Version、Url、HttpHeader、Cookies等信息
-
HttpResponse
- Http响应信息
-
DefaultHttpHandler
-
实现IHttpHandler,负责Middleware责任链的创建、执行
-
private IMiddleware BuildMiddlewareChain() { var builder = new MiddlewareChainBuilder(); builder.Use(new StaticFileMiddleware()); builder.Use(new MvcMiddleware(route)); return builder.Build(); } public async Task<HttpResponse> ProcessAsync(HttpRequest httpRequest) { var chain = BuildMiddlewareChain(); return await chain.Invoke(httpRequest); }
-
-
MvcMiddleware
-
内置的中间件,mvc功能具体实现[FIlter模式实现]
-
public override async Task<HttpResponse> Invoke(HttpRequest httpRequest) { try { var context = new ActionExecuteContext { HttpRequest = httpRequest }; var (controller, methodInfo, parameter) = route.Route(httpRequest); if (controller == null) { return await HttpResponseHelper.CreateNotFoundResponseAsync(); } context.Controller = controller; context.Action = methodInfo; ((ControllerBase)controller).Request = httpRequest; var filterList = GetFilters(controller, methodInfo); var stack = new Stack<IFilter>(); for (var i = 0; i < filterList.Count; i++) { var filter = filterList[i]; await filter.OnActionExecutingAsync(context); if (context.Final) { return context.HttpResponse; } stack.Push(filter); } await controller.OnActionExecutingAsync(context); if (context.Final) { return context.HttpResponse; } var parameters = new List<object>(); if (parameter != null) { parameters.Add(parameter); } if (methodInfo.ReturnType.IsGenericType) //Task<IActionResult> { var actionResult = await (methodInfo.Invoke(controller, parameters.ToArray()) as Task<IActionResult>); context.HttpResponse = await actionResult.ExecuteResultAsync(); } else { var actionResult = methodInfo.Invoke(controller, parameters.ToArray()) as IActionResult; context.HttpResponse = await actionResult.ExecuteResultAsync(); } context.HttpResponse.Cookies.AddRange(controller.ResponseCookie); await controller.OnActionExecutedAsync(context); if (context.Final) { return context.HttpResponse; } while (stack.Count != 0) { var filter = stack.Pop(); await filter.OnActionExecutedAsync(context); if (context.Final) { return context.HttpResponse; } } return context.HttpResponse; } catch (Exception e) { return await HttpResponseHelper.CreateDefaultErrorResponseAsync(e); } }
-
-
EasyRoute
-
实现最简单的路由解析【URL—> IController/Method】
-
Controller实例化使用netcore自带的IOC框架实现
-
public (IController, MethodInfo, object) Route(HttpRequest request) { var path = request.AbsolutePath; Type controllerType; MethodInfo methodInfo; switch (request.HttpMethod) { case HttpMethod.Get: if (httpGetRoutes.ContainsKey(path)) { (controllerType, methodInfo) = httpGetRoutes[path]; } else { return (null, null, null); } break; case HttpMethod.Post: if (httpPostRoutes.ContainsKey(path)) { (controllerType, methodInfo) = httpPostRoutes[path]; } else { return (null, null, null); } break; default://Unsupport httpmethod return (null, null, null); } var controllerObj = ServiceLocator.Instance.GetService(controllerType) as IController; //var controllerObj = Activator.CreateInstance(controllerType) as IController; object parameter = null; var parameterType = methodInfo.GetParameters().SingleOrDefault()?.ParameterType; if (parameterType != null) { parameter = ResolveParameter(parameterType, request); } return (controllerObj, methodInfo, parameter); }
-
-
IActionResult
-
执行结果的抽象,类比MVC的IActionResult
-
内置类型
-
HttpStatusCodeResult:只返回特定StatusCode,没有具体内容
-
JsonResult:返回JSON结果,content-type:application/json
-
RedirectResult:返回302
-
ViewResult:使用DotLiquid作为视图渲染引擎
public async Task<HttpResponse> ExecuteResultAsync() { var absoluteName = $"Views/{ViewName}"; Template template; if (viewCache.ContainsKey(absoluteName)) { template = viewCache[absoluteName]; } else { var templateStr = Template.FileSystem.ReadTemplateFile(new Context(CultureInfo.CurrentCulture), absoluteName); template = Template.Parse(templateStr); viewCache.Add(absoluteName, template); } var content = template.Render(Hash.FromAnonymousObject(ViewData)); var res = new HttpResponse(); await res.WriteBodyAsync(Constants.DefaultEncoding.GetBytes(content)); return res; }
-
-
-
IController
- mvc控制器接口
-
HttpCookie
- cookie操作类
-
IFilter
-
过滤器接口
public interface IFilter { int Order { get; set; } Task OnActionExecutingAsync(ActionExecuteContext context); Task OnActionExecutedAsync(ActionExecuteContext context); }
-
-
-
其他
- 本项目只为学习使用,如有错误,请指出
- 本项目为另一个项目 EasyProxy 的附属产物,所以没有独立的github仓库,具体目录为 HttpServer