.NET中間件以及VUE攔截器聯合使用

来源:https://www.cnblogs.com/ke210/archive/2022/07/06/16418310.html
-Advertisement-
Play Games

.NET中間件以及VUE攔截器聯合使用 工作中遇見的問題,邊學邊弄,記錄一下 Vue的UI庫使用的是antvue 3.2.9版本的。 業務邏輯 特性 //特性 public class ModelEsignNameAttribute : Attribute { public ModelEsignNa ...


.NET中間件以及VUE攔截器聯合使用

工作中遇見的問題,邊學邊弄,記錄一下

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;
  }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 文章開始之前,我給大家推薦一個人工智慧學習網站,首先說我之前是完全不涉及人工智慧領域的,但是我盡然看懂了,以後老哥我就要參與人工智慧了。如果你也想學習,點擊跳轉到網站 最近打算寫一個用於股票體檢的軟體,比如股權質押比過高的股票不合格,ROE小於10的股票不合格,PE大於80的股票不合格等等等等,就像 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • MySQL主從同步是基於Bin Log實現的,而Bin Log記錄的是原始SQL語句。 Bin Log共有三種日誌格式,可以binlog_format配置參數指定。 ...
  • 歡迎關註公眾號:bin的技術小屋,如果大家在看文章的時候發現圖片載入不了,可以到公眾號查看原文 本系列Netty源碼解析文章基於 4.1.56.Final版本 最近在 Review Netty 代碼的時候,不小心用我的肉眼抓到了一個隱藏很深很深的記憶體泄露 Bug。 於是筆者將這個故事....哦不 . ...
  • 這兩篇的mvc都是一些開發多的註解呀和一些配置的問題,只需要記住一些該有的註解,它們的使用跟Servlet是十分相似的,還有ssm整合和springboot了,整體來說我寫的代碼都很少很多都是直接抄的代碼,主要是要去瞭解這些控制項,始終要記得的是ioc開發模式很多東西都是屬於是bean ...
  • 作者:須臾之餘 地址:https://my.oschina.net/u/3995125 寫在前面:設計模式源於生活,而又高於生活! 什麼是適配器模式 定義:將一個系統的介面轉換成另外一種形式,從而使原來不能直接調用的介面變得可以調用。 適配器模式角色劃分 適配器模式涉及3個角色: 1.源(Adapt ...
  • Seata Seata 是一款開源的分散式事務解決方案,致力於在微服務架構下提供高性能和簡單易用的分散式事務服務。在 Seata 開源之前,Seata 對應的內部版本在阿裡經濟體內部一直扮演著分散式一致性中間件的角色,幫助經濟體平穩的度過歷年的雙11,對各BU業務進行了有力的支撐。經過多年沉澱與積累 ...
  • java方法的定義與調用 java方法是語句的集合,他們在一起執行一個功能。 方法是解決一類問題的步驟的有序組合 方法包含於類或對象中 方法在程式中被創建,在其他地方被引用 代碼示例: public class Demo01 { //main方法 public static void main(St ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...