前言  

  在上一篇中简单讲了一些基础知识,例如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. Java基础教程(7)--运算符

      现在,我们已经学会了如何声明和初始化变量,但你可能想知道如何操作它们.运算符是对一个,两个或三个操作数执行特定操作并返回结果的特殊符号.下表列出了Java中的运算符:   表格中的运算符是按照从上 ...

  2. 四、闭锁之CountDownLatch

    一.简介 闭锁是Java的一种同步工具类.我们在程序运行过程中,某个任务需要等待其它一个到多个的任务全部完成才会执行,这个等待的期间就叫做闭锁. CountDownLatch是闭锁的一种实现,它支持一 ...

  3. 最新的dubbo和zookeeper整合的问题

    最新的dubbo和zookeeper整合的问题 生活本不易,流人遂自安 博主最新在做小项目练手,在进行dubbo和zookeeper整合的时候遇到了一些问题,在这里这些问题做个小总结吧. 首先需要说明 ...

  4. 撩课-Web大前端每天5道面试题-Day3

    1. javascript的typeof返回哪些数据类型? 答案: undefined string boolean number symbol(ES6) Object Function 2. 列举3 ...

  5. Exception in thread "main" java.nio.channels.NotYetConnectedException

    import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocke ...

  6. CentOS6.5下连网以及输入法下载

    宽带拨号连网: 1.系统--首选项--网络连接(或点击桌面右上角连网图标--VPN连接--VPN配置)       2.添加--选择DSL--勾自动连接(也可不勾)--DSL下填写用户名.密码--应用 ...

  7. 在 Ubuntu上使用 MySQL

    MySQL 安装配置 https://help.ubuntu.com/12.04/serverguide/mysql.html MySQL Manual http://dev.mysql.com/do ...

  8. POJ P2318 TOYS与POJ P1269 Intersecting Lines——计算几何入门题两道

    rt,计算几何入门: TOYS Calculate the number of toys that land in each bin of a partitioned toy box. Mom and ...

  9. Single Number 数组中除了某个元素出现一次,其他都出现两次,找出这个元素

    Given an array of integers, every element appears twice except for one. Find that single one. Note:Y ...

  10. python django 环境搭建

    一. 版本选择 Django 1.5.x 支持 Python 2.6.5 Python 2.7, Python 3.2 和 3.3. Django 1.6.x 支持 Python 2.6.X, 2.7 ...