Есть несколько вещей, о которых нужно знать.
Сегодня я столкнулся с той же проблемой. Как и вы, я не привязываю свое представление напрямую к моей модели, но использую промежуточный класс ViewDataModel, который содержит экземпляр модели и любые параметры / конфигурации, которые я хотел бы отправить в представление.
В итоге я изменил BindProperty
в DataAnnotationsModelBinder, чтобы обойти NullReferenceException
, и мне лично не нравилось связывать свойства только в том случае, если они действительны (см. Причины ниже).
protected override void BindProperty(ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor) {
string fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
// Only bind properties that are part of the request
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) {
var innerContext = new ModelBindingContext() {
Model = propertyDescriptor.GetValue(bindingContext.Model),
ModelName = fullPropertyKey,
ModelState = bindingContext.ModelState,
ModelType = propertyDescriptor.PropertyType,
ValueProvider = bindingContext.ValueProvider
};
IModelBinder binder = Binders.GetBinder(propertyDescriptor.PropertyType);
object newPropertyValue = ConvertValue(propertyDescriptor, binder.BindModel(controllerContext, innerContext));
ModelState modelState = bindingContext.ModelState[fullPropertyKey];
if (modelState == null)
{
var keys = bindingContext.ValueProvider.FindKeysWithPrefix(fullPropertyKey);
if (keys != null && keys.Count() > 0)
modelState = bindingContext.ModelState[keys.First().Key];
}
// Only validate and bind if the property itself has no errors
//if (modelState.Errors.Count == 0) {
SetProperty(controllerContext, bindingContext, propertyDescriptor, newPropertyValue);
if (OnPropertyValidating(controllerContext, bindingContext, propertyDescriptor, newPropertyValue)) {
OnPropertyValidated(controllerContext, bindingContext, propertyDescriptor, newPropertyValue);
}
//}
// There was an error getting the value from the binder, which was probably a format
// exception (meaning, the data wasn't appropriate for the field)
if (modelState.Errors.Count != 0) {
foreach (var error in modelState.Errors.Where(err => err.ErrorMessage == "" && err.Exception != null).ToList()) {
for (var exception = error.Exception; exception != null; exception = exception.InnerException) {
if (exception is FormatException) {
string displayName = GetDisplayName(propertyDescriptor);
string errorMessage = InvalidValueFormatter(propertyDescriptor, modelState.Value.AttemptedValue, displayName);
modelState.Errors.Remove(error);
modelState.Errors.Add(errorMessage);
break;
}
}
}
}
}
}
Я также изменил это так, чтобы it всегда связывает данные в свойстве независимо от того, действительны они или нет. Он не был должным образом протестирован, хотя он прошел модульные тесты в проекте , который начал Брайан Уилсон, и большую часть моего собственного ограниченного тестирования. Чтобы полностью завершить этот вопрос, я хотел бы услышать Брэда Уилсона мысли об этом решении.
Как заметил Мартин, исправить эту проблему просто.
В методе BindProperty вы найдете эту строку кода:
if (modelState.Errors.Count == 0) {
Ее следует изменить на:
if (modelState == null || modelState.Errors.Count == 0) {
] Мы планируем включить поддержку DataAnnotations в MVC 2, который будет включать DataAnnotationsModelBinder. Эта функция будет частью первой CTP.