Web API - Как получить в контроллере DateTime ('dd/MM/yyyy') в качестве параметра Url?

Каждый раз, когда мой контроллер получает дату в виде дд / мм / гггг, он декодируется как MM / дд / гггг. Можно ли сказать контроллеру, как декодировать параметр URL?

Мой метод в контроллере:

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

Мой JavaScript:

var $startDate = $('#startDate').val();
var $endDate = $('#endDate').val();

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

Я знаю, что могу получить дату в контроллере в виде строки и затем проанализировать ее или изменить ее в своем javascript на ISO8601, прежде чем вставлять URL-адрес, но я хочу знать, могу ли я сообщить своему контроллеру, как декодировать полученный параметр.

РЕДАКТИРОВАТЬ: Я использовал контроллер MVC, и это не было проблемой, он начал неправильно декодировать после того, как я перешел на ApiController, поэтому код работал, и я надеюсь сохранить как есть.

1 ответ

Решение

Мне удается решить мою проблему с помощью привязки модели, как это предложили @Jakotheshadows и @Amy.

Я использовал код из этого ответа о ModelBinders в Web Api с несколькими изменениями из этого ответа (он на португальском, но код понятен).

Итак, мой код прямо сейчас:

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

я использовал try а также DateTime.Parse как предлагается во второй ссылке, потому что первая всегда выдает исключение, даже с try и catch.

ModelBinderProvider я использовал, как он предложил:

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

И я настраиваю как предложено здесь (также ответ для первой ссылки), но в моем WebApiConfig.cs (не работал в Global.asax), как это:

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

я думаю globalization из Web.config, uiCulture а также culture должен быть установлен на культуру, которую вы хотите, и enableClientBasedCulture быть установленным как true как здесь предлагается, но я не уверен, потому что я не хотел менять код, чтобы проверить его.

Другие вопросы по тегам