Как обрабатывать динамические c страницы ошибок в. net MVC Core? - PullRequest
8 голосов
/ 23 марта 2020

В настоящее время у меня есть

app.UseExceptionHandler("/Home/Error");

Я хочу указать путь относительно исходного пути.

Например, если

Tenant1 / PageThatThrowsError then app .UseExceptionHandler ("Tenant1 / Home / Error");

, но если

Tenant2 / PageThatThrowsError, то app.UseExceptionHandler ("Tenant2 / Home / Error");

Я думал, что смогу сделать

app.UseExceptionHandler(
    new ExceptionHandlerOptions
    {
        ExceptionHandler = async (ctx) =>
        {
            //logic that extracts tenant
            ctx.Request.Path = new PathString(Invariant($"{tenant}/Home/Error"));
        }
    }
);

, но это выдает 500

РЕДАКТИРОВАТЬ: Все текущие решения, которые, например, используют перенаправления теряет текущий контекст ошибки и не позволяет контроллеру, например, вызвать HttpContext.Features.Get ().

1 Ответ

2 голосов
/ 26 марта 2020

Мы предполагаем, что приложению требуются маршруты и конечные точки /Tenant1/Home/Error и /Tenant2/Home/Error. Вы можете решить эту проблему, используя этот код:

app.UseExceptionHandler(
    new ExceptionHandlerOptions
    {
        ExceptionHandler = async (ctx) =>
        {
            string tenant = ctx.Request.Host.Value.Split('/')[0];
            ctx.Response.Redirect($"/{tenant}/Home/Error");
        },
    }
);

Другое эквивалентное решение - поместить следующий код в startup.cs:

app.UseExceptionHandler("$/{tenant}/Home/Error");

Мы предполагаем, что tenant происходит откуда-то как appsettings. Затем вы можете легко получить исключения для желаемой конечной точки, написав простой маршрут для вашего действия:

[Route("/{TenantId}/Home/Error")]
public IActionResult Error(string TenantId)
{
    string Id = TenantId;
    // Here you can write your logic and decide what to do based on TenantId
    return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

или вы можете создать два разных действия:

[Route("/Tenant1/Home/Error")]
public IActionResult Error()
{
    return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
[Route("/Tenant2/Home/Error")]
public IActionResult Error()
{
    return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

Обновление:

Если ваши арендаторы добавляются динамически и не могут быть включены в ваши appsettings.json (что мы и предполагали в приведенных выше решениях), вы можете написать промежуточное ПО для обработки Исключения, вот как:

Добавьте промежуточное ПО в свой метод Startup.cs in Configure:

app.UseMiddleware(typeof(ErrorHandlingMiddleware));

На следующей строке добавьте маршрут для ошибок (точно после промежуточное программное обеспечение):

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

Создайте класс для своего промежуточного программного обеспечения и добавьте следующий код:

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate next;
    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context /* other dependencies */)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex,this.next);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception ex, RequestDelegate next)
    {
        string tenant = "tenant1";//write your logic something like this: context.Request.Path.Value.Split('/')[0];
        context.Request.Path = new PathString($"/{tenant}/Home/Error");
        context.Request.HttpContext.Features.Set<Exception>(ex);// add any object you want to the context
        return next.Invoke(context);
    }
}

Обратите внимание, что вы можете добавить в контекст все, что захотите, например this: context.Request.HttpContext.Features.Set<Exception>(ex);.

И, наконец, вы должны создать действие с соответствующей маршрутизацией, чтобы записать туда свои логи c:

[Route("/{TenantId}/Home/Error")]
public IActionResult Error(string TenantId)
{
    string Id = TenantId;
    var exception= HttpContext.Features.Get<Exception>();// you can get the object which was set on the middle-ware
    return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}

Обратите внимание, что объект, который был установлен на промежуточное ПО, теперь можно получить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...