23

私は大きなMVC3Webアプリケーションに取り組んでおり、そのModelState.IsValid方法に悩まされています。

ModelStateは、投稿されているデータを検証するために、ほぼすべてのコントローラーで使用されています。ビューはすべて、異なるクラスを含むViewModelsに基づいており、これらのクラスには明らかに、としてマークできるプロパティが含まれてい[Required]ます。

私が抱えている問題は、必要なプロパティが必要ない場合があり、それが真になるModelState.Removeようにメソッドを使用する必要があることModelState.IsValidです。

私の質問は、を使用することModelState.Removeです。これは物事を行う正しい方法ですか、それともより効率的なアプローチがありますか。

4

5 に答える 5

20

これが私の解決策です-MVCHTMLヘルパーをモデルにしたのRemoveFor()拡張メソッド:ModelState

    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);
            }
        }
    }

使用方法は次のとおりです。

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);
}

ですから、あなたの質問に答えて、これが正しい方法であるというユースケースは間違いなくあると思います。このような強く型付けされたヘルパーは、見やすくなり、多くのことを心配している場合は正当化するのが簡単になります。マジックストリングの。

于 2012-12-23T03:54:56.037 に答える
18

2つの異なるコンテキストでプロパティを使用して同じビューモデルを使用している場合[Required]、1つはプロパティが必要であり、もう1つはそうではない場合は、手動で変更する必要がありModelStateます。

別の方法は、別のビューモデルを使用することです。おそらく、問題の必須プロパティを除くすべてのプロパティを持つ基本クラスがあります。次に、そこから2つのビューモデルを導出します。1つは必要なプロパティを持ち、もう1つは必要でないプロパティを持ちます(重複です、私は知っています)。それらを完全に分離して、継承を使用しないことを決定できます。

于 2011-07-27T11:00:11.120 に答える
11

基本的に、あなたの問題は、あなたのクラスが[必須]で飾られている間、それが常に真実であるとは限らないということです。trueでないコンテキストで操作している場合は、プロパティを[必須]として定義していないクラスを実際に使用する必要があります。

特定の使用法に対して正しく定義されているViewModelを実際に使用する必要があります。これは、一部のクラスを複製することを意味する場合があります。ViewModelはUIの実装に関連付けられており、ドメインモデルのクラスを使用する場合もありますが、常に正しいとは限りません。

それができない場合、オプションはModelState.IsValidを使用しないか、ModelState.Removeを引き続き使用することです。

しかし論理的には、ViewModelが「検証可能」であり、特定の検証エラーを無視する必要がないことは理にかなっています。

于 2011-07-27T11:00:59.080 に答える
1

私は完全にスティーブ・モーガン氏と一緒です

したがって、ViewModelが常に何らかのプロパティを必要としない場合Requiredは、それを必須として装飾するべきではありません。

なぜこの問題を望んでいるのかわかりませんが、場合によっては、価値がある場合はそうする必要があるとPropertyOne思いRequiredますPropertyTwo この場合、CustomValidationAttributeこれら2つのプロパティを確認する必要がある場合があります。

私はこのようなものを使用しています:

[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;
    }
}

注:Statics.GetPropertyValue(...)プロパティから値を取得して比較する以外に何もしません。

これがお役に立てば幸いです:)

于 2011-07-27T12:59:36.670 に答える
1

あなたの財産が常に必要とされないならば、あなたはそれをで飾るべきではありません[Required]

検証を行うための良い代替手段は、インターフェースIValidatableObjectを実装することです。

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) });
        }
    }
}

注:この種の検証は、サーバー側でのみ機能します。

他の選択肢?

他の回答で述べたように、ビューと検証が大きく異なる場合は、2つ以上のモデルを作成することをお勧めします。

于 2016-11-21T18:59:20.077 に答える