2014-10-01 2 views
0

Я использую пользовательский IModelBinder, чтобы попытаться преобразовать строки в NodaTime LocalDates. Моя LocalDateBinder выглядит следующим образом:Сделать веб-API IModelBinder применимым ко всем экземплярам типа

public class LocalDateBinder : IModelBinder 
{ 
    private readonly LocalDatePattern _localDatePattern = LocalDatePattern.IsoPattern; 

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) 
    { 
     if (bindingContext.ModelType != typeof(LocalDate)) 
      return false; 

     var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (val == null) 
      return false; 

     var rawValue = val.RawValue as string; 

     var result = _localDatePattern.Parse(rawValue); 
     if (result.Success) 
      bindingContext.Model = result.Value; 

     return result.Success; 
    } 
} 

В моем WebApiConfig зарегистрировать этот ModelBinder используя SimpleModelBinderProvider, а-ля

var provider = new SimpleModelBinderProvider(typeof(LocalDate), new LocalDateBinder()); 
config.Services.Insert(typeof(ModelBinderProvider), 0, provider); 

Это прекрасно работает, когда у меня есть действие, которое принимает параметр типа LocalDate, но если У меня более сложное действие, которое использует LocalDate внутри другой модели, оно никогда не запускается. Например:

[HttpGet] 
[Route("validateDates")] 
public async Task<IHttpActionResult> ValidateDates(string userName, [FromUri] LocalDate beginDate, [FromUri] LocalDate endDate) 
{ 
    //works fine 
} 

[HttpPost] 
[Route("")] 
public async Task<IHttpActionResult> Create(CreateRequest createRequest) 
{ 
    //doesn't bind LocalDate properties inside createRequest (other properties are bound correctly) 
    //i.e., createRequest.StartDate isn't bound 
} 

Я полагаю, что это что-то делать с тем, как я регистрируя модель связующего с Web API, но я в растерянности относительно того, что мне нужно исправить - нужно ли мне пользовательский поставщик связующего?

+0

Для тех, кто смотрит на это, я так и не понял. Однако реальная проблема заключалась в том, что мои настройки сериализации JSON стали способом десериализации объектов NodaTime - мне нужно было переопределить обработчики DateTime по умолчанию. –

ответ

1

Ваш CreateRequest является сложным типом, который не имеет преобразователя типа, определенного в качестве связующего. В этом случае Web Api попытается использовать форматтера медиа-типа. Когда вы используете JSON, он попытается использовать форматировщик JSON по умолчанию, который является Newtonsoft Json.Net в стандартной конфигурации. Json.Net не знает, как обрабатывать типы Noda Time из коробки.

Чтобы Json.Net способен обрабатывать типы Нода времени, вы должны установить NodaTime.Serialization.JsonNet и добавить что-то вроде этого в код запуска ...

public void Config(IAppBuilder app) 
{ 
    var config = new HttpConfiguration(); 
    config.Formatters.JsonFormatter.SerializerSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); 
    app.UseWebApi(config); 
} 

После этого, ваш второй пример будет работать, как и ожидалось , и ModelState.IsValid будет false, если вход был не в правильном формате Noda Time.

Дополнительную информацию о привязке параметров в Web API см. В http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api.