Skip to content

Instantly share code, notes, and snippets.

@geirsagberg
Created July 10, 2018 07:33
Show Gist options
  • Save geirsagberg/f06c376a23ff95f8176379e32e0b2e40 to your computer and use it in GitHub Desktop.
Save geirsagberg/f06c376a23ff95f8176379e32e0b2e40 to your computer and use it in GitHub Desktop.
Delimited query string value provider
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Primitives;
namespace Utils
{
/// <inheritdoc />
/// <summary>
/// A <see cref="T:Microsoft.AspNetCore.Mvc.ModelBinding.IValueProviderFactory" /> that creates
/// <see cref="T:Microsoft.AspNetCore.Mvc.ModelBinding.IValueProvider" /> instances that
/// read optionally delimited values from the request query-string.
/// </summary>
public class DelimitedQueryStringValueProviderFactory : IValueProviderFactory
{
private static readonly char[] DefaultDelimiters = {','};
private readonly char[] delimiters;
public DelimitedQueryStringValueProviderFactory()
: this(DefaultDelimiters)
{
}
public DelimitedQueryStringValueProviderFactory(params char[] delimiters)
{
if (delimiters == null || delimiters.Length == 0) {
this.delimiters = DefaultDelimiters;
} else {
this.delimiters = delimiters;
}
}
/// <inheritdoc />
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null) {
throw new ArgumentNullException(nameof(context));
}
var valueProvider = new DelimitedQueryStringValueProvider(
context.ActionContext.HttpContext.Request.Query,
context.ActionContext.HttpContext.Features.Get<IRequestCultureFeature>().RequestCulture.Culture,
delimiters);
context.ValueProviders.Add(valueProvider);
return Task.CompletedTask;
}
}
public class DelimitedQueryStringValueProvider : QueryStringValueProvider
{
private readonly IQueryCollection queryCollection;
public char[] Delimiters { get; }
public DelimitedQueryStringValueProvider(
IQueryCollection values,
CultureInfo culture,
char[] delimiters)
: base(BindingSource.Query, values, culture)
{
queryCollection = values;
Delimiters = delimiters;
}
public override ValueProviderResult GetValue(string key)
{
if (key == null) {
throw new ArgumentNullException(nameof(key));
}
var values = queryCollection[key];
if (values.Count == 0) {
return ValueProviderResult.None;
}
if (values.Any(x => Delimiters.Any(x.Contains))) {
var stringValues = new StringValues(values
.SelectMany(x => x.Split(Delimiters, StringSplitOptions.RemoveEmptyEntries))
.ToArray());
return new ValueProviderResult(stringValues, Culture);
}
return new ValueProviderResult(values, Culture);
}
}
public static class ValueProviderFactoriesExtensions
{
/// <summary>
/// Allows parsing query strings on the form of ?array=value1,value2,value3 etc.
/// </summary>
public static void AddDelimitedValueProviderFactory(
this IList<IValueProviderFactory> valueProviderFactories,
params char[] delimiters)
{
AddDelimitedQueryStringValueProviderFactory(valueProviderFactories, delimiters);
AddDelimitedFormValueProviderFactory(valueProviderFactories, delimiters);
}
private static void AddDelimitedFormValueProviderFactory(IList<IValueProviderFactory> valueProviderFactories, char[] delimiters)
{
var formValueProviderFactory = valueProviderFactories.OfType<FormValueProviderFactory>().FirstOrDefault();
if (formValueProviderFactory == null) {
valueProviderFactories.Insert(0,
new DelimitedFormValueProviderFactory(delimiters));
} else {
valueProviderFactories.Insert(valueProviderFactories.IndexOf(formValueProviderFactory),
new DelimitedFormValueProviderFactory(delimiters));
valueProviderFactories.Remove(formValueProviderFactory);
}
}
private static void AddDelimitedQueryStringValueProviderFactory(IList<IValueProviderFactory> valueProviderFactories, char[] delimiters)
{
var queryStringValueProviderFactory = valueProviderFactories.OfType<QueryStringValueProviderFactory>().FirstOrDefault();
if (queryStringValueProviderFactory == null) {
valueProviderFactories.Insert(0,
new DelimitedQueryStringValueProviderFactory(delimiters));
} else {
valueProviderFactories.Insert(valueProviderFactories.IndexOf(queryStringValueProviderFactory),
new DelimitedQueryStringValueProviderFactory(delimiters));
valueProviderFactories.Remove(queryStringValueProviderFactory);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment