2016-09-01 6 views
0

У меня есть число контроллеров этой формы:сердечника ASPnet Параметр контроллера даты и времени обходит modelvalid проверить

public IActionResult GetSomething(int id, DateTime from) { 
    ... 
} 

В id и from параметры даны на запрос в качестве параметров запроса. Если id не поставляется, состояние ModelValid установлено в значение false. Но если from не поставляется, ModelValid имеет значение true и из него установлено значение 1900-01-01 00:00:00 (DateTime.Min).

Как сделать ModelState ложным, если требуемый параметр DateTime не указан?

ответ

0

Я решил пойти на внедрение связующего для модели DateTime. Следующий код не будет устанавливать IsValid = true в ModelState, если отсутствует аргумент DateTime. DateTime? (с нулевым значением DateTime) обрабатывается отлично, но опять же, если параметр запроса отсутствует, IsValid устанавливается в значение false вместо установки значения параметра по умолчанию.

Сначала DateTimeModelBinderProvider:

public class DateTimeModelBinderProvider : IModelBinderProvider 
{ 
    /// <inheritdoc /> 
    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
     if (context == null) 
     { 
      throw new ArgumentNullException(nameof(context)); 
     } 

     if (!context.Metadata.IsComplexType) 
     { 
      // We can handle DateTime and nullable DateTime 
      if ((context.Metadata.ModelType == typeof(DateTime)) || 
       (context.Metadata.IsNullableValueType && context.Metadata.UnderlyingOrModelType == typeof(DateTime))) 
       return new DateTimeModelBinder(context.Metadata.ModelType); 
     } 

     return null; 
    } 
} 

Далее DateTimeModelBinder. Большая часть кода скопирована дословно из github. Некоторые из них могут быть опущены, но он работает как есть:

public class DateTimeModelBinder : IModelBinder 
{ 
    private readonly TypeConverter _typeConverter; 

    public DateTimeModelBinder(Type type) 
    { 
     if (type == null) 
     { 
      throw new ArgumentNullException(nameof(type)); 
     } 

     _typeConverter = TypeDescriptor.GetConverter(type); 
    } 

    /// <inheritdoc /> 
    public Task BindModelAsync(ModelBindingContext bindingContext) 
    { 
     if (bindingContext == null) 
     { 
      throw new ArgumentNullException(nameof(bindingContext)); 
     } 

     var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (valueProviderResult == ValueProviderResult.None) 
     { 
      // Do not accept an empty value provider result as being ok for DateTime (is ok for DateTime?) 
      bindingContext.ModelState.TryAddModelError(
        bindingContext.ModelName, 
        bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
         valueProviderResult.ToString())); 

      // no entry 
      return Task.CompletedTask; 
     } 

     bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); 

     try 
     { 
      var value = valueProviderResult.FirstValue; 

      object model = null; 
      if (!string.IsNullOrWhiteSpace(value)) 
      { 
       model = new DateTimeConverter().ConvertFrom(
        context: null, 
        culture: valueProviderResult.Culture, 
        value: value); 
      } 

      if (bindingContext.ModelType == typeof(string)) 
      { 
       var modelAsString = model as string; 
       if (bindingContext.ModelMetadata.ConvertEmptyStringToNull && 
        string.IsNullOrEmpty(modelAsString)) 
       { 
        model = null; 
       } 
      } 

      // When converting newModel a null value may indicate a failed conversion for an otherwise required 
      // model (can't set a ValueType to null). This detects if a null model value is acceptable given the 
      // current bindingContext. If not, an error is logged. 
      if (model == null && !bindingContext.ModelMetadata.IsReferenceOrNullableType) 
      { 
       bindingContext.ModelState.TryAddModelError(
        bindingContext.ModelName, 
        bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
         valueProviderResult.ToString())); 

       return Task.CompletedTask; 
      } 
      else 
      { 
       bindingContext.Result = ModelBindingResult.Success(model); 
       return Task.CompletedTask; 
      } 
     } 
     catch (Exception exception) 
     { 
      var isFormatException = exception is FormatException; 
      if (!isFormatException && exception.InnerException != null) 
      { 
       // TypeConverter throws System.Exception wrapping the FormatException, 
       // so we capture the inner exception. 
       exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException; 
      } 

      bindingContext.ModelState.TryAddModelError(
       bindingContext.ModelName, 
       exception, 
       bindingContext.ModelMetadata); 

      // Were able to find a converter for the type but conversion failed. 
      return Task.CompletedTask; 
     } 
    } 
} 

Также не забудьте активировать его. Я вставляю его в начале списка поставщиков, чтобы обеспечить, чтобы мой поставщик DateTime использовался вместо предпочтительного обработчика по умолчанию:

 var mvc = services.AddMvc(config => { 
      config.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider()); 
     }); 
0

Вы можете решить эту проблему, создав модель, которая имеет атрибут проверки для свойства «От». Я не проверил код. Но код должен быть похож:

public class Model 
{ 
    public int Id { get; set; } 
    [DateTimeShouldHaveValue] 
    public DateTime From { get; set; } 
} 

public class DateTimeShouldHaveValueAttribute : ValidationAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     if (value == null) 
      return false; 

     var dateTimeTmp = value.ToString(); 
     DateTime dateTime; 
     DateTime.TryParse(dateTimeTmp, out dateTime); 
     if (dateTime == DateTime.MinValue) 
      return false; 

     return true; 
    } 
} 

public IActionResult GetSomething(Model model) 
{ 

} 

 Смежные вопросы

  • Нет связанных вопросов^_^