Most of my api routes are segmented like so:
/api/{segment}/MyEntity
(i.e. "/api/SegmentA/MyEntity")
Where I've defined a ModelBinder that converts from the string to a Segment
object like so:
class SegmentModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (value == null || String.IsNullOrEmpty(value.AttemptedValue))
return false;
bindingContext.Model = **logic to find segment object from value.AttemptedValue**;
return true;
}
}
Configured as:
GlobalConfiguration.Configuration.BindParameter(typeof(Segment), new SegmentModelBinder());
So my routes end up looking like this:
public class MyEntityController : BaseController
{
[HttpGet, Route("api/{segment}/MyEntity")]
public IEnumerable<MyEntity> Get(Segment segment)
{
...
}
}
The problem is, I'm now attempting to generate documentation for these Api calls, and ApiExplorer
is completely confused by these routes and ignores them.
How do I tell it that for these routes, when it sees a parameter of type Segment
, it's really just a string from the route?
Switching from using a ModelBinder
to TypeConverter
resolved the problem:
[TypeConverter(typeof(MyEntityConverter))]
public class MyEntity
{....
-
public class MyEntityConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
var key = value as string;
if (!String.IsNullOrEmpty(key))
return **Find Entity**;
return base.ConvertFrom(context, culture, value);
}
}
Edit:
If you ever return this entity in call, you need this in there as well, otherwise the newtonsoft json serializer will serialize the class to the type name:
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return false;
}