如何为 [FromQuery] 对象 Asp.Net 核心使用 DataMember 名称,ModelBinding
How to use DataMember Name for [FromQuery] object Asp.Net core, ModelBinding
对于 [FromBody] 参数,我可以使用 DataMember.Name 来设置 属性 的自定义名称,但它不适用于 [FromQuery]。我想这取决于模型绑定
我想像 ?status=a&status=b&status=c
一样处理查询
带有查询对象[FromQuery]MyQuery
[DataContract]
class MyQuery {
[DataMember(Name = "status")
public IReadOnlyList<string> Statuses { get; set; }
}
我能做到
class MyQuery {
[FromQuery("status")
public IReadOnlyList<string> Statuses { get; set; }
}
但我想避免 AspNetCore
的模型依赖,有什么解决方案吗?
(有similar question about Web API 2但没有回答)
我没有找到使用标准属性的方法,我可以使用 statuses
名称,对字符串集合使用自定义属性
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
internal class StringCollectionAttribute : Attribute
{
}
并使用自定义模型活页夹
public class StringCollectionBinderProvider : IModelBinderProvider
{
private static readonly Type BinderType = typeof(StringCollectionBinder);
private static readonly Type ModelType = typeof(List<string>);
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var propertyAttributes = (context.Metadata as DefaultModelMetadata)?.Attributes.PropertyAttributes;
var isStringCollection =
propertyAttributes?.Any(x => x is StringCollectionAttribute) == true
&& context.Metadata.ModelType.IsAssignableFrom(ModelType);
return isStringCollection ? new BinderTypeModelBinder(BinderType) : null;
}
}
public class StringCollectionBinder : IModelBinder
{
private const char ValueSeparator = ',';
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
var valueCollection = bindingContext.ValueProvider.GetValue(modelName);
if (valueCollection == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueCollection);
var stringCollection = valueCollection.FirstValue;
if (string.IsNullOrEmpty(stringCollection))
{
return Task.CompletedTask;
}
var collection = stringCollection.Split(ValueSeparator).ToList();
bindingContext.Result = ModelBindingResult.Success(collection);
return Task.CompletedTask;
}
}
对于 [FromBody] 参数,我可以使用 DataMember.Name 来设置 属性 的自定义名称,但它不适用于 [FromQuery]。我想这取决于模型绑定
我想像 ?status=a&status=b&status=c
带有查询对象[FromQuery]MyQuery
[DataContract]
class MyQuery {
[DataMember(Name = "status")
public IReadOnlyList<string> Statuses { get; set; }
}
我能做到
class MyQuery {
[FromQuery("status")
public IReadOnlyList<string> Statuses { get; set; }
}
但我想避免 AspNetCore
的模型依赖,有什么解决方案吗?
(有similar question about Web API 2但没有回答)
我没有找到使用标准属性的方法,我可以使用 statuses
名称,对字符串集合使用自定义属性
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
internal class StringCollectionAttribute : Attribute
{
}
并使用自定义模型活页夹
public class StringCollectionBinderProvider : IModelBinderProvider
{
private static readonly Type BinderType = typeof(StringCollectionBinder);
private static readonly Type ModelType = typeof(List<string>);
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var propertyAttributes = (context.Metadata as DefaultModelMetadata)?.Attributes.PropertyAttributes;
var isStringCollection =
propertyAttributes?.Any(x => x is StringCollectionAttribute) == true
&& context.Metadata.ModelType.IsAssignableFrom(ModelType);
return isStringCollection ? new BinderTypeModelBinder(BinderType) : null;
}
}
public class StringCollectionBinder : IModelBinder
{
private const char ValueSeparator = ',';
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
var valueCollection = bindingContext.ValueProvider.GetValue(modelName);
if (valueCollection == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueCollection);
var stringCollection = valueCollection.FirstValue;
if (string.IsNullOrEmpty(stringCollection))
{
return Task.CompletedTask;
}
var collection = stringCollection.Split(ValueSeparator).ToList();
bindingContext.Result = ModelBindingResult.Success(collection);
return Task.CompletedTask;
}
}