4

How do I bind a list of Guids passed on the query string for a web-api call.

I've tried comma separated list, an array, etc. but they always come up with an empty guid on the controller action

public endPoint:

public ApiResult Get([FromUri]List<Guid> listIds)

What I've tried

endpoint?listIds=78CC5308-5A3D-40C2-8D7C-3AAB0CAC618B,6DA7AFB8-D862-4861-8EA2-EE5EB9BC7C6A

endpoint?listIds=["78CC5308-5A3D-40C2-8D7C-3AAB0CAC618B","6DA7AFB8-D862-4861-8EA2-EE5EB9BC7C6A"]

All I get each time I try is a list with one element and it is the empty GUID

2
  • Try getting them as an array of strings instead of Guid objects. That said, I recommend you do a bit of reading up about passing large amounts of data in GET requests. It's not really the best way to do it. A cleaner way is to POST a request that returns an ID that you then GET the results with. Commented Jul 15, 2019 at 20:44
  • A large amount of data like a list of GUIDs should be sent in body IMO. Commented Jul 22, 2019 at 4:07

3 Answers 3

9

The right way for webapi is using the query parameter multiple times,no matter the type.

i.e:

endpoint?listIds=1234-5678&listIds=5555-4444....
Sign up to request clarification or add additional context in comments.

Comments

2

The trick is to add an individual entry for each guid in the query string. So the values bind properly when I GET

endpoint?listIds=78CC5308-5A3D-40C2-8D7C-3AAB0CAC618B&listIds=6DA7AFB8-D862-4861-8EA2-EE5EB9BC7C6A

Comments

0

You could customize QueryStringValueProvider like below :

SeparatedQueryStringValueProvider

public class SeparatedQueryStringValueProvider : QueryStringValueProvider
{
    private readonly string _key;
    private readonly string _separator;
    private readonly IQueryCollection _values;

    public SeparatedQueryStringValueProvider(IQueryCollection values, string separator)
        : this(null, values, separator)
    {
    }

    public SeparatedQueryStringValueProvider(string key, IQueryCollection values, string separator)
        : base(BindingSource.Query, values, CultureInfo.InvariantCulture)
    {
        _key = key;
        _values = values;
        _separator = separator;
    }

    public override ValueProviderResult GetValue(string key)
    {
        var result = base.GetValue(key);

        if (_key != null && _key != key)
        {
            return result;
        }

        if (result != ValueProviderResult.None && result.Values.Any(x => x.IndexOf(_separator, StringComparison.OrdinalIgnoreCase) > 0))
        {
            var splitValues = new StringValues(result.Values
                .SelectMany(x => x.Split(new[] { _separator }, StringSplitOptions.None)).ToArray());
            return new ValueProviderResult(splitValues, result.Culture);
        }

        return result;
    }
}

Add an IValueProviderFactory. Factories are – as the name suggests – responsible for providing instances of value providers. Our factory is very simple :

public class SeparatedQueryStringValueProviderFactory : IValueProviderFactory
{
    private readonly string _separator;
    private readonly string _key;

    public SeparatedQueryStringValueProviderFactory(string separator) : this(null, separator)
    {
    }

    public SeparatedQueryStringValueProviderFactory(string key, string separator)
    {
        _key = key;
        _separator = separator;
    }

    public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
    {
        context.ValueProviders.Insert(0, new SeparatedQueryStringValueProvider(_key, context.ActionContext.HttpContext.Request.Query, _separator));
        return Task.CompletedTask;
    }
}

To apply the value provider globally to our entire API, we can register the factory in the MVC Options, at application startup.

services.AddMvc(opts =>
{
     opts.ValueProviderFactories.Insert(0, new SeparatedQueryStringValueProviderFactory(","));
 });

Note: the value provider is applied against a method (an action), not against an individual parameter of that action. This means that typically, if you create a custom value provider strategy it would be applied to all parameters of an action. For how to remedy this defect, you can refer to this link : https://www.strathweb.com/2017/07/customizing-query-string-parameter-binding-in-asp-net-core-mvc/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.