我想出了另一种方法
ParameterBindingAttribute
和
HttpParameterBinding
。
/// <summary>
/// Applies to an Array type, specifies the string that is used to split elements.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class ArraySeparatorAttribute : ParameterBindingAttribute
{
string _separator;
public ArraySeparatorAttribute(string separator)
{
_separator = separator;
}
public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
{
if (typeof(System.Collections.IEnumerable).IsAssignableFrom(parameter.ParameterType))
return new ArraySeparatorParameterBinding(parameter, _separator);
throw new NotSupportedException($"{nameof(ArraySeparatorAttribute)} can only be applied to array.");
}
}
internal class ArraySeparatorParameterBinding : HttpParameterBinding
{
string _separator;
public ArraySeparatorParameterBinding(HttpParameterDescriptor parameter, string separator) : base(parameter)
{
_separator = separator;
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
string separatorListString = (string)actionContext.RequestContext.RouteData.Values[Descriptor.ParameterName];
var elements = separatorListString.Split(new string[] { _separator }, StringSplitOptions.RemoveEmptyEntries);
ValueProviderResult r = new ValueProviderResult(elements, null, System.Globalization.CultureInfo.InvariantCulture);
actionContext.ActionArguments[Descriptor.ParameterName] = r.ConvertTo(Descriptor.ParameterType);
var tsc = new TaskCompletionSource<object>();
tsc.SetResult(null);
return tsc.Task;
}
}
用法如下
[RoutePrefix("API/Compatibility")]
public class CompatibilityController : ApiController
{
[Route("{organizationIds}")]
public Guid Get([ArraySeparator(";")] Guid[] organizationIds)
{
return Guid.NewGuid();
}
}