DynamicDictionaryJsonModelBinderProvider Class

json 到动态字典的模型绑定提供器。

Definition

Namespace: QuickAdmin.Common.ModelBinders
Assembly: QuickAdmin.Net (in QuickAdmin.Net.dll) Version: 2.0.13
C#
public class DynamicDictionaryJsonModelBinderProvider : IModelBinderProvider
Inheritance
object    DynamicDictionaryJsonModelBinderProvider
Implements
IModelBinderProvider

Remarks

将创建 json 到 DynamicDictionary/List<DynamicDictionary> 的模型绑定器,可用来代替 DTO 对象(不用去设计一堆 DTO)。 DynamicDictionary 同时具备 DynamicObject 类以及字典类的功能,参见其文档。
支持接收前端用 "application/json""application/x-www-form-urlencoded" 提交来的 json 字符串,能够自动识别属性类型并支持递归解析嵌套对象, 参见示例。

Example

例如前端提交来的以下 json:
C#
{
  "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# 结果将为:
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:
C#
// 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 示例:
C#
[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" 提交:
C#
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>
C#
[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)
{
    ...
}

Constructors

DynamicDictionaryJsonModelBinderProviderInitializes a new instance of the DynamicDictionaryJsonModelBinderProvider class

Methods

Public Methods

GetBinder Creates a IModelBinder based on ModelBinderProviderContext.

See Also