ASP.NET Core のアプリケーション モデルの使用

作成者: Steve Smith

ASP.NET Core MVC では、MVC アプリのコンポーネントを表す アプリケーション モデル を定義できます。 MVC 要素の動作を変更するには、このモデルを読み取り、操作します。 既定では、MVC は特定の規則に従って、コントローラーと見なされるクラス、それらのクラスのメソッドはアクション、およびパラメーターとルーティングの動作を決定します。 カスタム規則を作成してグローバルまたは属性として適用することで、アプリのニーズに合わせてこの動作をカスタマイズします。

モデルとプロバイダー ( IApplicationModelProvider )

ASP.NET Core mvc アプリケーションモデルには、mvc アプリケーションを記述する抽象インターフェイスと具象実装クラスの両方が含まれています。 このモデルは、既定の規則に従ってアプリのコントローラー、アクション、アクション パラメーター、ルート、およびフィルターを検出する MVC の結果です。 アプリケーションモデルを使用して、既定の MVC 動作とは異なる規則に従うようにアプリを変更します。 パラメーター、名前、ルート、およびフィルターは、すべてアクションおよびコントローラーの構成データとして使用されます。

ASP.NET Core MVC アプリケーション モデルの構造は、次のとおりです。

  • ApplicationModel
    • コントローラー (ControllerModel)
      • アクション (ActionModel)
        • パラメーター (ParameterModel)

このモデルでは、各レベルで、共通の Properties コレクションにアクセスできます。下位レベルでは、階層の上位レベルで設定されたプロパティ値にアクセスしたり上書きしたりできます。 このプロパティは、アクションの作成時、ActionDescriptor.Properties に保存されます。 そして要求の処理時に、規則によって追加または変更されたすべてのプロパティに、ActionContext.ActionDescriptor を介してアクセスできます。 プロパティの使用は、アクションごとにフィルター、モデルバインダー、およびその他のアプリモデルの側面を構成するための優れた方法です。

注意

コレクションは、 ActionDescriptor.Properties アプリの起動後にスレッドセーフ (書き込み用) ではありません。 このコレクションにデータを安全に追加するには、規則が最善の方法です。

ASP.NET CoreMVC は、インターフェイスによって定義されたプロバイダーパターンを使用して、アプリケーションモデルを読み込み IApplicationModelProvider ます。 このセクションでは、このプロバイダーがどのように機能するかについての、いくつかの内部実装に関する詳細を説明します。 プロバイダーパターンの使用は高度なテーマであり、主にフレームワークで使用されます。 ほとんどのアプリでは、プロバイダーパターンではなく、規約を使用する必要があります。

インターフェイスの実装 IApplicationModelProvider では、各実装が OnProvidersExecuting そのプロパティに基づいて昇順にを呼び出して、相互にラップし Order ます。 次いで、OnProvidersExecuted メソッドが逆順で呼び出されます。 このフレームワークでは、次のいくつかのプロバイダーが定義されます。

1 番目 (Order=-1000):

  • DefaultApplicationModelProvider

次 (Order=-990):

  • AuthorizationApplicationModelProvider
  • CorsApplicationModelProvider

注意

の同じ値を持つ2つのプロバイダーが呼び出される順序は定義されていないため、 Order 依存することはできません。

注意

IApplicationModelProvider は、フレームワークの作成者が拡張する高度な概念です。 一般に、アプリは規約を使用する必要があり、フレームワークではプロバイダーを使用する必要があります。 重要な違いは、プロバイダーは常に規則の前に実行されるということです。

DefaultApplicationModelProvider は ASP.NET Core MVC で使用される多数の既定の動作を確立します。 次の役割があります。

  • コンテキストにグローバル フィルターを追加する
  • コンテキストにコントローラーを追加する
  • アクションとしてパブリック コントローラー メソッドを追加する
  • コンテキストにアクション メソッド パラメーターを追加する
  • ルートおよびその他の属性を適用する

いくつかの組み込みの動作は、DefaultApplicationModelProvider によって実装されます。 このプロバイダーは、、、およびの各インスタンスを参照するを構築する役割を担い ControllerModel ActionModel PropertyModel ParameterModel ます。 クラスは、 DefaultApplicationModelProvider 今後変更される可能性がある内部フレームワークの実装の詳細です。

AuthorizationApplicationModelProvider は、AuthorizeFilter 属性および AllowAnonymousFilter 属性に関連付けられた動作を適用します。 詳細については、「ASP.NET Core での単純な ASP.NET Core」を参照してください。

は、 CorsApplicationModelProvider およびに関連付けられている動作を実装し IEnableCorsAttribute IDisableCorsAttribute ます。 詳細については、「ASP.NET Core でクロスオリジン要求 (CORS) を有効にする」を参照してください。

このセクションで説明するフレームワークの内部プロバイダーに関する情報は、 .NET API ブラウザーでは使用できません。 ただし、プロバイダーはASP.NET Core 参照ソース (dotnet/aspnetcore GitHub リポジトリ)で検査できます。 GitHub 検索を使用して名前でプロバイダーを検索し、[分岐/タグの切り替え] ボックスの一覧でソースのバージョンを選択します。

規約

このアプリケーション モデルでは、モデルまたはプロバイダー全体をオーバーライドするよりも簡単に、モデルの動作をカスタマイズできる、規則の抽象化を定義できます。 これらの抽象化は、アプリの動作を変更するために推奨される方法です。 規則は、カスタマイズを動的に適用するコードを記述する方法を提供します。 フィルターはフレームワークの動作を変更する手段を提供しますが、カスタマイズによって、アプリ全体の動作を制御できます。

次の規則があります。

規則を適用するには、それらを MVC オプションに追加するか、属性を実装してコントローラー、アクション、またはアクションパラメーターに適用します ( フィルターに似ています)。フィルターとは異なり、規則は、各要求の一部としてではなく、アプリの開始時にのみ実行されます。

注意

Razorページルートとアプリケーションモデルプロバイダーの規則の詳細については、「」を参照してください ASP.NET Core での Razor ページのルートとアプリの規則

を変更します。 ApplicationModel

アプリケーションモデルにプロパティを追加するには、次の規則を使用します。

using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace AppModelSample.Conventions
{
    public class ApplicationDescription : IApplicationModelConvention
    {
        private readonly string _description;

        public ApplicationDescription(string description)
        {
            _description = description;
        }

        public void Apply(ApplicationModel application)
        {
            application.Properties["description"] = _description;
        }
    }
}

アプリケーションモデルの規則は、MVC がに追加されたときのオプションとして適用され Startup.ConfigureServices ます。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Conventions.Add(new ApplicationDescription("My Application Description"));
        options.Conventions.Add(new NamespaceRoutingConvention());
    });
}

プロパティは、 ActionDescriptor.Properties コントローラーアクション内のコレクションからアクセスできます。

public class AppModelController : Controller
{
    public string Description()
    {
        return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
    }
}

説明を変更する ControllerModel

コントローラーモデルには、カスタムプロパティを含めることもできます。 カスタムプロパティは、アプリケーションモデルで指定されている名前と同じ名前を持つ既存のプロパティをオーバーライドします。 次の規則属性では、コントローラー レベルで説明が追加されます。

using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace AppModelSample.Conventions
{
    public class ControllerDescriptionAttribute : Attribute, IControllerModelConvention
    {
        private readonly string _description;

        public ControllerDescriptionAttribute(string description)
        {
            _description = description;
        }

        public void Apply(ControllerModel controllerModel)
        {
            controllerModel.Properties["description"] = _description;
        }
    }
}

この規則は、コントローラーの属性として適用されます。

[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
    public string Index()
    {
        return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
    }

説明を変更する ActionModel

個別のアクションには、アプリケーションレベルまたはコントローラーレベルで既に適用されている動作をオーバーライドすることによって、個別の属性規則を適用できます。

using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace AppModelSample.Conventions
{
    public class ActionDescriptionAttribute : Attribute, IActionModelConvention
    {
        private readonly string _description;

        public ActionDescriptionAttribute(string description)
        {
            _description = description;
        }

        public void Apply(ActionModel actionModel)
        {
            actionModel.Properties["description"] = _description;
        }
    }
}

コントローラー内のアクションにこれを適用すると、コントローラーレベルの規則がどのようにオーバーライドされるかが示されます。

[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
    public string Index()
    {
        return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
    }

    [ActionDescription("Action Description")]
    public string UseActionDescriptionAttribute()
    {
        return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
    }
}

を変更します。 ParameterModel

次の規則をアクション パラメーターに適用して、BindingInfo を変更することができます。 次の規則では、パラメーターがルートパラメーターである必要があります。 クエリ文字列値など、その他の潜在的なバインドソースは無視されます。

using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;

namespace AppModelSample.Conventions
{
    public class MustBeInRouteParameterModelConvention : Attribute, IParameterModelConvention
    {
        public void Apply(ParameterModel model)
        {
            if (model.BindingInfo == null)
            {
                model.BindingInfo = new BindingInfo();
            }
            model.BindingInfo.BindingSource = BindingSource.Path;
        }
    }
}

この属性は、任意のアクション パラメーターに適用できます。

public class ParameterModelController : Controller
{
    // Will bind:  /ParameterModel/GetById/123
    // WON'T bind: /ParameterModel/GetById?id=123
    public string GetById([MustBeInRouteParameterModelConvention]int id)
    {
        return $"Bound to id: {id}";
    }
}

すべてのアクションパラメーターに規則を適用するには、の MustBeInRouteParameterModelConvention をに追加し MvcOptions Startup.ConfigureServices ます。

options.Conventions.Add(new MustBeInRouteParameterModelConvention());

名前を変更する ActionModel

次の規則は、ActionModel が適用されるアクションの 名前 を更新してそれを変更します。 この新しい名前は、属性にパラメーターとして提供されます。 この新しい名前はルーティングによって使用されるため、このアクションメソッドに到達するために使用されるルートに影響します。

using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace AppModelSample.Conventions
{
    public class CustomActionNameAttribute : Attribute, IActionModelConvention
    {
        private readonly string _actionName;

        public CustomActionNameAttribute(string actionName)
        {
            _actionName = actionName;
        }

        public void Apply(ActionModel actionModel)
        {
            // this name will be used by routing
            actionModel.ActionName = _actionName;
        }
    }
}

この属性は、HomeController のアクション メソッドに適用されます。

// Route: /Home/MyCoolAction
[CustomActionName("MyCoolAction")]
public string SomeName()
{
    return ControllerContext.ActionDescriptor.ActionName;
}

メソッド名は SomeName ですが、このメソッド名を使用する MVC 規則をこの属性はオーバーライドし、アクション名を MyCoolAction に置換します。 したがって、このアクションに到達するのに使用されるルートは、/Home/MyCoolAction です。

注意

このセクションのこの例は、基本的に組み込みを使用する場合と同じです ActionNameAttribute

カスタムルーティング規則

を使用して、 IApplicationModelConvention ルーティングの動作をカスタマイズします。 たとえば、次の規則では、コントローラーの名前空間をルートに組み込み、 . 名前空間内のを / ルートに置き換えます。

using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Linq;

namespace AppModelSample.Conventions
{
    public class NamespaceRoutingConvention : IApplicationModelConvention
    {
        public void Apply(ApplicationModel application)
        {
            foreach (var controller in application.Controllers)
            {
                var hasAttributeRouteModels = controller.Selectors
                    .Any(selector => selector.AttributeRouteModel != null);

                if (!hasAttributeRouteModels
                    && controller.ControllerName.Contains("Namespace")) // affect one controller in this sample
                {
                    // Replace the . in the namespace with a / to create the attribute route
                    // Ex: MySite.Admin namespace will correspond to MySite/Admin attribute route
                    // Then attach [controller], [action] and optional {id?} token.
                    // [Controller] and [action] is replaced with the controller and action
                    // name to generate the final template
                    controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel()
                    {
                        Template = controller.ControllerType.Namespace.Replace('.', '/') + "/[controller]/[action]/{id?}"
                    };
                }
            }

            // You can continue to put attribute route templates for the controller actions depending on the way you want them to behave
        }
    }
}

規則は、のオプションとして追加され Startup.ConfigureServices ます。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Conventions.Add(new ApplicationDescription("My Application Description"));
        options.Conventions.Add(new NamespaceRoutingConvention());
    });
}

ヒント

MvcOptions 次の方法を使用して、ミドルウェアに規則を追加します。 {CONVENTION}プレースホルダーは、次のように追加する規則です。

services.Configure<MvcOptions>(c => c.Conventions.Add({CONVENTION}));

次の例では、コントローラーの名前に属性ルーティングを使用していないルートに規則を適用し Namespace ます。

using Microsoft.AspNetCore.Mvc;

namespace AppModelSample.Controllers
{
    public class NamespaceRoutingController : Controller
    {
        // using NamespaceRoutingConvention
        // route: /AppModelSample/Controllers/NamespaceRouting/Index
        public string Index()
        {
            return "This demonstrates namespace routing.";
        }
    }
}

でのアプリケーションモデルの使用 WebApiCompatShim

ASP.NET Core MVC と ASP.NET Web API 2 とでは使用する規則のセットが異なります。 カスタム規則を使用すると、web API アプリの動作と一貫性を持つように ASP.NET Core MVC アプリの動作を変更できます。 Microsoft は、この目的に特化した WebApiCompatShim NuGet パッケージを提供しています。

注意

ASP.NET Web API からの移行の詳細については、「」を参照してください ASP.NET Web API から ASP.NET Core への移行

Web API Compatibility Shim を使用するには:

  • パッケージを Microsoft.AspNetCore.Mvc.WebApiCompatShim プロジェクトに追加します。
  • で を呼び出して、MVC に規則を AddWebApiConventions 追加します Startup.ConfigureServices
services.AddMvc().AddWebApiConventions();

Shim が提供するこの規則は、それに特定の属性が適用されたアプリの一部にのみ適用されます。 次の 4 つの属性は、Shim の規則でどのコントローラーが規則を変更する必要があるかを制御するために使用されます。

アクション規則

UseWebApiActionConventionsAttribute は、HTTP メソッドを名前に基づいてアクションにマップするために使用されます (たとえば、 Get は にマップされます HttpGet )。 これは、属性のルーティングを使用しないアクションにのみ適用されます。

オーバーロード

UseWebApiOverloadingAttribute は規則を適用するために使用 WebApiOverloadingApplicationModelConvention されます。 この規則は、アクションの選択プロセスに OverloadActionConstraint を追加します。これによって、候補のアクションは、要求で省略可能でないすべてのパラメーターが満たされるものに制限されます。

パラメーター規則

UseWebApiParameterConventionsAttribute は、アクション規則を適用 WebApiParameterConventionsApplicationModelConvention するために使用されます。 この規則では、アクション パラメーターとして使用される単純な型は、要求本文からバインドされる複雑な型に対し、既定で URI からバインドされることが指定されます。

ルート

UseWebApiRoutesAttribute は、コントローラー規則 WebApiApplicationModelConvention が適用されるかどうかを制御します。 有効にすると、この規則は、ルートにエリアのサポートを追加するために使用され、コントローラーがエリア内に含まれるかどうかを示 api します。

一連の規則に加えて、互換性パッケージには、Web API によって提供される基本クラスを置き System.Web.Http.ApiController 換える基本クラスが含まれています。 これにより、Web API 用に記述され、 から継承された Web API コントローラーは、MVC での実行中に動作 ASP.NET Core ApiController できます。 前に示 UseWebApi* した属性はすべて、基本コントローラー クラスに適用されます。 は、Web API で検出されたプロパティ、メソッド、および結果型と互換性 ApiController のある型を公開します。

ApiExplorer 使用してアプリを文書化する

このアプリケーション モデルは、アプリの構造をスキャンするために使用できる ApiExplorerModel プロパティを各レベルで公開します。 これは 、Swagger のようなツールを使用して Web API のヘルプ ページを生成するために使用できます。 プロパティは、アプリのモデルの公開する部分を指定するために設定できる ApiExplorer IsVisible プロパティを公開します。 規則を使用してこの設定を構成します。

using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace AppModelSample.Conventions
{
    public class EnableApiExplorerApplicationConvention : IApplicationModelConvention
    {
        public void Apply(ApplicationModel application)
        {
            application.ApiExplorer.IsVisible = true;
        }
    }
}

この方法 (および必要に応じて追加の規則) を使用すると、アプリ内の任意のレベルで API の可視性が有効または無効になります。