Bagikan melalui


Bekerja dengan model aplikasi di ASP.NET Core

Oleh Steve Smith

ASP.NET Core MVC mendefinisikan model aplikasi yang mewakili komponen aplikasi MVC. Baca dan manipulasi model ini untuk memodifikasi perilaku elemen MVC. Secara default, MVC mengikuti konvensi tertentu untuk menentukan kelas mana yang dianggap pengontrol, metode mana pada kelas tersebut adalah tindakan, dan bagaimana parameter dan perilaku perutean. Sesuaikan perilaku ini agar sesuai dengan kebutuhan aplikasi dengan membuat konvensi kustom dan menerapkannya secara global atau sebagai atribut.

Model dan Penyedia (IApplicationModelProvider)

Model aplikasi ASP.NET Core MVC mencakup antarmuka abstrak dan kelas implementasi konkret yang menjelaskan aplikasi MVC. Model ini adalah hasil dari MVC menemukan pengontrol, tindakan, parameter tindakan, rute, dan filter aplikasi sesuai dengan konvensi default. Dengan bekerja dengan model aplikasi, ubah aplikasi untuk mengikuti konvensi yang berbeda dari perilaku MVC default. Parameter, nama, rute, dan filter semuanya digunakan sebagai data konfigurasi untuk tindakan dan pengontrol.

Model Aplikasi MVC Inti ASP.NET memiliki struktur berikut:

  • ApplicationModel
    • Pengontrol (ControllerModel)
      • Tindakan (ActionModel)
        • Parameter (ParameterModel)

Setiap tingkat model memiliki akses ke koleksi umum Properties , dan tingkat yang lebih rendah dapat mengakses dan menimpa nilai properti yang diatur oleh tingkat yang lebih tinggi dalam hierarki. Properti dipertahankan saat ActionDescriptor.Properties tindakan dibuat. Kemudian ketika permintaan sedang ditangani, properti apa pun yang ditambahkan atau dimodifikasi konvensi dapat diakses melalui ActionContext.ActionDescriptor. Menggunakan properti adalah cara yang bagus untuk mengonfigurasi filter, pengikat model, dan aspek model aplikasi lainnya berdasarkan per tindakan.

Catatan

Koleksi ActionDescriptor.Properties tidak aman utas (untuk penulisan) setelah pengaktifan aplikasi. Konvensi adalah cara terbaik untuk menambahkan data dengan aman ke koleksi ini.

ASP.NET Core MVC memuat model aplikasi menggunakan pola penyedia, yang ditentukan oleh IApplicationModelProvider antarmuka. Bagian ini mencakup beberapa detail implementasi internal tentang bagaimana fungsi penyedia ini. Penggunaan pola penyedia adalah subjek tingkat lanjut, terutama untuk penggunaan kerangka kerja. Sebagian besar aplikasi harus menggunakan konvensi, bukan pola penyedia.

Implementasi antarmuka "bungkus IApplicationModelProvider " satu sama lain, di mana setiap implementasi memanggil OnProvidersExecuting dalam urutan naik berdasarkan propertinya Order . Metode OnProvidersExecuted ini kemudian dipanggil dalam urutan terbalik. Kerangka kerja mendefinisikan beberapa penyedia:

Pertama (Order=-1000):

  • DefaultApplicationModelProvider

Kemudian (Order=-990):

  • AuthorizationApplicationModelProvider
  • CorsApplicationModelProvider

Catatan

Urutan di mana dua penyedia dengan nilai yang sama untuk Order dipanggil tidak terdefinisi dan tidak boleh diandalkan.

Catatan

IApplicationModelProvider adalah konsep lanjutan untuk diperluas oleh penulis kerangka kerja. Secara umum, aplikasi harus menggunakan konvensi, dan kerangka kerja harus menggunakan penyedia. Perbedaan utamanya adalah bahwa penyedia selalu berjalan sebelum konvensi.

menetapkan DefaultApplicationModelProvider banyak perilaku default yang digunakan oleh ASP.NET Core MVC. Tanggung jawabnya meliputi:

  • Menambahkan filter global ke konteks
  • Menambahkan pengontrol ke konteks
  • Menambahkan metode pengontrol publik sebagai tindakan
  • Menambahkan parameter metode tindakan ke konteks
  • Menerapkan rute dan atribut lainnya

Beberapa perilaku bawaan diimplementasikan oleh DefaultApplicationModelProvider. Penyedia ini bertanggung jawab untuk membangun , yang pada gilirannya ControllerModelmereferensikan ActionModel, PropertyModel, dan ParameterModel instans. Kelas DefaultApplicationModelProvider ini adalah detail implementasi kerangka kerja internal yang dapat berubah di masa mendatang.

AuthorizationApplicationModelProvider bertanggung jawab untuk menerapkan perilaku yang terkait dengan AuthorizeFilter atribut dan AllowAnonymousFilter . Untuk informasi selengkapnya, lihat Otorisasi sederhana di ASP.NET Core.

Menerapkan CorsApplicationModelProvider perilaku yang terkait dengan IEnableCorsAttribute dan IDisableCorsAttribute. Untuk informasi selengkapnya, lihat Mengaktifkan Permintaan Lintas Asal (CORS) di ASP.NET Core.

Informasi tentang penyedia internal kerangka kerja yang dijelaskan di bagian ini tidak tersedia melalui browser .NET API. Namun, penyedia dapat diperiksa di sumber referensi ASP.NET Core (repositori GitHub dotnet/aspnetcore). Gunakan pencarian GitHub untuk menemukan penyedia berdasarkan nama dan pilih versi sumber dengan daftar dropdown Beralih cabang/tag .

Konvensi

Model aplikasi mendefinisikan abstraksi konvensi yang menyediakan cara yang lebih sederhana untuk menyesuaikan perilaku model daripada mengesampingkan seluruh model atau penyedia. Abstraksi ini adalah cara yang disarankan untuk memodifikasi perilaku aplikasi. Konvensi menyediakan cara untuk menulis kode yang menerapkan kustomisasi secara dinamis. Meskipun filter menyediakan sarana untuk memodifikasi perilaku kerangka kerja, penyesuaian mengizinkan kontrol atas cara kerja seluruh aplikasi.

Konvensi berikut tersedia:

Konvensi diterapkan dengan menambahkannya ke opsi MVC atau dengan menerapkan atribut dan menerapkannya ke pengontrol, tindakan, atau parameter tindakan (mirip dengan filter). Tidak seperti filter, konvensi hanya dijalankan saat aplikasi dimulai, bukan sebagai bagian dari setiap permintaan.

Catatan

Untuk informasi tentang Razor konvensi penyedia model aplikasi dan rute Halaman, lihat Razor Konvensi aplikasi dan rute halaman di ASP.NET Core.

Mengubah ApplicationModel

Konvensi berikut digunakan untuk menambahkan properti ke model aplikasi:

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

Konvensi model aplikasi diterapkan sebagai opsi ketika MVC ditambahkan dalam Startup.ConfigureServices:

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

Properti dapat diakses dari ActionDescriptor.Properties koleksi dalam tindakan pengontrol:

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

ControllerModel Mengubah deskripsi

Model pengontrol juga dapat menyertakan properti kustom. Properti kustom mengambil alih properti yang ada dengan nama yang sama yang ditentukan dalam model aplikasi. Atribut konvensi berikut menambahkan deskripsi di tingkat pengontrol:

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

Konvensi ini diterapkan sebagai atribut pada pengontrol:

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

ActionModel Mengubah deskripsi

Konvensi atribut terpisah dapat diterapkan ke tindakan individual, mengambil alih perilaku yang sudah diterapkan pada tingkat aplikasi atau pengontrol:

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

Menerapkan ini ke tindakan dalam pengontrol menunjukkan bagaimana tindakan ini mengambil alih konvensi tingkat pengontrol:

[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"];
    }
}

Mengubah ParameterModel

Konvensi berikut dapat diterapkan ke parameter tindakan untuk memodifikasi .BindingInfo Konvensi berikut mengharuskan parameter menjadi parameter rute. Sumber pengikatan potensial lainnya, seperti nilai string kueri, diabaikan:

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

Atribut dapat diterapkan ke parameter tindakan apa pun:

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}";
    }
}

Untuk menerapkan konvensi ke semua parameter tindakan, tambahkan ke MustBeInRouteParameterModelConvention MvcOptions di Startup.ConfigureServices:

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

ActionModel Mengubah nama

Konvensi berikut memodifikasi ActionModel untuk memperbarui nama tindakan yang diterapkannya. Nama baru disediakan sebagai parameter untuk atribut . Nama baru ini digunakan oleh perutean, sehingga memengaruhi rute yang digunakan untuk mencapai metode tindakan ini:

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

Atribut ini diterapkan ke metode tindakan dalam HomeController:

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

Meskipun nama metode adalah SomeName, atribut mengambil alih konvensi MVC menggunakan nama metode dan mengganti nama tindakan dengan MyCoolAction. Dengan demikian, rute yang digunakan untuk mencapai tindakan ini adalah /Home/MyCoolAction.

Catatan

Contoh ini di bagian ini pada dasarnya sama dengan menggunakan bawaan ActionNameAttribute.

Konvensi perutean kustom

IApplicationModelConvention Gunakan untuk menyesuaikan cara kerja perutean. Misalnya, konvensi berikut menggabungkan namespace pengontrol ke dalam rute mereka, mengganti . di namespace layanan dengan / dalam rute:

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
        }
    }
}

Konvensi ditambahkan sebagai opsi dalam Startup.ConfigureServices:

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

Tip

Tambahkan konvensi ke middleware melalui MvcOptions menggunakan pendekatan berikut. Tempat {CONVENTION} penampung adalah konvensi untuk menambahkan:

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

Contoh berikut menerapkan konvensi untuk rute yang tidak menggunakan perutean atribut di mana pengontrol atas Namespace namanya:

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.";
        }
    }
}

Penggunaan model aplikasi di WebApiCompatShim

ASP.NET Core MVC menggunakan serangkaian konvensi yang berbeda dari ASP.NET Web API 2. Dengan menggunakan konvensi kustom, Anda dapat memodifikasi perilaku aplikasi MVC Core ASP.NET agar konsisten dengan aplikasi API web. Microsoft mengirimkan WebApiCompatShim paket NuGet khusus untuk tujuan ini.

Catatan

Untuk informasi selengkapnya tentang migrasi dari ASP.NET Web API, lihat Migrasi dari ASP.NET Web API ke ASP.NET Core.

Untuk menggunakan Shim Kompatibilitas API Web:

  • Tambahkan paket Microsoft.AspNetCore.Mvc.WebApiCompatShim ke proyek.
  • Tambahkan konvensi ke MVC dengan memanggil AddWebApiConventions di Startup.ConfigureServices:
services.AddMvc().AddWebApiConventions();

Konvensi yang disediakan oleh shim hanya diterapkan pada bagian aplikasi yang memiliki atribut tertentu yang diterapkan pada mereka. Empat atribut berikut digunakan untuk mengontrol pengontrol mana yang harus memiliki konvensi yang dimodifikasi oleh konvensi shim:

Konvensi tindakan

UseWebApiActionConventionsAttribute digunakan untuk memetakan metode HTTP ke tindakan berdasarkan namanya (misalnya, Get akan memetakan ke HttpGet). Ini hanya berlaku untuk tindakan yang tidak menggunakan perutean atribut.

Kelebihan beban

UseWebApiOverloadingAttribute digunakan untuk menerapkan WebApiOverloadingApplicationModelConvention konvensi. Konvensi ini menambahkan OverloadActionConstraint ke proses pemilihan tindakan, yang membatasi tindakan kandidat untuk mereka yang permintaannya memenuhi semua parameter non-opsional.

Konvensi parameter

UseWebApiParameterConventionsAttribute digunakan untuk menerapkan WebApiParameterConventionsApplicationModelConvention konvensi tindakan. Konvensi ini menentukan bahwa jenis sederhana yang digunakan sebagai parameter tindakan terikat dari URI secara default, sementara jenis kompleks terikat dari isi permintaan.

Rute

UseWebApiRoutesAttribute mengontrol apakah WebApiApplicationModelConvention konvensi pengontrol diterapkan. Ketika diaktifkan, konvensi ini digunakan untuk menambahkan dukungan untuk area ke rute dan menunjukkan pengontrol berada di area tersebut api .

Selain serangkaian konvensi, paket kompatibilitas mencakup System.Web.Http.ApiController kelas dasar yang menggantikan yang disediakan oleh API web. Ini memungkinkan pengontrol API web Anda yang ditulis untuk API web dan mewarisinya ApiController agar berfungsi saat berjalan di ASP.NET Core MVC. Semua atribut yang UseWebApi* tercantum sebelumnya diterapkan ke kelas pengontrol dasar. Mengekspos ApiController properti, metode, dan jenis hasil yang kompatibel dengan yang ditemukan di API web.

Gunakan ApiExplorer untuk mendokumen aplikasi

Model aplikasi mengekspos ApiExplorerModel properti di setiap tingkat yang dapat digunakan untuk melintasi struktur aplikasi. Ini dapat digunakan untuk menghasilkan halaman bantuan untuk API web menggunakan alat seperti Swagger. Properti ApiExplorer mengekspos IsVisible properti yang dapat diatur untuk menentukan bagian mana dari model aplikasi yang harus diekspos. Konfigurasikan pengaturan ini menggunakan konvensi:

using Microsoft.AspNetCore.Mvc.ApplicationModels;

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

Menggunakan pendekatan ini (dan konvensi tambahan jika diperlukan), visibilitas API diaktifkan atau dinonaktifkan di tingkat apa pun dalam aplikasi.