summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/StardewModdingAPI.Web/Controllers/ModsController.cs22
-rw-r--r--src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs58
-rw-r--r--src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs27
-rw-r--r--src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs6
-rw-r--r--src/StardewModdingAPI.Web/Models/ModInfoModel.cs11
-rw-r--r--src/StardewModdingAPI.Web/Models/ModSearchModel.cs9
-rw-r--r--src/StardewModdingAPI.Web/Startup.cs16
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>