我正在编写asp.net mvc 5 web api。我有以下代码,我想将网络API称为http://localhost/API/Compatibility/59dd2c60-c340-4735-8ecb-85efc60c7b14;d126d9b3-4516-46ca-bd6c-1a8c23740b90
[RoutePrefix("API/Compatibility")]
public class CompatibilityController : ApiController
{
[Route("{organizationIds}")]
public Guid Get(IList<Guid> organizationIds)
{
...
}
}
目前参数organizationIds
无法从URL接收值。我理解这是因为默认模型绑定器不知道如何分离GUID。
定制模型活页夹似乎很有帮助。
我的其他网络API可能使用分号以外的其他分隔符。因此,我是否可以创建SemicolonSeparatedBinder
并传入分隔符,而不是创建CommaSeparatedBinder
,PipeSeparatedBinder
,SymbolSeparatedBinder
等等?
可以这样做吗?
[Route("{organizationIds}")]
public Guid Get([ModelBinder(typeof(SymbolSeparatedBinder), separator=";")]
IList<string> organizationIds)
{
...
}
答案 0 :(得分:1)
ModelBinder
属性需要绑定器的类型。这里最好的解决方案是使用常量字符参数化的泛型类,例如SymbolSeparatedBinder<','>
,SymbolSeparatedBinder<';'>
。但是C#does not support这与C ++不同。
对于此问题,您仍然可以使用简单而优雅的解决方案。使用抽象SymbolSeparatedBinder
属性定义基本Separator
类,该属性应使用特定的分隔符字符覆盖:
public abstract class SymbolSeparatedBinder : IModelBinder
{
protected abstract char Separator { get; }
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
// Put all logic here. Use Separator property for splitting.
// ...
return true;
}
}
public class SemicolonSeparatedBinder : SymbolSeparatedBinder
{
protected override char Separator => ';';
}
public class CommaSeparatedBinder : SymbolSeparatedBinder
{
protected override char Separator => ',';
}
[Route("{organizationIds}")]
public Guid Get([ModelBinder(typeof(CommaSeparatedBinder))]
IList<string> organizationIds)
{
...
}
使用此类解决方案可避免重复绑定代码。唯一的缺点是必须为每个支持的分隔符声明一个类。
答案 1 :(得分:0)
我使用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();
}
}