简体   繁体   中英

How to use DataMember Name for [FromQuery] object Asp.Net core, ModelBinding

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;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM