前言  

  在上一篇中简单讲了一些基础知识,例如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 开发日记(三)基础框架搭建的更多相关文章

  1. LayIM.AspNetCore Middleware 开发日记(二)预备知识介绍

    前言 开发一个AspNetCore的中间件需要理解RequestDelegate.另外,还需要理解.NET Core中的依赖注入.还有一个就是内嵌资源的访问.例如:EmbeddedFileProvid ...

  2. LayIM.AspNetCore Middleware 开发日记(一)闲言碎语

    前言 前几天写博客的时候突然看见了历史上的今天.不禁感慨时光如梭,这系列博客后来被我标注了已经过时,但是还有很多小伙伴咨询我.既然过时就要更新,正好 .NET Core 也出来很久了,于是乎想到把La ...

  3. LayIM.AspNetCore Middleware 开发日记(四)主角登场(LayIM介绍)

    前言 在前几篇中已经初步介绍了开发AspNetCore中间件的一些基础知识,不过都没有很深入的去研究,后续还是需要去看看源码.本篇呢,终于有点开头的味道了,就是要介绍LayIM了,其实标题写的是主角, ...

  4. LayIM.AspNetCore Middleware 开发日记(五)Init接口实现细节

    前言 “一旦开始了就要坚持下去“.为什么本文的第一句话是这么一句话呢,因为我经常就是开头轰轰烈烈,结果越来越枯燥,就不想做下去了.但是版图就放弃又那么不甘心,继续加油吧. 吐槽完毕,进入正题.在上一篇 ...

  5. LayIM.AspNetCore Middleware 开发日记(六)嵌入资源的使用,layim.config的封装

    前言 距离上一篇博客竟然已经10多天了...工作上的事,个人原因,种种吧.不多说废话,本文将会重点介绍layim的入口配置. LayIM配置 其实在开发者文档里面已经描述的很清楚了.除了几个重要的接口 ...

  6. LayIM.AspNetCore Middleware 开发日记(七)Asp.Net.Core.SignalR闪亮登场

    前言   前几篇介绍了整个中间件的构成,路由,基本配置等等.基本上没有涉及到通讯部分.不过已经实现了融云的通讯功能,由于是第三方的就不在单独去写.正好.NET Core SignalR已经出来好久了, ...

  7. PHP 设计模式 笔记与总结(2)开发 PSR-0 的基础框架

    [PSR-0 规范的三项约定]: ① 命名空间必须与绝对路径一致 ② 类名的首字母必须大写 ③ 除入口文件外,其他".php"必须只有一个类(不能有可执行的代码) [开发符合 PS ...

  8. onvif开发实战2--总结框架搭建

    完成框架搭建后,编写自己的主函数起onvif服务 编写makefile objs = onvif.o onvif_func.o duration.o soapC.o soapServer.o stds ...

  9. 微信公众账号开发教程(二) 基础框架搭建——转自http://www.cnblogs.com/yank/p/3392394.html

    上一章,我们已经初步讲解了微信公众账号开发的基本原理,今天我们来探索设计实现. 首先我们设计了模块层次图,当然图中只是给出一种实现方式,不局限于此.具体见下图. 主要功能介绍如下: 1)请求接口层.处 ...

随机推荐

  1. 7、包装类、System、Math、Arrays、大数据运算

    基本类型封装 基本数据类型对象包装类概述 *A:基本数据类型对象包装类概述 *a.基本类型包装类的产生 在实际程序使用中,程序界面上用户输入的数据都是以字符串类型进行存储的.而程序开发中,我们需要把字 ...

  2. 撩课-Mysql详解第3部分sql分类

    学习地址:[撩课-JavaWeb系列1之基础语法-前端基础][撩课-JavaWeb系列2之XML][撩课-JavaWeb系列3之MySQL][撩课-JavaWeb系列4之JDBC][撩课-JavaWe ...

  3. 使用TreeDMS进行MySQL数据库的Web页面远程管理

    在互联网应用蓬勃发展的时代背景下,各种各样的网络平台,网络应用,移动应用层出不穷,那么这些应用及平台都需要使用到数据库.如何高效的对数据进行日常维护.管理.监控成为迫切需要解决的问题. 基于web的方 ...

  4. UVA401(回文子串和镜像串)

    可以先设一个常量镜像串,直接返回比较 #include <iostream> #include <string> #include <cstring> #inclu ...

  5. java 通用对象排序

    一个排序类,一个排序util? no.no.no…… 使用反射机制,写了一个通用的对象排序util,欢迎指正. 实体类: package entity; public class BaseTypeEn ...

  6. input自定义样式上传图片

    在我们写网页的时候,有很多各种各样的上传图片的样式,但是input 的 type="file" 的样式是不可被更改的. 其实我们要的只是input的点击,清楚这点就行了. CSS部 ...

  7. Android学习笔记(2)----LocationManager的使用

    今天使用Android的LocationManager制作了一款获取当前经纬坐标位置的软件. LocationManager获取的只是经纬坐标点,为了解析出当前经纬坐标点的实际位置,可以使用Googl ...

  8. linux fack 文件系统修复命令

    [简介] fsck命令被用于检查并且试图修复文件系统中的错误.当文件系统发生错误四化,可用fsck指令尝试加以修复. [选项]必要参数 -a 非互交模式,自动修复 -c 检查是否存在有损坏的区块. - ...

  9. 五、python小功能记录——打包程序

    使用pyinstaller打包Python程序 安装工具 :pip3 install pyinstaller 在Python程序文件夹上(不点进去)按住shift并且右键,在弹出的选项中点击" ...

  10. 快速设置UITableView不同section对应于不同种类的cell

    快速设置UITableView不同section对应于不同种类的cell 本文主要是为了写明如何在UITableView中,一个section对应于一种类型的cell,写起来不凌乱. 在不封装任何类的 ...