web-dev-qa-db-fra.com

Comment signaler une erreur à $ .ajax sans lever d'exception dans le contrôleur MVC?

J'ai un contrôleur et une méthode telle que définie ...

[HttpPost]
public ActionResult UpdateUser(UserInformation model){

   // Instead of throwing exception
   throw new InvalidOperationException("Something went wrong");


   // I need something like 
   return ExecutionError("Error Message");

   // which should be received as an error to my 
   // $.ajax at client side...

}

Problèmes d'exceptions

  1. Nous devons enregistrer des exceptions en cas d’erreurs de périphérique ou de réseau, telles que des erreurs de connectivité SQL. 
  2. Ces messages sont comme des messages de validation pour les utilisateurs, nous ne voulons pas nous connecter.
  3. L'exception d'exceptions entraîne également l'inondation de l'Observateur d'événements.

Il me faut un moyen simple de signaler un statut http personnalisé à mon appel $ .ajax afin qu’il en résulte une erreur côté client, mais je ne souhaite pas en générer une.

METTRE À JOUR

Je ne peux pas modifier le script client car il devient incompatible avec les autres sources de données. 

Jusqu'à présent, HttpStatusCodeResult devrait fonctionner, mais c'est IIS qui est à l'origine du problème ici. Peu importe le message d'erreur que j'ai défini, j'ai essayé toutes les réponses, je ne reçois toujours que le message par défaut. 

32
Akash Kava

C’est là que les codes d’état HTTP entrent en jeu. Avec Ajax, vous pourrez les gérer en conséquence.

[HttpPost]
public ActionResult UpdateUser(UserInformation model){
    if (!UserIsAuthorized())
        return new HttpStatusCodeResult(401, "Custom Error Message 1"); // Unauthorized
    if (!model.IsValid)
        return new HttpStatusCodeResult(400, "Custom Error Message 2"); // Bad Request
    // etc.
}

Voici une liste des codes d’état définis .

46
Dennis Traub

La description

Pourquoi ne pas retourner un objet sur votre page et l’analyser dans votre rappel ajax.

Échantillon

[HttpPost]
public ActionResult UpdateUser(UserInformation model)
{
    if (SomethingWentWrong)
        return this.Json(new { success = false, message = "Uuups, something went wrong!" });

    return this.Json(new { success=true, message=string.Empty});
}

jQuery

$.ajax({
  url: "...",
  success: function(data){
    if (!data.success) 
    {
       // do something to show the user something went wrong using data.message
    } else {
       // YES! 
    }
  }
});
9
dknaack

Vous pouvez créer une méthode d'assistance dans un contrôleur de base qui renverra une erreur de serveur, mais avec votre code d'état personnalisé. Exemple:

public abstract class MyBaseController : Controller
{
    public EmptyResult ExecutionError(string message)
    {
        Response.StatusCode = 550;
        Response.Write(message);
        return new EmptyResult();
    }
}

Vous appellerez cette méthode dans vos actions si nécessaire. Dans votre exemple:

[HttpPost]
public ActionResult UpdateUser(UserInformation model){

   // Instead of throwing exception
   // throw new InvalidOperationException("Something went wrong");


   // The thing you need is 
   return ExecutionError("Error Message");

   // which should be received as an error to my 
   // $.ajax at client side...

}

Les erreurs (y compris le code personnalisé '550') peuvent être gérées globalement côté client de la manière suivante:

$(document).ready(function () {
    $.ajaxSetup({
        error: function (x, e) {
            if (x.status == 0) {
                alert('You are offline!!\n Please Check Your Network.');
            } else if (x.status == 404) {
                alert('Requested URL not found.');
/*------>*/ } else if (x.status == 550) { // <----- THIS IS MY CUSTOM ERROR CODE
                alert(x.responseText);
            } else if (x.status == 500) {
                alert('Internel Server Error.');
            } else if (e == 'parsererror') {
                alert('Error.\nParsing JSON Request failed.');
            } else if (e == 'timeout') {
                alert('Request Time out.');
            } else {
                alert('Unknow Error.\n' + x.responseText);
            }
        }
    });
});
4
shizik

C’est une classe où j’ai écrit les exceptions d’envoi aux requêtes ajax en JSON

public class FormatExceptionAttribute : HandleErrorAttribute
    {
        public override void OnException(ExceptionContext filterContext)
        {
            if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.Result = new JsonResult()
                                        {
                                            ContentType = "application/json",
                                            Data = new
                                                    {
                                                        name = filterContext.Exception.GetType().Name,
                                                        message = filterContext.Exception.Message,
                                                        callstack = filterContext.Exception.StackTrace
                                                    },
                                            JsonRequestBehavior = JsonRequestBehavior.AllowGet
                                        };

                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.StatusCode = 500;
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
            }
            else
            {
                base.OnException(filterContext);
            }
        }
    }

Il est enregistré avec MVC dans le fichier Global.asax.cs de votre application, comme suit:

GlobalFilters.Filters.Add(new FormatExceptionAttribute());
2
Jason

Le meilleur moyen que j'ai trouvé est le suivant:

// Return error status and custom message as 'errorThrown' parameter of ajax request
return new HttpStatusCodeResult(400, "Ajax error test");
1
GP24

D'après ce que BigMike a publié, c'est ce que j'ai fait dans mon projet Web NON MVC/Web API.

Response.ContentType = "application/json";
Response.StatusCode = 400;
Response.Write (ex.Message);

Pour ce que cela vaut (et merci BigMike!) Cela a fonctionné parfaitement.

1
roblem

J'utilise cette classe particulière pour les erreurs Ajax

public class HttpStatusCodeResultWithJson : JsonResult
{
    private int _statusCode;
    private string _description;
    public HttpStatusCodeResultWithJson(int statusCode, string description = null)
    {
        _statusCode = statusCode;
        _description = description;
    }
    public override void ExecuteResult(ControllerContext context)
    {
        var httpContext = context.HttpContext;
        var response = httpContext.Response;
        response.StatusCode = _statusCode;
        response.StatusDescription = _description;
        base.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
        base.ExecuteResult(context);
    }
}

Le code d'état est un code d'état HTTP personnalisé et, dans une fonction d'erreur Ajax globale, je le teste comme suit:

MyNsp.ErrorAjax = function (xhr, st, str) {
        if (xhr.status == '418') {
            MyNsp.UI.Message("Warning: session expired!");
            return;
        }
        if (xhr.status == "419") {
            MyNsp.UI.Message("Security Token Missing");
            return;
        }
        var msg = 'Error: ' + (str ? str : xhr.statusText);
        MyNsp.UI.Message('Error. - status:' + st + "(" + msg + ")");
        return;
    };
1
BigMike