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

ASP.NET中如何将非JSON对象字符串转为DiscriminatorTags结构体?

问题描述

我正在为以下DiscriminatorTags结构体创建自定义ModelBinder,以便将其作为Query Parameter传递:

[Serializable]
[ModelBinder(BinderType = typeof(DiscriminatorTagsBinder))]
public struct DiscriminatorTags : IDiscriminatorTags
{
    public DiscriminatorTags(List<int> tags, string discriminator, bool selected)
    {
        this.Tags = tags;
        this.Discriminator = discriminator;
        this.Selected = selected;
    }

    [Required]
    public List<int> Tags { get; set; }
    [Required]
    public string Discriminator { get; set; }
    [Required]
    public bool Selected { get; set; }
}

对应的Binder代码如下:

public class DiscriminatorTagsBinder : IModelBinder
{
    public DiscriminatorTagsBinder()
    {
    }

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

        var modelName = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        var x = JsonSerializer.Deserialize<DiscriminatorTags>(valueProviderResult.FirstValue);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
        var value = valueProviderResult.FirstValue;

        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(valueProviderResult);
        return Task.CompletedTask;
    }
}

但需要反序列化的字符串并非JSON格式,而是类似C#对象初始化的格式:

DiscriminatorTags(tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,14, 15, 16, 17, 18, 900], selected: true, discriminator: GroceryItm)

使用JsonSerializer.Deserialize会抛出JsonException,需要将该非JSON字符串转换为DiscriminatorTags结构体类型。

解决方案

由于目标字符串是自定义格式,无法直接用JSON序列化器解析,我们可以通过正则表达式提取字段值,再手动构造结构体实例。

1. 编写正则表达式提取字段

针对目标格式,使用正则匹配出tags数组、selected布尔值和discriminator字符串:

var pattern = @"DiscriminatorTags\(tags: \[(?<tags>[^\]]+)\], selected: (?<selected>true|false), discriminator: (?<discriminator>\w+)\)";
var match = Regex.Match(inputString, pattern);
  • (?<tags>[^\]]+):匹配tags数组内的所有数字和分隔符
  • (?<selected>true|false):匹配布尔值true或false
  • (?<discriminator>\w+):匹配discriminator的字符串值(假设无特殊字符)

2. 修改ModelBinder实现

替换原Binder中的JSON反序列化逻辑,改用正则解析并构造结构体:

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

        var modelName = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
        var inputString = valueProviderResult.FirstValue;

        if (string.IsNullOrEmpty(inputString))
        {
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        // 使用正则提取字段
        var pattern = @"DiscriminatorTags\(tags: \[(?<tags>[^\]]+)\], selected: (?<selected>true|false), discriminator: (?<discriminator>\w+)\)";
        var match = Regex.Match(inputString, pattern);

        if (!match.Success)
        {
            bindingContext.ModelState.AddModelError(modelName, "Invalid DiscriminatorTags format");
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        // 解析tags列表
        var tagsStr = match.Groups["tags"].Value;
        var tags = tagsStr.Split(',')
                          .Select(s => int.TryParse(s.Trim(), out var num) ? num : -1)
                          .Where(num => num != -1)
                          .ToList();

        // 解析selected布尔值
        if (!bool.TryParse(match.Groups["selected"].Value, out var selected))
        {
            bindingContext.ModelState.AddModelError(modelName, "Invalid selected value");
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        // 获取discriminator值
        var discriminator = match.Groups["discriminator"].Value;

        // 构造结构体实例
        var result = new DiscriminatorTags(tags, discriminator, selected);

        // 验证结构体必填字段
        var validationContext = new ValidationContext(result);
        var validationResults = new List<ValidationResult>();
        if (!Validator.TryValidateObject(result, validationContext, validationResults, validateAllProperties: true))
        {
            foreach (var validationResult in validationResults)
            {
                bindingContext.ModelState.AddModelError(modelName, validationResult.ErrorMessage);
            }
            bindingContext.Result = ModelBindingResult.Failed();
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(result);
        return Task.CompletedTask;
    }
}

3. 注意事项

  • 如果discriminator值包含空格或特殊字符,需要调整正则表达式(例如将\w+改为[^,)]+以兼容带空格的内容)
  • 代码中增加了完整的错误处理:格式不匹配、字段解析失败时,会将错误信息添加到ModelState,便于后续业务层验证
  • 可选保留结构体字段验证逻辑,确保[Required]特性的约束生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:53:32