Làm thế nào để có được tất cả các lỗi từ ASP.Net MVC modelState?


453

Tôi muốn lấy tất cả các thông báo lỗi ra khỏi modelState mà không biết các giá trị chính. Vòng qua để lấy tất cả các thông báo lỗi mà ModelState chứa.

Tôi có thể làm cái này như thế nào?


5
Nếu bạn chỉ hiển thị các lỗi, thì đó @Html.ValidationSummary()là cách nhanh chóng để hiển thị tất cả chúng bằng dao cạo.
levininja

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

Câu trả lời:


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

Xem thêm Làm cách nào để có được bộ sưu tập Lỗi trạng thái mô hình trong ASP.NET MVC? .


22
Rất hữu ích. Lưu ý trong một số trường hợp, chẳng hạn như lỗi liên kết và yêu cầu xấu, sẽ có các mục ModelState với chuỗi trống cho Value.ErrorMessagevà thay vào đóValue.Exception.Message
AaronLS

5
Lỗi là tốt nhưng đôi khi bạn cũng muốn khóa của modelstate (tức là tên của trường). bạn có thể có được điều đó bằng cách thay đổi dòng đầu tiên thành này: foreach (KeyValuePair<string, ModelState> kvp in htmlHelper.ViewData.ModelState) {và chèn dòng này bên dưới nó : var modelState = kvp.Value;. Bạn có thể lấy chìa khóa từkvp.Key
viggity

533

Sử dụng LINQ :

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

69
Được sửa đổi để trả về IEnumerable <string> chỉ bằng thông báo lỗi :: var allErrors = ModelState.Values.SelectMany (v => v.Errors.Select (b => b.ErrorMessage));
Kieran

6
Điều này thật tuyệt, nhưng thật không may, Cửa sổ Xem / Ngay lập tức không hỗ trợ lambda :(
AaronLS

3
Đúng! Tôi (bạn, bất cứ ai) cần "sử dụng System.Linq;" trong top Nếu không, bạn nhận được thông báo 'Giá trị không chứa định nghĩa cho Chọn nhiều'. Nó đã bị mất trong trường hợp của tôi.
Estevez

2
Tại sao lại sử dụng var ?????? bạn không thể viết `IEnumerable <ModelError> 'chứ ???
Hakan Fıstık

6
@ hakam-fostok @ jb06 bạn đều đúng cả. Gõ List<string> errors = new List<string>()thay vì var errors = new List<string>()thực sự là một sự lãng phí thời gian, nhưng viết IEnumerable<ModelError> allErrors = ModelState.Values.SelectMany(v => v.Errors);, trong đó kiểu trả về không thực sự rõ ràng, thực sự lớn hơn về khả năng đọc. (ngay cả khi studio hình ảnh có thể cung cấp cho bạn khi di chuột)
aprovent 18/07/2016

192

Dựa trên bản án LINQ, nếu bạn muốn nối tất cả các thông báo lỗi thành một chuỗi:

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

5
Tùy chọn khác là thực hiện các thao tác sau: ModelState.Values.SelectMany (x => x.Errors) .Select (x => x.ErrorMessage) .JoinString (";");
Tod Thomson

3
@Tod, là IEnumerable.JoinString () phương thức mở rộng của riêng bạn? Xem stackoverflow.com/q/4382034/188926
Dunc

2
Này Dunc - vâng tôi nghi ngờ tôi đã thêm phương thức mở rộng đó vào cơ sở mã của mình và đã quên nó và sau đó nghĩ rằng đó là một phương thức khung LOL :(
Tod Thomson

5
hoặc ... ModelState.Values.SelectMany (O => O.Errors) .Select (O => O.ErrorMessage) .Aggregate ((U, V) => U + "," + V)
fordareh

2
Điều này hoạt động rất tốt khi bạn đang sử dụng web api và trả về kết quả IHttpActionResult. Vì vậy, bạn chỉ có thể làm: trả về BadRequest (tin nhắn); Cảm ơn, Dunc!
Phường giàu

32

Tôi đã có thể làm điều này bằng cách sử dụng một chút 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;
}

Phương pháp trên trả về một danh sách các lỗi xác nhận.

Đọc thêm :

Cách đọc tất cả các lỗi từ ModelState trong ASP.NET MVC


17

Trong quá trình gỡ lỗi, tôi thấy hữu ích khi đặt một bảng ở cuối mỗi trang của mình để hiển thị tất cả các lỗi 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>

nếu có bất kỳ trường hợp cạnh nào ở đây khi điều này không thành công, vui lòng chỉ chỉnh sửa câu trả lời để khắc phục
Simon_Weaver

12

Khi tôi phát hiện ra đã làm theo lời khuyên trong các câu trả lời cho đến nay, bạn có thể có ngoại lệ xảy ra mà không có thông báo lỗi được đặt, do đó, để nắm bắt tất cả các vấn đề bạn thực sự cần phải có cả ErrorMessage và Exception.

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

hoặc như một phương pháp mở rộng

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

}

Tại sao bạn muốn có một chuỗi với tất cả các lỗi trong đó? không có ý nghĩa khi bạn muốn làm một cái gì đó với nó trong chế độ xem, một loạt danh sách là cách tốt hơn imho
Daniël Tulp

1
Tìm lỗi. Vấn đề đầu tiên của tôi là tìm hiểu những gì đã xảy ra với ứng dụng của tôi. Tôi đã không cố nói với người dùng chỉ cần tìm hiểu những gì đang xảy ra. Bên cạnh đó, việc chuyển đổi ví dụ đó từ việc tạo ra một chuỗi các liệt kê thành một thứ khác, ví dụ như thông báo lỗi và ngoại lệ, điều thực sự hữu ích là biết rằng bạn cần cả hai thông tin
Alan Macdonald

BTW bạn đã nhận ra phương thức mở rộng thứ hai trả về IEnumerable <String> chứ không chỉ là một chuỗi lớn?
Alan Macdonald

8

Trong trường hợp bất kỳ ai cũng muốn trả về Tên của thuộc tính Model để ràng buộc thông báo lỗi trong chế độ xem được gõ mạnh.

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

Bằng cách này, bạn thực sự có thể buộc lỗi trong trường đã ném lỗi.


7

Chỉ xuất ra các thông báo Lỗi là không đủ cho tôi, nhưng điều này đã tạo ra mánh khóe.

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
Như một cảnh báo, các cặp giá trị khóa trong ModelState có thể bao gồm các giá trị NULL, đó là lý do tại sao mã gốc ở đây bao gồm một số doanh nghiệp C # 6 dễ thương với toán tử hợp nhất null (?.), Do đó, việc chuyển sang ?? ở cuối biểu thức. Biểu thức ban đầu cần bảo vệ khỏi các lỗi null là: state.Value.?AtteemedValue ?? "[VÔ GIÁ TRỊ]". Theo như tôi biết, mã ở trạng thái hiện tại của nó, mà không xử lý lén lút các trường hợp trong đó state.Value == null, có nguy cơ.
Josh Sutterfield

5

Để chỉ trong trường hợp ai đó cần nó, tôi đã thực hiện và sử dụng lớp tĩnh sau trong các dự án của mình

Ví dụ sử dụng:

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

Công dụng:

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

Lớp học:

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

Cảm ơn CodeArtist !! Tôi đã thực hiện một thay đổi nhỏ trong mã dưới đây thực hiện.
Alfred Severo

4

Và điều này cũng hoạt động:

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

@Yasser Bạn đã thấy câu trả lời của Toto chưa?
Người đàn ông Muffin

@TheMuffinMan vâng tôi có. Còn nó thì sao ?
Yasser Shaikh

@Yasser Đó là câu trả lời tốt nhất. Không có gì sai với cái này, nhưng không có điểm nào trong việc sử dụng nó khi SelectManycó sẵn.
Người đàn ông Muffin

4

Hữu ích cho việc chuyển mảng thông báo lỗi sang View, có lẽ thông qua Json:

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

4

Điều này đang mở rộng dựa trên câu trả lời từ @Dunc. Xem bình luận xml doc

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

3

Ngoài ra, ModelState.Values.ErrorMessagecó thể trống, nhưng ModelState.Values.Exception.Messagecó thể chỉ ra lỗi.


0

Trong triển khai của bạn, bạn đang thiếu Class tĩnh, điều này nên được.

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

hơn

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

0

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

chỉ cần sử dụng Trình trợ giúp thẻ tóm tắt asp-xác thực

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.