DynamicDictionaryJsonModelBinderProvider Class
json 到动态字典的模型绑定提供器。
将创建 json 到
DynamicDictionary/
List<DynamicDictionary> 的模型绑定器,可用来代替 DTO 对象(不用去设计一堆 DTO)。
DynamicDictionary 同时具备
DynamicObject 类以及字典类的功能,参见其文档。
支持接收前端用
"application/json" 或
"application/x-www-form-urlencoded" 提交来的 json 字符串,能够自动识别属性类型并支持递归解析嵌套对象,
参见示例。
例如前端提交来的以下 json:
{
"name": "Alice",
"age": 30,
"isAdmin": true,
"roles": ["admin", "editor"],
"address": {
"city": "Xian",
"zip": "710000"
},
"history": [
{ "year": 2020, "event": "joined" },
{ "year": 2022, "event": "promoted" }
],
"birthDate": "1990-05-20",
"lastLogin": "2023-11-01T08:30:00Z",
"locked": "false",
"salary": 12345.67,
"recentArticleIds": [101, 102, 103],
"dailySteps": [5000, null, 8000],
"auditTrail": [2023, "approved", null, true, { "step": 1 }]
}
后端用此 Provider 模型绑定时得到的 C# 结果将为:
new DynamicDictionary
{
["name"] = "Alice", // string
["age"] = 30L, // long (整型全部解析为 long)
["isAdmin"] = true, // bool
["roles"] = new List<string> { "admin", "editor" }, // List<string>
["address"] = new DynamicDictionary // 嵌套 DynamicDictionary
{
["city"] = "Xian",
["zip"] = "710000" // 源 json 里是字符串 "710000",解析后仍为字符串,不会转为整型
},
["history"] = new List<DynamicDictionary> // 嵌套 DynamicDictionary 列表
{
new DynamicDictionary
{
["year"] = 2020L,
["event"] = "joined"
},
new DynamicDictionary
{
["year"] = 2022L,
["event"] = "promoted"
}
},
["birthDate"] = new DateTime(1990, 5, 20), // DateTime
["lastLogin"] = DateTime.Parse("2023-11-01T08:30:00Z"), // UTC DateTime
["locked"] = "false", // string (源 json 里是字符串 "false",解析后仍为字符串,不会转为布尔)
["salary"] = 12345.67D, // double (浮点数值,先尝试解析为 double,若精度大于 double 将解析为 decimal)
["recentArticleIds"] = new List<long> { 101L, 102L, 103L }, // List<long>
["dailySteps"] = new List<long?> { 5000L, null, 8000L }, // List<long?> (因为源 json 里有 null,自动解析为 long? 列表)
["auditTrail"] = new List<object> // List<object> (类型混杂列表,解析为 List<object>)
{
2023L,
"approved",
null,
true,
new DynamicDictionary
{
["step"] = 1L
}
}
};
具体用法:
首先在启动代码里注册 DynamicDictionaryJsonModelBinderProvider:
// Razor Pages 项目用:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
// 插入 DynamicDictionaryJsonModelBinderProvider
options.ModelBinderProviders.Insert(0, new DynamicDictionaryJsonModelBinderProvider());
});
// MVC 项目用:
builder.Services.AddControllersWithViews()
.AddMvcOptions(options =>
{
// 插入 DynamicDictionaryJsonModelBinderProvider
options.ModelBinderProviders.Insert(0, new DynamicDictionaryJsonModelBinderProvider());
});
在后端 Razor页面Handler、视图控制器Action、API控制器Action 方法里指定输入参数为
DynamicDictionary,以下为 API 示例:
[ApiController]
[Route("api/[controller]/[action]")]
public class MyTestController : ControllerBase
{
[HttpPost]
[ValidateAntiForgeryToken]
public Task<IActionResult> SaveDataAsync(DynamicDictionary input)
{
dynamic obj = input;
Console.WriteLine($"name = {obj.name}");
Console.WriteLine($"age = {obj.age}");
Console.WriteLine($"address.city = {obj.address.city}");
return Task.FromResult<IActionResult>(ServiceResult.Ok().ToCamelCaseJsonContentResult());
}
}
前端可用
"application/json" 或
"application/x-www-form-urlencoded" 提交:
var input = {
"name": "Alice",
"age": 30,
"isAdmin": true,
"roles": ["admin", "editor"],
"address": {
"city": "Xian",
"zip": "710000"
}
};
QF.ajaxPostJson({
url: '~/api/MyTest/SaveData',
data: input,
success: function (res) {
console.log(res);
},
error: function () {
console.warn('post error');
}
});
// 或者:
QF.ajaxPostForm({
url: '~/api/MyTest/SaveData',
data: {
input: JSON.stringify(input)
},
success: function (res) {
console.log(res);
},
error: function () {
console.warn('post error');
}
});
/*
注:QF 是 QuickAdmin.Net 提供的 js 对象,QF.ajaxPostJson()/QF.ajaxPostForm() 是对 $.ajax() 的封装,将分别发送 application/json 和 application/x-www-form-urlencoded 请求。
url 可传入相对地址(~/打头),将被自动转为绝对地址(支持应用程序部署到子目录的场景,例如 IIS 虚拟目录下)。
QF.ajaxPostJson() 里会自动把传入的 data 对象用 JSON.stringify() 转为 json 字符串然后再提交。
参见:https://quickadmin.net/guide/qf-reference.html#post-%E6%96%B9%E6%B3%95
*/
若前端提交来的是 json 数组,则在后端方法指定输入参数为
List<DynamicDictionary> 或
IList<DynamicDictionary>:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SaveDataAsync(List<DynamicDictionary> inputs)
{
foreach (dynamic obj in inputs)
{
Console.WriteLine($"name = {obj.name}");
Console.WriteLine($"age = {obj.age}");
Console.WriteLine($"address.city = {obj.address.city}");
}
...
}
// 或者
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SaveDataAsync(IList<DynamicDictionary> inputs)
{
...
}