ASP.NET Core'da Razor Pages'a Giriş

Rick Anderson, Dave Brock ve Kirk Larkin

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

Razor Pages, kod sayfası odaklı senaryoların denetleyici ve görünümleri kullanmaya kıyasla daha kolay ve daha üretken olmasını sağlayabilir.

Model-Görünüm-Denetleyici yaklaşımını kullanan bir öğretici arıyorsanız bkz. ASP.NET Core MVC'yi kullanmaya başlama.

Bu belgede Razor Pages'a giriş bilgileri sağlanır. Bu adım adım bir öğretici değildir. Bölümlerden bazılarının fazla ileri düzeyde olduğunu düşünüyorsanız, bkz. Razor Pages'ı kullanmaya başlama. ASP.NET Core'a genel bir bakış için bkz. ASP.NET Core'a giriş.

Önkoşullar

Razor Pages projesi oluşturma

Razor Pages projesi oluşturmaya yönelik ayrıntılı yönergeler için bkz. Razor Pages'ı kullanmaya başlama.

Razor Pages

Razor Pages Program.cs dosyasında etkinleştirilir:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Önceki kodda:

Temel bir sayfayı ele alalım:

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

Yukarıdaki kod, ASP.NET Core uygulamasında denetleyiciler ve görünümlerle kullanılan bir Razor görünüm dosyasına çok benzer. Bunu farklı kılan @page yönergesidir. @page dosyayı bir MVC eylemine dönüştürür. Bu da istekleri bir denetleyiciden geçmeden, doğrudan işlediği anlamına gelir. @page, sayfadaki ilk Razor yönergesi olmalıdır. @page diğer Razor yapılarının davranışını etkiler. Razor Pages dosya adlarının .cshtml soneki vardır.

Aşağıdaki iki dosyada PageModel sınıfının kullanıldığı benzer bir sayfa gösterilir. Pages/Index2.cshtml dosyası:

@page
@using RazorPagesIntro.Pages
@model Index2Model

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

Pages/Index2.cshtml.cs sayfa modeli:

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;

namespace RazorPagesIntro.Pages
{
    public class Index2Model : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }
}

Kural gereği PageModel sınıf dosyasının adı sonuna .cs eklenmiş Razor Sayfa dosyasının adıyla aynıdır. Örneğin yukarıdaki Razor Sayfası Pages/Index2.cshtml adını taşır. PageModel sınıfını içeren dosya Pages/Index2.cshtml.cs olarak adlandırılır.

URL yollarının sayfalarla ilişkileri, sayfanın dosya sistemindeki konumuna göre belirlenir. Aşağıdaki tabloda bir Razor Sayfa yolu ve eşleşen URL gösterilir:

Dosya adı ve yol eşleşen URL
/Pages/Index.cshtml / veya /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store veya /Store/Index

Notlar:

  • Çalışma zamanı Razor Pages dosyalarını varsayılan olarak Pages klasöründe arar.
  • URL bir sayfa içermediğinde varsayılan sayfa Index sayfasıdır.

Temel form yazma

Razor Pages, web tarayıcıları tarafından kullanılan yaygın desenlerin uygulama oluşturulurken kolayca uygulanmasını sağlamak için tasarlanmıştır. Model bağlama, Etiket Yardımcıları ve HTML yardımcıları, Razor Sayfa sınıfında tanımlanan özelliklerle çalışır. Contact modeli için temel bir "bize ulaşın" formu uygulayan bir sayfayı düşünün:

Bu belgedeki örnekler için , DbContext Program.cs dosyasında başlatılır.

Bellek içi veritabanı Microsoft.EntityFrameworkCore.InMemory NuGet paketini gerektirir.

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Veri modeli:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Models
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(10)]
        public string? Name { get; set; }
    }
}

Veritabanı bağlamı:

using Microsoft.EntityFrameworkCore;

namespace RazorPagesContacts.Data
{
    public class CustomerDbContext : DbContext
    {
        public CustomerDbContext (DbContextOptions<CustomerDbContext> options)
            : base(options)
        {
        }

        public DbSet<RazorPagesContacts.Models.Customer> Customer => Set<RazorPagesContacts.Models.Customer>();
    }
}

Pages/Customers/Create.cshtml görünüm dosyası:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>

Pages/Customers/Create.cshtml.cs sayfa modeli:

public class CreateModel : PageModel
{
    private readonly Data.CustomerDbContext _context;

    public CreateModel(Data.CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [BindProperty]
    public Customer? Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        if (Customer != null) _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

Kurala göre PageModel sınıfı <PageName>Model olarak adlandırılır ve sayfayla aynı ad alanında yer alır.

PageModel sınıfı, bir sayfanın mantığının sunumundan ayrılmasına olanak sağlar. Sayfaya gönderilen istekler için herhangi bir sayfa işleyicisini ve sayfayı işlemek için kullanılan verileri tanımlar. Bu ayrım şunları sağlar:

Sayfanın POST istekleri üzerinde çalıştırılan (kullanıcı formu gönderdiğinde) bir OnPostAsyncişleyici yöntemi vardır. Herhangi bir HTTP fiili için işleyici yöntemleri eklenebilir. En yaygın işleyiciler şunlardır:

  • Sayfa için gereken durumu başlatmak için OnGet. Yukarıdaki kodda OnGet yöntemi CreateModel.cshtmlRazor Sayfasını görüntüler.
  • Form gönderilerini işlemek için OnPost.

Async adlandırma son eki isteğe bağlıdır, ancak genellikle zaman uyumsuz işlevler için kural tarafından kullanılır. Yukarıdaki kod, Razor Pages için tipik bir koddur.

Denetleyicileri ve görünümleri kullanan ASP.NET uygulamalarını biliyorsanız:

  • Yukarıdaki örnekte yer alan OnPostAsync kodu tipik bir denetleyici koduna benzer.
  • Model bağlama, doğrulama ve eylem sonuçları gibi MVC temel öğelerinin çoğu, Denetleyiciler ve Razor Pages ile aynı şekilde çalışır.

Yukarıdaki OnPostAsync yöntemi:

[BindProperty]
public Customer? Customer { get; set; }

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    if (Customer != null) _context.Customer.Add(Customer);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

OnPostAsync temel akışı:

Doğrulama hatalarını denetleyin.

  • Hata yoksa, verileri kaydedin ve yeniden yönlendirin.
  • Hatalar varsa, doğrulama iletileriyle birlikte sayfayı yeniden gösterin. Çoğu durumda, doğrulama hataları istemci üzerinde algılanır ve sunucuya hiçbir zaman gönderilmez.

Pages/Customers/Create.cshtml görünüm dosyası:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>

Pages/Customers/Create.cshtml dosyasından işlenen HTML:

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input type="text" data-val="true"
           data-val-length="The field Name must be a string with a maximum length of 10."
           data-val-length-max="10" data-val-required="The Name field is required."
           id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
    <input type="submit" />
    <input name="__RequestVerificationToken" type="hidden"
           value="<Antiforgery token here>" />
</form>

Yukarıdaki kodda formu gönderme:

  • Geçerli verilerle:

    • OnPostAsync işleyici yöntemi RedirectToPage yardımcı yöntemini çağırır. RedirectToPage, bir RedirectToPageResult örneği döndürür. RedirectToPage:

      • Bir eylemin sonucudur.
      • RedirectToAction veya RedirectToRoute yöntemine benzer (denetleyicilerde ve görünümlerde kullanılır).
      • Sayfalar için özelleştirilir. Yukarıdaki örnekte kök Dizin sayfasına yeniden yönlendirir (/Index). RedirectToPage, Sayfalar için URL oluşturma bölümünde ayrıntılı olarak açıklanır.
  • Sunucuya geçirilen doğrulama hatalarıyla:

    • OnPostAsync işleyici yöntemi Page yardımcı yöntemini çağırır. Page, bir PageResult örneği döndürür. Döndürülen Page, denetleyicilerdeki eylemlerin View döndürmesine benzer. PageResult, işleyici yöntemi için varsayılan dönüş türüdür. void döndüren bir işleyici yöntemi sayfayı işler.
    • Yukarıdaki örnekte formu hiç değer olmadan göndermek ModelState.IsValid özelliğinin false döndürmesiyle sonuçlanır. Bu örnekte istemcide doğrulama hatası görüntülenmez. Doğrulama hatasının işlenmesi, bu belgenin ilerleyen bölümlerinde ele alınmıştır.
    [BindProperty]
    public Customer? Customer { get; set; }
    
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        if (Customer != null) _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • İstemci tarafı doğrulaması tarafından algılanan doğrulama hatalarıyla:

    • Veriler sunucuya gönderilmez.
    • İstemci tarafı doğrulaması, bu belgenin ilerleyen bölümlerinde açıklanmıştır.

Customer özelliği model bağlamayı kabul etmek için [BindProperty] özniteliğini kullanır:

[BindProperty]
public Customer? Customer { get; set; }

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    if (Customer != null) _context.Customer.Add(Customer);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

[BindProperty], istemi tarafından değiştirilmemesi gereken özelliklerin bulunduğu modellerde kullanılmamalıdır. Daha fazla bilgi için bkz. Aşırı gönderim.

Razor Pages varsayılan olarak özellikleri yalnızca GET dışındaki fiillerle bağlar. Özelliklere bağlama işlemi HTTP verilerini model türüne dönüştürmek üzere kod yazma gereğini ortadan kaldırır. Bağlama, form alanlarını işlemek ve girişi kabul etmek için aynı özelliği kullanarak (<input asp-for="Customer.Name">) kodu azaltır.

Uyarı

Güvenlik nedeniyle GET isteği verilerini sayfa modeli özelliklerine bağlamayı kabul etmeniz gerekir. Kullanıcı girişini özelliklere eşlemeden önce doğrulayın. Sorgu dizesi veya yönlendirme değerlerini kullanan senaryolarla ilgilenirken GET bağlamasını kabul etmek yararlı olur.

GET isteklerinde bir özelliği bağlamak için [BindProperty] özniteliğinin SupportsGet özelliğini true olarak ayarlayın:

[BindProperty(SupportsGet = true)]

Daha fazla bilgi için bkz. ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Pages/Customers/Create.cshtml görünüm dosyasını gözden geçirme:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>
  • Yukarıdaki kodda giriş etiketi yardımcısı<input asp-for="Customer.Name" /> HTML <input> öğesini Customer.Name model ifadesine bağlar.
  • @addTagHelper, Etiket Yardımcılarını kullanılabilir duruma getirir.

Giriş sayfası

Index.cshtml giriş sayfasıdır:

@page
@model RazorPagesContacts.Pages.Customers.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Contacts home page</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
        @if (Model.Customers != null)
        {
            foreach (var contact in Model.Customers)
            {
                <tr>
                    <td> @contact.Id </td>
                    <td>@contact.Name</td>
                    <td>
                        <!-- <snippet_Edit> -->
                        <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
                        <!-- </snippet_Edit> -->
                        <!-- <snippet_Delete> -->
                        <button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
                        <!-- </snippet_Delete> -->
                    </td>
                </tr>
            }
        }
        </tbody>
    </table>
    <a asp-page="Create">Create New</a>
</form>

İlişkili PageModel sınıfı (Index.cshtml.cs):

public class IndexModel : PageModel
{
    private readonly Data.CustomerDbContext _context;
    public IndexModel(Data.CustomerDbContext context)
    {
        _context = context;
    }

    public IList<Customer>? Customers { get; set; }

    public async Task OnGetAsync()
    {
        Customers = await _context.Customer.ToListAsync();
    }

    public async Task<IActionResult> OnPostDeleteAsync(int id)
    {
        var contact = await _context.Customer.FindAsync(id);

        if (contact != null)
        {
            _context.Customer.Remove(contact);
            await _context.SaveChangesAsync();
        }

        return RedirectToPage();
    }
}

Index.cshtml dosyası aşağıdaki işaretlemeyi içerir:

<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |

<a /a>Bağlayıcı Etiketi Yardımcısı Edit sayfasına bağlantı oluşturmak için asp-route-{value} özniteliğini kullanmıştır. Bağlantı, kişi kimliğiyle birlikte yönlendirme verilerini içerir. Örneğin, https://localhost:5001/Edit/1. Etiket Yardımcıları, Razor dosyalarında HTML öğelerinin oluşturulmasına ve işlenmesine sunucu tarafı kodun katılmasını etkinleştirir.

Index.cshtml dosyası her müşteri kişisi için bir sil düğmesi oluşturmaya yönelik işaretleme içerir:

<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>

İşlenen HTML:

<button type="submit" formaction="/Customers?id=1&amp;handler=delete">delete</button>

Sil düğmesi HTML'de işlendiğinde formaction öğesi şu parametreleri içerir:

  • asp-route-id özniteliğiyle belirtilen müşteri kişi kimliği.
  • asp-page-handler özniteliğiyle belirtilen handler.

Düğme seçildiğinde sunucuya bir form POST isteği gönderilir. Kurala göre işleyici yönteminin adı, OnPost[handler]Async şemasına uygun olarak handler parametresinin değeri temelinde seçilir.

Bu örnekte handlerdelete olduğundan, POST isteğini işlemek için OnPostDeleteAsync işleyici yöntemi kullanılır. asp-page-handler farklı bir değere ayarlanırsa (örneğin remove), OnPostRemoveAsync adlı bir işleyici yöntemi seçilir.

public async Task<IActionResult> OnPostDeleteAsync(int id)
{
    var contact = await _context.Customer.FindAsync(id);

    if (contact != null)
    {
        _context.Customer.Remove(contact);
        await _context.SaveChangesAsync();
    }

    return RedirectToPage();
}

OnPostDeleteAsync yöntemi:

  • Sorgu dizesinden id değerini alır.
  • FindAsync ile müşteri kişisi için veritabanını sorgular.
  • Müşteri kişisi bulunursa kaldırılır ve veritabanı güncelleştirilir.
  • Kök Dizin sayfasını (/Index) yeniden yönlendirmek için RedirectToPage yöntemini çağırır.

Edit.cshtml dosyası

@page "{id:int}"
@model RazorPagesContacts.Pages.Customers.EditModel

@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Customer</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Customer!.Id" />
            <div class="form-group">
                <label asp-for="Customer!.Name" class="control-label"></label>
                <input asp-for="Customer!.Name" class="form-control" />
                <span asp-validation-for="Customer!.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="./Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

İlk satır @page "{id:int}" yönergesini içerir. "{id:int}" yönlendirme kısıtlaması sayfaya int yönlendirme verilerini içeren istekleri kabul etmesini bildirir. Sayfaya yönelik istek int öğesine dönüştürülebilecek yönlendirme verilerini içermiyorsa, çalışma zamanı bir HTTP 404 (bulunamadı) hatası döndürür. Kimliği isteğe bağlı yapmak için yönlendirme kısıtlamasının sonuna ? ekleyin:

@page "{id:int?}"

Edit.cshtml.cs dosyası:

public class EditModel : PageModel
{
    private readonly RazorPagesContacts.Data.CustomerDbContext _context;

    public EditModel(RazorPagesContacts.Data.CustomerDbContext context)
    {
        _context = context;
    }

    [BindProperty]
    public Customer? Customer { get; set; }

    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        Customer = await _context.Customer.FirstOrDefaultAsync(m => m.Id == id);
        
        if (Customer == null)
        {
            return NotFound();
        }
        return Page();
    }

    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see https://aka.ms/RazorPagesCRUD.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        if (Customer != null)
        {
            _context.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CustomerExists(Customer.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
        }

        return RedirectToPage("./Index");
    }

    private bool CustomerExists(int id)
    {
        return _context.Customer.Any(e => e.Id == id);
    }
}

Doğrulama

Doğrulama kuralları:

  • Model sınıfında bildirim temelli olarak belirtilir.
  • Uygulamanın her yerinde zorlanır.

System.ComponentModel.DataAnnotations ad alanı, bir sınıfa veya özelliğe uygulanan bir dizi yerleşik doğrulama özniteliği sağlar. DataAnnotations biçimlendirmeye yardımcı olan ve hiçbir doğrulama sağlamayan [DataType] gibi biçimlendirme öznitelikleri de içerir.

Customer modelini ele alalım:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Models
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(10)]
        public string? Name { get; set; }
    }
}

Aşağıdaki Create.cshtml görünüm dosyasını kullanarak:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer!.Name"></span>
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

Yukarıdaki kod:

  • jQuery ve jQuery doğrulama betiklerini içerir.

  • <div /> ve <span />Etiket Yardımcılarını kullanarak şunları etkinleştirir:

    • İstemci tarafı doğrulaması.
    • Doğrulama hatası işleme.
  • Aşağıdaki HTML'yi oluşturur:

    <p>Enter a customer name:</p>
    
    <form method="post">
        Name:
        <input type="text" data-val="true"
               data-val-length="The field Name must be a string with a maximum length of 10."
               data-val-length-max="10" data-val-required="The Name field is required."
               id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
        <input type="submit" />
        <input name="__RequestVerificationToken" type="hidden"
               value="<Antiforgery token here>" />
    </form>
    
    <script src="/lib/jquery/dist/jquery.js"></script>
    <script src="/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
    

Ad değeri olmadan Create form gönderilmesi, formda "Ad alanı zorunludur." hata iletisinin görüntülenmesine neden olur. İstemcide JavaScript etkinleştirildiyse tarayıcı hatayı sunucuya göndermeden görüntüler.

[StringLength(10)] özniteliği işlenen HTML'de data-val-length-max="10" oluşturur. data-val-length-max, tarayıcıların belirtilen maksimum uzunluktan fazlasını girmesini önler. Gönderiyi düzenlemek ve yeniden yürütmek için Fiddler gibi bir araç kullanılırsa:

  • 10 karakterden uzun bir ad ile.
  • "Alan Adı uzunluk üst sınırı 10 olan bir dize olmalıdır." hata iletisi döndürülür.

Aşağıdaki Movie modeli ele alalım:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string Rating { get; set; }
    }
}

Doğrulama öznitelikleri, uygulandıkları model özelliklerinde zorlanacak davranışı belirtir:

  • Required ve MinimumLength öznitelikleri özelliğin bir değer olması gerektiğini belirtir ama kullanıcının bu doğrulamaya uymak için boşluk girmesi engellenemez.

  • RegularExpression özniteliği girilebilecek karakterleri sınırlamak için kullanılır. Yukarıdaki kodda "Genre":

    • Yalnızca harfleri kullanmalıdır.
    • İlk harfin büyük harf olması gerekir. Boşluk, sayı ve özel karakterlere izin verilmez.
  • RegularExpression "Rating":

    • İlk karakterin büyük harf olmasını gerektirir.
    • Sonraki alanlarda özel karakterlere ve sayılara izin verir. "PG-13" değeri Rating için geçerlidir ama "Genre" için başarısız olur.
  • Range özniteliği, bir değeri belirtilen bir aralık içinde kısıtlar.

  • StringLength özniteliği bir dize özelliğinin boyut üst sınırını ve isteğe bağlı olarak boyut alt sınırını ayarlar.

  • Değer türleri (decimal, int, float, DateTime gibi) doğal olarak gereklidir ve [Required] özniteliği gerekmez.

Movie modeli için Create page, geçersiz değerleri içeren hatalar görüntüler:

Birden çok jQuery istemci tarafı doğrulama hatası içeren Movie görünümü formu

Daha fazla bilgi için bkz.

CSS yalıtımı

Aşağıdakileri azaltmak veya önlemek için CSS stillerini tek tek sayfalara, görünümlere ve bileşenlere yalıtır:

  • Bakımı zor olabilen genel stillere bağımlılıklar.
  • İç içe yerleştirilmiş içerikte stil çakışmaları.

Bir sayfa veya görünüme kapsamlı CSS dosyası eklemek için CSS stillerini .cshtml dosyasının adıyla eşleşen bir yardımcı .cshtml.css dosyasına yerleştirir. Aşağıdaki örnekte, yalnızca Index.cshtml sayfası ya da görünümüne CSS stillerini sağlayan bir Index.cshtml.css dosyası bulunuyor.

Pages/Index.cshtml.css (Razor Pages) veya Views/Index.cshtml.css (MVC):

h1 {
    color: red;
}

CSS yalıtımı derleme zamanında gerçekleşir. Çerçeve, uygulamanın sayfaları veya görünümleri tarafından işlenen işaretlemeyle eşleşecek şekilde CSS seçicileri yeniden yazar. Yeniden yazılan CSS stilleri statik bir varlık ({APP ASSEMBLY}.styles.css) olarak paketlenir ve oluşturulur. {APP ASSEMBLY} yer tutucusu projenin derleme adıdır. Paketlenmiş CSS stillerinin bağlantısı uygulamanın düzenine yerleştirilir.

Uygulamanın Pages/Shared/_Layout.cshtml (Razor Pages) veya Views/Shared/_Layout.cshtml (MVC) dosyasının <head> içeriğinde, paketlenmiş CSS stillerinin bağlantısını ekleyin veya bağlantının mevcut olduğunu onaylayın:

<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />

Aşağıdaki örnekte uygulamanın derleme adı WebApp'tır:

<link rel="stylesheet" href="WebApp.styles.css" />

Kapsamlı CSS dosyasında tanımlanan stiller yalnızca eşleşen dosyanın işlenmiş çıkışına uygulanır. Yukarıdaki örnekte, uygulamanın başka bir yerinde tanımlanan h1 CSS bildirimlerinin hiçbiri Index başlık stiliyle çalışmaz. Kapsamlı CSS dosyaları için CSS stili basamaklandırma ve devralma kuralları etkin kalır. Örneğin doğrudan Index.cshtml dosyasındaki <h1> öğesine uygulanan stiller, Index.cshtml.css dosyasındaki kapsamlı CSS dosyası stillerini geçersiz kılar.

Not

Paketleme gerçekleşirken CSS stili yalıtımını garanti etmek için CSS'nin Razor kod bloklarına aktarılması desteklenmez.

CSS yalıtımı yalnızca HTML öğeleri için geçerlidir. CSS yalıtımı Etiket Yardımcıları için desteklenmez.

Paketlenmiş CSS dosyası içinde her sayfa, görünüm veya Razor bileşeni b-{STRING} biçiminde kapsam tanımlayıcısı ile ilişkilendirilir; burada {STRING} yer tutucusu, çerçeve tarafından oluşturulan on karakterli bir dizedir. Aşağıdaki örnek Razor Pages uygulamasının Index sayfasındaki önceki <h1> öğesi için stili sağlar:

/* /Pages/Index.cshtml.rz.scp.css */
h1[b-3xxtam6d07] {
    color: red;
}

Paketlenmiş dosyadan CSS stilinin uygulandığı Index sayfasında, kapsam tanımlayıcısı bir HTML özniteliği olarak eklenir:

<h1 b-3xxtam6d07>

Tanımlayıcı bir uygulama için benzersizdir. Derleme zamanında {STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css kuralıyla bir proje paketi oluşturulur; burada {STATIC WEB ASSETS BASE PATH} yer tutucusu, statik web varlıkları temel yoludur.

NuGet paketleri veya Razor sınıf kitaplıkları gibi başka projeler kullanılırsa, paketlenmiş dosya:

  • CSS içeri aktarmalarını kullanarak stillere başvurur.
  • Stilleri kullanan uygulamanın statik web varlığı olarak yayımlanmaz.

CSS ön işlemci desteği

CSS ön işlemcileri değişken, iç içe yerleştirme, modül, mixin ve devralma gibi özellikleri kullanarak CSS geliştirmeyi iyileştirmek için kullanışlıdır. CSS yalıtımı Sass veya Less gibi CSS ön işlemcilerini yerel olarak desteklemese de, ön işlemci derlemesi çerçevenin derleme işlemi sırasında CSS seçicileri yeniden yazmasından önce gerçekleştiği sürece, CSS ön işlemcileri sorunsuzca tümleştirilir. Örneğin Visual Studio'yu kullanarak mevcut ön işlemci derlemesini Visual Studio Görev Çalıştırıcı Gezgini'nde bir Derleme Öncesi görevi olarak yapılandırın.

AspNetCore.SassCompiler gibi birçok üçüncü taraf NuGet paketi SASS/SCSS dosyalarını CSS yalıtımı gerçekleşmeden önce, derleme işleminin başlangıcında derleyebilir ve ek yapılandırma gerekmez.

CSS yalıtımı yapılandırması

CSS yalıtımı bazı gelişmiş senaryolarda, örneğin mevcut araçlara veya iş akışlarına bağımlılıklar olduğunda yapılandırmaya izin verir.

Kapsam tanımlayıcısının biçimini özelleştirme

Bu bölümde {Pages|Views} yer tutucusu Razor Pages uygulamaları için Pages veya MVC uygulamaları için Views olur.

Varsayılan olarak kapsam tanımlayıcıları b-{STRING} biçimini kullanır; burada {STRING} yer tutucusu, çerçeve tarafından oluşturulan on karakterli bir dizedir. Kapsam tanımlayıcısının biçimini özelleştirmek için proje dosyasını istenen desene güncelleştirin:

<ItemGroup>
  <None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Yukarıdaki örnekte Index.cshtml.css için oluşturulan CSS, b-{STRING} olan kapsam tanımlayıcısını custom-scope-identifier olarak değiştirir.

Kapsamlı CSS dosyalarıyla devralma özelliği elde etmek için kapsam tanımlayıcılarını kullanın. Aşağıdaki proje dosyası örneğinde, BaseView.cshtml.css dosyası görünümler genelinde ortak olan stilleri içerir. DerivedView.cshtml.css dosyası bu stilleri devralır.

<ItemGroup>
  <None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" />
  <None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Kapsam tanımlayıcılarını birden çok dosyada paylaşmak için joker karakter (*) işlecini kullanın:

<ItemGroup>
  <None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" />
</ItemGroup>

Statik web varlıkları için temel yolu değiştirme

Kapsamlı CSS dosyası uygulamanın kökünde oluşturulur. Proje dosyasında varsayılan yolu değiştirmek için StaticWebAssetBasePath özelliğini kullanın. Aşağıdaki örnekte kapsamlı CSS dosyası ve uygulamanın kalan varlıkları _content yoluna yerleştirilir:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

Otomatik paketlemeyi devre dışı bırakma

Çerçevenin kapsamlı dosyaları çalışma zamanında yayımlamasını ve yüklemesini geri çevirmek için DisableScopedCssBundling özelliğini kullanın. Bu özelliği kullanırken, yalıtılmış CSS dosyalarını obj dizininden alma, çalışma zamanında bu dosyaları yayımlama ve yükleme görevleri diğer araçların veya işlemlerin sorumluluğundadır:

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

Razor sınıf kitaplığı (RCL) desteği

Razor sınıf kitaplığı (RCL) yalıtılmış stiller sağladığında, <link> etiketinin href özniteliği {STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css dosyasına işaret eder. Buradaki yer tutucular:

  • {STATIC WEB ASSET BASE PATH}: Statik web varlığı temel yolu.
  • {PACKAGE ID}: Kitaplığın paket tanımlayıcısı. Proje dosyasında paket tanımlayıcısı belirtilmezse, paket tanımlayıcısı varsayılan olarak projenin derleme adını alır.

Aşağıdaki örnekte:

  • Statik web varlığı temel yolu _content/ClassLib şeklindedir.
  • Sınıf kitaplığının derleme adı ClassLib şeklindedir.

Pages/Shared/_Layout.cshtml (Razor Pages) veya Views/Shared/_Layout.cshtml (MVC):

<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">

RCL'ler hakkında daha fazla bilgi için aşağıdaki makaleleri inceleyin:

Blazor CSS yalıtımı hakkında bilgi için bkz. ASP.NET Core Blazor CSS yalıtımı.

OnGet işleyici geri dönüşü ile HEAD isteklerini işleme

HEAD istekleri belirli bir kaynak için üst bilgileri almaya olanak tanır. GET isteklerinden farklı olarak HEAD istekleri bir yanıt gövdesi döndürmez.

Normal olarak HEAD istekleri için bir OnHead işleyicisi oluşturulur ve çağrılır:

public void OnHead()
{
    HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}

OnHead işleyicisi tanımlanmadıysa, Razor Pages OnGet işleyicisini çağırmaya geri döner.

XSRF/CSRF ve Razor Pages

Razor Pages Sahtecilik önleme doğrulaması ile korunur. FormTagHelper, HTML form öğelerine sahtecilik önleme belirteçleri ekler.

Razor Pages ile düzenleri, kısmi görünümleri, şablonları ve Etiket Yardımcılarını kullanma

Pages, Razor görünüm altyapısının tüm özellikleriyle çalışır. Düzenler, kısmi görünümler, şablonlar, Etiket Yardımcıları, _ViewStart.cshtml ve _ViewImports.cshtml geleneksel Razor görünümlerde olduğu gibi çalışır.

Şimdi bu özelliklerden bazılarından yararlanarak bu sayfanın karışıklığını azaltalım.

Pages/Shared/_Layout.cshtml dosyasına bir düzen sayfası ekleyin:

<!DOCTYPE html>
<html>
<head>
    <title>RP Sample</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body>
    <a asp-page="/Index">Home</a>
    <a asp-page="/Customers/Create">Create</a>
    <a asp-page="/Customers/Index">Customers</a> <br />

    @RenderBody()
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</body>
</html>

Düzen:

  • Her sayfanın düzenini denetler (sayfanın düzeni geri çevirmemiş olması koşuluyla).
  • JavaScript ve stil sayfaları gibi HTML yapılarını içeri aktarır.
  • @RenderBody() yönteminin çağrıldığı Razor sayfasının içeriği işlenir.

Daha fazla bilgi için bkz. Düzen sayfası.

Layout özelliği Pages/_ViewStart.cshtml içinde ayarlanır:

@{
    Layout = "_Layout";
}

Düzen, Pages/Shared klasöründe yer alır. Pages, geçerli sayfayla aynı klasörden başlayıp hiyerarşik olarak diğer görünümleri (düzenler, şablonlar, kısmi görünümler) arar. Pages/Shared klasöründeki düzen, Pages klasörünün altındaki herhangi bir Razor sayfasından kullanılabilir.

Düzen dosyası Pages/Shared klasöründe yer almalıdır.

Düzen dosyasını Views/Shared klasörüne koymamanızı öneririz. Views/Shared bir MVC görünümleri desenidir. Razor Pages'ın yok kurallarına değil klasör hiyerarşisine dayanması amaçlanmıştır.

Razor Sayfasından yapılan görünüm araması Pages klasörünü içerir. MVC denetleyicileri ve geleneksel Razor görünümleri ile kullanılan düzenler, şablonlar ve kısmi görünümler kullanılabilir.

Bir Pages/_ViewImports.cshtml dosyası ekleyin:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@namespace öğreticinin devamında açıklanmıştır. @addTagHelper yönergesi, Pages klasöründeki tüm sayfalara yerleşik Etiket Yardımcılarını getirir.

Sayfada ayarlanan @namespace yönergesi:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

@namespace yönergesi sayfa için ad alanını ayarlar. @model yönergesinin ad alanını içermesi gerekmez.

@namespace yönergesi _ViewImports.cshtml dosyasına eklendiğinde, belirtilen ad alanı @namespace yönergesini içeri aktaran Sayfada oluşturulan ad alanı için ön ek sağlar. Oluşturulan ad alanının kalan bölümü (sonek bölümü), _ViewImports.cshtml dosyasını içeren klasör ile sayfayı içeren klasör arasındaki noktayla ayrılmış göreli yoldur.

Örneğin PageModel sınıfı Pages/Customers/Edit.cshtml.cs açıkça ad alanını ayarlar:

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

Dosya Pages/_ViewImports.cshtml açıkça ad alanını ayarlar:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Pages/Customers/Edit.cshtmlRazor Sayfası için oluşturulan ad alanı PageModel sınıfı ile aynıdır.

@namespacegeleneksel Razor görünümleriyle de çalışır.

Pages/Customers/Create.cshtml görünüm dosyasını ele alalım:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer!.Name"></span>
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

_ViewImports.cshtml ve önceki düzen dosyasıyla güncelleştirilmiş Pages/Customers/Create.cshtml görünüm dosyası:

@page
@model CreateModel

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer!.Name" />
    <input type="submit" />
</form>

Yukarıdaki kodda _ViewImports.cshtml dosyası ad alanını ve Etiket Yardımcılarını içeri aktarmıştır. Düzen dosyası JavaScript dosyalarını içeri aktarmıştır.

Razor Pages başlangıç projesi, istemci tarafı doğrulaması ekleyen Pages/_ValidationScriptsPartial.cshtml dosyasını içerir.

Kısmi görünümler hakkında daha fazla bilgi için bkz. ASP.NET Core'da kısmi görünümler.

Sayfalar için URL oluşturma

Daha önce gösterilen Create sayfası RedirectToPage kullanır:

public class CreateModel : PageModel
{
    private readonly Data.CustomerDbContext _context;

    public CreateModel(Data.CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [BindProperty]
    public Customer? Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        if (Customer != null) _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

Uygulamanın dosya/klasör yapısı aşağıdaki gibidir:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

      • Create.cshtml
      • Edit.cshtml
      • Index.cshtml

Pages/Customers/Create.cshtml ve Pages/Customers/Edit.cshtml sayfaları başarılı olduktan sonra Pages/Customers/Index.cshtml konumuna yeniden yönlendirilir. ./Index dizesi önceki sayfaya erişmek için kullanılan göreli sayfa adıdır. Pages/Customers/Index.cshtml sayfasında URL'ler oluşturmak için kullanılır. Örneğin:

  • Url.Page("./Index", ...)
  • <a asp-page="./Index">Customers Index Page</a>
  • RedirectToPage("./Index")

Mutlak sayfa adı olan /Index, Pages/Index.cshtml sayfasına URL'ler oluşturmak için kullanılır. Örneğin:

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">Home Index Page</a>
  • RedirectToPage("/Index")

Sayfa adı, baştaki / ile birlikte /Pages kök klasöründen sayfaya giden yoldur (örneğin /Index). Yukarıdaki URL oluşturma örnekleri, URL'yi sabit kodlamaya göre daha gelişmiş seçenekler ve işlevsel özellikler sunar. URL oluşturma işleminde yönlendirme kullanılır ve hedef yolda yönlendirmenin nasıl tanımlandığına göre parametreler oluşturulabilir ve kodlanabilir.

Sayfalar için URL oluşturma işleminde göreli adlar desteklenir. Aşağıdaki tabloda, Pages/Customers/Create.cshtml dosyasında farklı RedirectToPage parametreleri kullanılarak hangi Dizin sayfasının seçildiği gösterilir.

RedirectToPage(x) Sayfa
RedirectToPage("/Index") Pages/Index
RedirectToPage("./Index"); Pages/Customers/Index
RedirectToPage("../Index") Pages/Index
RedirectToPage("Index") Pages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index") ve RedirectToPage("../Index")göreli adlardır. Hedef sayfanın adını hesaplamak için RedirectToPage parametresi geçerli sayfanın yoluyla birleştirilir.

Karmaşık bir yapıya sahip siteler oluştururken göreli ad bağlama yararlı olur. Klasördeki sayfalar arasında bağlantı oluşturmak için göreli adlar kullanıldığında:

  • Klasörün yeniden adlandırılması göreli bağlantıları kesmez.
  • Bağlantılar klasör adını içermedikleri için kesilmez.

Sayfayı farklı bir Area hedefine yönlendirmek için alanı belirtin:

RedirectToPage("/Index", new { area = "Services" });

Daha fazla bilgi için bkz. ASP.NET Core'da alanlar ve ASP.NET Core'da Razor Pages yönlendirmesi ve uygulama kuralları.

ViewData özniteliği

Veriler ViewDataAttribute ile bir sayfaya geçirilebilir. [ViewData] özniteliğine sahip özelliklerin değerleri ViewDataDictionary sınıfında depolanır ve buradan yüklenir.

Aşağıdaki örnekte AboutModelTitle özelliğine [ViewData] özniteliğini uygular:

public class AboutModel : PageModel
{
    [ViewData]
    public string Title { get; } = "About";

    public void OnGet()
    {
    }
}

Hakkında sayfasında Title özelliğine bir model özelliği olarak erişin:

<h1>@Model.Title</h1>

Düzende, title özelliği ViewData sözlüğünden okunur:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
    ...

TempData

ASP.NET Core TempData özelliğini kullanıma sunar. Bu özellik verileri okunana kadar depolar. Verileri silmeden incelemek için Keep ve Peek yönteleri kullanılabilir. TempData, veriler birden fazla istek için gerekli olduğunda yeniden yönlendirme için kullanışlıdır.

Aşağıdaki kod TempData özelliğini kullanarak Message değerini ayarlar:

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateDotModel(AppDbContext db)
    {
        _db = db;
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";
        return RedirectToPage("./Index");
    }
}

Pages/Customers/Index.cshtml dosyasında yer alan aşağıdaki işaretleme TempData özelliğini kullanarak Message değerini görüntüler.

<h3>Msg: @Model.Message</h3>

Pages/Customers/Index.cshtml.cs sayfa modeli [TempData] özniteliğini Message özelliğine uygular.

[TempData]
public string Message { get; set; }

Daha fazla bilgi için bkz. TempData.

Sayfa başına birden çok işleyici

Aşağıdaki sayfa asp-page-handler Etiket Yardımcısını kullanarak iki işleyici için işaretleme oluşturur:

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <!-- <snippet_Handlers> -->
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
        <!-- </snippet_Handlers> -->
    </form>
</body>
</html>

Yukarıdaki örnekte yer alan formun iki gönder düğmesi vardır ve bunlardan her biri FormActionTagHelper kullanarak farklı bir URL'ye gönderir. asp-page-handler özniteliği asp-page özniteliğinin yardımcısıdır. asp-page-handler, sayfa tarafından tanımlanan işleyici yöntemlerinin her birine gönderen URL'ler oluşturur. Örnek geçerli sayfaya bağlandığından asp-page belirtilmez.

Sayfa modeli:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateFATHModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateFATHModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostJoinListAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }

        public async Task<IActionResult> OnPostJoinListUCAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Customer.Name = Customer.Name?.ToUpperInvariant();
            return await OnPostJoinListAsync();
        }
    }
}

Yukarıdaki kod adlandırılmış işleyici yöntemleri kullanır. Adlandırılmış işleyici yöntemleri adın On<HTTP Verb> öğesinden sonraki ve Async öğesinden (varsa) önceki bölümündeki metin alınarak oluşturulur. Yukarıdaki örnekte sayfa yöntemleri OnPostJoinListAsync ve OnPostJoinListUCAsync'dir. OnPost ve Async kaldırıldığında işleyici adları JoinList ve JoinListUC olur.

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

Yukarıdaki kod kullanıldığında OnPostJoinListAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH?handler=JoinList olur. OnPostJoinListUCAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH?handler=JoinListUC şeklindedir.

Özel yollar

@page yönergesini kullanarak:

  • Sayfa için özel bir yol belirtin. Örneğin Hakkında sayfasının yolu @page "/Some/Other/Path" ile /Some/Other/Path olarak ayarlanabilir.
  • Segmentleri sayfanın varsayılan yoluna ekleyin. Örneğin "item" segmenti @page "item" ile sayfanın varsayılan yoluna eklenebilir.
  • Parametreleri sayfanın varsayılan yoluna ekleyin. Örneğin id kimlik parametresi @page "{id}" içeren bir sayfada gerekli olabilir.

Yolun başındaki bir tilde (~) ile belirtilen köke göre yol desteklenir. Örneğin @page "~/Some/Other/Path" ile @page "/Some/Other/Path" aynıdır.

URL'de ?handler=JoinList gibi sorgu dizelerinden hoşlanmıyorsanız işleyici adını URL'nin yol bölümüne yerleştirecek şekilde yolu değiştirin. Yol, @page yönergesinden sonra çift tırnak içine alınmış bir yönlendirme şablonu eklenerek özelleştirilebilir.

@page "{handler?}"
@model CreateRouteModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Yukarıdaki kod kullanıldığında OnPostJoinListAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH/JoinList olur. OnPostJoinListUCAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH/JoinListUC şeklindedir.

handler öğesini izleyen ?, yönlendirme parametresinin isteğe bağlı olduğu anlamına gelir.

JavaScript (JS) dosyalarının birlikte yerleştirilmesi

Sayfalar ve görünümler için JavaScript (JS) dosyalarının birlikte yerleştirilmesi, uygulamadaki betikleri düzenlemenin kullanışlı bir yoludur.

Aşağıdaki dosya adı uzantısı kurallarını kullanarak JS dosyalarını aynı konuma yerleştirin:

  • Razor Pages uygulamalarının sayfaları ve MVC uygulamalarının görünümleri: .cshtml.js. Örnekler:
    • Razor Pages uygulamasının Pages/Index.cshtml konumundaki Index sayfası için Pages/Index.cshtml.js.
    • MVC uygulamasının Views/Home/Index.cshtml konumundaki Index görünümü için Views/Home/Index.cshtml.js.

Aynı konumda yer alan JS dosyaları, projedeki dosyanın yolu aracılığıyla genel olarak adreslenebilir:

  • Uygulamadaki bir birlikte bulunan betik dosyasındaki sayfalar ve görünümler:

    {PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js

    • {PATH} yer tutucusu sayfanın, görünümün veya bileşenin yoludur.
    • {PAGE, VIEW, OR COMPONENT} yer tutucusu sayfa, görünüm veya bileşendir.
    • {EXTENSION} yer tutucusu sayfanın, görünümün veya bileşenin uzantısını eşleştirir (razor veya cshtml).

    Razor Pages örneği:

    Index sayfası için bir JS dosyası Pages klasöründe (Pages/Index.cshtml.js) Index sayfasının (Pages/Index.cshtml) yanına yerleştirilir. Index sayfasında, Pages klasöründeki yolda betiğe başvurulur:

    @section Scripts {
      <script src="~/Pages/Index.cshtml.js"></script>
    }
    

    Uygulama yayımlandığında çerçeve betiği otomatik olarak web köküne taşır. Yukarıdaki örnekte betik bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Pages\Index.cshtml.js konumuna taşınır; burada {TARGET FRAMEWORK MONIKER} yer tutucusu Hedef Çerçeve Bilinen Adı'dır (TFM). Index sayfasında betiğin göreli URL'sinde değişiklik yapmak gerekmez.

    Uygulama yayımlandığında çerçeve betiği otomatik olarak web köküne taşır. Yukarıdaki örnekte betik bin\Release\{TARGET FRAMEWORK MONIKER}\publish\wwwroot\Components\Pages\Index.razor.js konumuna taşınır; burada {TARGET FRAMEWORK MONIKER} yer tutucusu Hedef Çerçeve Bilinen Adı'dır (TFM). Index bileşeninde betiğin göreli URL'sinde değişiklik yapmak gerekmez.

  • Razor sınıf kitaplığı (RCL) tarafından sağlanan betikler için:

    _content/{PACKAGE ID}/{PATH}/{PAGE, VIEW, OR COMPONENT}.{EXTENSION}.js

    • {PACKAGE ID} yer tutucusu RCL'nin paket tanımlayıcısıdır (veya uygulama tarafından başvurulan bir sınıf kitaplığı için kitaplık adıdır).
    • {PATH} yer tutucusu sayfanın, görünümün veya bileşenin yoludur. RCL'nin köküne bir Razor bileşeni yerleştirilirse, yol segmenti eklenmez.
    • {PAGE, VIEW, OR COMPONENT} yer tutucusu sayfa, görünüm veya bileşendir.
    • {EXTENSION} yer tutucusu sayfanın, görünümün veya bileşenin uzantısını eşleştirir (razor veya cshtml).

Gelişmiş yapılandırma ve ayarlar

Aşağıdaki bölümlerde gösterilen yapılandırma ve ayarlar uygulamaların çoğunda gerekli değildir.

Gelişmiş seçenekleri yapılandırmak için RazorPagesOptions'ı yapılandıran AddRazorPages aşırı yüklemesini kullanın:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
{
    options.RootDirectory = "/MyPages";
    options.Conventions.AuthorizeFolder("/MyPages/Admin");
});

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Sayfalara kök dizin ayarlamak veya sayfalara uygulama modeli kuralları eklemek için RazorPagesOptions'ı kullanın. Kurallar hakkında daha fazla bilgi için bkz. Razor Pages yetkilendirme kuralları.

Görünümleri önceden derlemek için bkz. Razor görünümü derleme.

Razor Pages'ın içerik kökünde olduğunu belirtme

Varsayılan olarak Razor Pages'ın kökü /Pages dizinindedir. Razor Pages'ın uygulamanın içerik kökünde (ContentRootPath) olduğunu belirtmek için WithRazorPagesAtContentRoot ekleyin:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
{
    options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
  .WithRazorPagesAtContentRoot();

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Razor Pages'in özel kök dizininde olduğunu belirtme

Razor Pages'ın uygulamada özel bir kök dizinde olduğunu belirtmek için WithRazorPagesRoot ekleyin (göreli bir yol sağlayın):

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Data;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages(options =>
{
    options.Conventions.AuthorizeFolder("/MyPages/Admin");
})
  .WithRazorPagesRoot("/path/to/razor/pages");

builder.Services.AddDbContext<CustomerDbContext>(options =>
    options.UseInMemoryDatabase("name"));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Ek kaynaklar

Razor Pages projesi oluşturma

Razor Pages projesi oluşturmaya yönelik ayrıntılı yönergeler için bkz. Razor Pages'ı kullanmaya başlama.

Razor Pages

Razor Pages Startup.cs dosyasında etkinleştirilir:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

Temel bir sayfayı ele alalım:

@page

<h1>Hello, world!</h1>
<h2>The time on the server is @DateTime.Now</h2>

Yukarıdaki kod, ASP.NET Core uygulamasında denetleyiciler ve görünümlerle kullanılan bir Razor görünüm dosyasına çok benzer. Bunu farklı kılan @page yönergesidir. @page dosyayı bir MVC eylemine dönüştürür. Bu da istekleri bir denetleyiciden geçmeden, doğrudan işlediği anlamına gelir. @page, sayfadaki ilk Razor yönergesi olmalıdır. @page diğer Razor yapılarının davranışını etkiler. Razor Pages dosya adlarının .cshtml soneki vardır.

Aşağıdaki iki dosyada PageModel sınıfının kullanıldığı benzer bir sayfa gösterilir. Pages/Index2.cshtml dosyası:

@page
@using RazorPagesIntro.Pages
@model Index2Model

<h2>Separate page model</h2>
<p>
    @Model.Message
</p>

Pages/Index2.cshtml.cs sayfa modeli:

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;

namespace RazorPagesIntro.Pages
{
    public class Index2Model : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }
}

Kural gereği PageModel sınıf dosyasının adı sonuna .cs eklenmiş Razor Sayfa dosyasının adıyla aynıdır. Örneğin yukarıdaki Razor Sayfası Pages/Index2.cshtml adını taşır. PageModel sınıfını içeren dosya Pages/Index2.cshtml.cs olarak adlandırılır.

URL yollarının sayfalarla ilişkileri, sayfanın dosya sistemindeki konumuna göre belirlenir. Aşağıdaki tabloda bir Razor Sayfa yolu ve eşleşen URL gösterilir:

Dosya adı ve yol eşleşen URL
/Pages/Index.cshtml / veya /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store veya /Store/Index

Notlar:

  • Çalışma zamanı Razor Pages dosyalarını varsayılan olarak Pages klasöründe arar.
  • URL bir sayfa içermediğinde varsayılan sayfa Index sayfasıdır.

Temel form yazma

Razor Pages, web tarayıcıları tarafından kullanılan yaygın desenlerin uygulama oluşturulurken kolayca uygulanmasını sağlamak için tasarlanmıştır. Model bağlama, Etiket Yardımcıları ve HTML yardımcıları, Razor Sayfa sınıfında tanımlanan özelliklerle çalışır. Contact modeli için temel bir "bize ulaşın" formu uygulayan bir sayfayı düşünün:

Bu belgedeki örnekler için Startup.cs dosyasında DbContext başlatılır.

Bellek içi veritabanı Microsoft.EntityFrameworkCore.InMemory NuGet paketini gerektirir.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<CustomerDbContext>(options =>
                      options.UseInMemoryDatabase("name"));
    services.AddRazorPages();
}

Veri modeli:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Models
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(10)]
        public string Name { get; set; }
    }
}

Veritabanı bağlamı:

using Microsoft.EntityFrameworkCore;
using RazorPagesContacts.Models;

namespace RazorPagesContacts.Data
{
    public class CustomerDbContext : DbContext
    {
        public CustomerDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }
}

Pages/Create.cshtml görünüm dosyası:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Pages/Create.cshtml.cs sayfa modeli:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;
using RazorPagesContacts.Models;
using System.Threading.Tasks;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateModel : PageModel
    {
        private readonly CustomerDbContext _context;

        public CreateModel(CustomerDbContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Customers.Add(Customer);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

Kurala göre PageModel sınıfı <PageName>Model olarak adlandırılır ve sayfayla aynı ad alanında yer alır.

PageModel sınıfı, bir sayfanın mantığının sunumundan ayrılmasına olanak sağlar. Sayfaya gönderilen istekler için herhangi bir sayfa işleyicisini ve sayfayı işlemek için kullanılan verileri tanımlar. Bu ayrım şunları sağlar:

Sayfanın POST istekleri üzerinde çalıştırılan (kullanıcı formu gönderdiğinde) bir OnPostAsyncişleyici yöntemi vardır. Herhangi bir HTTP fiili için işleyici yöntemleri eklenebilir. En yaygın işleyiciler şunlardır:

  • Sayfa için gereken durumu başlatmak için OnGet. Yukarıdaki kodda OnGet yöntemi CreateModel.cshtmlRazor Sayfasını görüntüler.
  • Form gönderilerini işlemek için OnPost.

Async adlandırma son eki isteğe bağlıdır, ancak genellikle zaman uyumsuz işlevler için kural tarafından kullanılır. Yukarıdaki kod, Razor Pages için tipik bir koddur.

Denetleyicileri ve görünümleri kullanan ASP.NET uygulamalarını biliyorsanız:

  • Yukarıdaki örnekte yer alan OnPostAsync kodu tipik bir denetleyici koduna benzer.
  • Model bağlama, doğrulama ve eylem sonuçları gibi MVC temel öğelerinin çoğu, Denetleyiciler ve Razor Pages ile aynı şekilde çalışır.

Yukarıdaki OnPostAsync yöntemi:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Customers.Add(Customer);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

OnPostAsync temel akışı:

Doğrulama hatalarını denetleyin.

  • Hata yoksa, verileri kaydedin ve yeniden yönlendirin.
  • Hatalar varsa, doğrulama iletileriyle birlikte sayfayı yeniden gösterin. Çoğu durumda, doğrulama hataları istemci üzerinde algılanır ve sunucuya hiçbir zaman gönderilmez.

Pages/Create.cshtml görünüm dosyası:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Pages/Create.cshtml dosyasından işlenen HTML:

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input type="text" data-val="true"
           data-val-length="The field Name must be a string with a maximum length of 10."
           data-val-length-max="10" data-val-required="The Name field is required."
           id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
    <input type="submit" />
    <input name="__RequestVerificationToken" type="hidden"
           value="<Antiforgery token here>" />
</form>

Yukarıdaki kodda formu gönderme:

  • Geçerli verilerle:

    • OnPostAsync işleyici yöntemi RedirectToPage yardımcı yöntemini çağırır. RedirectToPage, bir RedirectToPageResult örneği döndürür. RedirectToPage:

      • Bir eylemin sonucudur.
      • RedirectToAction veya RedirectToRoute yöntemine benzer (denetleyicilerde ve görünümlerde kullanılır).
      • Sayfalar için özelleştirilir. Yukarıdaki örnekte kök Dizin sayfasına yeniden yönlendirir (/Index). RedirectToPage, Sayfalar için URL oluşturma bölümünde ayrıntılı olarak açıklanır.
  • Sunucuya geçirilen doğrulama hatalarıyla:

    • OnPostAsync işleyici yöntemi Page yardımcı yöntemini çağırır. Page, bir PageResult örneği döndürür. Döndürülen Page, denetleyicilerdeki eylemlerin View döndürmesine benzer. PageResult, işleyici yöntemi için varsayılan dönüş türüdür. void döndüren bir işleyici yöntemi sayfayı işler.
    • Yukarıdaki örnekte formu hiç değer olmadan göndermek ModelState.IsValid özelliğinin false döndürmesiyle sonuçlanır. Bu örnekte istemcide doğrulama hatası görüntülenmez. Doğrulama hatasının işlenmesi, bu belgenin ilerleyen bölümlerinde ele alınmıştır.
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();
    
        return RedirectToPage("./Index");
    }
    
  • İstemci tarafı doğrulaması tarafından algılanan doğrulama hatalarıyla:

    • Veriler sunucuya gönderilmez.
    • İstemci tarafı doğrulaması, bu belgenin ilerleyen bölümlerinde açıklanmıştır.

Customer özelliği model bağlamayı kabul etmek için [BindProperty] özniteliğini kullanır:

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

    public CreateModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

[BindProperty], istemi tarafından değiştirilmemesi gereken özelliklerin bulunduğu modellerde kullanılmamalıdır. Daha fazla bilgi için bkz. Aşırı gönderim.

Razor Pages varsayılan olarak özellikleri yalnızca GET dışındaki fiillerle bağlar. Özelliklere bağlama işlemi HTTP verilerini model türüne dönüştürmek üzere kod yazma gereğini ortadan kaldırır. Bağlama, form alanlarını işlemek ve girişi kabul etmek için aynı özelliği kullanarak (<input asp-for="Customer.Name">) kodu azaltır.

Uyarı

Güvenlik nedeniyle GET isteği verilerini sayfa modeli özelliklerine bağlamayı kabul etmeniz gerekir. Kullanıcı girişini özelliklere eşlemeden önce doğrulayın. Sorgu dizesi veya yönlendirme değerlerini kullanan senaryolarla ilgilenirken GET bağlamasını kabul etmek yararlı olur.

GET isteklerinde bir özelliği bağlamak için [BindProperty] özniteliğinin SupportsGet özelliğini true olarak ayarlayın:

[BindProperty(SupportsGet = true)]

Daha fazla bilgi için bkz. ASP.NET Core Community Standup: Bind on GET discussion (YouTube).

Pages/Create.cshtml görünüm dosyasını gözden geçirme:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>
  • Yukarıdaki kodda giriş etiketi yardımcısı<input asp-for="Customer.Name" /> HTML <input> öğesini Customer.Name model ifadesine bağlar.
  • @addTagHelper, Etiket Yardımcılarını kullanılabilir duruma getirir.

Giriş sayfası

Index.cshtml giriş sayfasıdır:

@page
@model RazorPagesContacts.Pages.Customers.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Contacts home page</h1>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var contact in Model.Customer)
            {
                <tr>
                    <td> @contact.Id  </td>
                    <td>@contact.Name</td>
                    <td>
                        <!-- <snippet_Edit> -->
                        <a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |
                        <!-- </snippet_Edit> -->
                        <!-- <snippet_Delete> -->
                        <button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>
                        <!-- </snippet_Delete> -->
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <a asp-page="Create">Create New</a>
</form>

İlişkili PageModel sınıfı (Index.cshtml.cs):

public class IndexModel : PageModel
{
    private readonly CustomerDbContext _context;

    public IndexModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IList<Customer> Customer { get; set; }

    public async Task OnGetAsync()
    {
        Customer = await _context.Customers.ToListAsync();
    }

    public async Task<IActionResult> OnPostDeleteAsync(int id)
    {
        var contact = await _context.Customers.FindAsync(id);

        if (contact != null)
        {
            _context.Customers.Remove(contact);
            await _context.SaveChangesAsync();
        }

        return RedirectToPage();
    }
}

Index.cshtml dosyası aşağıdaki işaretlemeyi içerir:

<a asp-page="./Edit" asp-route-id="@contact.Id">Edit</a> |

<a /a>Bağlayıcı Etiketi Yardımcısı Edit sayfasına bağlantı oluşturmak için asp-route-{value} özniteliğini kullanmıştır. Bağlantı, kişi kimliğiyle birlikte yönlendirme verilerini içerir. Örneğin, https://localhost:5001/Edit/1. Etiket Yardımcıları, Razor dosyalarında HTML öğelerinin oluşturulmasına ve işlenmesine sunucu tarafı kodun katılmasını etkinleştirir.

Index.cshtml dosyası her müşteri kişisi için bir sil düğmesi oluşturmaya yönelik işaretleme içerir:

<button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>

İşlenen HTML:

<button type="submit" formaction="/Customers?id=1&amp;handler=delete">delete</button>

Sil düğmesi HTML'de işlendiğinde formaction öğesi şu parametreleri içerir:

  • asp-route-id özniteliğiyle belirtilen müşteri kişi kimliği.
  • asp-page-handler özniteliğiyle belirtilen handler.

Düğme seçildiğinde sunucuya bir form POST isteği gönderilir. Kurala göre işleyici yönteminin adı, OnPost[handler]Async şemasına uygun olarak handler parametresinin değeri temelinde seçilir.

Bu örnekte handlerdelete olduğundan, POST isteğini işlemek için OnPostDeleteAsync işleyici yöntemi kullanılır. asp-page-handler farklı bir değere ayarlanırsa (örneğin remove), OnPostRemoveAsync adlı bir işleyici yöntemi seçilir.

public async Task<IActionResult> OnPostDeleteAsync(int id)
{
    var contact = await _context.Customers.FindAsync(id);

    if (contact != null)
    {
        _context.Customers.Remove(contact);
        await _context.SaveChangesAsync();
    }

    return RedirectToPage();
}

OnPostDeleteAsync yöntemi:

  • Sorgu dizesinden id değerini alır.
  • FindAsync ile müşteri kişisi için veritabanını sorgular.
  • Müşteri kişisi bulunursa kaldırılır ve veritabanı güncelleştirilir.
  • Kök Dizin sayfasını (/Index) yeniden yönlendirmek için RedirectToPage yöntemini çağırır.

Edit.cshtml dosyası

@page "{id:int}"
@model RazorPagesContacts.Pages.Customers.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers


<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
    <div asp-validation-summary="All"></div>
    <input asp-for="Customer.Id" type="hidden" />
    <div>
        <label asp-for="Customer.Name"></label>
        <div>
            <input asp-for="Customer.Name" />
            <span asp-validation-for="Customer.Name"></span>
        </div>
    </div>

    <div>
        <button type="submit">Save</button>
    </div>
</form>

İlk satır @page "{id:int}" yönergesini içerir. "{id:int}" yönlendirme kısıtlaması sayfaya int yönlendirme verilerini içeren istekleri kabul etmesini bildirir. Sayfaya yönelik istek int öğesine dönüştürülebilecek yönlendirme verilerini içermiyorsa, çalışma zamanı bir HTTP 404 (bulunamadı) hatası döndürür. Kimliği isteğe bağlı yapmak için yönlendirme kısıtlamasının sonuna ? ekleyin:

@page "{id:int?}"

Edit.cshtml.cs dosyası:

public class EditModel : PageModel
{
    private readonly CustomerDbContext _context;

    public EditModel(CustomerDbContext context)
    {
        _context = context;
    }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnGetAsync(int id)
    {
        Customer = await _context.Customers.FindAsync(id);

        if (Customer == null)
        {
            return RedirectToPage("./Index");
        }

        return Page();
    }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Attach(Customer).State = EntityState.Modified;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            throw new Exception($"Customer {Customer.Id} not found!");
        }

        return RedirectToPage("./Index");
    }

}

Doğrulama

Doğrulama kuralları:

  • Model sınıfında bildirim temelli olarak belirtilir.
  • Uygulamanın her yerinde zorlanır.

System.ComponentModel.DataAnnotations ad alanı, bir sınıfa veya özelliğe uygulanan bir dizi yerleşik doğrulama özniteliği sağlar. DataAnnotations biçimlendirmeye yardımcı olan ve hiçbir doğrulama sağlamayan [DataType] gibi biçimlendirme öznitelikleri de içerir.

Customer modelini ele alalım:

using System.ComponentModel.DataAnnotations;

namespace RazorPagesContacts.Models
{
    public class Customer
    {
        public int Id { get; set; }

        [Required, StringLength(10)]
        public string Name { get; set; }
    }
}

Aşağıdaki Create.cshtml görünüm dosyasını kullanarak:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer.Name"></span>
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

Yukarıdaki kod:

  • jQuery ve jQuery doğrulama betiklerini içerir.

  • <div /> ve <span />Etiket Yardımcılarını kullanarak şunları etkinleştirir:

    • İstemci tarafı doğrulaması.
    • Doğrulama hatası işleme.
  • Aşağıdaki HTML'yi oluşturur:

    <p>Enter a customer name:</p>
    
    <form method="post">
        Name:
        <input type="text" data-val="true"
               data-val-length="The field Name must be a string with a maximum length of 10."
               data-val-length-max="10" data-val-required="The Name field is required."
               id="Customer_Name" maxlength="10" name="Customer.Name" value="" />
        <input type="submit" />
        <input name="__RequestVerificationToken" type="hidden"
               value="<Antiforgery token here>" />
    </form>
    
    <script src="/lib/jquery/dist/jquery.js"></script>
    <script src="/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
    

Ad değeri olmadan Create form gönderilmesi, formda "Ad alanı zorunludur." hata iletisinin görüntülenmesine neden olur. İstemcide JavaScript etkinleştirildiyse tarayıcı hatayı sunucuya göndermeden görüntüler.

[StringLength(10)] özniteliği işlenen HTML'de data-val-length-max="10" oluşturur. data-val-length-max, tarayıcıların belirtilen maksimum uzunluktan fazlasını girmesini önler. Gönderiyi düzenlemek ve yeniden yürütmek için Fiddler gibi bir araç kullanılırsa:

  • 10 karakterden uzun bir ad ile.
  • "Alan Adı uzunluk üst sınırı 10 olan bir dize olmalıdır." hata iletisi döndürülür.

Aşağıdaki Movie modeli ele alalım:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string Rating { get; set; }
    }
}

Doğrulama öznitelikleri, uygulandıkları model özelliklerinde zorlanacak davranışı belirtir:

  • Required ve MinimumLength öznitelikleri özelliğin bir değer olması gerektiğini belirtir ama kullanıcının bu doğrulamaya uymak için boşluk girmesi engellenemez.

  • RegularExpression özniteliği girilebilecek karakterleri sınırlamak için kullanılır. Yukarıdaki kodda "Genre":

    • Yalnızca harfleri kullanmalıdır.
    • İlk harfin büyük harf olması gerekir. Boşluk, sayı ve özel karakterlere izin verilmez.
  • RegularExpression "Rating":

    • İlk karakterin büyük harf olmasını gerektirir.
    • Sonraki alanlarda özel karakterlere ve sayılara izin verir. "PG-13" değeri Rating için geçerlidir ama "Genre" için başarısız olur.
  • Range özniteliği, bir değeri belirtilen bir aralık içinde kısıtlar.

  • StringLength özniteliği bir dize özelliğinin boyut üst sınırını ve isteğe bağlı olarak boyut alt sınırını ayarlar.

  • Değer türleri (decimal, int, float, DateTime gibi) doğal olarak gereklidir ve [Required] özniteliği gerekmez.

Movie modeli için Create page, geçersiz değerleri içeren hatalar görüntüler:

Birden çok jQuery istemci tarafı doğrulama hatası içeren Movie görünümü formu

Daha fazla bilgi için bkz.

OnGet işleyici geri dönüşü ile HEAD isteklerini işleme

HEAD istekleri belirli bir kaynak için üst bilgileri almaya olanak tanır. GET isteklerinden farklı olarak HEAD istekleri bir yanıt gövdesi döndürmez.

Normal olarak HEAD istekleri için bir OnHead işleyicisi oluşturulur ve çağrılır:

public void OnHead()
{
    HttpContext.Response.Headers.Add("Head Test", "Handled by OnHead!");
}

OnHead işleyicisi tanımlanmadıysa, Razor Pages OnGet işleyicisini çağırmaya geri döner.

XSRF/CSRF ve Razor Pages

Razor Pages Sahtecilik önleme doğrulaması ile korunur. FormTagHelper, HTML form öğelerine sahtecilik önleme belirteçleri ekler.

Razor Pages ile düzenleri, kısmi görünümleri, şablonları ve Etiket Yardımcılarını kullanma

Pages, Razor görünüm altyapısının tüm özellikleriyle çalışır. Düzenler, kısmi görünümler, şablonlar, Etiket Yardımcıları, _ViewStart.cshtml ve _ViewImports.cshtml geleneksel Razor görünümlerde olduğu gibi çalışır.

Şimdi bu özelliklerden bazılarından yararlanarak bu sayfanın karışıklığını azaltalım.

Pages/Shared/_Layout.cshtml dosyasına bir düzen sayfası ekleyin:

<!DOCTYPE html>
<html>
<head>
    <title>RP Sample</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</head>
<body>
    <a asp-page="/Index">Home</a>
    <a asp-page="/Customers/Create">Create</a>
    <a asp-page="/Customers/Index">Customers</a> <br />

    @RenderBody()
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</body>
</html>

Düzen:

  • Her sayfanın düzenini denetler (sayfanın düzeni geri çevirmemiş olması koşuluyla).
  • JavaScript ve stil sayfaları gibi HTML yapılarını içeri aktarır.
  • @RenderBody() yönteminin çağrıldığı Razor sayfasının içeriği işlenir.

Daha fazla bilgi için bkz. Düzen sayfası.

Layout özelliği Pages/_ViewStart.cshtml içinde ayarlanır:

@{
    Layout = "_Layout";
}

Düzen, Pages/Shared klasöründe yer alır. Pages, geçerli sayfayla aynı klasörden başlayıp hiyerarşik olarak diğer görünümleri (düzenler, şablonlar, kısmi görünümler) arar. Pages/Shared klasöründeki düzen, Pages klasörünün altındaki herhangi bir Razor sayfasından kullanılabilir.

Düzen dosyası Pages/Shared klasöründe yer almalıdır.

Düzen dosyasını Views/Shared klasörüne koymamanızı öneririz. Views/Shared bir MVC görünümleri desenidir. Razor Pages'ın yok kurallarına değil klasör hiyerarşisine dayanması amaçlanmıştır.

Razor Sayfasından yapılan görünüm araması Pages klasörünü içerir. MVC denetleyicileri ve geleneksel Razor görünümleri ile kullanılan düzenler, şablonlar ve kısmi görünümler kullanılabilir.

Bir Pages/_ViewImports.cshtml dosyası ekleyin:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@namespace öğreticinin devamında açıklanmıştır. @addTagHelper yönergesi, Pages klasöründeki tüm sayfalara yerleşik Etiket Yardımcılarını getirir.

Sayfada ayarlanan @namespace yönergesi:

@page
@namespace RazorPagesIntro.Pages.Customers

@model NameSpaceModel

<h2>Name space</h2>
<p>
    @Model.Message
</p>

@namespace yönergesi sayfa için ad alanını ayarlar. @model yönergesinin ad alanını içermesi gerekmez.

@namespace yönergesi _ViewImports.cshtml dosyasına eklendiğinde, belirtilen ad alanı @namespace yönergesini içeri aktaran Sayfada oluşturulan ad alanı için ön ek sağlar. Oluşturulan ad alanının kalan bölümü (sonek bölümü), _ViewImports.cshtml dosyasını içeren klasör ile sayfayı içeren klasör arasındaki noktayla ayrılmış göreli yoldur.

Örneğin PageModel sınıfı Pages/Customers/Edit.cshtml.cs açıkça ad alanını ayarlar:

namespace RazorPagesContacts.Pages
{
    public class EditModel : PageModel
    {
        private readonly AppDbContext _db;

        public EditModel(AppDbContext db)
        {
            _db = db;
        }

        // Code removed for brevity.

Dosya Pages/_ViewImports.cshtml açıkça ad alanını ayarlar:

@namespace RazorPagesContacts.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Pages/Customers/Edit.cshtmlRazor Sayfası için oluşturulan ad alanı PageModel sınıfı ile aynıdır.

@namespacegeleneksel Razor görünümleriyle de çalışır.

Pages/Create.cshtml görünüm dosyasını ele alalım:

@page
@model RazorPagesContacts.Pages.Customers.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<p>Validation: customer name:</p>

<form method="post">
    <div asp-validation-summary="ModelOnly"></div>
    <span asp-validation-for="Customer.Name"></span>
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

_ViewImports.cshtml ve önceki düzen dosyasıyla güncelleştirilmiş Pages/Create.cshtml görünüm dosyası:

@page
@model CreateModel

<p>Enter a customer name:</p>

<form method="post">
    Name:
    <input asp-for="Customer.Name" />
    <input type="submit" />
</form>

Yukarıdaki kodda _ViewImports.cshtml dosyası ad alanını ve Etiket Yardımcılarını içeri aktarmıştır. Düzen dosyası JavaScript dosyalarını içeri aktarmıştır.

Razor Pages başlangıç projesi, istemci tarafı doğrulaması ekleyen Pages/_ValidationScriptsPartial.cshtml dosyasını içerir.

Kısmi görünümler hakkında daha fazla bilgi için bkz. ASP.NET Core'da kısmi görünümler.

Sayfalar için URL oluşturma

Daha önce gösterilen Create sayfası RedirectToPage kullanır:

public class CreateModel : PageModel
{
    private readonly CustomerDbContext _context;

    public CreateModel(CustomerDbContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customers.Add(Customer);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }
}

Uygulamanın dosya/klasör yapısı aşağıdaki gibidir:

  • /Pages

    • Index.cshtml

    • Privacy.cshtml

    • /Customers

      • Create.cshtml
      • Edit.cshtml
      • Index.cshtml

Pages/Customers/Create.cshtml ve Pages/Customers/Edit.cshtml sayfaları başarılı olduktan sonra Pages/Customers/Index.cshtml konumuna yeniden yönlendirilir. ./Index dizesi önceki sayfaya erişmek için kullanılan göreli sayfa adıdır. Pages/Customers/Index.cshtml sayfasında URL'ler oluşturmak için kullanılır. Örneğin:

  • Url.Page("./Index", ...)
  • <a asp-page="./Index">Customers Index Page</a>
  • RedirectToPage("./Index")

Mutlak sayfa adı olan /Index, Pages/Index.cshtml sayfasına URL'ler oluşturmak için kullanılır. Örneğin:

  • Url.Page("/Index", ...)
  • <a asp-page="/Index">Home Index Page</a>
  • RedirectToPage("/Index")

Sayfa adı, baştaki / ile birlikte /Pages kök klasöründen sayfaya giden yoldur (örneğin /Index). Yukarıdaki URL oluşturma örnekleri, URL'yi sabit kodlamaya göre daha gelişmiş seçenekler ve işlevsel özellikler sunar. URL oluşturma işleminde yönlendirme kullanılır ve hedef yolda yönlendirmenin nasıl tanımlandığına göre parametreler oluşturulabilir ve kodlanabilir.

Sayfalar için URL oluşturma işleminde göreli adlar desteklenir. Aşağıdaki tabloda, Pages/Customers/Create.cshtml dosyasında farklı RedirectToPage parametreleri kullanılarak hangi Dizin sayfasının seçildiği gösterilir.

RedirectToPage(x) Sayfa
RedirectToPage("/Index") Pages/Index
RedirectToPage("./Index"); Pages/Customers/Index
RedirectToPage("../Index") Pages/Index
RedirectToPage("Index") Pages/Customers/Index

RedirectToPage("Index"), RedirectToPage("./Index") ve RedirectToPage("../Index")göreli adlardır. Hedef sayfanın adını hesaplamak için RedirectToPage parametresi geçerli sayfanın yoluyla birleştirilir.

Karmaşık bir yapıya sahip siteler oluştururken göreli ad bağlama yararlı olur. Klasördeki sayfalar arasında bağlantı oluşturmak için göreli adlar kullanıldığında:

  • Klasörün yeniden adlandırılması göreli bağlantıları kesmez.
  • Bağlantılar klasör adını içermedikleri için kesilmez.

Sayfayı farklı bir Area hedefine yönlendirmek için alanı belirtin:

RedirectToPage("/Index", new { area = "Services" });

Daha fazla bilgi için bkz. ASP.NET Core'da alanlar ve ASP.NET Core'da Razor Pages yönlendirmesi ve uygulama kuralları.

ViewData özniteliği

Veriler ViewDataAttribute ile bir sayfaya geçirilebilir. [ViewData] özniteliğine sahip özelliklerin değerleri ViewDataDictionary sınıfında depolanır ve buradan yüklenir.

Aşağıdaki örnekte AboutModelTitle özelliğine [ViewData] özniteliğini uygular:

public class AboutModel : PageModel
{
    [ViewData]
    public string Title { get; } = "About";

    public void OnGet()
    {
    }
}

Hakkında sayfasında Title özelliğine bir model özelliği olarak erişin:

<h1>@Model.Title</h1>

Düzende, title özelliği ViewData sözlüğünden okunur:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>@ViewData["Title"] - WebApplication</title>
    ...

TempData

ASP.NET Core TempData özelliğini kullanıma sunar. Bu özellik verileri okunana kadar depolar. Verileri silmeden incelemek için Keep ve Peek yönteleri kullanılabilir. TempData, veriler birden fazla istek için gerekli olduğunda yeniden yönlendirme için kullanışlıdır.

Aşağıdaki kod TempData özelliğini kullanarak Message değerini ayarlar:

public class CreateDotModel : PageModel
{
    private readonly AppDbContext _db;

    public CreateDotModel(AppDbContext db)
    {
        _db = db;
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _db.Customers.Add(Customer);
        await _db.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";
        return RedirectToPage("./Index");
    }
}

Pages/Customers/Index.cshtml dosyasında yer alan aşağıdaki işaretleme TempData özelliğini kullanarak Message değerini görüntüler.

<h3>Msg: @Model.Message</h3>

Pages/Customers/Index.cshtml.cs sayfa modeli [TempData] özniteliğini Message özelliğine uygular.

[TempData]
public string Message { get; set; }

Daha fazla bilgi için bkz. TempData.

Sayfa başına birden çok işleyici

Aşağıdaki sayfa asp-page-handler Etiket Yardımcısını kullanarak iki işleyici için işaretleme oluşturur:

@page
@model CreateFATHModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <!-- <snippet_Handlers> -->
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
        <!-- </snippet_Handlers> -->
    </form>
</body>
</html>

Yukarıdaki örnekte yer alan formun iki gönder düğmesi vardır ve bunlardan her biri FormActionTagHelper kullanarak farklı bir URL'ye gönderir. asp-page-handler özniteliği asp-page özniteliğinin yardımcısıdır. asp-page-handler, sayfa tarafından tanımlanan işleyici yöntemlerinin her birine gönderen URL'ler oluşturur. Örnek geçerli sayfaya bağlandığından asp-page belirtilmez.

Sayfa modeli:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesContacts.Data;

namespace RazorPagesContacts.Pages.Customers
{
    public class CreateFATHModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateFATHModel(AppDbContext db)
        {
            _db = db;
        }

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostJoinListAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();
            return RedirectToPage("/Index");
        }

        public async Task<IActionResult> OnPostJoinListUCAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Customer.Name = Customer.Name?.ToUpperInvariant();
            return await OnPostJoinListAsync();
        }
    }
}

Yukarıdaki kod adlandırılmış işleyici yöntemleri kullanır. Adlandırılmış işleyici yöntemleri adın On<HTTP Verb> öğesinden sonraki ve Async öğesinden (varsa) önceki bölümündeki metin alınarak oluşturulur. Yukarıdaki örnekte sayfa yöntemleri OnPostJoinListAsync ve OnPostJoinListUCAsync'dir. OnPost ve Async kaldırıldığında işleyici adları JoinList ve JoinListUC olur.

<input type="submit" asp-page-handler="JoinList" value="Join" />
<input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />

Yukarıdaki kod kullanıldığında OnPostJoinListAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH?handler=JoinList olur. OnPostJoinListUCAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH?handler=JoinListUC şeklindedir.

Özel yollar

@page yönergesini kullanarak:

  • Sayfa için özel bir yol belirtin. Örneğin Hakkında sayfasının yolu @page "/Some/Other/Path" ile /Some/Other/Path olarak ayarlanabilir.
  • Segmentleri sayfanın varsayılan yoluna ekleyin. Örneğin "item" segmenti @page "item" ile sayfanın varsayılan yoluna eklenebilir.
  • Parametreleri sayfanın varsayılan yoluna ekleyin. Örneğin id kimlik parametresi @page "{id}" içeren bir sayfada gerekli olabilir.

Yolun başındaki bir tilde (~) ile belirtilen köke göre yol desteklenir. Örneğin @page "~/Some/Other/Path" ile @page "/Some/Other/Path" aynıdır.

URL'de ?handler=JoinList gibi sorgu dizelerinden hoşlanmıyorsanız işleyici adını URL'nin yol bölümüne yerleştirecek şekilde yolu değiştirin. Yol, @page yönergesinden sonra çift tırnak içine alınmış bir yönlendirme şablonu eklenerek özelleştirilebilir.

@page "{handler?}"
@model CreateRouteModel

<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" asp-page-handler="JoinList" value="Join" />
        <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />
    </form>
</body>
</html>

Yukarıdaki kod kullanıldığında OnPostJoinListAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH/JoinList olur. OnPostJoinListUCAsync yöntemine gönderen URL yolu https://localhost:5001/Customers/CreateFATH/JoinListUC şeklindedir.

handler öğesini izleyen ?, yönlendirme parametresinin isteğe bağlı olduğu anlamına gelir.

Gelişmiş yapılandırma ve ayarlar

Aşağıdaki bölümlerde gösterilen yapılandırma ve ayarlar uygulamaların çoğunda gerekli değildir.

Gelişmiş seçenekleri yapılandırmak için RazorPagesOptions'ı yapılandıran AddRazorPages aşırı yüklemesini kullanın:

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
    {
        options.RootDirectory = "/MyPages";
        options.Conventions.AuthorizeFolder("/MyPages/Admin");
    });
}

Sayfalara kök dizin ayarlamak veya sayfalara uygulama modeli kuralları eklemek için RazorPagesOptions'ı kullanın. Kurallar hakkında daha fazla bilgi için bkz. Razor Pages yetkilendirme kuralları.

Görünümleri önceden derlemek için bkz. Razor görünümü derleme.

Razor Pages'ın içerik kökünde olduğunu belirtme

Varsayılan olarak Razor Pages'ın kökü /Pages dizinindedir. Razor Pages'ın uygulamanın içerik kökünde (ContentRootPath) olduğunu belirtmek için WithRazorPagesAtContentRoot ekleyin:

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
        {
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        })
        .WithRazorPagesAtContentRoot();
}

Razor Pages'in özel kök dizininde olduğunu belirtme

Razor Pages'ın uygulamada özel bir kök dizinde olduğunu belirtmek için WithRazorPagesRoot ekleyin (göreli bir yol sağlayın):

public void ConfigureServices(IServiceCollection services)
{            
    services.AddRazorPages(options =>
        {
            options.Conventions.AuthorizeFolder("/MyPages/Admin");
        })
        .WithRazorPagesRoot("/path/to/razor/pages");
}

Ek kaynaklar