基于SqlSugar的开发框架循序渐进介绍(24)– 使用Serialize.Linq对Lambda表达式进行序列化和反序列化

  • Post category:C#

在上篇随笔《基于SqlSugar的开发框架循序渐进介绍(23)– Winform端管理系统中平滑增加对Web API对接的需求 》中介绍了基于一个接口,实现对两种不同接入方式(直接访问数据库实现,基于Web API代理类实现)的处理,由于定义的接口中,我们为了方便,也是用了Lambda表达式的进行一些参数的处理,那么如果在Web API代理类中,Lambda表达式是不能直接传递给Web API的控制器的,那么如何对这个Lambda表达式进行序列化和反序列化还原就是一个急需解决的问题。 本篇随笔介绍采用Serialize.Linq 第三方组件的方式实现对Lambda表达式进行序列化和反序列化的处理。

1、Lambda表达式的接口使用

Lambda 表达式本质上是一个匿名函数,是C#中一种特殊语法,它的引入,使得匿名方法更加简单易用,最直接的是在方法体内调用代码或者为委托传入方法体的形式与过程变得更加优雅。 使用Lambda表达式可大大减少代码量,使得代码更加的优美、简洁,更有可观性。由于Lambda表达式的便利性,因此虽然在整合多个接入实现比较麻烦一些,我依旧希望通过寻找方法实现对Lambda表达式的兼容处理。

例如,以下就是一个根据名称简单进行判断的Lambda表达式的处理。

/// <summary>
/// 新增状态下的数据保存
/// </summary>
/// <returns></returns>
public async override Task<bool> SaveAddNew()
{
    CustomerInfo info = tempInfo;//必须使用存在的局部变量,因为部分信息可能被附件使用
    SetInfo(info);
    try
    {
        #region 新增数据
        //检查是否还有其他相同关键字的记录
        bool isExist = await BLLFactory<ICustomerService>.Instance.IsExistAsync(s=> s.Name.Equals(info.Name));
        if (isExist)
        {
            MessageDxUtil.ShowTips("指定的【姓名】已经存在,不能重复添加,请修改");
            return false;
        }

        var success = await BLLFactory<ICustomerService>.Instance.InsertAsync(info);
        if (success)
        {
            //可添加其他关联操作
            return true;
        }
        #endregion
    }
    catch (Exception ex)
    {
        LogTextHelper.Error(ex);
        MessageDxUtil.ShowError(ex.Message);
    }
    return false;
}  

它的函数原型就是一个Lambda表达式,如下所示的定义

/// <summary>
/// 判断是否存在指定条件的记录
/// </summary>
/// <param name="input">表达式条件</param>
/// <returns></returns>
Task<bool> IsExistAsync(Expression<Func<TEntity, bool>> input);

有些稍微复杂一点的函数,如下定义所示。

/// <summary>
/// 获取某字段数据字典列表
/// </summary>
Task<List<string>> GetFieldList(Expression<Func<TEntity, object>> selector, Expression<Func<TEntity, bool>> where = null);

调用的时候,如下所示。

/// <summary>
/// 初始化数据字典
/// </summary>
private async void InitDictItem()
{
    //初始化代码            
    var list = await BLLFactory<IFormService>.Instance.GetFieldList(s=> s.Category);
    this.txtCategory.BindDictItems(list, "");
}

不过简单是简单了,但是本身Lambda表达式不能直接传递给Web API端参数,因为它无法直接序列化进行传递。

我们在之前说过,接入两种不同的数据提供方式。

 因此我们为了继续使用Lambda表达是的优点,就需要使用Serialize.Linq对Lambda表达式进行序列化和反序列化。这样就可以在Web API端和Web API 代理端对Lambda表达式进行正常的使用了。

  

2、采用Serialize.Linq 对Lambda表达式进行序列化和反序列化的处理

 首先在需要的地方,引入Serialize.Linq对Lambda表达式进行序列化和反序列化处理。

 为了更好通用的实现Lambda表达式的正常序列化为文本,以及对文本的反序列化到Lambda表达式,我们这里编写了一个扩展函数,以便更方便的处理。

    /// <summary>
    /// 对Lambda表达式的序列号和反序列化处理
    /// </summary>
    public static class SerializeExtension
    {
        /// <summary>
        /// 序列化 LINQ Expression 表达式为JSON文本
        /// </summary>
        /// <typeparam name="TEntity">处理对象类型</typeparam>
        /// <typeparam name="TResult">返回结果类型</typeparam>
        /// <param name="express"></param>
        /// <returns></returns>
        public static string SerializeText<TEntity, TResult>(this Expression<Func<TEntity, TResult>> express)
        {
            //使用Serialize.Linq组件序列化表达式,传递给API端,API端需要对应反序列化的处理操作进行转换Expression
            var serializer = new ExpressionSerializer(new JsonSerializer());
            var expressJson = serializer.SerializeText(express);

            //接收端的反序列化处理
            //var express = (Expression<Func<TEntity, TResult>>)serializer.DeserializeText(expressJson);

            return expressJson;
        }

        /// <summary>
        /// 反序列化JSON文本为LINQ Expression 表达式
        /// </summary>
        /// <typeparam name="TEntity">处理对象类型</typeparam>
        /// <typeparam name="TResult">返回结果类型</typeparam>
        /// <param name="text"></param>
        /// <returns></returns>
        public static Expression<Func<TEntity, TResult>> DeserializeText<TEntity, TResult>(this string json)
        {
            Expression<Func<TEntity, TResult>> express = null;
            if (!string.IsNullOrWhiteSpace(json))
            {
                var serializer = new ExpressionSerializer(new JsonSerializer());
                express = (Expression<Func<TEntity, TResult>>)serializer.DeserializeText(json);
            }
            return express;
        }
    }

这样我们来看看两个对Lambda表达式的Web API代理类的封装处理代码

        /// <summary>
        /// 根据条件,获取所有记录
        /// </summary>
        public virtual async Task<ListResultDto<TEntity>> GetAllAsync(Expression<Func<TEntity, bool>> input, string orderBy = null)
        {
            var express = input.SerializeText(); //使用扩展函数处理生成JSON
            var postData = new
            {
                express,
                orderBy
            };
            return await DoActionAsync<ListResultDto<TEntity>>("all-expression", postData, HttpVerb.Post);
        }

        /// <summary>
        /// 根据条件计算记录数量
        /// </summary>
        /// <returns></returns>
        public virtual async Task<long> CountAsync(Expression<Func<TEntity, bool>> input)
        {
            var expressJson = input.SerializeText(); //使用扩展函数处理生成JSON
            return await DoActionAsync<long>("count-expression", expressJson, HttpVerb.Post);
        }

而对应的在Web API的基类控制器中,我们对这个通用的实现处理下就可以了

        /// <summary>
        /// 根据条件,获取所有记录
        /// </summary>
        [HttpPost]
        [Route("all-expression")]
        public async Task<ListResultDto<TEntity>> GetAllAsync(ExpressionOrderDto input)
        {
            ListResultDto<TEntity>? result = null;

            string json = input.expression;
            var express = json.DeserializeText<TEntity, bool>();

            if (express != null)
            {
                result = await _service.GetAllAsync(express!);
            }

            return result;
        }

        [HttpPost]
        [Route("count-expression")]
        public virtual async Task<long> CountAsync(dynamic expressJson)
        {
            long result = 0;
            string json = expressJson;
            var express = json.DeserializeText<TEntity, bool>();

            if (express != null)
            {
                result = await _service.CountAsync(express!);
            }
            return result;
        }

这样在服务器端的Web API控制器上,就还原了原先的Lambda表达式,可以正常的接收到客户端提交的条件处理了。

通过这样的迂回的方式,我们就可以在常规的接口,以及Web  API的代理类中,都可以使用到Lambda表达式带来的便利性了,而不需要为了兼容而抛弃Lambda表达式接口参数的方式了。

我们可以把其中相关的Lambda表达式,放在一个区块中,方便查看和处理,如下代码所示是在服务端的Web API控制器的基类函数处理代码。

SqlSugar开发框架介绍:https://www.iqidi.com/Framework/sugarIndex.htm 

 

系列文章:

基于SqlSugar的开发框架的循序渐进介绍(1)–框架基础类的设计和使用

基于SqlSugar的开发框架循序渐进介绍(2)– 基于中间表的查询处理

基于SqlSugar的开发框架循序渐进介绍(3)– 实现代码生成工具Database2Sharp的整合开发

基于SqlSugar的开发框架循序渐进介绍(4)– 在数据访问基类中对GUID主键进行自动赋值处理 

基于SqlSugar的开发框架循序渐进介绍(5)– 在服务层使用接口注入方式实现IOC控制反转

基于SqlSugar的开发框架循序渐进介绍(6)– 在基类接口中注入用户身份信息接口 

基于SqlSugar的开发框架循序渐进介绍(7)– 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

 《基于SqlSugar的开发框架循序渐进介绍(8)– 在基类函数封装实现用户操作日志记录

基于SqlSugar的开发框架循序渐进介绍(9)– 结合Winform控件实现字段的权限控制

基于SqlSugar的开发框架循序渐进介绍(10)– 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理

基于SqlSugar的开发框架循序渐进介绍(11)– 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结

基于SqlSugar的开发框架循序渐进介绍(12)– 拆分页面模块内容为组件,实现分而治之的处理

基于SqlSugar的开发框架循序渐进介绍(13)– 基于ElementPlus的上传组件进行封装,便于项目使用

基于SqlSugar的开发框架循序渐进介绍(14)– 基于Vue3+TypeScript的全局对象的注入和使用

 《基于SqlSugar的开发框架循序渐进介绍(15)– 整合代码生成工具进行前端界面的生成

基于SqlSugar的开发框架循序渐进介绍(16)– 工作流模块的功能介绍

基于SqlSugar的开发框架循序渐进介绍(17)– 基于CSRedis实现缓存的处理

 《基于SqlSugar的开发框架循序渐进介绍(18)– 基于代码生成工具Database2Sharp,快速生成Vue3+TypeScript的前端界面和Winform端界面

基于SqlSugar的开发框架循序渐进介绍(19)– 基于UniApp+Vue的移动前端的功能介绍

基于SqlSugar的开发框架循序渐进介绍(20)– 在基于UniApp+Vue的移动端实现多条件查询的处理

基于SqlSugar的开发框架循序渐进介绍(21)– 在工作流列表页面中增加一些转义信息的输出,在后端进行内容转换

 《基于SqlSugar的开发框架循序渐进介绍(22)– Vue3+TypeScript的前端工作流模块中实现统一的表单编辑和表单详情查看处理 

基于SqlSugar的开发框架循序渐进介绍(23)– Winform端管理系统中平滑增加对Web API对接的需求

基于SqlSugar的开发框架循序渐进介绍(24)– 使用Serialize.Linq对Lambda表达式进行序列化和反序列化