在asp.net core 下定义统一的入参和出参格式
在使用.net core 開發Api的過程中,為了統一輸入參數的格式,并增加一些全局必須含有的字段,比如:Code,Message,Lang等等,能采取的變通方式還是有幾種的,然而都不夠優雅,為了需求更優雅的解決方式,本文采用asp.net core支持的自定義模型綁定以及結果過濾方式解決,測試效果達到了預期目的。
MVC過濾器
對于熟悉asp.net 的朋友來說,使用過濾器還是比較容易的,過濾器本身有著嚴格的順序,選用哪一種過濾器,必然是經過思考才能進行抉擇的,對于輸入參數來說,我們想修改參數值,可能比較方便的是選擇在操作過濾器上實現。
- 授權過濾器(Authorization)最先運行,用于確定是否已針對當前請求為當前用戶授權。?如果請求未獲授權,它們可以讓管道短路。 
- 資源過濾器(Resource)是授權后最先處理請求的篩選器。?它們可以在篩選器管道的其余階段運行之前以及管道的其余階段完成之后運行代碼。?出于性能方面的考慮,可以使用它們來實現緩存或以其他方式讓篩選器管道短路。?它們在模型綁定之前運行,所以可以影響模型綁定。 
- 操作過濾器可(Action)以在調用單個操作方法之前和之后立即運行代碼。?它們可用于處理傳入某個操作的參數以及從該操作返回的結果。不可在 Razor Pages 中使用操作篩選器。 
- 異常過濾器(Exception)用于在向響應正文寫入任何內容之前,對未經處理的異常應用全局策略。 
- 結果過濾器(Result)可以在執行單個操作結果之前和之后立即運行代碼。?僅當操作方法成功執行時,它們才會運行。?對于必須圍繞視圖或格式化程序的執行的邏輯,它們很有用。 
過濾器在?MVC 操作調用管道中執行,其大致位置如下:
?不同類型的過濾器操作順序如下:
實現結果過濾器的目的
寫過濾器的目的是把mvc控制器的Action返回結果加上固定返回格式,比如下圖返回一個字符串數組,我們需要的格式是一個包含該內容的json格式。
?用戶最終接收到的是下列內容。
{ "Code":123, "Message":"這是一個異常信息", "Data": ["values1","values2"], "RequestId":"0001" }當然為了實現該目的,你可以定義一個模板類,每個返回值都增加上諸如:Result<IEnumerable<string>>,或者定義一個基類,大家都集成自這個基類,也都可以實現,就是感覺不夠優雅。
結果過濾器
可以參考如下實現。
?難點:輸入參數
輸入參數的目的是從下列json中解析出Data結果數據綁定到mvc的action模型上。
{"Data":{ "desc": "string", "parameters": "string", "ttid": "string", "guid": "string" },"Lang":"zh_cn","RequestId":"ee27c35e-f8f9-4619-aabf-3125e84bcf90"}如上所示,你可以定義一個模板類或子類,然后同結果一樣,但不夠優雅優雅~~~~,啊哈哈,強迫癥...
這里采用微軟提供的模型綁定器解決該問題。ASP.NET Core MVC 中的模型綁定將 HTTP 請求中的數據映射到操作方法參數。?這些參數可能是簡單類型的參數,如字符串、整數或浮點數,也可能是復雜類型的參數。?這是 MVC 的一項強大功能,因為不管數據的大小和復雜性,將傳入數據映射到對應位置都是經常重復的方案。MVC 通過將綁定抽象出來解決了這一問題,使開發者不必在每個應用中重寫同一代碼的稍微不同版本。?向類型轉換器代碼寫入自己的文本不僅繁瑣乏味,而且容易出錯。
先實現一個繼承自IModelBinder的類來實現綁定處理的核心工作。
public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); } string modelBindingKey; if (bindingContext.IsTopLevelObject) { modelBindingKey = bindingContext.BinderModelName ?? string.Empty; } else { modelBindingKey = bindingContext.ModelName; } var httpContext = bindingContext.HttpContext; try { var args = await GetRequestValueAsync(httpContext.Request); httpContext.Items.Add("_Args", args); var type = bindingContext.ModelType; var argsType = typeof(Args<>).MakeGenericType(type); dynamic modelRtn = JsonConvert.DeserializeObject(args, argsType); if (modelRtn == null) { var message = $"序列化輸入參數為Args<{type.FullName}>時,結果為不期望的空值"; bindingContext.ModelState.AddModelError(modelBindingKey, message); return; } bindingContext.Result = ModelBindingResult.Success(modelRtn.v); modelRtn.v = null; var model = modelRtn.ToNormalizing(); if (string.IsNullOrEmpty(model.rid)) { model.rid = Guid.NewGuid().ToString("N"); } httpContext.Items.Add("_ArgsObject", model); } catch (Exception exception) { bindingContext.ModelState.AddModelError(modelBindingKey, exception, bindingContext.ModelMetadata); } }?是時候建立一個ModelBinderProvider來建立上述綁定了。只需要實現IModelBinderProvider接口即可。
public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.BindingInfo.BindingSource != null && context.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Body)) { return new QtBodyModelBinder(_options); } return null; }增加過濾和綁定
services.AddMvc(options => { options.ModelBinderProviders.Insert(index, new QtBodyModelBinderProvider(options)); options.Filters.Add(typeof(QtResultFilter)); }) ;應用
控制器內的使用還是按照原有方式,簡單明了,而傳入的參數和輸出的參數已經按照我們的json格式整理了,啊哈哈,終于不用糾結不優雅了~~~~
總結
以上是生活随笔為你收集整理的在asp.net core 下定义统一的入参和出参格式的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: C#位图BitArray 小试牛刀
- 下一篇: 6月统计|.NET薪资一旦高起来,岂是其
