JsonConverter等效于HTTP GET参数

在为HTTP POST函数编写C#Web API控制器时,我可以在参数对象的属性上使用Newtonsoft JSON的属性。 特别是,我可以在enum类型的属性上使用JsonConverter属性 ,将从客户端接收的字符串表示forms转换为其中一个enum值(对于响应对象,则返回):

 public class MyArgumentsDTO { [JsonConverter(typeof(SomeEnumConverter))] public SomeEnum MyValue { get; set; } } // in the controller: [Route("doSomething")] [HttpPost] public Boolean DoSomething(MyArgumentsDTO options); 

但是,对于期望这种enum类型的参数的HTTP GET方法,我该怎么办?

 [Route("getSomething")] [HttpGet] public Boolean GetSomething(SomeEnum myValue); 

是否有一个属性,我可以用相应的参数来装饰,以指示(字符串到枚举)转换器?

(要清楚,我使用枚举作为一个例子,因为我经常使用这种技术(使用HTTP POST)和枚举。假设任何适用于枚举的解决方案都适用于任何其他(可能是复杂的)数据类型。)


当然,我可以将参数声明为string并在方法体中自行进行转换。 然而,这似乎是不洁净的,我同意相关答案中的陈述:

将所有枚举参数定义为字符串,然后在任何地方解析它们意味着您必须在每个操作上执行此操作,并且您需要提出一致的方法,以便所有解析错误都符合。

不幸的是,我不理解该答案中提出的解决方案,因为它甚至没有涉及使用该TypeEnum提到的TypeEnum


当我需要一个enum参数时,使用HTTP POST代替HTTP GET方法似乎也有些错误。 我认为不应该根据这些内部技术来选择HTTP方法。

ASP.NET模型绑定器正确地对枚举进行反序列化。 尝试定义一些简单的枚举,例如

 public enum Color { None, Green, Red, } [Route("getSomething")] [HttpGet] public string Get(Color color) { // ... } 

如果您GET /api/values/color=Green ,则颜色将正确设置为Color.Green 。 如果您需要一些自定义值转换(如#FF0000Color.Red ),使用自定义类型转换器(见下文)的方法将适合您。

ASP.NET还提供了从URL中反序列化更复杂数据类型的可能性。 最简单的方法是实现自定义类型转换器。 这是我前一段时间开发的应用程序的示例。 它使用具有:格式的唯一标识符的订单,即NY:123LA: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) 

为了解决这个问题并使用Url参数正确创建orderId ,我们可以实现将字符串值转换为OrderId实例的自定义Type Converter:

 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); } } 

要将此Type Converter与OrderId类关联,只需添加TypeConverter属性:

 [TypeConverter(typeof(OrderIdTypeConverter))] public class OrderId 

现在,如果我们获得Url /api/Orders/?orderId=NYC:123 ,将使用正确填充的OrderId实例调用操作GetOrderDetails

ASP.NET提供了另一个可扩展点,用于从URL绑定模型。 它们是IModelBinderIValueProvider接口的自定义实现。 查看此文章了解更多详细信息。

如果您无法为您不控制的类型设置类型转换器,则使用自定义模型绑定器的方法应该适合您。 以下是用于自定义枚举值转换的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转换器。