分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 教程案例

LayIM.AspNetCore Middleware 开发日记(三)基础框架搭建

发布时间:2023-09-06 01:57责任编辑:胡小海关键词:暂无标签

前言  

  在上一篇中简单讲了一些基础知识,例如Asp.Net Core Middleware 的使用,DI的简单使用以及嵌入式资源的使用方法等。本篇就是结合基础知识来构建一个基础框架出来。

  那么框架有什么功能呢?

  1. 拦截LayIM请求
  2. 简单路由功能
  3. 路由调度器
  4. 通用接口

  下面就基于以上四点搭建基础框架。其他缓存,日志什么的就先不在介绍。

拦截LayIM请求

  正如上一篇介绍的那样,实现一个中间件就可以做拦截请求操作,换句话说,如果是layim的请求,我们不要放过。如果不是,那么拜拜。但是由于我们又使用了系统的 EmbeddedFileProvider ,所以静态资源交给系统去处理就好。这里呢我使用一个很简单的方式来判断是否是LayIM的请求,就是通过请求的path前缀去判断。在 LayIMMiddleware入口方法Invoke中,通过IsLayIMRequest扩展方法去判断是否是LayIM请求。代码如下:

     /// <summary> ???????/// 是否LayIM接口请求 ???????/// </summary> ???????/// <param name="context"></param> ???????/// <param name="options"></param> ???????/// <returns></returns> ???????public static bool IsLayIMRequest(this HttpContext context, LayIMOptions options) ???????{ ???????????return IsConfigPath(context.Request.Path.Value) || context.Request.Path.Value.StartsWith(options.ApiPrefix, StringComparison.CurrentCultureIgnoreCase); ???????}

  没错,就这么简单粗暴,用了一个StartWith方法。代码中IsConfigPath以后在讲。在这里,前缀可以是用户自定义的。可以在UselayIM中传入定义方法:

 ?app.UseLayIM(options => { ??????options.ApiPrefix = "/mylayim"; ?});

  比如上文中我改成了/mylayim开头的,测试一下。

  

  可以看到,正常处理。

简单路由功能

  正如上文中的路径 /mylayim/init?uid=1 是如何进行处理的呢?这里我们的路由就要出场了。之前这段代码还是借鉴了Hangfire中 的代码实现的。它的路由很简单,就是通过正则去匹配。不过我这里实现的路由没有那么强大,为了方便,很多url都定义死了。而且不支持url中带参数解析的情况,例如 init/{uid}.不过这个后期会考虑。路由匹配代码如下:

 ???????/// <summary> ???????/// 通过path找到对应的Dispatcher ???????/// </summary> ???????/// <param name="path"></param> ???????/// <returns></returns> ???????private Tuple<ILayIMDispatcher, Match> FindDispatcherMatch(string path) ???????{ ???????????if (string.IsNullOrEmpty(path)) ???????????{ ???????????????path = "/"; ???????????} ???????????foreach (var dispatcher in dispatchers) ???????????{ ???????????????var pattern = $"^{dispatcher.Item1}$" ; ???????????????var match = Regex.Match(path, pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Singleline); ???????????????if (match.Success) ???????????????{ ???????????????????return new Tuple<ILayIMDispatcher, Match>(dispatcher.Item2, match); ???????????????} ???????????} ???????????return null; ???????}

  没错就这么一个方法实现了路由,是不是很简单。(复杂的还没去研究。。。。)从代码中我们可以看到方法返回了一个 Tuple<ILayIMDispatcher, Match> ,这个ILayIMDispatcher是何方神圣呢?让我们进入下一节吧。

路由调度器(ILayIMDispatcher)

  这个调度器翻译的不是很准确,不过大家理解就好。如果不理解的话,看下面的图就知道了。

  

  接口ILayIMDispatcher里面就一个方法

 Task Dispatch(HttpContext context);

  那么他们又可以细分为多种类型,在CQRS的概念里,我们对聚合的增删改都属于命令(Command),那么我们可以定义一个CommandDispatcher,不过我这里没有那么严格按照CQRS的方式,所以查询我也把他归类为查询命令:QueryCommandDispatcher。

  下面我们看一下具体代码:

 internal class QueryCommandDispatcher<TResult> : CommandDispatcher<TResult> ???{ ???????protected override string AllowMethod => HttpGet; ???????private readonly Func<HttpContext, TResult> executeFunction; ???????public QueryCommandDispatcher(Func<HttpContext, TResult> executeFunction) ???????{ ???????????this.executeFunction = executeFunction; ???????} ???}

  在构造函数里面我们传入了一个 Func<HttpContext, TResult>,那么这个Func就是我们的业务逻辑了。

  比如在路由里,我们添加 /layim/init 的 QueryCommandDispatcher。代码如下:

 ??????????//layim初始化接口 ???????????routes.AddQueryCommand<object>("/init", context => ???????????{ ???????????????//这里只是演示(逻辑未实现) ???????????????return context.Request.Query["uid"]; ???????????});

  其中AddQueryCommand是路由的一个扩展方法:

/// <summary> ???????/// 注册返回值为TResult类型的命令路由 ???????/// </summary> ???????/// <typeparam name="TResult">返回类型</typeparam> ???????/// <param name="routes">当前路有集合</param> ???????/// <param name="path">路径</param> ???????/// <param name="command">执行命令</param> ???????public static void AddQueryCommand<TResult>(this RoutesCollection routes, string path, Func<HttpContext, TResult> command) ???????{ ???????????Error.ThrowIfNull(path, nameof(path)); ???????????Error.ThrowIfNull(command, nameof(command)); ???????????routes.Add(path, new QueryCommandDispatcher<TResult>(command)); ???????}

  那么,这样的话,路由第一步先找到相对应  /layim/init 的调度器,然后执行Dispatch方法即可,最后返回所需要的数据。正如第一节里的截图那个最终处理效果。

通用接口

   通用接口其实在之前的文章中有讲过,他的作用就是业务和框架解耦。也就是说我设计好一个通用接口,如果用户不想使用框架的默认实现,可以自行定义实现方法,然后通过依赖注入的形式替换掉框架默认实现,这里不在赘述。比如框架的默认实现是Dapper,那么用户可以自己改为EntityFramework或者其他实现。

总结

  本文简单的介绍了框架的结构和基本实现,实现较为简单,功能相对来说比较单一,不过由于是偏向LayIM业务的,所以并没有想把它设计的多么复杂,功能多么强大,而且主要是能力不够,哈哈哈哈。

       博客预告:LayIM.AspNetCore Middleware 开发日记(四)主角登场(LayIM介绍)

  项目地址:https://github.com/fanpan26/LayIM.AspNetCore (本文代码对应blog3分支或者直接查看master)欢迎小伙伴们star 围观 提意见。

LayIM.AspNetCore Middleware 开发日记(三)基础框架搭建

原文地址:https://www.cnblogs.com/panzi/p/9108984.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved