asp.net mvc - validaciones - ¿Es la forma correcta de usar ModelState.Remove para tratar con ModelState?
validationsummary que es (5)
Aquí está mi solución: un método de extensión RemoveFor()
en ModelState
, inspirado en los ayudantes HTML de MVC:
public static void RemoveFor<TModel>(this ModelStateDictionary modelState,
Expression<Func<TModel, object>> expression)
{
string expressionText = ExpressionHelper.GetExpressionText(expression);
foreach (var ms in modelState.ToArray())
{
if (ms.Key.StartsWith(expressionText + ".") || ms.Key == expressionText)
{
modelState.Remove(ms);
}
}
}
Así es como se usa:
if (model.CheckoutModel.ShipToBillingAddress == true)
{
// REUSE BILLING ADDRESS FOR SHIPPING ADDRESS
ShoppingCart.ShippingAddress = ShoppingCart.BillingAddress;
// REMOVE MODELSTATE ERRORS FOR SHIPPING ADDRESS
ModelState.RemoveFor<SinglePageStoreModel>(x => model.CheckoutModel.ShippingAddress);
}
Así que, en respuesta a su pregunta, creo que definitivamente hay casos de uso en los que esta es la forma correcta de hacerlo, y un ayudante con este tipo hace que sea mucho más agradable de ver, y más fácil de justificar si le preocupan los lotes de cuerdas mágicas.
Estoy trabajando en una gran aplicación web MVC3 y tengo una molestia con respecto al método ModelState.IsValid
.
ModelState se está utilizando en casi todos mis controladores para validar los datos que se están publicando. Todas las vistas se basan en ViewModels que contienen diferentes clases y estas clases obviamente contienen propiedades que podrían marcarse como [Required]
.
El problema que tengo es que las propiedades requeridas a veces no son necesarias y tengo que usar el método ModelState.Remove
para que ModelState.IsValid
convierta en verdadero.
Mi pregunta es mediante el uso de ModelState.Remove
. ModelState.Remove
, ¿es esta la forma correcta de hacer las cosas o hay un enfoque más eficiente?
Estoy totalmente con el Sr. Steve Morgan
Por lo tanto, si su ViewModel no siempre necesita que se requiera alguna propiedad, entonces no debe decorarla como se requiere.
No sé por qué quiere este problema, pero supongo que, en algunos casos, necesita PropertyOne
para que sea PropertyTwo
si PropertyTwo
tiene valor. En este caso, es posible que necesite hacer su CustomValidationAttribute
para verificar estas dos propiedades.
Estoy usando algo como esto:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class PropertyNeededAttribute : ValidationAttribute
{
private const string defaultErrorMessage = "''{0}'' needs ''{1}'' to be valid.";
public PropertyNeededAttribute(string originalProperty, string neededProperty)
: base(defaultErrorMessage)
{
NeededProperty = neededProperty;
OriginalProperty = originalProperty;
}
public string NeededProperty { get; private set; }
public string OriginalProperty { get; private set; }
public override object TypeId
{
get { return new object(); }
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
OriginalProperty, NeededProperty);
}
public override bool IsValid(object value)
{
object neededValue = Statics.GetPropertyValue(value, NeededProperty);
object originalValue = Statics.GetPropertyValue(value, OriginalProperty);
if (originalValue != null && neededValue == null)
return false;
return true;
}
}
nota: Statics.GetPropertyValue(...)
no hace nada más que obtener el valor de la propiedad para compararlo.
Espero que esto haya ayudado :)
Fundamentalmente, su problema es que si bien sus clases están decoradas con [Requerido], no siempre es cierto. Si está operando en un contexto donde no es cierto, realmente debería usar una clase que no define la propiedad como [Requerida].
Realmente deberías usar un ViewModel que esté correctamente definido para su uso específico y que pueda significar duplicar algunas clases. Un ViewModel está asociado con la implementación de la interfaz de usuario y si bien puede usar clases de su modelo de dominio, no siempre es lo correcto.
En su defecto, las opciones son no usar ModelState.IsValid o continuar usando ModelState.Remove.
Pero lógicamente, tiene sentido que su ViewModel sea ''validable'', no tener que ignorar ciertos errores de validación.
Si está utilizando el mismo modelo de vista con una propiedad [Required]
en dos contextos diferentes, uno donde se requiere la propiedad y otro donde no lo es, entonces deberá modificar manualmente el ModelState
como lo está haciendo.
Una alternativa es utilizar un modelo de vista diferente. Tal vez tenga una clase base con todas las propiedades excepto la propiedad requerida en cuestión. Luego, derive dos modelos de vista, uno con la propiedad donde se requiere y otro con la propiedad donde no está (es la duplicación, lo sé). Puede decidir mantenerlos completamente separados por completo y no usar herencia.
Si su propiedad no siempre es necesaria, no debe decorarla con [Required]
.
Una buena alternativa para hacer su validación es implementar la interfaz IValidatableObject .
Por ejemplo, supongamos que desea que el campo sea un State
requerido solo cuando el país es United States
. Podrías hacerlo de esa manera:
public class AddressModel : IValidatableObject
{
[Required]
public string Country { get; set; }
public string State { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(Country == "United States" && String.IsNullOrEmpty(State))
{
yield return new ValidationResult("State is required for United States", new [] { nameof(State) });
}
}
}
Nota: este tipo de validación solo funciona en el lado del servidor.
¿Otras alternativas?
Como se mencionó en otras respuestas, a veces es una buena idea crear 2 o más modelos si las vistas y validaciones son muy diferentes.