Bagaimana cara mendapatkan semua Kesalahan dari ASP.Net MVC modelState?

453

Saya ingin mendapatkan semua pesan kesalahan dari modelState tanpa mengetahui nilai-nilai kunci. Looping through untuk mengambil semua pesan kesalahan yang berisi ModelState.

Bagaimana saya bisa melakukan ini?

chobo2
sumber
5
Jika Anda hanya menampilkan kesalahan, maka itu @Html.ValidationSummary()adalah cara cepat untuk menampilkan semuanya dengan pisau cukur.
levininja
11
foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors)) { DoSomething(error); }
Razvan Dumitru

Jawaban:

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

Lihat juga Bagaimana saya mendapatkan koleksi Model State Errors di ASP.NET MVC? .

Oren Trutner
sumber
22
Sangat membantu. Catatan dalam beberapa skenario, seperti kegagalan pengikatan dan permintaan buruk, akan ada entri ModelState dengan string kosong untuk Value.ErrorMessagedan sebagai gantinyaValue.Exception.Message
AaronLS
5
Kesalahan memang bagus tetapi kadang-kadang Anda juga menginginkan kunci dari modelstate (yaitu nama bidang). Anda bisa mendapatkan bahwa dengan mengubah baris pertama yang ini: foreach (KeyValuePair<string, ModelState> kvp in htmlHelper.ViewData.ModelState) {dan masukkan baris di bawahnya ini: var modelState = kvp.Value;. Anda bisa mendapatkan kunci darikvp.Key
viggity
534

Menggunakan LINQ :

IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);
mmutilva
sumber
69
Dimodifikasi untuk mengembalikan IEnumerable <string> hanya dengan pesan kesalahan :: var allErrors = ModelState.Values.SelectMany (v => v.Errors.Select (b => b.ErrorMessage));
Kieran
6
Ini bagus, tetapi sayangnya Watch / Immediate windows tidak mendukung lambda's :(
AaronLS
3
Iya! Saya (Anda, siapa pun) perlu "menggunakan System.Linq;" di atas. Kalau tidak, Anda mendapat pesan 'Nilai tidak mengandung definisi untuk Pilih banyak'. Itu hilang dalam kasus saya.
Estevez
2
kenapa sih penggunaan var ?????? tidak bisakah kamu menulis `IEnumerable <ModelError> 'sebagai gantinya ???
Hakan Fıstık
6
@ hakam-fostok @ jb06 Anda berdua benar. Mengetik List<string> errors = new List<string>()bukannya var errors = new List<string>()benar-benar buang-buang waktu, tetapi menulis IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);, di mana jenis kembali tidak terlalu jelas, benar-benar lebih besar dalam hal keterbacaan. (Bahkan jika visual studio dapat memberikannya kepada Anda di mouse)
disetujui
192

Bangunan di atas LINQ verison, jika Anda ingin menggabungkan semua pesan kesalahan menjadi satu string:

string messages = string.Join("; ", ModelState.Values
                                        .SelectMany(x => x.Errors)
                                        .Select(x => x.ErrorMessage));
Dunc
sumber
5
Pilihan lain adalah melakukan yang berikut: ModelState.Values.SelectMany (x => x.Errors) .Pilih (x => x.ErrorMessage) .JoinString (";");
Tod Thomson
3
@Tod, apakah IEnumerable.JoinString () metode ekstensi Anda sendiri? Lihat stackoverflow.com/q/4382034/188926
Dunc
2
Hei Dunc - ya saya curiga saya telah menambahkan metode ekstensi ke basis kode saya dan lupa tentang hal itu dan kemudian berpikir itu adalah metode kerangka kerja LOL :(
Tod Thomson
5
atau ... ModelState.Values.SelectMany (O => O.Errors) .Pilih (O => O.ErrorMessage) .Agregate ((U, V) => U + "," + V)
fordareh
2
Ini berfungsi dengan baik ketika Anda menggunakan api web dan mengembalikan hasil IHttpActionResult. Jadi, Anda bisa melakukan: mengembalikan BadRequest (pesan); Terima kasih, Dunc!
Rich Ward
32

Saya bisa melakukan ini menggunakan LINQ kecil,

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

Metode di atas mengembalikan daftar kesalahan validasi.

Bacaan lebih lanjut :

Cara membaca semua kesalahan dari ModelState di ASP.NET MVC

Yasser Shaikh
sumber
17

Selama debugging, saya merasa berguna untuk meletakkan tabel di bagian bawah setiap halaman saya untuk menunjukkan semua kesalahan 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
sumber
jika ada kasus tepi di sini di mana ini gagal tolong edit jawaban untuk memperbaikinya
Simon_Weaver
12

Seperti yang saya temukan setelah mengikuti saran dalam jawaban yang diberikan sejauh ini, Anda bisa mendapatkan pengecualian yang terjadi tanpa pesan kesalahan yang ditetapkan, jadi untuk menangkap semua masalah Anda benar-benar perlu mendapatkan ErrorMessage dan Exception.

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

atau sebagai metode ekstensi

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

}
Alan Macdonald
sumber
mengapa Anda ingin string dengan semua kesalahan di dalamnya? tidak masuk akal ketika Anda ingin melakukan sesuatu dengan itu dalam tampilan, array daftar adalah cara yang lebih baik
Daniël Tulp
1
Untuk debug. Masalah pertama saya adalah mencari tahu apa yang salah dengan aplikasi saya. Saya tidak mencoba memberi tahu pengguna hanya mencari tahu apa yang salah. Selain itu sepele untuk mengubah contoh itu dari membuat enumerasi string ke enumerasi sesuatu yang lain, misalnya pesan kesalahan dan pengecualian sehingga hal yang sangat berguna adalah mengetahui bahwa Anda memerlukan kedua bit informasi
Alan Macdonald
BTW Anda memang menyadari metode ekstensi kedua mengembalikan IEnumerable <String> dan bukan hanya string tunggal besar?
Alan Macdonald
8

Jika ada yang ingin mengembalikan properti Model of Name untuk mengikat pesan kesalahan dalam tampilan yang diketik dengan kuat.

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

Dengan cara ini Anda bisa mengikat kesalahan dengan bidang yang melempar kesalahan.

james31rock
sumber
7

Mengeluarkan hanya pesan kesalahan itu sendiri tidak cukup untuk saya, tetapi ini berhasil.

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));
Josh Sutterfield
sumber
1
Sebagai peringatan, pasangan nilai kunci di ModelState dapat menyertakan nilai NULL, itulah sebabnya kode asli di sini menyertakan beberapa bisnis C # 6 yang lucu dengan operator null-coalesce (?), Maka dari itu mencari kari ke ?? di akhir ungkapan. Ekspresi asli yang harus dilindungi dari kesalahan nol adalah: state.Value.?AttemptedValue ?? "[BATAL]". Sejauh yang saya tahu, kode dalam keadaan saat ini, tanpa penanganan kasus yang licik di mana state.Value == null, berisiko.
Josh Sutterfield
5

Untuk berjaga-jaga jika seseorang membutuhkannya saya membuat dan menggunakan kelas statis berikut dalam proyek saya

Contoh penggunaan:

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

Usings:

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

Kelas:

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
sumber
Terima kasih CodeArtist !! Saya membuat sedikit perubahan pada kode di bawah implementasinya.
Alfred Severo
4

Dan ini juga bekerja:

var query = from state in ModelState.Values
    from error in state.Errors
    select error.ErrorMessage;
var errors = query.ToArray(); // ToList() and so on...
Amiry ravy
sumber
@ Yasser Sudahkah Anda melihat jawaban Toto?
The Muffin Man
@ TheMuffinMan ya saya punya. Bagaimana dengan itu?
Yasser Shaikh
@ Yasser Ini jawaban terbaik. Tidak ada yang salah dengan ini, tetapi tidak ada gunanya menggunakannya ketika SelectManytersedia.
The Muffin Man
4

Berguna untuk meneruskan berbagai pesan kesalahan ke Lihat, mungkin melalui Json:

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

Ini memperluas jawaban dari @Dunc. Lihat komentar doc 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;            
    }
}
Chris Marisic
sumber
3

Selain itu, ModelState.Values.ErrorMessagemungkin kosong, tetapi ModelState.Values.Exception.Messagemungkin mengindikasikan kesalahan.

Jason Dufair
sumber
0

Dalam implementasi Anda Anda kehilangan Kelas statis, ini seharusnya.

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

agak

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

<div class="text-danger" style="direction:rtl" asp-validation-summary="All"></div>

cukup gunakan Tag-tag penolong validasi-ringkasan

Armin Azhdari
sumber