zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Qt 打开UI是提示Runtime Error! 。。。 然后奔溃
    Qt exe和动态 库获取运行所需库
    区分EXE或者动态库dll是32位或者64位方法
    QFile 读2进制文件
    MFC 动态库编译错误
    Qt 编译错误
    Qt QNetworkProxy类帮助翻译
    Qt QHttpMultiPart类帮助翻译
    Qt QNetworkCookie帮助翻译
    Qt QHttpPart翻译
  • 原文地址:https://www.cnblogs.com/zcode/p/11527485.html
Copyright © 2011-2022 走看看