summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI.Web
diff options
context:
space:
mode:
Diffstat (limited to 'src/StardewModdingAPI.Web')
-rw-r--r--src/StardewModdingAPI.Web/Controllers/ModsController.cs8
-rw-r--r--src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs58
-rw-r--r--src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs27
-rw-r--r--src/StardewModdingAPI.Web/Models/ModSearchModel.cs9
-rw-r--r--src/StardewModdingAPI.Web/Startup.cs13
5 files changed, 100 insertions, 15 deletions
diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs
index c7b2aba7..d3b49445 100644
--- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs
+++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs
@@ -29,13 +29,13 @@ namespace StardewModdingAPI.Web.Controllers
** Public methods
*********/
/// <summary>Fetch version metadata for the given mods.</summary>
- /// <param name="search">The mod update search criteria.</param>
- [HttpPost]
- public async Task<ModInfoModel[]> Post([FromBody] ModSearchModel search)
+ /// <param name="modKeys">The namespaced mod keys to search.</param>
+ [HttpGet]
+ public async Task<ModInfoModel[]> Post(IEnumerable<string> modKeys)
{
IList<ModInfoModel> result = new List<ModInfoModel>();
- foreach (string modKey in search.ModKeys)
+ foreach (string modKey in modKeys)
{
// parse mod key
if (!this.TryParseModKey(modKey, out string vendorKey, out string modID))
diff --git a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs
new file mode 100644
index 00000000..119b18e6
--- /dev/null
+++ b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs
@@ -0,0 +1,58 @@
+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
new file mode 100644
index 00000000..1b3f0073
--- /dev/null
+++ b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs
@@ -0,0 +1,27 @@
+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/Models/ModSearchModel.cs b/src/StardewModdingAPI.Web/Models/ModSearchModel.cs
deleted file mode 100644
index 852ea439..00000000
--- a/src/StardewModdingAPI.Web/Models/ModSearchModel.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace StardewModdingAPI.Web.Models
-{
- /// <summary>The mod update search criteria.</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 c7a5e8fe..c1f03b34 100644
--- a/src/StardewModdingAPI.Web/Startup.cs
+++ b/src/StardewModdingAPI.Web/Startup.cs
@@ -1,8 +1,11 @@
-using Microsoft.AspNetCore.Builder;
+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 StardewModdingAPI.Web.Framework;
namespace StardewModdingAPI.Web
{
@@ -35,7 +38,13 @@ namespace StardewModdingAPI.Web
/// <param name="services">The service injection container.</param>
public void ConfigureServices(IServiceCollection services)
{
- services.AddMvc();
+ 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());
+ });
}
/// <summary>The method called by the runtime to configure the HTTP request pipeline.</summary>