Обработка исключения в ядре asp.net?

У меня есть основное приложение asp.net. Реализация метода настройки перенаправляет пользователя на страницу «Ошибка» при возникновении исключения (в среде, отличной от среды разработки).

Однако это работает только в том случае, если исключение происходит внутри контроллера. Если исключение возникает вне контроллера, например, в моем настраиваемом промежуточном программном обеспечении, пользователь не перенаправляется на страницу ошибки.

Как перенаправить пользователя на страницу «Ошибка», если в промежуточном программном обеспечении есть исключение.

     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseStaticFiles();
        app.UseSession();
        app.UseMyMiddleware();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

Обновление 1
Я обновил код выше, добавив следующие две строки, которые отсутствовали в исходном сообщении.

        app.UseSession();
        app.UseMyMiddleware();

Также я выяснил, почему app.UseExceptionHandler не смог выполнить перенаправление на страницу с ошибкой.
Когда в моем коде промежуточного программного обеспечения возникает исключение, app.UseExceptionHandler("\Home\Error") перенаправляет на \Home\Error, как и ожидалось; но поскольку это новый запрос, мое промежуточное ПО снова выполнялось и снова генерировало исключение.
Итак, чтобы решить проблему, я изменил свое промежуточное ПО на выполнение только if context.Request.Path != "/Home/Error"

Я не уверен, что это правильный способ решить эту проблему, но он работает.

public class MyMiddleWare
{
    private readonly RequestDelegate _next;
    private readonly IDomainService _domainService;

    public MyMiddleWare(RequestDelegate next, IDomainService domain)
    {
        _next = next;
        _domainService = domain;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Path != "/Home/Error")
        {
            if (context.User.Identity.IsAuthenticated && !context.Session.HasKey(SessionKeys.USERINFO))
            {           
                // this method may throw exception if domain service is down
                var userInfo = await _domainService.GetUserInformation(context.User.Name).ConfigureAwait(false);                    

                context.Session.SetUserInfo(userInfo);
            }
        }

        await _next(context);
    }
}

public static class MyMiddleWareExtensions
{
    public static IApplicationBuilder UseMyMiddleWare(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleWare>();
    }
 }

person LP13    schedule 15.11.2016    source источник
comment
Где в примере находится ваше настраиваемое промежуточное ПО? Я думаю, что UseExeptionHandler сможет справиться с этим, но ваше промежуточное ПО необходимо зарегистрировать после этого.   -  person Tseng    schedule 15.11.2016


Ответы (2)


Вы можете использовать для обработки исключений UseExceptionHandler(), поместите этот код в свой Startup.cs.

UseExceptionHandler можно использовать для глобальной обработки исключений. Вы можете получить все детали объекта исключения, такие как трассировка стека, внутреннее исключение и другие. А затем вы можете показать их на экране. Здесь

Здесь вы можете узнать больше об этом диагностическом промежуточном программном обеспечении и узнать, как использовать IExceptionFilter и создать свой собственный обработчик исключений.

   app.UseExceptionHandler(
                options =>
                {
                    options.Run(
                        async context =>
                        {
                            context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
                            context.Response.ContentType = "text/html";
                            var ex = context.Features.Get<IExceptionHandlerFeature>();
                            if (ex != null)
                            {
                                var err = $"<h1>Error: {ex.Error.Message}</h1>{ex.Error.StackTrace}";
                                await context.Response.WriteAsync(err).ConfigureAwait(false);
                            }
                        });
                }
            );

Вы также должны удалить настройку по умолчанию, например UseDeveloperExceptionPage(), если вы ее используете, она всегда показывает страницу ошибок по умолчанию.

   if (env.IsDevelopment())
        {
            //This line should be deleted
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
person M. Wiśnicki    schedule 15.11.2016
comment
Я уже читал эту статью раньше. Однако я думаю, что проблема возникает всякий раз, когда вы устанавливаете response.StatusCode на 500, браузер не показывает html, который отправляет сервер, вместо этого браузер показывает свою собственную страницу ошибки для кода 500. В fiddler я вижу, что в теле ответа есть сообщение об ошибке, которое отправляет сервер, но браузер не показывает это сообщение об ошибке. - person LP13; 15.11.2016
comment
Просто удалите из startup.cs app.UseDeveloperExceptionPage (); - person M. Wiśnicki; 15.11.2016
comment
Кстати, я также создал настраиваемый атрибут фильтра исключений, производный от ExceptionFilterAttribute. Это позаботится обо всех исключениях внутри контроллера. Я ищу обработку исключений в промежуточном программном обеспечении. Даже если я обрабатываю глобально с помощью app.UseExceptionHandler или создаю собственное промежуточное ПО для обработки исключений, оно не перенаправляет пользователя на просмотр ошибок. - person LP13; 15.11.2016
comment
@ LP13 Вам нужно удалить app.UseDeveloperExceptionPage (); и будет работать. - person M. Wiśnicki; 15.11.2016
comment
Я не думаю, что проблема, как я сказал в своем сообщении, происходит в среде без разработки - person LP13; 15.11.2016
comment
можно ли использовать UseExceptionHandler со страницей ошибок по умолчанию? Я хочу фиксировать сведения об ошибках, но сохранить существующее поведение и страницы. - person Semen Shekhovtsov; 08.12.2016

Вам следует написать собственное промежуточное ПО для обработки пользовательской обработки исключений. И убедитесь, что вы добавили его в начало (если возможно, первым) вашего стека промежуточного программного обеспечения, потому что исключения, которые происходят в промежуточном программном обеспечении, которое находится «раньше» в стеке, не будут обрабатываться.

Пример:

public class CustomExceptionMiddleware
{
    private readonly RequestDelegate _next;

    public CustomExceptionMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try 
        {
            await _next.Invoke(context);
        } 
        catch (Exception e) 
        {
            // Handle exception
        }
    }
}
person Andrius    schedule 15.11.2016
comment
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware делает то же самое, что вы предложили. Это промежуточное ПО перенаправляет по указанному пути в случае исключения. Вы можете увидеть код github.com / aspnet / Diagnostics / blob / dev / src / - person LP13; 15.11.2016