我有表示不同类型的Id的structs。该结构具有int属性"Id",具有(int Id(参数的公共构造函数,并实现IEquatable接口。我希望我的ASP.Net核心WebAPI应用程序以某种方式将这些结构绑定到查询中传入的整数Id。我知道有自定义的模型绑定器,但要使用它,我需要为所有查询模型实现自定义的模型捆绑器,因为用自定义模型绑定器标记每个键结构属性是不够的-我需要注册自定义模型绑定程序提供程序,在那里我切换ModelType并返回单个模型绑定器
public class CustomModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(DogQueryModel))
{
return new BinderTypeModelBinder(typeof(DogQueryModelBinder));
}
所以我不能只为每个Id结构创建一个模型绑定器——需要为每个查询模型创建它。
为了明确起见,我将提供该结构、查询模型和操作的一些示例代码:
public struct DogKey : IEquatable<DogKey>
{
public DogKey(int id)
{
Id = id;
}
public int Id { get; }
#region IEquatable implementation
#endregion IEquatable implementation
}
public class DogQueryModel
{
public DogKey Id { get; set; }
public SomeOtherKey OtherId { get; set; }
public string Name { get; set; }
}
[HttpGet("dog")]
public async Task<ActionResult<IList<DogResultModel>>> GetDogs([FromQuery]DogQueryModel dogQueryModel)
{
//use dogQueryModel.Id as DogKey struct
}
我想这样查询:https://localhost/api/v1/dogs/dog?id=1&otherId=2&Name=dogname
您可以通过实现类型转换器来实现这一点,文档中提到了它,但遗憾的是没有示例。我已经实现了使您的样本工作所必需的部分。
我在KeyConverter类中添加了一些通用约束,这些约束似乎符合您的需求,但它们不是必需的。
public class KeyConverter<T> : TypeConverter
where T : struct, IEquatable<T>
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
var stringValue = value as string;
if (!string.IsNullOrWhiteSpace(stringValue))
{
if(int.TryParse(stringValue, out int parsed))
{
return Activator.CreateInstance(typeof(T), new object[] { parsed });
}
}
return base.ConvertFrom(context, culture, value);
}
}
然后用TypeConverter
属性装饰关键类。
[TypeConverter(typeof(KeyConverter<DogKey>))]
public struct DogKey : IEquatable<DogKey>
{
public DogKey(int id)
{
Id = id;
}
public int Id { get; }
#region IEquatable implementation
#endregion IEquatable implementation
}
[TypeConverter(typeof(KeyConverter<CatKey>))]
public struct CatKey : IEquatable<CatKey>
{
public CatKey(int id)
{
Id = id;
}
public int Id { get; }
#region IEquatable implementation
#endregion IEquatable implementation
}