枚举被 ASP.NET 模型绑定器正确反序列化。尝试定义一些简单的枚举,例如
public enum Color
{
None,
Green,
Red,
}
[Route("getSomething")]
[HttpGet]
public string Get(Color color)
{
// ...
}
如果您 GET /api/values/color=Green,颜色将正确设置为 Color.Green。如果您需要一些自定义值转换(如 #FF0000 到 Color.Red),使用自定义类型转换器(见下文)的方法将适合您。
ASP.NET 还提供了从 url 反序列化更复杂数据类型的可能性。最简单的方法是实现自定义类型转换器。这是我前段时间开发的应用程序的示例。它适用于具有<department>:<order number> 格式的唯一标识符的订单,即NY:123 或LA:456。型号是
public class OrderId
{
public string DepartmentId { get; }
public int OrderNumber { get; }
public OrderId(string departmentId, int orderNumber)
{
DepartmentId = departmentId;
OrderNumber = orderNumber;
}
}
并且需要通过 HTTP GET 方法传递此类订单 ID:
[HttpGet]
public OrderDetails GetOrderDetails(OrderId orderId)
为了解决这个问题并让 orderId 从 Url 参数正确创建,我们可以实现自定义类型转换器,将字符串值转换为 OrderId 的实例:
public class OrderIdTypeConverter : TypeConverter
{
private static readonly Regex OrderIdRegex = new Regex("^(.+):(\\d+)$", RegexOptions.Compiled);
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var str = value as string;
if (str != null)
{
int orderId;
var match = OrderIdRegex.Match(str);
if (match.Success && Int32.TryParse(match.Groups[2].Value, out orderId))
{
return new OrderId(match.Groups[1].Value, orderId);
}
}
return base.ConvertFrom(context, culture, value);
}
}
要将此类型转换器与 OrderId 类相关联,只需添加 TypeConverter 属性:
[TypeConverter(typeof(OrderIdTypeConverter))]
public class OrderId
现在,如果我们获得 Url /api/Orders/?orderId=NYC:123,则将使用正确填充的 OrderId 实例调用操作 GetOrderDetails。
ASP.NET 为从 URL 绑定模型提供了另一个扩展点。它们是IModelBinder 和IValueProvider 接口的自定义实现。查看此article 了解更多详情。
如果您无法为您无法控制的类型设置类型转换器,则使用自定义模型绑定器的方法应该适合您。以下是用于自定义枚举值转换的IModelBinder 实现示例:
public class CustomEnumModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(Color))
{
return false;
}
ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (val == null)
{
return false;
}
string rawValue = val.RawValue as string;
if (rawValue == null)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Incorrect input value type");
return false;
}
// Your logic for converting string to enum.
if (rawValue == "FF0000")
{
bindingContext.Model = Color.Red;
return true;
}
bindingContext.ModelState.AddModelError(bindingContext.ModelName, $"Cannot convert {rawValue} to Color");
return false;
}
}
[Route("getSomething")]
[HttpGet]
public string Get([ModelBinder(typeof(CustomEnumModelBinder))] Color color)
{
// ...
}
通过一些额外的工作,您可以实现某种可以聚合现有 Json 转换器的通用模型绑定器。