.NET中间件与VUE拦截器联合使用详情

 更新时间:2022年7月19日 13:36  点击:245 作者:ke210

前言:

工作中遇见的问题,边学边弄,记录一下Vue的UI库使用的是antvue 3.2.9版本的。

业务逻辑

特性:

//特性
    public class ModelEsignNameAttribute : Attribute
    {
        public ModelEsignNameAttribute(string nameProp, string id, string reversion = "", ModelESignType eSignType = ModelESignType.Modeling, string middleModelId = "")
        {

        }
    }

接口加上特性:

        /// <summary>
        ///  添加或者修改方法
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
		//特性上添加参数的地址
        [ModelEsignName("Bolg.BolgBaseEditDto.BolgName", "Document.Id", "Bolg.BolgRevision")]
        public async Task<Output> CreateOrUpdate(CreateOrUpdateBolgInput input)
        {
            var doc = await _XXXXManager.FindRdoById(input.Bolg.Id.Value);

            // 文档id为空,新增
            if (doc == null || !input.Bolg.BolgBaseId.HasValue)
            {
                return await this.Create(input.Bolg);
            }

            // 更新
            return await this.Update(input.Bolg);
        }

中间件代码:

namespace GCT.MedPro.Middleware
{
    public class ModelESignCheckMiddleware : IMiddleware
    {
		#region 依赖注入等内容
			....
        #endregion
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {

            if (await ShouldCheckESign(context))
            {
                // 不需要电子签名
                await next(context);
            }

        }
        /// <summary>
        /// 是否需要拦截
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        private async Task<bool> ShouldCheckESign(HttpContext actionContext)
        {
            var whetherSignature = true;

            var request = actionContext.Request;//获取请求值
            var currentUser = actionContext.User.Identity.Name;
            var serviceAction = actionContext
                    .GetEndpoint()?
                    .Metadata
                    .GetMetadata<ControllerActionDescriptor>();
            if (serviceAction == null)
            {
                return whetherSignature;
            }
            //通过接口特性来筛选是否需要进行拦截
            var attrObj = serviceAction.MethodInfo.CustomAttributes
                .FirstOrDefault(x => x.AttributeType == typeof(ModelEsignNameAttribute));

            if (attrObj == null)
            {
                return whetherSignature;
            }
            
            string inputbody = default;
            actionContext.Request.EnableBuffering();
            
            //Post请求获取请求参数,转换JSON
            if (request.Method.ToLower().Equals("post"))
            {
                var requestReader = new StreamReader(actionContext.Request.Body);
                var body = await requestReader.ReadToEndAsync();
                inputbody = UpperFirst(body); //首字母大写    全局搜索可得下方有
            }
            else   //GET请求以及其他方式获取
            {
                var reqString = request.QueryString.Value.Remove(0, 1);
                string[] parts = reqString.Split("&");
                JObject json = new JObject();

                foreach (string part in parts)
                {
                    String[] keyVal = part.Split("=");
                    json.Add(keyVal[0], keyVal[1]);
                }
                inputbody = JsonConvert.SerializeObject(json);
                inputbody = UpperFirst(inputbody);
            }
            
            var inputObj = JObject.Parse(inputbody);//转换JObject
            
            
            #region 获取特性传入的参数,,总五位参数
			var actionName = serviceAction.ActionName;
            var namePath = attrObj.ConstructorArguments[0].Value.ToString();
            var idPath = attrObj.ConstructorArguments[1].Value.ToString();
            var revsionPath = attrObj.ConstructorArguments[2].Value.ToString();
            var typePath = (ModelESignType)attrObj.ConstructorArguments[3].Value;
            var middlePath = attrObj.ConstructorArguments[4].Value.ToString();
        	#endregion
            var middleModelId = GetValueName(inputObj, middlePath);//通过JObject获取对应值
            //接口控制器名称
            var typeName = serviceAction.ControllerTypeInfo.FullName;
            //重置请求Body指针  
            actionContext.Request.Body.Position = 0;
            //验证方法,自己写个,自已业务的处理验证
            var output = await CheckSign(middleModelId);
            
            if (!output.SignStatus)
            {
                actionContext.Request.EnableBuffering();
                Stream originalBody = actionContext.Response.Body;
                try
                {
                    using (var ms = new MemoryStream())
                    {
                        //修改响应状态麻420
                        actionContext.Response.Body = ms;
                        actionContext.Response.StatusCode = 420;
                        ms.Position = 0;
                        //写入数据
                        var responseBody = TextJosn.JsonSerializer.Serialize(output);
                        var memoryStream = new MemoryStream();
                       
                        var sw = new StreamWriter(memoryStream);
                         //自己编辑的实体写入响应体
                        sw.Write(responseBody);
                        sw.Flush();
		
                        //重置响应指针
                        memoryStream.Position = 0;
                        //复制到原body上
                        await memoryStream.CopyToAsync(originalBody);
                    }
                }
                finally
                {
                    actionContext.Response.Body = originalBody;
                    actionContext.Request.Body.Position = 0;
                }

                whetherSignature = false;
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(output.ErrorMessage))
                {
                    var serializerSettings = new JsonSerializerSettings
                    {
                        // 设置为驼峰命名
                        ContractResolver = new Newtonsoft.Json.Serialization
                            .CamelCasePropertyNamesContractResolver()
                    };
                    //错误友好提示,适配中间件中抛出错误,修改响应体
                    var exception = new UserFriendlyException(output.ErrorMessage);
                    actionContext.Response.StatusCode = 500;
                    actionContext.Response.ContentType = "application/json; charset=utf-8";
                    //写入
                    await actionContext.Response.WriteAsync(
                    JsonConvert.SerializeObject(
                        new AjaxResponse(
                            _errorInfoBuilder.BuildForException(exception),
                            true
                             ), serializerSettings
                         )
                    );
                    whetherSignature = false;
                }
            }

            return whetherSignature;
        }
		//取出json的Name值
        private string GetValueName(JObject inputObj, string path)
        {
            string result = null;
            if (!string.IsNullOrWhiteSpace(path))
            {
                result = inputObj.SelectToken(path).ToObject<string>();
            }
            return result;
        }
        /// <summary>
        /// Json字符串首字母转大写
        /// </summary>
        /// <param name="strJsonData">json字符串</param>
        /// <returns></returns>
        public static string UpperFirst(string strJsonData)
        {
            MatchCollection matchCollection = Regex.Matches(strJsonData, "\\\"[a-zA-Z0-9]+\\\"\\s*:");
            foreach (Match item in matchCollection)
            {
                string res = Regex.Replace(item.Value, @"\b[a-z]\w+", delegate (Match match)
                {
                    string val = match.ToString();
                    return char.ToUpper(val[0]) + val.Substring(1);
                });
                strJsonData = strJsonData.Replace(item.Value, res);
            }
            return strJsonData;
        }
    }
}

Vue拦截器,拦截失败的响应,状态码为420的,中间件修改的响应的状态码:

import { AppConsts } from '/@/abpPro/AppConsts';
import { abpService } from '/@/shared/abp';
import { Modal } from 'ant-design-vue';
import axios, { AxiosResponse } from 'axios';
import abpHttpConfiguration from './abp-http-configuration.service';
const apiHttpClient = axios.create({
  baseURL: AppConsts.remoteServiceBaseUrl,
  timeout: 300000,
});
// 请求拦截器
apiHttpClient.interceptors.request.use(
  (config: any) => {
     // ....
    return config;
  },
  (error: any) => {
    return Promise.reject(error);
  },
);
// 响应拦截器
apiHttpClient.interceptors.response.use(
  (response: AxiosResponse) => {
    // 响应成功拦截器
    if (response.data.__abp) {
      response.data = response.data.result;
    }
    return response;
  },
  (error: any) => {
    // 响应失败拦截器
   	//方法里存在异步,使用一个Promise包裹起来
    return new Promise((resolve, reject) => {
      // 关闭所有模态框
      Modal.destroyAll();
      const errorResponse = error.response;
      const ajaxResponse = abpHttpConfiguration.getAbpAjaxResponseOrNull(error.response);
      if (ajaxResponse != null) {
        abpHttpConfiguration.handleAbpResponse(errorResponse, ajaxResponse);
        reject(error);
      } else {
        if (errorResponse.status == 420) {
          //abpHttpConfiguration中自己写的一个模态框弹窗,把响应数据传入其中
          abpHttpConfiguration.needIntercept(errorResponse.data)
            .toPromise()//Observable转Promise
            .then((value) => {
              if (value) {
                // resolve 原先的请求地址,重发请求
                resolve(apiHttpClient(errorResponse.config));
              } else {
                reject(error);
              }
            });
        } else {
          abpHttpConfiguration.handleNonAbpErrorResponse(errorResponse);
          reject(error);
        }
      }
    });
  },
);
export default apiHttpClient;

模态框弹窗,返回的bool类型:

//是否验证需求通过弹窗
  needIntercept(error): Observable<Boolean> {
    return new Observable<Boolean>((obs) => {
      if (error != undefined && error.SignStatus != null && !error.SignStatus) {
        //弹出模态框
        this.modalCreate(error).subscribe(
          (b) => {
            obs.next(b);
            obs.complete();
          },
          (error) => console.log(error, 123),
          () => {
            obs.next(false);
            obs.complete();
          },
        );
      } else {
        obs.next(false);
        obs.complete();
      }
    });
  }
  //电子签名弹窗
  modalCreate(responseBody: any): Observable<Boolean> {
    let sub;
    if (!responseBody.IsAccountSign) {
      //弹出模态框,指定的组件GESignNameComponent ,传入参数
      sub = modalHelper.create(
        GESignNameComponent,
        {
          relationId: responseBody.ModelSignNameId,
          listEsignRequirementId: responseBody.ListSignRequirementId,
        },
      );
    } else {
      //弹出模态框,GESignNameAccountComponent ,传入参数
      sub = modalHelper.create(
        GESignNameAccountComponent,
        {
          relationId: responseBody.ModelSignNameId,
          listEsignRequirementId: responseBody.ListSignRequirementId,
        },
      );
    }
    return sub;
  }

到此这篇关于.NET中间件与VUE拦截器联合使用详情的文章就介绍到这了,更多相关.NET VUE拦截器内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://www.cnblogs.com/ke210/p/16418310.html

[!--infotagslink--]

相关文章

  • ASP.NET购物车实现过程详解

    这篇文章主要为大家详细介绍了ASP.NET购物车的实现过程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
  • vue中activated的用法

    这篇文章主要介绍了vue中activated的用法,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...2021-01-03
  • 基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能

    这篇文章主要介绍了基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23
  • Antd-vue Table组件添加Click事件,实现点击某行数据教程

    这篇文章主要介绍了Antd-vue Table组件添加Click事件,实现点击某行数据教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-17
  • Vue组件跨层级获取组件操作

    这篇文章主要介绍了Vue组件跨层级获取组件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-28
  • .NET Core下使用Kafka的方法步骤

    这篇文章主要介绍了.NET Core下使用Kafka的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • vue 实现动态路由的方法

    这篇文章主要介绍了vue 实现动态路由的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-06
  • 在ASP.NET 2.0中操作数据之七十二:调试存储过程

    在开发过程中,使用Visual Studio的断点调试功能可以很方便帮我们调试发现程序存在的错误,同样Visual Studio也支持对SQL Server里面的存储过程进行调试,下面就让我们看看具体的调试方法。...2021-09-22
  • antdesign-vue结合sortablejs实现两个table相互拖拽排序功能

    这篇文章主要介绍了antdesign-vue结合sortablejs实现两个table相互拖拽排序功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-09
  • vue 获取到数据但却渲染不到页面上的解决方法

    这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-19
  • Vue基于localStorage存储信息代码实例

    这篇文章主要介绍了Vue基于localStorage存储信息代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-16
  • vue项目页面嵌入代码块vue-prism-editor的实现

    这篇文章主要介绍了vue项目页面嵌入代码块vue-prism-editor的实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-30
  • Win10 IIS 安装.net 4.5的方法

    这篇文章主要介绍了Win10 IIS 安装及.net 4.5及Win10安装IIS并配置ASP.NET 4.0的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • Vue 3.0中jsx语法的使用

    这篇文章主要介绍了Vue 3.0 中 jsx 语法使用,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...2020-11-13
  • vue Treeselect下拉树只能选择第N级元素实现代码

    这篇文章主要介绍了vue Treeselect下拉树只能选择第N级元素实现代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-01
  • vue项目多环境配置(.env)的实现

    最常见的多环境配置,就是开发环境配置,和生产环境配置,本文主要介绍了vue项目多环境配置的实现,感兴趣的可以了解一下...2021-07-20
  • vue实现同时设置多个倒计时

    这篇文章主要为大家详细介绍了vue实现同时设置多个倒计时,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-05-20
  • Vue select 绑定动态变量的实例讲解

    这篇文章主要介绍了Vue select 绑定动态变量的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-23
  • Ant design vue table 单击行选中 勾选checkbox教程

    这篇文章主要介绍了Ant design vue table 单击行选中 勾选checkbox教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-25
  • vue实现div单选多选功能

    这篇文章主要为大家详细介绍了vue实现div单选多选功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-07-16