Có một cách để làm điều đó mà không cần mã boilerplate ở phía trên cùng của mỗi hành động điều khiển.
Bạn sẽ cần phải thay thế mô hình mặc định chất kết dính với một trong những của riêng bạn:
protected void Application_Start()
{
// ...
ModelBinderProviders.BinderProviders.Clear();
ModelBinderProviders.BinderProviders.Add(new CustomModelBinderProvider());
// ...
}
cung cấp mô hình chất kết dính của bạn trông như thế này:
public class CustomModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(Type modelType)
{
return new CustomModelBinder();
}
}
Bây giờ tạo ra một mô hình chất kết dính tùy chỉnh mà thực sự buộc xác nhận. Đây là nơi nâng hạng nặng được thực hiện:
public class CustomModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
ForceModelValidation(bindingContext);
}
private static void ForceModelValidation(ModelBindingContext bindingContext)
{
var model = bindingContext.Model as IValidatableObject;
if (model == null) return;
var modelState = bindingContext.ModelState;
var errors = model.Validate(new ValidationContext(model, null, null));
foreach (var error in errors)
{
foreach (var memberName in error.MemberNames)
{
// Only add errors that haven't already been added.
// (This can happen if the model's Validate(...) method is called more than once, which will happen when
// there are no property-level validation failures.)
var memberNameClone = memberName;
var idx = modelState.Keys.IndexOf(k => k == memberNameClone);
if (idx < 0) continue;
if (modelState.Values.ToArray()[idx].Errors.Any()) continue;
modelState.AddModelError(memberName, error.ErrorMessage);
}
}
}
}
Bạn cũng sẽ cần một phương pháp mở rộng IndexOf. Đây là triển khai giá rẻ nhưng sẽ hoạt động:
public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
if (source == null) throw new ArgumentNullException("source");
if (predicate == null) throw new ArgumentNullException("predicate");
var i = 0;
foreach (var item in source)
{
if (predicate(item)) return i;
i++;
}
return -1;
}
Thành thật mà nói, tôi bắt đầu thích hành vi mặc định này. Nếu bạn thực hiện xác thực cấp doanh nghiệp trong phương thức Xác thực của bạn có liên quan đến các công cụ đắt tiền như kết nối cơ sở dữ liệu, thì tốt hơn là KHÔNG gọi cho chúng trừ khi mô hình hợp lệ. – Graham