本人接手的時候,專案已經存在了,
但同時跟我一起接手的前端,提出了專業的要求,
輸出要有統一格式,
要有swagger
但專案以前是用.NET Framework框架寫的,不是純卒的webapi,
無奈,我把他升級為最新的.Net6框架,基本都能應付前端的需求, 但發現一個嚴重問題,以前接收引數是非常自由的,自動系結非常高,比如定義int型別的引數,前端傳null值,也能自動還原為默認的0值,但升到.Net6 采用webapi模式后,不靈了,重新定義為int?工程太大。找了網上好多資料和微軟的官方檔案,加上本論壇大佬們的熱心幫助和解答,終于給我解決了,寫了個自定義重新系結資料模形的方法,但有個隱患,在重新系結的程序中,必須事先知道引數本身的型別,所以我用swith,例舉了所有我專案用到的型別進行還原,而且int[]這種型別,現在還沒解決,不知怎么還原。如果能把前端為null值的引數去除以后,再用系統自動系結的方法系結模形就完美了,但網上一直找不到相關的語法,不知高人有沒有辦法,謝謝指點。
using BLL;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace ZFY_API.Filter
{
/// <summary>
/// 此功能是過濾值為null的引數
/// </summary>
public class UserModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
JObject j = new JObject();
//獲得介面引數型別
Type Type = bindingContext.ModelMetadata.ModelType;
//定義一個介面型別引數
var Data = Activator.CreateInstance(Type);
//獲取引數,以jobject形式保存備用
object C = new object();
string bodyStr = string.Empty;
using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body, Encoding.UTF8, true, 1024, true))
{
var bodyRead = reader.ReadToEndAsync();
j = JsonConvert.DeserializeObject<JObject>(bodyRead.Result);
}
JObject jParam = new JObject();
foreach (var rs in j)
{
if (rs.Value == null)//排除null的傳參
{
jParam.Add(new JProperty(rs.Key, rs.Value));
}
}
//手工重新系結資料模型
string obStr = jParam.ToString();
C = JsonConvert.DeserializeObject<Object>(obStr);
IEnumerable<JProperty> properties = j.Properties();
foreach (System.Reflection.PropertyInfo info in Type.GetProperties())
{
string Name = info.Name;
string type = info.PropertyType.Name.ToLower();
foreach (var rs in j)
{
if (rs.Value.ToStr().Length > 0 && Name.ToLower() == rs.Key.ToLower())
{
switch (type)
{
case "int32":
info.SetValue(Data, (int)rs.Value);
break;
case "decimal":
info.SetValue(Data, (decimal)rs.Value);
break;
case "double":
info.SetValue(Data, (double)rs.Value);
break;
case "byte":
info.SetValue(Data, (byte)rs.Value);
break;
case "string":
info.SetValue(Data, (string)rs.Value);
break;
case "boolean":
info.SetValue(Data, (bool)rs.Value);
break;
case "int32[]":
info.SetValue(Data, GetObjectFromJson<int[]>(rs.Value.ToString(), info.PropertyType));
break;
case "string[]":
info.SetValue(Data, rs.Value.ToString().Split(','));
break;
default:
info.SetValue(Data, GetObjectFromJson<imgObj[]>(rs.Value.ToString(), info.PropertyType));
break;
}
}
}
}
////自動系結資料模型
// var model = bindingContext.Result.Model;
bindingContext.Result = ModelBindingResult.Success(Data);
return Task.CompletedTask;
}
public static T GetObjectFromJson<T>(string jsonString, Type type)
{
var dcSerializer = new DataContractJsonSerializer(type);
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
{
return (T)dcSerializer.ReadObject(stream);
}
}
}
}
需要解決的問題是如何將這行代碼GetObjectFromJson<imgObj[]> 里面的<imgObj[]>換成泛指的,要不每種型別我都要列一個,
如GetObjectFromJson<string>
GetObjectFromJson<Int>
GetObjectFromJson<bool>
GetObjectFromJson<jobject>
... ...
等等,象這種簡單,已知的型別還好,但如果
特別是自定義的型別,這個是無可預知的
這方法就行不通了,所以 如果解決了提到的不足,直接在Startup注入就更簡單了
uj5u.com熱心網友回復:
原來是我想多了,其實不用 swith,直接標object類就行了info.SetValue(Data, GetObjectFromJson<object>(rs.Value.ToString(), info.PropertyType));
uj5u.com熱心網友回復:
額,我表示你這個前端???哦,你上一個帖子說“他要求你不準給他傳null,要你轉換成空字串,空集合,空物件”,然后這帖子說“你不能給我null,我可以給你傳null,你自己看著辦”
上個帖子我就說了,這樣的美工你可以不伺候,伺候不來的。他下個要求是“我覺著這個api不好,我要自己拼接資料的,你應該幫我把資料拼接好。比如我用easyui的表格,你看做個表格多麻煩。你后端把表頭,資料,轉換都在后端按easyui的datagrid都拼接好怎么樣”
ps:你的要求我們總體上可以在 “全域序列化”中配置default value,但是null和0其實還是不一樣,同時對于這樣的前埠子不能隨意開,你要對這種前端隨意開這種完全不講規則的,不講道理的口子。后面的事情,你還真控制不住
uj5u.com熱心網友回復:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddControllers(
//全域配置Json序列化處理
.AddJsonOptions(options =>
{
//我們通常在這里進行序列化和反序列化的全域配置
}
);
}
msdn的標準說明:
https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#support-polymorphic-deserialization
注意看最后一段“如何處理null值”標準手法是自己實作Converter
當然,我還是的說,這樣的前端你要不注意控控,后面有的一忙,。“你給我null不行,我給你給你null請接著”這還玩啥哦,合作的基礎呢?(合著錯的都是別人,他的都是對的,都必須聽他的)
uj5u.com熱心網友回復:
在細化一下,微軟自己已經寫了例子https://github.com/dotnet/runtime/blob/81bf79fd9aa75305e55abe2f7e9ef3f60624a3a1/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullValueType.cs
private class Int32NullConverter : JsonConverter<int>
{
public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return 0;
}
return reader.GetInt32();
}
public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/284866.html
標籤:C#
