3

Everytime my controller receives a date as dd/MM/yyyy it decode as MM/dd/yyyy. Is it possible to tell the controller how to decode the parameter of the url?

My method in controller:

[HttpGet]
public JsonResult<IList<Callers>> GetListOfCallers(DateTime startDate, DateTime endDate)
 {
 // myCode....
 }

My javascript:

var $startDate = $('#startDate').val();
var $endDate = $('#endDate').val();
$.get(rootUrl + "api/report/GetListOfCallers?startDate=" + $startDate + "&endDate=" + $endDate, function (data) {
 // myCode....
 });

I know I can receive the date in controller as string and then parse it, or change it in my javascript to ISO8601 before putting in the url, but I want to know if I can tell my controller how to decode the parameter received.

EDIT: I was using MVC controller and this was not a problem, it started decoding incorrectly after I changed to ApiController, so the code was working and I hope to keep as it is.

asked Sep 6, 2017 at 19:54
12
  • I believe you need to convert it from string to date, and in the process of decoding the string to a date, you can customize that however you want. Commented Sep 6, 2017 at 20:01
  • 1
    Model binding is your friend, here is what my googling on the subject related to your question revealed: vickram.me/custom-datetime-model-binding-in-asp-net-web-api Commented Sep 6, 2017 at 20:05
  • I agree, custom model binding is the way to go here. Commented Sep 6, 2017 at 20:08
  • @Jakotheshadows Model binding works for url as well? I thought it was only for post methods. Commented Sep 6, 2017 at 20:14
  • 1
    @Robert I don't think it changes, but it's a solution I don't want to use. I want a solution to implement in all projects so others programmers don't have to worry about conversions. Commented Sep 8, 2017 at 16:14

1 Answer 1

3

I manage to solve my problem using Model binding as suggested by @Jakotheshadows and @Amy.

I used the code from this answer about ModelBinders in Web Api with a few tweaks from this answer (it's in portuguese, but the code is clear).

So my code right now:

using System;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
namespace Site.Services
{
 public class DateTimeModelBinder : IModelBinder
 {
 public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
 {
 ValidateBindingContext(bindingContext);
 if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName) ||
 !CanBindType(bindingContext.ModelType))
 {
 return false;
 }
 var modelName = bindingContext.ModelName;
 var attemptedValue = bindingContext.ValueProvider
 .GetValue(modelName).AttemptedValue;
 try
 {
 bindingContext.Model = DateTime.Parse(attemptedValue);
 }
 catch (FormatException e)
 {
 bindingContext.ModelState.AddModelError(modelName, e);
 }
 return true;
 }
 private static void ValidateBindingContext(ModelBindingContext bindingContext)
 {
 if (bindingContext == null)
 {
 throw new ArgumentNullException("bindingContext");
 }
 if (bindingContext.ModelMetadata == null)
 {
 throw new ArgumentException("ModelMetadata cannot be null", "bindingContext");
 }
 }
 public static bool CanBindType(Type modelType)
 {
 return modelType == typeof(DateTime) || modelType == typeof(DateTime?);
 }
 }
}

I used try and DateTime.Parse as suggested in the second link, because the first always throwed an exception even with try and catch.

The ModelBinderProvider I used as he suggested:

using System;
using System.Web.Http;
using System.Web.Http.ModelBinding;
namespace Site.Services
{
 public class DateTimeModelBinderProvider : ModelBinderProvider
 {
 readonly DateTimeModelBinder binder = new DateTimeModelBinder();
 public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
 {
 if (DateTimeModelBinder.CanBindType(modelType))
 {
 return binder;
 }
 return null;
 }
 }
}

And I configure as suggested here (also an answer for the first link), but in my WebApiConfig.cs (didn't work in Global.asax), like this:

using Site.Services;
using System;
using System.Web.Http;
namespace Site
{
 public static class WebApiConfig
 {
 public static void Register(HttpConfiguration config)
 {
 config.BindParameter(typeof(DateTime), new DateTimeModelBinder());
 config.BindParameter(typeof(DateTime?), new DateTimeModelBinder());
 //Rest of my code
 config.MapHttpAttributeRoutes();
 config.Routes.MapHttpRoute(
 name: "DefaultApi",
 routeTemplate: "api/{controller}/{action}/{id}",
 defaults: new { id = RouteParameter.Optional }
 );
 }
 }
}

I think the globalization of the Web.config, the uiCulture and culture must be set to the culture you want and enableClientBasedCulture be set as true as suggest here, but I'm not sure because I didn't want to change the code to test it.

answered Sep 8, 2017 at 19:06

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.