Last active
September 8, 2016 17:21
-
-
Save joncloud/4d4eb078dcf24adab7b5b228f1babfbb to your computer and use it in GitHub Desktop.
Range query parameter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [Route("api/[controller]")] | |
| public class ValuesController : Controller | |
| { | |
| // GET api/values | |
| [HttpGet] | |
| public IActionResult Get([FromQuery]Criteria criteria) | |
| { | |
| if (criteria == null) | |
| { | |
| return NotFound(); | |
| } | |
| return Ok(criteria); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class Criteria | |
| { | |
| public Range<int> integer { get; set; } | |
| public Range<decimal> number { get; set; } | |
| public Range<DateTime> date { get; set; } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class Range<T> | |
| where T : IComparable<T> | |
| { | |
| delegate bool TryParseDelegate(string s, out T result); | |
| delegate bool TryParseDateTime(string s, out DateTime result); | |
| delegate bool TryParseInt32(string s, out int result); | |
| delegate bool TryParseSingle(string s, out decimal result); | |
| internal static readonly char[] Separator = new[] { '~' }; | |
| static readonly TryParseDelegate Parser; | |
| static Range() | |
| { | |
| if (typeof(T) == typeof(DateTime)) | |
| { | |
| TryParseDateTime d = DateTime.TryParse; | |
| Parser = (TryParseDelegate)Delegate.CreateDelegate(typeof(TryParseDelegate), d.Method); | |
| } | |
| if (typeof(T) == typeof(int)) | |
| { | |
| TryParseInt32 d = int.TryParse; | |
| Parser = (TryParseDelegate)Delegate.CreateDelegate(typeof(TryParseDelegate), d.Method); | |
| } | |
| if (typeof(T) == typeof(decimal)) | |
| { | |
| TryParseSingle d = decimal.TryParse; | |
| Parser = (TryParseDelegate)Delegate.CreateDelegate(typeof(TryParseDelegate), d.Method); | |
| } | |
| } | |
| public Range(T start, T end) | |
| { | |
| if (end.CompareTo(start) < 0) | |
| throw new ArgumentOutOfRangeException(nameof(end), end, "Range end must occur after start."); | |
| Start = start; | |
| End = end; | |
| } | |
| public T Start { get; } | |
| public T End { get; } | |
| public static bool TryParse(string s, out Range<T> range) | |
| { | |
| range = null; | |
| if (Parser == null) return false; | |
| if (s == null) return false; | |
| var parts = s.Split(Separator); | |
| if (parts.Length == 2) | |
| { | |
| T start, end; | |
| if (Parser(parts[0], out start) && | |
| Parser(parts[1], out end) && | |
| start.CompareTo(end) <= 0) | |
| { | |
| range = new Range<T>(start, end); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class RangeModelBinder<T> : IModelBinder | |
| where T : IComparable<T> | |
| { | |
| public Task BindModelAsync(ModelBindingContext bindingContext) | |
| { | |
| var key = bindingContext.ModelName; | |
| var value = bindingContext.ValueProvider.GetValue(key); | |
| Range<T> range; | |
| if (Range<T>.TryParse(value.FirstValue, out range)) | |
| bindingContext.Result = ModelBindingResult.Success(range); | |
| return Task.CompletedTask; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class RangeModelBinderProvider<T> : IModelBinderProvider | |
| where T : IComparable<T> | |
| { | |
| public IModelBinder GetBinder(ModelBinderProviderContext context) | |
| { | |
| if (context.Metadata.ModelType == typeof(Range<T>)) | |
| return new RangeModelBinder<T>(); | |
| return null; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| services.AddMvc().AddMvcOptions(options => | |
| { | |
| // Binders must come first otherwise default binders will take over. | |
| options.ModelBinderProviders.Insert(0, new RangeModelBinderProvider<DateTime>()); | |
| options.ModelBinderProviders.Insert(0, new RangeModelBinderProvider<decimal>()); | |
| options.ModelBinderProviders.Insert(0, new RangeModelBinderProvider<int>()); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment