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
相关产品推荐
相关产品推荐

