如何让API自动解析GET路由参数为自定义领域对象?
可以将领域对象用作API GET路由参数吗?
完全可以,你可以通过自定义模型绑定器或类型转换器实现字符串到自定义Id领域对象的自动转换,从而在一处统一完成值的验证,避免重复代码。以下是具体实现方案:
方案一:使用自定义模型绑定器(推荐API场景)
模型绑定器能更好地处理参数转换时的错误,并将验证错误反馈到ModelState,方便返回标准化的错误响应。
1. 实现自定义模型绑定器
创建一个实现IModelBinder的类,处理字符串到Id对象的转换及异常捕获:
public class IdModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); string rawValue = valueProviderResult.FirstValue; try { var id = new Id(rawValue); bindingContext.Result = ModelBindingResult.Success(id); } catch (ArgumentNullException ex) { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex.Message); } catch (ValidationException ex) { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex.Message); } return Task.CompletedTask; } }
2. 关联模型绑定器与Id类
通过[ModelBinder]属性标记Id类,指定使用自定义绑定器:
[ModelBinder(BinderType = typeof(IdModelBinder))] public class Id { public string Value { get; } public Id(string value) { if (string.IsNullOrEmpty(value)) { throw new ArgumentNullException("value"); } if (value.Length > 10) { throw new ValidationException("Invalid length"); } Value = value.Trim(); } }
3. 修改API动作
直接将参数类型改为Id,并校验ModelState:
public async Task<IActionResult> CancelOnlineMeeting(Id id) { if (!ModelState.IsValid) { return BadRequest(ModelState); } // 业务逻辑:使用id.Value return Ok($"Processing cancellation for meeting ID: {id.Value}"); }
方案二:使用类型转换器
如果不需要精细的错误反馈,类型转换器是更简洁的选择:
1. 实现类型转换器
public class IdTypeConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string strValue) { return new Id(strValue); } return base.ConvertFrom(context, culture, value); } }
2. 标记Id类
添加[TypeConverter]属性指定转换器:
[TypeConverter(typeof(IdTypeConverter))] public class Id { // 原构造函数和属性不变 }
3. 使用API动作
同样直接使用Id作为参数即可,不过转换异常会直接抛出,需要全局异常处理来捕获并返回响应。
核心优势
- 统一验证:所有使用
Id参数的API动作都会自动应用构造函数中的验证逻辑,无需重复编写。 - 领域驱动设计:将验证逻辑封装在领域对象内部,符合DDD的设计原则,保持业务逻辑的内聚性。
- 代码简洁:API动作无需再处理字符串验证,专注于业务逻辑实现。
内容的提问来源于stack exchange,提问作者Sam Jones
相关产品推荐
相关产品推荐

