web-dev-qa-db-fra.com

Puis-je renvoyer une erreur personnalisée de JsonResult à la méthode d'erreur ajax de jQuery?

Comment transmettre des informations d'erreur personnalisées d'une méthode ASP.NET MVC3 JsonResult à la fonction error (ou success ou complete, si nécessaire) de jQuery.ajax()? Idéalement, j'aimerais pouvoir:

  • Jetez toujours l'erreur sur le serveur (ceci est utilisé pour la journalisation)
  • Récupérer des informations personnalisées sur l'erreur sur le client

Voici une version de base de mon code:

Méthode Controller JsonResult

public JsonResult DoStuff(string argString)
{
    string errorInfo = "";

    try
    {
        DoOtherStuff(argString);
    }
    catch(Exception e)
    {
        errorInfo = "Failed to call DoOtherStuff()";
        //Edit HTTP Response here to include 'errorInfo' ?
        throw e;
    }

    return Json(true);
}

JavaScript

$.ajax({
    type: "POST",
    url: "../MyController/DoStuff",
    data: {argString: "arg string"},
    dataType: "json",
    traditional: true,
    success: function(data, statusCode, xhr){
        if (data === true)
            //Success handling
        else
            //Error handling here? But error still needs to be thrown on server...
    },
    error: function(xhr, errorType, exception) {
        //Here 'exception' is 'Internal Server Error'
        //Haven't had luck editing the Response on the server to pass something here
    }
});

Choses que j'ai essayées (ça n'a pas marché):

  • Retour des informations d'erreur du bloc catch
    • Cela fonctionne, mais l'exception ne peut pas être levée
  • Modification de la réponse HTTP dans le bloc catch
    • Puis inspecté xhr dans le gestionnaire d'erreurs jQuery
    • xhr.getResponseHeader(), etc. contenait la page d'erreur ASP.NET par défaut, mais aucune de mes informations
    • Je pense que cela peut être possible, mais je me suis juste trompé?
29
Drew Gaynor

Vous pouvez écrire un filtre d'erreur personnalisé:

public class JsonExceptionFilterAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.StatusCode = 500;
            filterContext.ExceptionHandled = true;
            filterContext.Result = new JsonResult
            {
                Data = new
                {
                    // obviously here you could include whatever information you want about the exception
                    // for example if you have some custom exceptions you could test
                    // the type of the actual exception and extract additional data
                    // For the sake of simplicity let's suppose that we want to
                    // send only the exception message to the client
                    errorMessage = filterContext.Exception.Message
                },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
    }
}

et enregistrez-le ensuite en tant que filtre global ou ne s'applique qu'à des contrôleurs/actions particuliers que vous souhaitez invoquer avec AJAX. 

Et sur le client:

$.ajax({
    type: "POST",
    url: "@Url.Action("DoStuff", "My")",
    data: { argString: "arg string" },
    dataType: "json",
    traditional: true,
    success: function(data) {
        //Success handling
    },
    error: function(xhr) {
        try {
            // a try/catch is recommended as the error handler
            // could occur in many events and there might not be
            // a JSON response from the server
            var json = $.parseJSON(xhr.responseText);
            alert(json.errorMessage);
        } catch(e) { 
            alert('something bad happened');
        }
    }
});

Évidemment, vous pourriez vous ennuyer rapidement pour écrire du code de traitement d'erreur répétitif pour chaque demande AJAX. Il serait donc préférable de l'écrire une fois pour toutes les demandes AJAX sur votre page:

$(document).ajaxError(function (evt, xhr) {
    try {
        var json = $.parseJSON(xhr.responseText);
        alert(json.errorMessage);
    } catch (e) { 
        alert('something bad happened');
    }
});

et alors:

$.ajax({
    type: "POST",
    url: "@Url.Action("DoStuff", "My")",
    data: { argString: "arg string" },
    dataType: "json",
    traditional: true,
    success: function(data) {
        //Success handling
    }
});

Une autre possibilité consiste à adapter un gestionnaire d'exception global que j'ai présenté afin que, dans ErrorController, vous vérifiiez s'il s'agissait d'une demande AJAX et renvoyiez simplement les détails de l'exception au format JSON.

50
Darin Dimitrov

Les conseils ci-dessus ne fonctionneraient pas sur IIS pour les clients distants. Ils recevront une page d'erreur standard telle que 500.htm au lieu d'une réponse avec un message . Vous devez utiliser le mode customError dans web.config, ou ajouter

<system.webServer>
        <httpErrors existingResponse="PassThrough" />
    </system.webServer>

ou 

"Vous pouvez également aller dans IIS manager -> Pages d'erreur, puis cliquez sur le bouton , Puis sur" Modifier les paramètres de fonction ... "et définissez l'option sur" Détails. errors "alors ce sera votre application qui traitera l'erreur et pas IIS."

10
Artem G

vous pouvez renvoyer JsonResult avec une erreur et suivre le statut côté javascript pour afficher le message d'erreur:

 JsonResult jsonOutput = null;
        try
        {
           // do Stuff
        }
        catch
        {
            jsonOutput = Json(
                 new
                 {
                     reply = new
                     {
                         status = "Failed",
                         message = "Custom message "
                     }
                 });
        }
        return jsonOutput ;
4
linktoarun

Mon projet MVC ne renvoyait aucun message d'erreur (personnalisé ou autre) ... J'ai constaté que cela fonctionnait bien pour moi:

$.ajax({
        url: '/SomePath/Create',
        data: JSON.stringify(salesmain),
        type: 'POST',
        contentType: 'application/json;',
        dataType: 'json',
        success: function (result) {

            alert("start JSON");
            if (result.Success == "1") {
                window.location.href = "/SomePath/index";
            }
            else {
                alert(result.ex);
            }

            alert("end JSON");
        },
        error: function (xhr) {

            alert(xhr.responseText);

        }
        //error: AjaxFailed
    });

La présentation de xhr.responseText a abouti à un message d’alerte très détaillé au format HTML.

0
John M