using System; using System.Collections.Generic; using System.Web.Mvc; using Portoa.Web; namespace VideoGameQuotes.Web.Models { public class ApiModel { public ApiModel() { Criteria = new Dictionary>(); } public bool FetchAll { get; set; } public int Id { get; set; } public SortMethod SortMethod { get; set; } public SortOrder SortOrder { get; set; } public IDictionary> Criteria { get; set; } } public class ApiModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var model = new ApiModel { SortMethod = SortMethod.None, SortOrder = SortOrder.Ascending }; ParseId(controllerContext, model); ParseSort(controllerContext, model); ParseCriteria(controllerContext, model); return model; } private static void ParseCriteria(ControllerContext controllerContext, ApiModel model) { var criteria = (controllerContext.RouteData.Values["criteria"] ?? string.Empty).ToString().Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); for (var i = 0; i < criteria.Length; i++) { switch (criteria[i]) { case "system": if (i < criteria.Length - 1) { model.Criteria["system"] = ParseCommaSeparatedCriterion(criteria[i + 1]); i++; } else { controllerContext.AddModelError("criteria", "Unable to parse criteria for key \"system\""); } break; default: controllerContext.AddModelError("criteria", string.Format("Unable to parse criteria for key \"{0}\"", criteria[i])); break; } } } private static IEnumerable ParseCommaSeparatedCriterion(string csv) { var values = csv.Split(','); foreach (var value in values) { int result; if (int.TryParse(value, out result)) { yield return result; } else { yield return value; } } } private static void ParseSort(ControllerContext controllerContext, ApiModel model) { var sortValue = controllerContext.HttpContext.Request.QueryString["sort"]; if (string.IsNullOrWhiteSpace(sortValue)) { return; } var sortValues = sortValue.Split('|'); try { model.SortMethod = (SortMethod)Enum.Parse(typeof(SortMethod), sortValues[0], ignoreCase: true); } catch { controllerContext.AddModelError("sort", string.Format("The sort method \"{0}\" is invalid", sortValues[0])); } if (sortValues.Length > 1) { try { model.SortOrder = (SortOrder)Enum.Parse(typeof(SortOrder), sortValues[1], ignoreCase: true); } catch { controllerContext.AddModelError("sort", string.Format("The sort order \"{0}\" is invalid", sortValues[1])); } } } private static void ParseId(ControllerContext controllerContext, ApiModel model) { var idValue = (controllerContext.RouteData.Values["id"] ?? string.Empty).ToString(); int id; if (int.TryParse(idValue, out id)) { if (id <= 0) { controllerContext.AddModelError("id", "Invalid value for id"); } else { model.Id = id; } } else { model.FetchAll = idValue == "all"; } } } }