วิธีรับข้อผิดพลาดทั้งหมดจาก ASP.Net MVC modelState?


453

ฉันต้องการรับข้อความแสดงข้อผิดพลาดทั้งหมดจาก modelState โดยไม่ทราบถึงค่าคีย์ วนรอบเพื่อคว้าข้อความแสดงข้อผิดพลาดทั้งหมดที่ ModelState มีอยู่

ฉันจะทำสิ่งนี้ได้อย่างไร


5
หากคุณเพิ่งแสดงข้อผิดพลาด@Html.ValidationSummary()เป็นวิธีที่รวดเร็วในการแสดงทั้งหมดในมีดโกน
levininja

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

คำตอบ:


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

ดูเพิ่มเติมฉันจะรับชุดข้อผิดพลาดของ Model State ใน ASP.NET MVC ได้อย่างไร .


22
มีประโยชน์มาก หมายเหตุในบางสถานการณ์เช่นการเชื่อมโยงล้มเหลวและคำขอไม่ถูกต้องจะมีรายการ ModelState ที่มีสตริงว่างสำหรับValue.ErrorMessageและแทน aValue.Exception.Message
AaronLS

5
ข้อผิดพลาดเป็นสิ่งที่ดี แต่บางครั้งคุณต้องการคีย์ของ modelstate ด้วย (เช่นชื่อของฟิลด์) คุณจะได้รับโดยการเปลี่ยนบรรทัดแรกนี้: และแทรกบรรทัดด้านล่างนี้:foreach (KeyValuePair<string, ModelState> kvp in htmlHelper.ViewData.ModelState) { var modelState = kvp.Value;คุณสามารถรับกุญแจได้จากkvp.Key
viggity

534

ใช้LINQ :

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

69
แก้ไขเพื่อส่งคืน <string> IEnumerable ด้วยข้อความแสดงข้อผิดพลาด :: var allErrors = ModelState.Values.SelectMany (v => v.Errors.Select (b => b.ErrorMessage);
Kieran

6
นี่เป็นสิ่งที่ดี แต่น่าเสียดายที่หน้าต่าง Watch / Immediate ไม่สนับสนุน lambda's :(
AaronLS

3
ใช่ ฉัน (คุณทุกคน) ต้องการ "ใช้ System.Linq;" ด้านบน มิฉะนั้นคุณจะได้รับข้อความ 'ค่าไม่ได้มีคำจำกัดความสำหรับ Select many' มันหายไปในกรณีของฉัน
Estevez

2
ทำไมในนรกโดยใช้ var ?????? คุณไม่สามารถเขียน `IEnumerable <ModelError> 'แทนได้ ???
Hakan Fı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);ซึ่งชนิดการส่งคืนไม่ชัดเจนจริง ๆ มีความสามารถในการอ่านได้ดีกว่า (แม้ว่าภาพสตูดิโอสามารถให้มันอยู่กับคุณในการเลื่อนเมาส์)
aprovent

192

การสร้างบนรูปแบบ LINQ หากคุณต้องการเข้าร่วมข้อความแสดงข้อผิดพลาดทั้งหมดในสตริงเดียว:

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

5
ตัวเลือกอื่นคือทำสิ่งต่อไปนี้: ModelState.Values.SelectMany (x => x.Errors) .Select (x => x.ErrorMessage) .JoinString (";");
ท็อดทอมสัน

3
@Tod เป็น IEnumerable.JoinString () วิธีการขยายของคุณเองหรือ ดูstackoverflow.com/q/4382034/188926
Dunc

2
เฮ้ Dunc - ใช่ฉันสงสัยว่าฉันได้เพิ่มวิธีการขยายไปยังฐานรหัสของฉันและลืมเกี่ยวกับมันแล้วคิดว่ามันเป็นวิธีการกรอบ LOL :(
ท็อดทอมสัน

5
หรือ ... ModelState.Values.SelectMany (O => O.Errors) .Select (O => O.ErrorMessage). Agregate ((U, V) => U + "," + V)
fordareh

2
วิธีนี้ใช้งานได้ดีเมื่อคุณใช้เว็บ API และส่งคืนผลลัพธ์ IHttpActionResult ดังนั้นคุณสามารถทำได้: ส่งคืน BadRequest (ข้อความ); ขอบคุณ Dunc!
ริชวอร์ด

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

วิธีการข้างต้นส่งกลับรายการข้อผิดพลาดในการตรวจสอบ

อ่านเพิ่มเติม :

วิธีอ่านข้อผิดพลาดทั้งหมดจาก ModelState ใน ASP.NET MVC


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

}

ทำไมคุณต้องการสตริงที่มีข้อผิดพลาดทั้งหมด? ไม่สมเหตุสมผลเมื่อคุณต้องการทำอะไรกับมันในมุมมองอาร์เรย์ของรายการเป็นวิธีที่ดีกว่า imho
Daniël Tulp

1
เพื่อทำการดีบั๊ก ปัญหาแรกของฉันคือการค้นหาสิ่งที่ผิดปกติกับแอพของฉัน ฉันไม่ได้พยายามบอกผู้ใช้เพียงแค่ค้นหาว่าเกิดอะไรขึ้น นอกจากนี้การแปลงตัวอย่างจากการสร้างการแจงนับของสตริงเป็นการแจกแจงอย่างอื่นเช่นข้อความแสดงข้อผิดพลาดและข้อยกเว้นดังนั้นสิ่งที่มีประโยชน์จริง ๆ ก็คือการรู้ว่าคุณต้องการข้อมูลทั้งสอง
Alan Macdonald

BTW คุณได้ตระหนักถึงวิธีการขยายที่สองคืน IEnumerable <String> และไม่ใช่แค่สตริงเดี่ยวขนาดใหญ่?
Alan Macdonald

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 ซึ่งเป็นสาเหตุที่รหัสต้นฉบับที่นี่รวมธุรกิจ C # 6 ที่น่ารักบางอย่างเข้ากับตัวดำเนินการ null-coalesce (?.) ดังนั้นจึงเป็นคำย่อของ ในตอนท้ายของการแสดงออก การแสดงออกเดิมที่ควรป้องกันจากข้อผิดพลาด null คือ: state.Value.AttemptedValue ?? "[โมฆะ]" เท่าที่ฉันรู้รหัสในสถานะปัจจุบันโดยไม่มีการจัดการกรณีที่ส่อเสียดที่ state.Value == null เป็นความเสี่ยง
Josh Sutterfield

5

สำหรับในกรณีที่มีคนต้องการฉันทำและใช้คลาสคงที่ต่อไปนี้ในโครงการของฉัน

ตัวอย่างการใช้งาน:

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;

ประเภท:

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 !! ฉันทำการเปลี่ยนแปลงเล็กน้อยในรหัสด้านล่างการนำไปใช้
Alfred Severo

4

และสิ่งนี้ก็ใช้ได้เช่นกัน:

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

@Yasser คุณเห็นคำตอบของ Toto แล้วหรือยัง
The Muffin Man

@ TheMuffinMan ใช่ฉันมี แล้วมันล่ะ?
Yasser Shaikh

@ Yasser มันเป็นคำตอบที่ดีที่สุด ไม่มีอะไรผิดปกติกับอันนี้ แต่ไม่มีประโยชน์ในการใช้เมื่อSelectManyพร้อมใช้งาน
ผู้ชายมัฟฟิน

4

มีประโยชน์สำหรับการส่งอาเรย์ของข้อความแสดงข้อผิดพลาดไปยัง View, บางทีผ่าน Json:

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

4

นี่คือการขยายตัวตามคำตอบจาก @Dunc ดูความคิดเห็น 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

นอกจากนี้ModelState.Values.ErrorMessageอาจว่างเปล่า แต่ModelState.Values.Exception.Messageอาจระบุข้อผิดพลาด


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.