ASP.NET Core MVC はグローバル ルーティング プレフィックスを構成します
はじめに
皆さんこんにちは。今日は、グローバル ルーティングに統一プレフィックスを追加する ASP.NET Core MVC の新機能を紹介します。厳密に言えば、これは新しい機能ではありませんが、Core MVC に固有の機能です。
アプリケーションの背景
Web API アプリケーションを作成しているときに、このシナリオに遭遇したことがあるかどうかはわかりません。つまり、すべてのインターフェイスが /api で始まり、API インターフェイスのリクエスト アドレスは次のようになります。
http://www.example.com/api/order/333
またはそのような要件
http://www.example.com/api/v2/order/333
以前は、この要件を達成したい場合は、[Route("/api/order")] のようなルーティング属性をコントローラーに追加すると、MVC フレームワークがルーティング テーブルをスキャンして /api/ order のようなリクエストと一致します。
しかし、2 番目の要件はバージョン番号を持つことです。元のコントローラーのルート定義は [Route("/api/v1/order")] であり、v2 にアップグレードする必要があります。 1 つの変更が必要です。混乱を引き起こす可能性があります。
これを行うための、よりシンプルで洗練された方法があります。以下を見てみましょう。
IApplicationModelConvention インターフェイス
まず、Microsoft.AspNetCore.Mvc.ApplicationModels 名前空間にある IApplicationModelConvention インターフェイスを使用する必要があります。インターフェイスの定義を見てみましょう。
public interface IApplicationModelConvention { void Apply(ApplicationModel application); }
MVC フレームワークにはいくつかの規則があることがわかっているため、このインターフェイスは主に、いくつかの MVC 規則をカスタマイズするために使用されます。ApplicationModel オブジェクトを指定することで、いくつかの規則を追加または変更できます。インターフェイスが ApplicationModel オブジェクトを持った apply メソッドを提供していることがわかります。このオブジェクトを使用して必要なものを変更できます。MVC フレームワーク自体がサービスの開始時にこのインターフェイスを挿入するため、このインターフェイスを実装するだけで済みます。わずかに設定できます。
次に、ApplicationModel オブジェクトが持つものを見てみましょう:
public class ApplicationModel : IPropertyModel, IFilterModel, IApiExplorerModel { public ApiExplorerModel ApiExplorer { get; set; } public IList<ControllerModel> Controllers { get; } public IList<IFilterMetadata> Filters { get; } public IDictionary<object, object> Properties { get; } }
ApiExplorer、Controllers、Filters、Properties などのプロパティがあることがわかります。
ApiExplorerModel: 主に、API 説明情報、グループ情報、可視性など、デフォルトの MVC API エクスプローラーの一部を構成します。
ControllerModel: 主に Comtroller のデフォルトの規則に関連するものです。これには多くのものが含まれるため、後でその中の 1 つを設定します。
IFilterMetadata: 空のインターフェイス。主にマーカーとして使用されます。
もう 1 つお伝えしなければならないことは、上記の Controllers プロパティが IList
次に、この機能を使用して今日のテーマを実装します。高評価ありがとうございます~ :)
グローバルルーティングに統一プレフィックスを追加してください
これ以上ナンセンスは必要ありません。コードに直接アクセスしてください。言いたいことはすべてコードの中にあります:
//定义个类RouteConvention,来实现 IApplicationModelConvention 接口 public class RouteConvention : IApplicationModelConvention { private readonly AttributeRouteModel _centralPrefix; public RouteConvention(IRouteTemplateProvider routeTemplateProvider) { _centralPrefix = new AttributeRouteModel(routeTemplateProvider); } //接口的Apply方法 public void Apply(ApplicationModel application) { //遍历所有的 Controller foreach (var controller in application.Controllers) { // 已经标记了 RouteAttribute 的 Controller var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); if (matchedSelectors.Any()) { foreach (var selectorModel in matchedSelectors) { // 在 当前路由上 再 添加一个 路由前缀 selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix, selectorModel.AttributeRouteModel); } } // 没有标记 RouteAttribute 的 Controller var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList(); if (unmatchedSelectors.Any()) { foreach (var selectorModel in unmatchedSelectors) { // 添加一个 路由前缀 selectorModel.AttributeRouteModel = _centralPrefix; } } } } }
それから、このクラスは自分たちで定義しました。
public static class MvcOptionsExtensions { public static void UseCentralRoutePrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute) { // 添加我们自定义 实现IApplicationModelConvention的RouteConvention opts.Conventions.Insert(0, new RouteConvention(routeAttribute)); } }
最後に、Startup.cs ファイルに上記の拡張メソッドを追加するだけです。
public class Startup { public Startup(IHostingEnvironment env) { //... } public void ConfigureServices(IServiceCollection services) { //... services.AddMvc(opt => { // 路由参数在此处仍然是有效的,比如添加一个版本号 opt.UseCentralRoutePrefix(new RouteAttribute("api/v{version}")); }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //... app.UseMvc(); } }
このうち、opt.UseCentralRoutePrefix は上記で定義した拡張メソッドであり、ルーティング パラメーターはここでも利用できるため、たとえば、インターフェイスのバージョン番号を指定できます。この後、すべてのコントローラの RoteAttribute にこのプレフィックスが追加され、元のバージョン番号の要件が完全に解決されます。それらは次のようになります:
[Route("order")] public class OrderController : Controller { // 路由地址 : /api/v{version}/order/details/{id} [Route("details/{id}")] public string GetById(int id, int version) { //上面是可以接收到版本号的,返回 version 和 id return $"other resource: {id}, version: {version}"; } } public class ItemController : Controller { // 路由地址: /api/v{version}/item/{id} [Route("item/{id}")] public string GetById(int id, int version) { //上面是可以接收到版本号的,返回 version 和 id return $"item: {id}, version: {version}"; } }
概要
上記の太字の言葉は、誰もがそれを理解して適用できることを願っています。この例は実際のニーズにおける非常に小さなシナリオにすぎず、特定のプロジェクトにもいくつか存在するでしょう。実際、MVC フレームワークについては、設計上の考え方やスケーラビリティなど、理解する必要があることがたくさんあります。 ASP.NET Core に興味がある場合は、学習結果の一部をブログで定期的に共有しますので、フォローしてください。
この記事が皆さんのお役に立てれば幸いです。このサイトを応援していただきありがとうございます!
ASP.NET Core MVC のグローバル ルーティング プレフィックスの構成に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。