22 Stimmen

Behandlung von Modellstatusfehlern in einer ajax-aufgerufenen Controller-Aktion, die eine PartialView zurückgibt

Ich habe eine POST-Controller-Aktion, die eine Teilansicht zurückgibt. Alles scheint ganz einfach zu sein, aber. Ich lade es mit $.ajax() , Einstellung Typ als html . Aber wenn mein Modell Validierung fehlschlägt, dachte ich, ich sollte nur einen Fehler mit Modellzustand Fehler werfen. Aber meine Antwort gibt immer 500 Serverfehler zurück.

Wie kann ich Modellstatusfehler zurückmelden, ohne Json mit welchem Ergebnis auch immer zurückzugeben. Ich möchte immer noch eine Teilansicht zurückgeben, die ich direkt an ein HTML-Element anhängen kann.

編集部

Ich möchte auch vermeiden, dass ein Fehler in der Teilansicht zurückgegeben wird. Dies würde auf dem Client wie ein Erfolg aussehen. Wenn der Client das Ergebnis parsen muss, um zu sehen, ob es ein tatsächlicher Erfolg ist, kann es zu Fehlern kommen. Designer können die Ausgabe der Teilansicht ändern, und allein das würde die Funktionalität zerstören. Ich möchte also eine Ausnahme auslösen, aber mit der richtigen Fehlermeldung an den Ajax-Client zurückgeben.

17voto

Robert Koritnik Punkte 100480

Lösung

Ich musste zwei separate Teile schreiben, die automatisch genau wie vorgesehen funktionieren .

Es sollte also eine Teilansicht zurückgeben, wenn der Controller-Aktionsprozess erfolgreich ist, und es sollte einen Fehler mit einigen Fehlerdetails ausgeben, wenn die Dinge nicht in Ordnung sind, so dass die Dinge auf der Client-Seite sowohl Erfolg als auch Fehler unterscheiden würden, anstatt immer den Erfolg zu behandeln.

Es gibt zwei Hauptbestandteile, mit denen dies erreicht wird:

  • Eine benutzerdefinierte Ausnahmeklasse die ausgelöst wird, wenn etwas schief läuft, damit wir zwischen allgemeinen Ausnahmen, die jederzeit aus beliebigen Gründen auftreten können, und Fehlern im Zusammenhang mit unserer Verarbeitung (insbesondere ungültiger Modellstatus) unterscheiden können
  • Filter für Ausnahmemaßnahmen die unsere benutzerdefinierte Ausnahme abfängt und das Ergebnis auf der Grundlage dieser Ausnahme vorbereitet; Wie Sie aus dem Code ersehen können, wird unsere benutzerdefinierte Ausnahme Informationen über Modellstatusfehler enthalten, so dass dieser Filter in der Lage sein wird, einen benutzerdefinierten HTTP-Statuscode sowie einige Textinformationen zurückzugeben

Nun aber zu den Details...

Externer Link : Alle diese Informationen (ausführliche Erklärungen sowie der gesamte Code) sind auch in meinem Blog verfügbar. Die neuesten Code-Updates werden immer sein dort veröffentlicht .

Benutzerdefinierte Ausnahmeklasse

Diese Klasse bietet zwei Dinge

  1. die Unterscheidung zwischen Modellstatusfehlern und regulären Ausnahmen zu erleichtern
  2. einige grundlegende Funktionen bereitstellen, die ich später nutzen kann

Diese Klasse wird später in meinem benutzerdefinierten Fehlerfilter verwendet.

public class ModelStateException : Exception
{
    public Dictionary<string, string> Errors { get; private set; }

    public ModelStateDictionary ModelState { get; private set; }

    public override string Message
    {
        get
        {
            if (this.Errors.Count > 0)
            {
                return this.Errors.First().Value;
            }
            return null;
        }
    }

    private ModelStateException()
    {
        this.Errors = new Dictionary<string, string>();
    }

    public ModelStateException(ModelStateDictionary modelState) : this()
    {
        this.ModelState = modelState;
        if (!modelState.IsValid)
        {
            foreach (KeyValuePair<string, ModelState> state in modelState)
            {
                if (state.Value.Errors.Count > 0)
                {
                    this.Errors.Add(state.Key, state.Value.Errors[0].ErrorMessage);
                }
            }
        }
    }
}

Attribut Fehlerfilter

Dieses Attribut hilft bei der Rückgabe von Fehlern an den Client in Form von HTTP-Fehlercodes, wenn Modellstatusfehler auftreten.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class HandleModelStateExceptionAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (filterContext.Exception != null && typeof(ModelStateException).IsInstanceOfType(filterContext.Exception) && !filterContext.ExceptionHandled)
        {
            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.ContentEncoding = Encoding.UTF8;
            filterContext.HttpContext.Response.HeaderEncoding = Encoding.UTF8;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            filterContext.HttpContext.Response.StatusCode = 400;
            filterContext.HttpContext.Response.StatusDescription = (filterContext.Exception as ModelStateException).Message;
        }
    }
}

Danach habe ich einfach meine Controller-Aktion mit meinem Attribut versehen und voila. Ich habe Fehler auf dem Client mit Code 400 und korrekte Informationen, die ich in meinem Filter festgelegt. Diese Informationen werden dann dem Benutzer angezeigt (wenn es sich um Modellstatusfehler handelt, zeigt es Informationen an, welche Formularfelder der Benutzer ändern sollte, um das Formular gültig zu machen).

[HandleModelStateException]
public ActionResult AddComment(MyModel data)
{
    // check if state is valid
    if (!this.ModelState.IsValid)
    {
        throw new ModelStateException(this.ModelState);
    }
    // get data from store
    return PartialView("Comment", /* store data */ );
}

Dies macht meinen Code wiederverwendbar mit jedem Modell Zustand Fehler und diese werden an den Client, wie sie sollten gesendet werden.

Ein einziges Problem (ist jetzt gelöst)

Aber es gibt noch ein Problem im Zusammenhang mit diesem Code. Wenn mein Fehleraktionsfilter StatusDescription und diese Zeichenfolge einige Sonderzeichen wie C enthält, erhalte ich auf dem Client einen Fehler. Es sei denn, ich verwende den IE (ich verwende Version 8). FF und CH zeigen Müll an. Deshalb habe ich Kodierungen eingestellt, aber es funktioniert nicht. Wenn jemand eine Lösung für diese Besonderheit hat, würde ich mich freuen, wenn ich sie hören könnte.
Wenn ich im Inhalt selbst eine Fehlermeldung eingebe, ist alles in Ordnung. Die Kodierung ist korrekt und ich kann anzeigen, was ich will.

3voto

Amitabh Punkte 54879

Versuchen Sie dies.

public ActionResult DoAjaxAction(Entity entity)
{
   if(ModelState.IsValid)
   {
     return PartialView("Valid_View", entity);
   }
   else
   {
     return PartialView("Invalid_View", entity);
   } 

}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X