Пользовательская привязка модели DateTime в ASP.NET Ядро 1 (RTM)

#c# #asp.net-core-mvc #model-binding #custom-model-binder #asp.net-core-webapi

#c# #asp.net-core-mvc #привязка модели #custom-model-binder #asp.net-core-webapi

Вопрос:

Я пишу и ASP.NET Приложение Core 1, в котором есть контроллер веб-API, где поставщик будет размещать данные.

Это упрощенная версия класса модели, к которой я буду привязывать входящие данные:

 public class Lead
{
    public int SupplierId { get; set; }
    public DateTime Date { get; set; }
}
  

Проблема в том, что даты будут опубликованы, например, с немецким форматированием 30.09.2016 . Я не хочу устанавливать глобальную культуру приложения de-DE , потому что а) я не немец, и б) остальная часть приложения будет работать с датами ISO.

Я решил написать пользовательское IModelBinder и, потому что это, по-видимому, обязательно в ASP.NET Ядро MVC, an IModelBinderProvider .

Вот моя реализация IModelBinderProvider :

 public class GermanDateTimeModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        if (!context.Metadata.IsComplexType amp;amp; 
                context.Metadata.ModelType == typeof(DateTime))
            return new GermanDateTimeBinder();

        return null;
    }
}
  

Проблема в том, что my IModelBinderProvider используется только для Lead класса, т. Е. context.Metadata.ModelType == typeof(Lead) .

Я бы ожидал, что привязка модели увидит, что мы не имеем дело с a DateTime , двигаться дальше, а затем возвращаться для каждого свойства Lead класса.
По-видимому, это не так, и мой обычай IModelBinder никогда не попадает.

Причина, по которой я говорю, что IModelBinderProvider это кажется обязательным, заключается в том, что я не нашел способа прямой регистрации IModelBinder в конвейере MVC; Вместо этого я должен зарегистрировать IModelBinderProvider:

 public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc(options =>
    {
        options.ModelBinderProviders.Insert(0, new GermanDateTimeModelBinderProvider());
    });
}
  

Как я могу получить ASP.NET Ядро MVC для применения моего пользовательского DateTime связующего к Date свойству Lead класса?
Может быть, есть способ пропустить весь IModelBinderProvider бизнес и использовать только an IModelBinder ?

Ответ №1:

Вы публикуете свои значения в формате JSON? Если это так, я бы посоветовал вам зарегистрировать пользовательский JsonConverter с JSON.NET . В конвертере вы будете использовать JsonSerializer с другой DateFormatString, в данном случае с немецким форматом даты. На все остальные JsonSerializer это не влияет.

 public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services
        .AddMvc()
        .AddJsonOptions(option =>
        {
            option.SerializerSettings.Converters.Add(new LeadConverter());
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddDebug();

        app.UseMvcWithDefaultRoute();
    }
}

public class LeadConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new System.NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jsonSerializer = new JsonSerializer
        {
            DateFormatString = "dd.MM.yyyy"
        };

        return jsonSerializer.Deserialize<Lead>(reader);
    }

    public override bool CanConvert(Type objectType) => objectType == typeof(Lead);
}
  

Комментарии:

1. Спасибо за ваш ответ, это действительно очень хороший подход. Однако у нас есть обходной путь с DTO, который имеет string insetad of DateTime , а затем мы используем AutoMapper для анализа дат. Итак, этот вопрос касается не столько того, как я могу обойти проблему, сколько того, как на самом деле реализовать пользовательский ModelBinder в ASp.NET Ядро 1 🙂