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 ProcessAsync(HttpRequest httpRequest)
          {
              var chain = BuildMiddlewareChain();
              return await chain.Invoke(httpRequest);
          }
    • MvcMiddleware

      • 内置的中间件,mvc功能具体实现[FIlter模式实现]

      • public override async Task 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();
                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();
                if (parameter != null)
                {
                    parameters.Add(parameter);
                }
        
                if (methodInfo.ReturnType.IsGenericType) //Task
                {
                    var actionResult = await (methodInfo.Invoke(controller, parameters.ToArray()) as Task);
                    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 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
      • 你可能感兴趣的:(netcore mvc 的简单实现)