asp.net-mvc 使用 ModelState.Remove 处理 ModelState 是否正确?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6843171/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it correct way to use ModelState.Remove to deal with ModelState?
提问by Hesky
Im working on a big MVC3 web application and have an annoyance regarding the ModelState.IsValidmethod.
我正在开发一个大型 MVC3 Web 应用程序,并且对该ModelState.IsValid方法感到烦恼。
ModelState is being used in nearly all of my controllers so to validate the data being posted.
The views are all based on ViewModels which contain different classes and these classes obviously contain properties which could be marked as [Required].
我几乎所有的控制器都使用 ModelState 来验证发布的数据。这些视图都基于包含不同类的 ViewModel,而这些类显然包含可以标记为[Required].
The problem i am having is the required properties are sometimes not required and im having to use the ModelState.Removemethod so that ModelState.IsValidbecomes true.
我遇到的问题是有时不需要所需的属性,我必须使用该ModelState.Remove方法才能ModelState.IsValid实现。
My question is by using ModelState.Remove, is this the correct way of doing things or is there a more efficient approach.
我的问题是通过使用ModelState.Remove,这是正确的做事方式还是有更有效的方法。
采纳答案by Russ Cam
If you're using the same view model with a [Required]property in two different contexts, one where the property is required and one where it isn't, then you'll need to manually alter the ModelStateas you're doing.
如果您[Required]在两种不同的上下文中使用具有属性的相同视图模型,一种是需要该属性的,另一种是不需要该属性的,那么您需要在执行时手动更改该属性ModelState。
An alternative is to use a different view model. Perhaps have a base class with all properties except the required property in question. Then derive two view models from it, one with the property where is it required and one with the property where it is not (it's duplication, I know). You may decide to keep them entirely separate altogether and not use inheritance.
另一种方法是使用不同的视图模型。也许有一个包含所有属性的基类,除了所讨论的必需属性。然后从中派生出两个视图模型,一个具有需要的属性,另一个具有不需要的属性(我知道这是重复的)。您可以决定将它们完全分开而不使用继承。
回答by Simon_Weaver
Here's my solution - a RemoveFor()extension method on ModelState, modelled after MVC HTML helpers:
这是我的解决方案 - 上的RemoveFor()扩展方法ModelState,模仿 MVC HTML 助手:
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);
}
}
}
Here's how it's used :
这是它的使用方法:
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);
}
So in answer to your question I believe there are definitely use-cases where this is the right way to do it, and a strongly typed helper like this makes it much nicer to look at - and easier to justify if you're concerned about lots of magic strings.
因此,在回答您的问题时,我相信肯定有用例是正确的方法,并且像这样的强类型帮助程序使它看起来更好看 - 如果您担心很多,则更容易证明其合理性的魔法字符串。
回答by Steve Morgan
Fundamentally, your issue is that while your classes are decorated with [Required], it's not always true. If you're operating in a context where it isn't true, you should really be using a class that doesn't define the property as being [Required].
从根本上说,您的问题是,虽然您的课程用 [Required] 装饰,但并不总是如此。如果您在不正确的上下文中操作,则您确实应该使用未将属性定义为 [Required] 的类。
You should really use a ViewModel that is correctly defined for its specific usage and that may mean duplicating some classes. A ViewModel is associated with the implementation of the UI and while it may use classes from your domain model, it's not always the right thing to do.
您确实应该使用针对其特定用途正确定义的 ViewModel,这可能意味着复制某些类。ViewModel 与 UI 的实现相关联,虽然它可能使用域模型中的类,但它并不总是正确的做法。
Failing that, the options are to either not use ModelState.IsValid, or to continue to use ModelState.Remove.
如果做不到这一点,选项是要么不使用ModelState.IsValid,或继续使用ModelState.Remove。
But logically, it makes sense for your ViewModel to be 'validatable', not to have to ignore certain validation errors.
但是,从逻辑上讲,这是有道理的你的ViewModel是“可验证的”,不要有忽略某些验证错误。
回答by Wahid Bitar
I'm totally with Mr.Steve Morgan
我完全支持史蒂夫摩根先生
So if your ViewModel doesn't always need some property to be Requiredthen you shouldn't decorate it as Required.
因此,如果您的 ViewModel 并不总是需要某些属性,Required那么您不应该将其装饰为必需的。
I don't know why you wanna this issue but I suppose that in some cases you need PropertyOneto be Requiredif PropertyTwohas value.In this case you may need to make your CustomValidationAttributeto check these two properties.
我不知道你为什么想这个问题,但我想,在某些情况下,你需要PropertyOne为Required是否PropertyTwo具有价值。在这种情况下,您可能需要CustomValidationAttribute检查这两个属性。
I'm using something like this :
我正在使用这样的东西:
[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;
}
}
note: Statics.GetPropertyValue(...)do nothing but get the value from the property to compare it.
注意:Statics.GetPropertyValue(...)除了从属性中获取值以进行比较之外,什么都不做。
Hope this helped :)
希望这有帮助:)
回答by Gudradain
If your property is not always required you should not decorate it with [Required].
如果您的财产并不总是需要,您不应该用 装饰它[Required]。
A good alternative to do your validation is to implement the interface IValidatableObject.
进行验证的一个很好的替代方法是实现接口IValidatableObject。
For example, let's say that you want to make the field Staterequired only when the country is United States. You could do it that way :
例如,假设您希望State仅在国家/地区为United States. 你可以这样做:
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) });
}
}
}
Note : This kind of validation only works on the server side.
注意:这种验证仅适用于服务器端。
Other alternatives?
其他选择?
As mentioned in other answers, it's sometimes a good idea to create 2 or more models if the views and validations are very different.
正如其他答案中提到的,如果视图和验证非常不同,有时创建 2 个或更多模型是个好主意。

