Emulators are correctly deserialized using ASP.NET model middleware. Try defining some simple listings, for example.
public enum Color { None, Green, Red, } [Route("getSomething")] [HttpGet] public string Get(Color color) {
If you get /api/values/color=Green , the color will be set correctly to Color.Green . If you need to convert custom values โโ(for example, from #FF0000 to Color.Red ) with a custom type converter (see below), you will work.
ASP.NET also provides the ability to deserialize more complex data types from a URL. The easiest way is to implement a custom type converter. Here is an example from an application that I developed some time ago. He worked with orders with unique identifiers in the format <department>:<order number> , i.e. NY:123 or LA:456 . Model
public class OrderId { public string DepartmentId { get; } public int OrderNumber { get; } public OrderId(string departmentId, int orderNumber) { DepartmentId = departmentId; OrderNumber = orderNumber; } }
And it was necessary to go through the following order identifiers using the HTTP GET method:
[HttpGet] public OrderDetails GetOrderDetails(OrderId orderId)
To solve this problem and make orderId correctly created from the Url parameter, we could implement a custom Type Converter that converts a string value into an orderId instance:
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); } }
To associate this type converter with the OrderId class, simply add the TypeConverter attribute:
[TypeConverter(typeof(OrderIdTypeConverter))] public class OrderId
Now, if we get Url /api/Orders/?orderId=NYC:123 , the GetOrderDetails action is called with a properly filled instance of orderId .
ASP.NET provides other extensibility points for binding a model to a URL. These are custom implementations of the IModelBinder and IValueProvider . See the article for more details.
If you cannot install a type converter for a type that you do not control, go for a custom template that should work for you. The following is an example implementation of IModelBinder to configure the conversion of enumeration values:
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; }
With a little extra work, you could implement a kind of universal binder that could aggregate existing Json converters.