You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何为类内自定义类型CustomString添加自定义ModelBinder?

自定义类型绑定请求体字段并通过DI控制格式的解决方案

问题描述

定义了WarehouseDTO类,其中Name字段为自定义类型CustomString,尝试通过自定义ModelBinder绑定请求体中的该字段,但调试发现ModelBinderProvider仅识别到WarehouseDTO的类型,内部CustomString字段未触发绑定逻辑。同时希望通过依赖注入决定CustomString的字符串格式(如大写、标题大小写)。

相关代码如下:

控制器代码

public async Task<IActionResult> Create([FromBody] WarehouseDTO warehouseDTO)

自定义ModelBinder与Provider代码

using Microsoft.AspNetCore.Mvc.ModelBinding;

public class CustomStringModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        if (bindingContext.BindingSource == BindingSource.Body)
        {
            var fieldName = bindingContext.FieldName;
            string val = bindingContext.ValueProvider.GetValue(fieldName).FirstValue;
            if (val == null)
            {
                val = bindingContext.ValueProvider.GetValue("Value").FirstValue;
            }

            bindingContext.Result = ModelBindingResult.Success(new CustomString(val));
        }

        return Task.CompletedTask;
    }
}

public class CustomStringBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.Metadata.ModelType == typeof(CustomString))
        {
            return new CustomStringModelBinder();
        }

        return null;
    }
}

WarehouseDTO代码

public class WarehouseDTO
{
    public int Id { get; set; }
    [ModelBinder(typeof(CustomStringModelBinder))]
    public CustomString Name { get; set; }
    // 其他字段...
}

解决方案

问题根源

使用[FromBody]特性时,ASP.NET Core默认通过JSON序列化器(如System.Text.Json或Newtonsoft.Json)直接反序列化整个请求体,不会触发ModelBinder系统,因此自定义的CustomStringModelBinder无法作用到WarehouseDTO内部的CustomString字段。

正确实现方式:自定义JSON转换器+依赖注入

通过自定义JSON转换器处理CustomString的反序列化,同时利用依赖注入注入格式控制服务,实现动态格式调整。

1. 定义格式控制接口与实现

先定义格式控制接口,以及具体的格式实现:

// 格式控制接口
public interface IStringFormatter
{
    string Format(string input);
}

// 示例:大写格式实现
public class UppercaseStringFormatter : IStringFormatter
{
    public string Format(string input)
    {
        return input?.ToUpperInvariant();
    }
}

// 示例:标题格式实现
public class TitleCaseStringFormatter : IStringFormatter
{
    public string Format(string input)
    {
        if (string.IsNullOrEmpty(input)) return input;
        return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(input.ToLower());
    }
}

2. 修改CustomString类,依赖格式接口

让CustomString通过构造函数注入IStringFormatter,由格式器处理字符串格式:

public class CustomString
{
    public string Value { get; }

    public CustomString(string value, IStringFormatter formatter)
    {
        Value = formatter.Format(value);
    }
}

3. 实现自定义JSON转换器

创建继承自JsonConverter<CustomString>的转换器,在反序列化时使用注入的格式器:

public class CustomStringJsonConverter : JsonConverter<CustomString>
{
    private readonly IStringFormatter _formatter;

    // 通过构造函数注入格式器
    public CustomStringJsonConverter(IStringFormatter formatter)
    {
        _formatter = formatter;
    }

    public override CustomString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var rawValue = reader.GetString();
        return new CustomString(rawValue, _formatter);
    }

    public override void Write(Utf8JsonWriter writer, CustomString value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.Value);
    }
}

4. 注册服务与转换器

在Program.cs(或Startup.cs)中注册格式器服务和自定义JSON转换器:

var builder = WebApplication.CreateBuilder(args);

// 注册格式器服务(可根据配置切换不同实现)
builder.Services.AddSingleton<IStringFormatter, UppercaseStringFormatter>();

// 配置控制器并添加自定义JSON转换器
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 从服务容器获取格式器实例
        var serviceProvider = builder.Services.BuildServiceProvider();
        var formatter = serviceProvider.GetRequiredService<IStringFormatter>();
        options.JsonSerializerOptions.Converters.Add(new CustomStringJsonConverter(formatter));
    });

var app = builder.Build();

app.MapControllers();

app.Run();

5. 调整WarehouseDTO

移除[ModelBinder]特性,因为不再需要ModelBinder:

public class WarehouseDTO
{
    public int Id { get; set; }
    public CustomString Name { get; set; }
    // 其他字段...
}

说明

  • 该方式直接参与JSON反序列化流程,完美适配[FromBody]场景。
  • 通过注册不同的IStringFormatter实现,可以动态切换CustomString的格式规则,满足依赖注入的需求。

内容的提问来源于stack exchange,提问作者Sora Teichman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:17:02