ASP.NET MVC Ajax Помилка обробки


117

Як обробляти винятки, кинуті в контролер, коли jquery ajax викликає дію?

Наприклад, я хотів би отримати глобальний код JavaScript, який виконується на будь-якому винятку сервера під час виклику ajax, який відображає повідомлення про виключення, якщо він знаходиться в режимі налагодження або просто звичайне повідомлення про помилку.

На стороні клієнта я зателефоную на функцію помилки ajax.

Чи потрібно мені на стороні сервера написати спеціальний фільтр дій?


8
Дивіться беккельманський пост для гарного прикладу. Відповідь Даріна на цю публікацію хороша, але не встановлює правильний код статусу для помилки.
День

6
На жаль, це посилання зараз розірвано
Кріс Невіл

1
Ось посилання на зворотну машину: web.archive.org/web/20111011105139/http://beckelman.net/post/…
BruceHill

Відповіді:


161

Якщо сервер надсилає якийсь код статусу, відмінний від 200, виконується зворотний виклик помилки:

$.ajax({
    url: '/foo',
    success: function(result) {
        alert('yeap');
    },
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('oops, something bad happened');
    }
});

і щоб зареєструвати обробник глобальних помилок, ви можете використовувати $.ajaxSetup()метод:

$.ajaxSetup({
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert('oops, something bad happened');
    }
});

Ще один спосіб - використовувати JSON. Таким чином, ви можете написати спеціальний фільтр дій на сервері, який ловить виняток і перетворює їх у відповідь JSON:

public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
        filterContext.Result = new JsonResult
        {
            Data = new { success = false, error = filterContext.Exception.ToString() },
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    }
}

а потім прикрасьте свою дію контролера цим атрибутом:

[MyErrorHandler]
public ActionResult Foo(string id)
{
    if (string.IsNullOrEmpty(id))
    {
        throw new Exception("oh no");
    }
    return Json(new { success = true });
}

і нарешті викликати це:

$.getJSON('/home/foo', { id: null }, function (result) {
    if (!result.success) {
        alert(result.error);
    } else {
        // handle the success
    }
});

1
Дякую за це, Останнє було тим, що я шукав. Отже, для винятку asp.net mvc, чи є певний спосіб, коли мені потрібно його перекинути, щоб він міг потрапити в обробник помилок jquery?
Шон Мклін

1
@Lol-кодер, незалежно від того, як ви кинете виняток усередині дії контролера, сервер поверне 500 код статусу і errorзворотний виклик буде виконаний.
Дарин Димитров

Дякую, ідеально, саме те, що я шукав.
Шон Мклін

1
Чи не був би код статусу 500 неправильним? Процитуємо цей хлопець broadcast.oreilly.com/2011/06 / ... : «Будучи не в змозі зрозуміти , що 4xx засіб помилок я переплуталися і через 5xx означає , що ви зіпсували» - де я це клієнт , і ви це сервер.
Кріс Невілл

Ця відповідь все ще справедлива для новіших версій ASPNET?
гог

73

Після googling я записую просту передачу винятків на основі фільтра дій MVC:

public class HandleExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    filterContext.Exception.Message,
                    filterContext.Exception.StackTrace
                }
            };
            filterContext.ExceptionHandled = true;
        }
        else
        {
            base.OnException(filterContext);
        }
    }
}

і написати в global.ascx:

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
      filters.Add(new HandleExceptionAttribute());
 }

а потім напишіть цей скрипт на макет або головну сторінку:

<script type="text/javascript">
      $(document).ajaxError(function (e, jqxhr, settings, exception) {
                       e.stopPropagation();
                       if (jqxhr != null)
                           alert(jqxhr.responseText);
                     });
</script>

Нарешті, слід увімкнути спеціальну помилку. а потім насолоджуйтесь :)


Я бачу помилку в Firebug butIt не перенаправляє на сторінку Помилка.?
користувач2067567

1
Дякую за це! слід позначати як відповідь IMO як його фільтрацію за запитами ajax і успадковує правильний клас, а не те, що успадковує
HandleErrorAttribute

2
Чудова відповідь! : D
Леніел Маккаферрі

1
Я думаю, що "Request.IsAjaxRequest ()" іноді не такий надійний.
Буде Хуан

Для конфігурації налагодження вона завжди працює, але не працює завжди в конфігурації випуску і повертає html, а натомість у когось немає рішення для такого випадку?
Хітендра

9

На жаль, жодна з відповідей мені не підходить. Дивно рішення набагато простіше. Повернення від контролера:

return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);

І обробляйте це як стандартну помилку HTTP на клієнті, як вам подобається.


@Will Huang: назва екземпляра винятку
schmendrick

Я маю навести перший аргумент int. Також коли я це роблю, результат передається ajax successобробнику, а не errorобробнику. Це очікувана поведінка?
Джонатан Вуд

4

Я швидко вирішив, тому що мені не вистачало часу, і це спрацювало нормально. Хоча я думаю, що кращим варіантом є використання фільтра винятку, можливо, моє рішення може допомогти у тому випадку, якщо потрібне просте рішення.

Я зробив наступне. У методі контролера я повернув JsonResult із властивістю "Успіх" всередині даних:

    [HttpPut]
    public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave) 
    {
        if (!ModelState.IsValid)
        {
            return new JsonResult
            {
                Data = new { ErrorMessage = "Model is not valid", Success = false },
                ContentEncoding = System.Text.Encoding.UTF8,
                JsonRequestBehavior = JsonRequestBehavior.DenyGet
            };
        }
        try
        {
            MyDbContext db = new MyDbContext();

            db.Entry(employeToSave).State = EntityState.Modified;
            db.SaveChanges();

            DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];

            if (employeToSave.Id == user.Id)
            {
                user.Company = employeToSave.Company;
                user.Language = employeToSave.Language;
                user.Money = employeToSave.Money;
                user.CostCenter = employeToSave.CostCenter;

                Session["EmployeLoggin"] = user;
            }
        }
        catch (Exception ex) 
        {
            return new JsonResult
            {
                Data = new { ErrorMessage = ex.Message, Success = false },
                ContentEncoding = System.Text.Encoding.UTF8,
                JsonRequestBehavior = JsonRequestBehavior.DenyGet
            };
        }

        return new JsonResult() { Data = new { Success = true }, };
    }

Пізніше під час дзвінка в ajax я просто попросив цю власність знати, чи є у мене виняток:

$.ajax({
    url: 'UpdateEmployeeConfig',
    type: 'PUT',
    data: JSON.stringify(EmployeConfig),
    contentType: "application/json;charset=utf-8",
    success: function (data) {
        if (data.Success) {
            //This is for the example. Please do something prettier for the user, :)
            alert('All was really ok');                                           
        }
        else {
            alert('Oups.. we had errors: ' + data.ErrorMessage);
        }
    },
    error: function (request, status, error) {
       alert('oh, errors here. The call to the server is not working.')
    }
});

Сподіваюся, це допомагає. Щасливий код! : P


4

Відповідно до відповіді aleho, ось повний приклад. Це працює як шарм і дуже просто.

Код контролера

[HttpGet]
public async Task<ActionResult> ChildItems()
{
    var client = TranslationDataHttpClient.GetClient();
    HttpResponseMessage response = await client.GetAsync("childItems);

    if (response.IsSuccessStatusCode)
        {
            string content = response.Content.ReadAsStringAsync().Result;
            List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
            return Json(content, JsonRequestBehavior.AllowGet);
        }
        else
        {
            return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
        }
    }
}

Код Javascript у вікні перегляду

var url = '@Html.Raw(@Url.Action("ChildItems", "WorkflowItemModal")';

$.ajax({
    type: "GET",
    dataType: "json",
    url: url,
    contentType: "application/json; charset=utf-8",
    success: function (data) {
        // Do something with the returned data
    },
    error: function (xhr, status, error) {
        // Handle the error.
    }
});

Сподіваюсь, це допомагає комусь іншому!


0

Для обробки помилок з викликів ajax на стороні клієнта ви призначаєте функцію error опції виклику ajax.

Щоб встановити стандартний стандарт за замовчуванням, ви можете використовувати функцію, описану тут: http://api.jquery.com/jQuery.ajaxSetup .


Відповідь, яку я дав понад 4 роки тому, раптом отримує голос "за"? Комусь хочеться пояснити причину?
Брайан Балл

1
Зверніться до SOF та попросіть їхню DBA запитати, хто голосував проти. Далі, повідомте цю особу, щоб вони могли пояснити. Не просто хто може дати причину.
JoshYates1980
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.