diff options
Diffstat (limited to 'src')
7 files changed, 30 insertions, 119 deletions
diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs index d3b49445..876f5248 100644 --- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -29,33 +29,39 @@ namespace StardewModdingAPI.Web.Controllers ** Public methods *********/ /// <summary>Fetch version metadata for the given mods.</summary> - /// <param name="modKeys">The namespaced mod keys to search.</param> - [HttpGet] - public async Task<ModInfoModel[]> Post(IEnumerable<string> modKeys) + /// <param name="search">The search options.</param> + [HttpPost] + public async Task<IDictionary<string, ModInfoModel>> Post([FromBody] ModSearchModel search) { - IList<ModInfoModel> result = new List<ModInfoModel>(); + // sort & filter keys + string[] modKeys = (search.ModKeys ?? new string[0]) + .Distinct(StringComparer.CurrentCultureIgnoreCase) + .OrderBy(p => p, StringComparer.CurrentCultureIgnoreCase) + .ToArray(); + // fetch mod info + IDictionary<string, ModInfoModel> result = new Dictionary<string, ModInfoModel>(StringComparer.CurrentCultureIgnoreCase); foreach (string modKey in modKeys) { // parse mod key if (!this.TryParseModKey(modKey, out string vendorKey, out string modID)) { - result.Add(new ModInfoModel(modKey, "The mod key isn't in a valid format. It should contain the mod repository key and mod ID like 'Nexus:541'.")); + result[modKey] = new ModInfoModel("The mod key isn't in a valid format. It should contain the mod repository key and mod ID like 'Nexus:541'."); continue; } // get matching repository if (!this.Repositories.TryGetValue(vendorKey, out IModRepository repository)) { - result.Add(new ModInfoModel(modKey, "There's no mod repository matching this namespaced mod ID.")); + result[modKey] = new ModInfoModel("There's no mod repository matching this namespaced mod ID."); continue; } // fetch mod info - result.Add(await repository.GetModInfoAsync(modID)); + result[modKey] = await repository.GetModInfoAsync(modID); } - return result.ToArray(); + return result; } diff --git a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs deleted file mode 100644 index 119b18e6..00000000 --- a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.ComponentModel; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.ModelBinding; - -namespace StardewModdingAPI.Web.Framework -{ - /// <summary>Maps comma-delimited values to an <see cref="System.Collections.Generic.IEnumerable{T}"/> parameter.</summary> - /// <remarks>Derived from <a href="https://stackoverflow.com/a/43655986/262123" />.</remarks> - public class CommaDelimitedModelBinder : IModelBinder - { - /********* - ** Public methods - *********/ - /// <summary>Attempts to bind a model.</summary> - /// <param name="bindingContext">The model binding context.</param> - public Task BindModelAsync(ModelBindingContext bindingContext) - { - // validate - if (bindingContext == null) - throw new ArgumentNullException(nameof(bindingContext)); - - // extract values - string modelName = bindingContext.ModelName; - ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); - string[] values = valueProviderResult - .ToString() - .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - Type elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0]; - if (values.Length == 0) - { - bindingContext.Result = ModelBindingResult.Success(Array.CreateInstance(elementType, 0)); - return Task.CompletedTask; - } - - // map values - TypeConverter converter = TypeDescriptor.GetConverter(elementType); - Array typedArray = Array.CreateInstance(elementType, values.Length); - try - { - for (int i = 0; i < values.Length; ++i) - { - string value = values[i]; - object convertedValue = converter.ConvertFromString(value); - typedArray.SetValue(convertedValue, i); - } - } - catch (Exception exception) - { - bindingContext.ModelState.TryAddModelError(modelName, exception, bindingContext.ModelMetadata); - } - - bindingContext.Result = ModelBindingResult.Success(typedArray); - return Task.CompletedTask; - } - } -} diff --git a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs deleted file mode 100644 index 1b3f0073..00000000 --- a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc.ModelBinding; - -namespace StardewModdingAPI.Web.Framework -{ - /// <summary>Provides comma-delimited model binds for mapping parameters.</summary> - /// <remarks>Derived from <a href="https://stackoverflow.com/a/43655986/262123" />.</remarks> - public class CommaDelimitedModelBinderProvider : IModelBinderProvider - { - /********* - ** Public methods - *********/ - /// <summary>Creates a model binder based on the given context.</summary> - /// <param name="context">The model binding context.</param> - public IModelBinder GetBinder(ModelBinderProviderContext context) - { - // validate - if (context == null) - throw new ArgumentNullException(nameof(context)); - - // get model binder - return context.Metadata.IsEnumerableType && !context.Metadata.ElementMetadata.IsComplexType - ? new CommaDelimitedModelBinder() - : null; - } - } -} diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs index 7e3ce4b6..02c2939a 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -44,12 +44,12 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories .As<NexusResponseModel>(); return response != null - ? new ModInfoModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url) - : new ModInfoModel($"{this.VendorKey}:{id}", "Found no mod with this ID."); + ? new ModInfoModel(response.Name, response.Version, response.Url) + : new ModInfoModel("Found no mod with this ID."); } catch (Exception ex) { - return new ModInfoModel($"{this.VendorKey}:{id}", ex.ToString()); + return new ModInfoModel(ex.ToString()); } } diff --git a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs index 723d6c73..180420cd 100644 --- a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs +++ b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs @@ -8,9 +8,6 @@ namespace StardewModdingAPI.Web.Models /********* ** Accessors *********/ - /// <summary>The namespaced mod key.</summary> - public string ModKey { get; } - /// <summary>The mod name.</summary> public string Name { get; } @@ -28,15 +25,13 @@ namespace StardewModdingAPI.Web.Models ** Public methods *********/ /// <summary>Construct a valid instance.</summary> - /// <param name="modKey">The namespaced mod key.</param> /// <param name="name">The mod name.</param> /// <param name="version">The mod's semantic version number.</param> /// <param name="url">The mod's web URL.</param> /// <param name="error">The error message indicating why the mod is invalid (if applicable).</param> [JsonConstructor] - public ModInfoModel(string modKey, string name, string version, string url, string error = null) + public ModInfoModel(string name, string version, string url, string error = null) { - this.ModKey = modKey; this.Name = name; this.Version = version; this.Url = url; @@ -44,11 +39,9 @@ namespace StardewModdingAPI.Web.Models } /// <summary>Construct an valid instance.</summary> - /// <param name="modKey">The namespaced mod key.</param> /// <param name="error">The error message indicating why the mod is invalid.</param> - public ModInfoModel(string modKey, string error) + public ModInfoModel(string error) { - this.ModKey = modKey; this.Error = error; } } diff --git a/src/StardewModdingAPI.Web/Models/ModSearchModel.cs b/src/StardewModdingAPI.Web/Models/ModSearchModel.cs new file mode 100644 index 00000000..b5bd12fb --- /dev/null +++ b/src/StardewModdingAPI.Web/Models/ModSearchModel.cs @@ -0,0 +1,9 @@ +namespace StardewModdingAPI.Web.Models +{ + /// <summary>Metadata for mods to look up.</summary> + public class ModSearchModel + { + /// <summary>The namespaced mod keys to search.</summary> + public string[] ModKeys { get; set; } + } +} diff --git a/src/StardewModdingAPI.Web/Startup.cs b/src/StardewModdingAPI.Web/Startup.cs index 2d9a95f1..abae06ec 100644 --- a/src/StardewModdingAPI.Web/Startup.cs +++ b/src/StardewModdingAPI.Web/Startup.cs @@ -1,12 +1,9 @@ -using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using StardewModdingAPI.Web.Framework; namespace StardewModdingAPI.Web { @@ -40,17 +37,8 @@ namespace StardewModdingAPI.Web public void ConfigureServices(IServiceCollection services) { services - .AddMvc(options => - { - // add support for comma-delimited parameters - ArrayModelBinderProvider arrayModelBinderProvider = options.ModelBinderProviders.OfType<ArrayModelBinderProvider>().First(); - options.ModelBinderProviders.Insert(options.ModelBinderProviders.IndexOf(arrayModelBinderProvider), new CommaDelimitedModelBinderProvider()); - }) - .AddJsonOptions(options => - { - // suppress null values in JSON responses - options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; - }); + .AddMvc() + .AddJsonOptions(options => options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore); // suppress null values in JSON responses } /// <summary>The method called by the runtime to configure the HTTP request pipeline.</summary> |