Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API ModelBinding From URI

So I have a custom Model Binder implemented for DateTime type and I register it like below:

void Application_Start(object sender, EventArgs e)
{
    // Code that runs on application startup
    GlobalConfiguration.Configuration.BindParameter(typeof(DateTime), new CurrentCultureDateTimeAPI());
}

and then I have setup 2 sample actions to see if my custom model binding takes place:

    [HttpGet]
    public void BindDateTime([FromUri]DateTime datetime)
    {
        //http://localhost:26171/web/api/BindDateTime?datetime=09/12/2014
    }


    [HttpGet]
    public void BindModel([FromUri]User user)
    {
        //http://localhost:26171/web/api/BindModel?Name=ibrahim&JoinDate=09/12/2014
    }

When I run and invoke both actions from mentioned URLs, user's JoinDate property successfully gets bound using the custom binder I configured but BindDateTime's datetime parameter does not get bound using the custom binder.

I have already specified in config that all DateTime should use my custom binder then why the indifference? Suggestions are highly appreciated.

CurrentCultureDateTimeAPI.cs:

public class CurrentCultureDateTimeAPI: IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var date = value.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);
        bindingContext.Model = date;
        return true;
    }
}

NOTE: If I use [FromUri(Binder=typeof(CurrentCultureDateTimeAPI))]DateTime datetime then it works as expected but then again why?

like image 928
lbrahim Avatar asked Jul 19 '14 20:07

lbrahim


People also ask

How do you force a Web API to read a complex type from the URI?

To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. The following example defines a GeoPoint type, along with a controller method that gets the GeoPoint from the URI.

How do I pass body parameters in Web API?

Use [FromUri] attribute to force Web API to get the value of complex type from the query string and [FromBody] attribute to get the value of primitive type from the request body, opposite to the default rules.


1 Answers

Pretty surprising too :)

My initial doubt was this line:

 GlobalConfiguration.Configuration.BindParameter(typeof(DateTime), new CurrentCultureDateTimeAPI());

MSDN says GlobalConfiguration => GlobalConfiguration provides a global System.Web.HTTP.HttpConfiguration for ASP.NET application.

But for weird reasons this does not seem to work with this particular scenario.

So,

Just add this line inside the static class WebApiConfig

 config.BindParameter(typeof(DateTime), new CurrentCultureDateTimeAPI());

so that your WebAPIConfig file looks like:

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "web/{controller}/{action}/{datetime}",
                defaults: new { controller = "API", datetime = RouteParameter.Optional }
            );

            config.BindParameter(typeof(DateTime), new CurrentCultureDateTimeAPI());
        }

And everything works fine because this method is directly invoked by WebAPI framework so for sure your CurrentCultureDateTimeAPI gets registered.

Checked this with your solution and works great.

Note: (From the comments) You can still support Attribute Routing and you need not comment out this line config.MapHttpAttributeRoutes().

But still, It would be great if somebody can tell why GlobalConfiguration does not work out

like image 60
now he who must not be named. Avatar answered Sep 30 '22 07:09

now he who must not be named.