ASP.Net MVC modelStateからすべてのエラーを取得する方法?


453

キーの値を知らなくても、modelStateからすべてのエラーメッセージを取り出したいのですが。ループして、ModelStateに含まれるすべてのエラーメッセージを取得します。

これどうやってするの?


5
エラーを表示するだけの場合@Html.ValidationSummary()は、それらをすべてかみそりで表示する簡単な方法です。
levininja 2014年

11
foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }
Razvan Dumitru 2014年

回答:


531
foreach (ModelState modelState in ViewData.ModelState.Values) {
    foreach (ModelError error in modelState.Errors) {
        DoSomethingWith(error);
    }
}

ASP.NET MVCでモデル状態エラーのコレクションを取得する方法も参照してください


22
非常に役立ちます。バインドの失敗や不正なリクエストなどの一部のシナリオではValue.ErrorMessage、代わりに空の文字列を含むModelStateエントリが存在することに注意してくださいValue.Exception.Message
AaronLS

5
エラーはいいですが、modelstateのキー(つまり、フィールドの名前)も必要になる場合があります。最初の行をthis:に変更し、その下に次の行をforeach (KeyValuePair<string, ModelState> kvp in htmlHelper.ViewData.ModelState) {挿入することで取得できますvar modelState = kvp.Value;。キーは次の場所から取得できますkvp.Key
活力

534

使用してLINQを

IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);

69
エラーメッセージのみを含むIEnumerable <string>を返すように変更されました。
キーラン2014

6
これはすばらしいことですが、残念ながらウォッチ/イミディエイトウィンドウはラムダをサポートしていません:(
AaronLS

3
はい!私(あなた、だれでも)は「System.Linqを使用する」必要があります。上に。それ以外の場合は、「値に複数選択の定義が含まれていません」というメッセージが表示されます。私の場合は欠けていました。
エステベス2014年

2
なぜ地獄でvarを使うのですか?????? 代わりに「IEnumerable <ModelError>」を記述できませんでしたか???
HakanFıstık

6
@ hakam-fostok @ jb06どちらも正しいです。のList<string> errors = new List<string>()代わりにタイプすることvar errors = new List<string>()は本当に時間の浪費ですIEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);が、戻り値のタイプが本当に明確ではない場合、書くことは読みやすさの点で本当に大きいです。(ビジュアルスタジオがマウスホバーであなたにそれを与えることができるとしても)
公認

192

すべてのエラーメッセージを1つの文字列に結合する場合は、LINQバージョンを基に構築します。

string messages = string.Join("; ", ModelState.Values
                                        .SelectMany(x => x.Errors)
                                        .Select(x => x.ErrorMessage));

5
もう1つのオプションは、次のことです。ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).JoinString( ";");
Tod Thomson

3
@ Tod、IEnumerable.JoinString()はあなた自身の拡張メソッドですか?stackoverflow.com/q/4382034/188926を
2013

2
Hey Dunc-はい、その拡張メソッドをコードベースに追加したことを忘れて、それを忘れて、それをフレームワークメソッドであると考えましたLOL :(
Tod Thomson

5
または... ModelState.Values.SelectMany(O => O.Errors).Select(O => O.ErrorMessage).Aggregate((U、V)=> U + "、" + V)
fordareh

2
これは、Web APIを使用していて、IHttpActionResultの結果を返すときにうまく機能します。だから、あなたはただ行うことができます:return BadRequest(messages); ありがとう、ダンク!
リッチワード

32

私は少しのLINQを使用してこれを行うことができました、

public static List<string> GetErrorListFromModelState
                                              (ModelStateDictionary modelState)
{
      var query = from state in modelState.Values
                  from error in state.Errors
                  select error.ErrorMessage;

      var errorList = query.ToList();
      return errorList;
}

上記のメソッドは、検証エラーのリストを返します。

参考文献 :

ASP.NET MVCでModelStateからすべてのエラーを読み取る方法


17

デバッグ中、各ページの下部にテーブルを配置して、すべてのModelStateエラーを表示すると便利です。

<table class="model-state">
    @foreach (var item in ViewContext.ViewData.ModelState) 
    {
        if (item.Value.Errors.Any())
        { 
        <tr>
            <td><b>@item.Key</b></td>
            <td>@((item.Value == null || item.Value.Value == null) ? "<null>" : item.Value.Value.RawValue)</td>
            <td>@(string.Join("; ", item.Value.Errors.Select(x => x.ErrorMessage)))</td>
        </tr>
        }
    }
</table>

<style>
    table.model-state
    {
        border-color: #600;
        border-width: 0 0 1px 1px;
        border-style: solid;
        border-collapse: collapse;
        font-size: .8em;
        font-family: arial;
    }

    table.model-state td
    {
        border-color: #600;
        border-width: 1px 1px 0 0;
        border-style: solid;
        margin: 0;
        padding: .25em .75em;
        background-color: #FFC;
    }
 </style>

これが失敗するエッジケースがある場合は、答えを編集して修正してください
Simon_Weaver

12

これまでの回答でアドバイスに従っていることを発見したので、エラーメッセージを設定しなくても例外が発生する可能性があるため、すべての問題をキャッチするには、ErrorMessageとExceptionの両方を取得する必要があります。

String messages = String.Join(Environment.NewLine, ModelState.Values.SelectMany(v => v.Errors)
                                                           .Select( v => v.ErrorMessage + " " + v.Exception));

または拡張メソッドとして

public static IEnumerable<String> GetErrors(this ModelStateDictionary modelState)
{
      return modelState.Values.SelectMany(v => v.Errors)
                              .Select( v => v.ErrorMessage + " " + v.Exception).ToList();

}

すべてのエラーを含む文字列が必要なのはなぜですか?ビューにそれで何かをしたい場合は、リストの配列がずっといい私見である意味がありません
ダニエルチューリップ

1
デバッグする。私の最初の問題は、私のアプリの何がうまくいかないのかを見つけることでした。私は、ユーザーに何が問題なのかを知るように告げるつもりはありませんでした。その上、その例を文字列の列挙の作成から別の列挙、たとえばエラーメッセージや例外の作成に変換するのは簡単です。そのため、本当に役立つのは、両方のビットの情報が必要であることを知っていることです
Alan Macdonald

ところで、2番目の拡張メソッドがIEnumerable <String>を返すのに、大きな単一の文字列だけではないことに気付きましたか?
アランマクドナルド

8

厳密に型指定されたビューでエラーメッセージをバインドするためにモデルプロパティの名前を返したい場合。

List<ErrorResult> Errors = new List<ErrorResult>();
foreach (KeyValuePair<string, ModelState> modelStateDD in ViewData.ModelState)
{
    string key = modelStateDD.Key;
    ModelState modelState = modelStateDD.Value;

    foreach (ModelError error in modelState.Errors)
    {
        ErrorResult er = new ErrorResult();
        er.ErrorMessage = error.ErrorMessage;
        er.Field = key;
        Errors.Add(er);
    }
}

このようにして、実際にエラーをスローしたフィールドとエラーを結び付けることができます。


7

エラーメッセージ自体を出力するだけでは不十分でしたが、これでうまくいきました。

var modelQuery = (from kvp in ModelState
                  let field = kvp.Key
                  let state = kvp.Value
                  where state.Errors.Count > 0
                  let val = state.Value?.AttemptedValue ?? "[NULL]"

                  let errors = string.Join(";", state.Errors.Select(err => err.ErrorMessage))
                  select string.Format("{0}:[{1}] (ERRORS: {2})", field, val, errors));

Trace.WriteLine(string.Join(Environment.NewLine, modelQuery));

1
警告として、ModelStateのキーと値のペアにNULL値が含まれている可能性があります。これが、元のコードにnull結合演算子(?。)を使用したかわいいC#6ビジネスが含まれていたため、?? 式の最後。nullエラーから保護する必要のある元の式は、state.Value。?AttemptedValue ??でした。"[ヌル]"。私が知る限り、state.Value == nullのケースをこっそり処理しない、現在の状態のコードは危険にさらされています。
Josh Sutterfield 2017年

5

誰かがそれを必要とする場合に備えて、私は自分のプロジェクトで次の静的クラスを使用しました

使用例:

if (!ModelState.IsValid)
{
    var errors = ModelState.GetModelErrors();
    return Json(new { errors });
}

使用:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using WebGrease.Css.Extensions;

クラス:

public static class ModelStateErrorHandler
{
    /// <summary>
    /// Returns a Key/Value pair with all the errors in the model
    /// according to the data annotation properties.
    /// </summary>
    /// <param name="errDictionary"></param>
    /// <returns>
    /// Key: Name of the property
    /// Value: The error message returned from data annotation
    /// </returns>
    public static Dictionary<string, string> GetModelErrors(this ModelStateDictionary errDictionary)
    {
        var errors = new Dictionary<string, string>();
        errDictionary.Where(k => k.Value.Errors.Count > 0).ForEach(i =>
        {
            var er = string.Join(", ", i.Value.Errors.Select(e => e.ErrorMessage).ToArray());
            errors.Add(i.Key, er);
        });
        return errors;
    }

    public static string StringifyModelErrors(this ModelStateDictionary errDictionary)
    {
        var errorsBuilder = new StringBuilder();
        var errors = errDictionary.GetModelErrors();
        errors.ForEach(key => errorsBuilder.AppendFormat("{0}: {1} -", key.Key,key.Value));
        return errorsBuilder.ToString();
    }
}

CodeArtistに感謝!! その実装の下にあるコードに小さな変更を加えました。
アルフレッドセベロ2015年

4

そしてこれもうまくいきます:

var query = from state in ModelState.Values
    from error in state.Errors
    select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...

@ヤセルトトの答えを見た?
マフィンマン

@TheMuffinManはい、あります。それはどうですか?
Yasser Shaikh 2014年

@Yasser最高の答えです。これには何の問題もありませんSelectManyが、利用可能な場合に使用しても意味がありません。
マフィン男

4

おそらくJsonを介して、エラーメッセージの配列をViewに渡すのに便利です。

messageArray = this.ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors, (modelState, error) => error.ErrorMessage).ToArray();

4

これは@Duncからの回答を拡張しています。XMLドキュメントコメントを参照してください

// ReSharper disable CheckNamespace
using System.Linq;
using System.Web.Mvc;


public static class Debugg
{
    /// <summary>
    /// This class is for debugging ModelState errors either in the quick watch 
    /// window or the immediate window.
    /// When the model state contains dozens and dozens of properties, 
    /// it is impossible to inspect why a model state is invalid.
    /// This method will pull up the errors
    /// </summary>
    /// <param name="modelState">modelState</param>
    /// <returns></returns>
    public static ModelError[]  It(ModelStateDictionary modelState)
    {
        var errors = modelState.Values.SelectMany(x => x.Errors).ToArray();
        return errors;            
    }
}


0

実装に静的クラスがありません。これは必要です。

if (!ModelState.IsValid)
{
    var errors =  ModelStateErrorHandler.GetModelErrors(this.ModelState);
    return Json(new { errors });
}

むしろ

if (!ModelState.IsValid)
{
    var errors = ModelState.GetModelErrors();
    return Json(new { errors });
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.