web-dev-qa-db-ja.com

MVCとASP.NetCoreを使用した動的URL書き換え

FragSwapper.com Webサイト(現在はAsp 2.0)をASP.NetCoreとMVC6で書き直していますが、通常はURL再書き込みツールとdbコードを分割する必要があることを実行しようとしています。いくつかのリダイレクトがありますが、ASP.NetCoreでMVCルーティングとリダイレクトを使用してそれを行う「より良い」方法があるかどうかを知りたいです。

これが私のシナリオです...

  • RLサイトへのアクセス:[root]

    対処法:通常の[ホーム]コントローラーと[インデックス]ビュー([ID]なし)に移動します。 ...今これを行います:

    app.UseMvc(routes =>
    {
      routes.MapRoute(
      name: "default",
      template: "{controller=Home}/{action=Index}/{id?}");
    });
    
  • RLサイトへのアクセス:[root]/ControllerName/... yada yada ...

    対処法:コントローラーなどに移動します...これもすべて機能します。

  • トリッキーなもの:サイトにアクセスするURL:[root]/SomeString

    対処法:データベースにアクセスし、いくつかのロジックを実行して、イベントIDが見つかったかどうかを判断します。そうした場合は、[イベント]コントローラーと[インデックス]ビュー、および見つけたものの[ID]に移動します。そうでない場合は、ホストIDを見つけて、[ホーム]コントローラーと[組織]に移動し、見つけた[ID]を表示します。イベントまたはホストが見つからない場合は、通常の[ホーム]コントローラーと[インデックス]ビュー([ID]なし)に移動します。

ここでの大きな落とし穴は、2つの異なるコントローラーの3つの完全に異なるビューの1つにリダイレクトしたいということです。

つまり、ユーザーがサイトのルートにアクセスし、その上に単一の「/ Something」があり、そのロジックがデータベース駆動型である場合に、何らかのロジックを実行したいということです。

質問を理解した場合は、今すぐ読むのをやめることができます...このすべてのロジックが必要な理由を理解する必要があると感じた場合は、より詳細なコンテキストを読むことができます。

私のサイトには基本的に2つのモードがあります:イベントを表示するモードとイベントを表示しないモードです!通常、一度に4つまたは5つのイベントが実行されますが、ほとんどのユーザーは1つのイベントにしか関心がありませんが、4か月ごとに異なるイベントです。[ホスト]エンティティがあり、各ホストは1年に最大4つのイベントを開催します。 、 一つずつ。ほとんどのユーザーは、1つのホストのイベントのみを気にします。

マップを表示できる回数には制限があり(無料)、実際には必要ないため、ユーザーが常にイベントマップにアクセスしてイベントを見つけ、クリックすることを避けようとしています。ユーザーが私のサイトにいる時間の99.99%は、ホーム画面ではなくイベント画面にあり、一度に1つのイベントにしか関心がありません。将来的には、彼らが私のWebサイトにアクセスした場合に、お気に入りのホストからのイベントまたは新しいイベントに直接アクセスできるようにコーディングしたいと思います。これにより、多くのクリックを回避し、[ホーム]コントローラーページを初心者向けに集中させることができます...しかし、私はまだ自動ログインを機能させていないので、それは後回しになっています。

しかし今のところ、私はホストが常にイベントに対して同じURLを持っていることを望んでいます:FragSwapper.com/ [ホストの略語] ...そしてそれは常に4ヶ月ごとに異なるIDを持つ彼らの現在のイベントに行くことを知っています!!!

クレイジー...私は知っています...しかし、技術的には非常に簡単です。MVCで物事がどのように行われるかを適切に行う方法がわかりません。

11
Kevin Fizz

更新:ASP.Net Core 1.1

リリースノート によると、新しい RewriteMiddleware が作成されました。

これにより、いくつかの異なる事前定義された書き換えオプションとユーティリティ拡張メソッドが提供され、この回答で行われたように要求パスが変更される可能性があります。たとえば、 RewriteRule の実装を参照してください。

特にOPの質問については、独自のIRuleクラスを実装する必要があります(最初から、または正規表現に基づくRewriteRuleのような既存のクラスを拡張する)。 RewriteOptionsの新しいAddMyRule()拡張メソッドで補完することもできます。


独自の ミドルウェア を作成し、MVCルーティングの前にリクエストパイプラインに追加できます。

これにより、MVCルートが評価される前に、コードをパイプラインに挿入できます。このようにして、次のことができるようになります。

  1. 着信リクエストのパスを検査する
  2. データベースで同じ値のeventIdまたはhostIdを検索します
  3. イベントまたはホストが見つかった場合は、着信要求パスをEvent/Index/{eventId}またはHome/Organization/{hostId}に更新します。
  4. 次のミドルウェア(MVCルーティング)に要求を処理させます。以前のミドルウェアによって行われた要求パスへの変更が表示されます

たとえば、 独自に作成EventIdUrlRewritingMiddlewareミドルウェアは、データベース内のeventIdに対して着信要求パスを照合しようとします。一致すると、元のリクエストパスがEvent/Index/{eventId}に変更されます。

public class EventIdUrlRewritingMiddleware
{
    private readonly RequestDelegate _next;        

    //Your constructor will have the dependencies needed for database access
    public EventIdUrlRewritingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        var path = context.Request.Path.ToUriComponent();

        if (PathIsEventId(path))
        {
            //If is an eventId, change the request path to be "Event/Index/{path}" so it is handled by the event controller, index action
            context.Request.Path = "/Event/Index" + path;
        }

        //Let the next middleware (MVC routing) handle the request
        //In case the path was updated, the MVC routing will see the updated path
        await _next.Invoke(context);

    }

    private bool PathIsEventId(string path)
    {            
        //The real midleware will try to find an event in the database that matches the current path
        //In this example I am just using some hardcoded string
        if (path == "/someEventId")
        {
            return true;
        }

        return false;
    }
}

次に、同じアプローチに従って別のクラスHostIdUrlRewritingMiddlewareを作成します。

最後に、Startup.Configureメソッドでパイプラインに新しいミドルウェアを追加し、ルーティングおよびMVCミドルウェアの前に追加されていることを確認します。

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

この構成では:

  • /HomeController.Indexアクションに移動します
  • /Home/AboutHomeController.Aboutアクションに移動します
  • /Event/Index/1EventController.Indexアクションid = 1に移動します
  • /someEventIdEventController.Indexアクションに移動します、id = someEventId

Httpリダイレクトは含まれないことに注意してください。ブラウザで/someEventIdを開くと、単一のhttpリクエストがあり、ブラウザはアドレスバーに/someEventIdを表示します。 (内部的に元のパスが更新された場合でも)

21
Daniel J.G.