For [FromBody] parameters I can use DataMember.Name to set custom name of property, but it doesn't work for [FromQuery]. I guess it depends on model binding
I want to process query like ?status=a&status=b&status=c
with query object [FromQuery]MyQuery
[DataContract]
class MyQuery {
[DataMember(Name = "status")
public IReadOnlyList<string> Statuses { get; set; }
}
I can do it like
class MyQuery {
[FromQuery("status")
public IReadOnlyList<string> Statuses { get; set; }
}
but I would like to avoid model dependency from AspNetCore
, is there any solutions?
(there is similar question about Web API 2 but it has not answer)
I didn't find way do to it with standart attributes, so I use statuses
name, use custom attribute for string collections
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
internal class StringCollectionAttribute : Attribute
{
}
and use custom model binder
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;
}
}