首页 > Web开发 > 详细

netcore mvc 的简单实现

时间:2019-09-16 16:23:05      阅读:70      评论:0      收藏:0      [点我收藏+]
  • 实现的功能

    • 简单的路由系统
    • 支持中间件
    • 简单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

netcore mvc 的简单实现

原文:https://www.cnblogs.com/zcode/p/11527485.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!