summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs
blob: 119b18e6d9f49d6928cf9c952106b7786f4a9acc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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;
        }
    }
}