.net MVC Coreで動的エラーページを処理するにはどうすればよいですか?


8

現在私は持っています

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

元のパスからの相対パスにしたい。

たとえば

Tenant1 / PageThatThrowsError、次に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()を呼び出すことを許可しません。


これが役立つかどうかはわからないdocs.microsoft.com/en-us/aspnet/core/fundamentals/...
パトリックMcvay

デフォルトの例外ハンドラーによって呼び出されるエラーメソッドでリダイレクト(すべてのテナントにエラーページがあると仮定)を処理するか、上記のリンクのようにして動的に応答を作成できます。
Patrick Mcvay

エラーハンドラーは、エラーコードを渡すなど、箱から出してたくさんのことを行います。それがまだあり、動的にURLを設定できるのは素晴らしいことです。
マードック

アプリケーションはTenant1 / Home / ErrorとTenant2 / Home / Errorをリッスンしますか?
Alireza Mahmoudi

はい。しかし、問題はそれをルーティングすることです
Murdock

回答:


2

私たちは、アプリケーションが経路およびエンドポイントを必要としていると仮定/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");

それはtenantappsettingsのようなどこかから来ていると思います。次に、アクションに単純なルートを記述することにより、目的のエンドポイントで例外を簡単に取得できます。

[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 });
}

または、2つの異なるアクションを作成できます。

[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.csin 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);
    }
}

次のように、必要なものをコンテキストに追加できることに注意してくださいcontext.Request.HttpContext.Features.Set<Exception>(ex);

そして最後に、適切なルーティングを持つアクションを作成して、そこにロジックを記述します。

[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 });
}

ミドルウェアに設定されたオブジェクトを取得できるようになりました。


HttpContext.Features.Get <IExceptionHandlerPathFeature>()を使用して、エラーコントローラー内で使用できます。リダイレクトを使用すると、そのコンテキストが失われ、取得できなくなります。
Murdock

@マードック2番目のソリューションはどうですか?2番目のソリューションは機能しているようです。
Alireza Mahmoudi

テナントは動的であるため、ルートを静的に追加できません。
Murdock

ルートapp.UseExceptionHandler($"/{tenant}/Home/Error");は静的ではありません!の代わりにあなたが望むものを置くことができ{tenant}Route("/{TenantId}/Home/Error")]あなたのルートでそれらのすべてを聞くことができます。
Alireza Mahmoudi

わかりましたが、.netはapp.UseExceptionHandler($ "/ {tenant} / Home / Error")でルーティングするテナントをどのようにして知っていますか?質問は、エラーを発生させた着信URLからそれを推測する方法を尋ねます。
Murdock
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.