Page 48 - MSDN Magazine, September 2017
P. 48
base type is similar to the base Controller type in that it provides a number of helper methods you can use when returning action results. When performing updates like adding a new record, you often want to redirect the user immediately after the operation, if successful. This eliminates the issue of browser refreshes triggering duplicate calls to the server, resulting in duplicate records (or worse). You can use RedirectToPage with no arguments to redirect to the default GET handler of the current Razor Page.
You can specify a named handler using the asp-page-handler tag helper, applied to a form, link or button:
<a asp-page-handler="Handler">Link Text</a>
<button type="submit" asp-page-handler="delete" asp-route-id="@id">Delete</button>
The asp-page-handler tag uses routing to build the URL. The handler name and any asp-route-parameter attributes are applied as querystring values by default. The Delete button in the previous code generates a URL like this one:
Ninjas?handler=delete&id=1
If you’d rather have the handler as part of the URL, you can specify this behavior with the @page directive:
@page "{handler?}/{id?}"
With this route specified, the generated link for the Delete button would be:
Ninjas/Delete/1
Filters
FiltersareanotherpowerfulfeatureofASP.NETCoreMVC(andone I covered in the August 2016 issue: msdn.microsoft.com/mt767699). If you’re using a Page Model in a separate file, you can use attribute-based filters with Razor Pages, including placing filter attributes on the page model class. Otherwise, you can still specify global filters when you configure MVC for your app. One of the most common uses of filters is to specify authorization policies within your app. You can configure folder- and page-based authorization policies globally:
services.AddMvc() .AddRazorPagesOptions(options => {
options.Conventions.AuthorizeFolder("/Account/Manage"); options.Conventions.AuthorizePage("/Account/Logout"); options.Conventions.AllowAnonymousToPage("/Account/Login");
});
Figure 7 Details.cshtml—Displaying Details for a Given Record Id
You can use all of the existing kinds of filters with Razor Pages except for Action filters, which apply only to action methods within Controllers. Razor Pages also introduce the new Page filter, repre- sented by IPageFilter (or IAsyncPageFilter). This filter lets you add code that will run after a particular page handler has been selected, or before or after a handler method executes. The first method can be used to change which handler is used to handle a request, for example:
public void OnPageHandlerSelected(PageHandlerSelectedContext context) {
context.HandlerMethod = context.ActionDescriptor.HandlerMethods.First(m => m.Name == "Add");
Figure 8 New.cshtml—Adds a New Plant
}
@page
@using WithRazorPages.Core.Interfaces; @using WithRazorPages.Core.Model; @inject IRepository<Plant> _repository
@functions {
[BindProperty]
public Plant Plant { get; set; }
public IActionResult OnPost() {
if(!ModelState.IsValid) return Page();
_repository.Add(Plant);
return RedirectToPage("./Index"); }
}
<h1>New Plant</h1>
<form method="post" class="form-horizontal">
<div asp-validation-summary="All" class="text-danger"></div> <div class="form-group">
<label asp-for="Plant.Name" class="col-md-2 control-label"></label> <div class="col-md-10">
<input asp-for="Plant.Name" class="form-control" />
<span asp-validation-for="Plant.Name" class="text-danger"></span> </div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary">Save</button>
</div> </div>
</form> <div>
<a asp-page="./Index">Plant List</a> </div>
Figure 9 Named Handlers
public async Task OnGetAsync() {
Ninjas = _ninjaRepository.List()
.Select(n => new NinjaViewModel { Id = n.Id, Name = n.Name }).ToList();
}
public async Task<IActionResult> OnPostAddAsync() {
_
var entity = new Ninja() {
Name = "Random Ninja" };
ninjaRepository.Add(entity);
return RedirectToPage(); }
public async Task<IActionResult> OnPostDeleteAsync(int id) {
var entityToDelete = _ninjaRepository.GetById(id); _ ninjaRepository.Delete(entityToDelete);
return RedirectToPage(); }
@page "{id:int}"
@using WithRazorPages.Core.Interfaces; @using WithRazorPages.Core.Model; @inject IRepository<Ninja> _repository
@functions {
public Ninja Ninja { get; set; }
public IActionResult OnGet(int id) {
Ninja = _repository.GetById(id);
// A void handler (no return) is equivalent to return Page()
return Page(); }
}
<h2>Ninja: @Ninja.Name</h2> <div>
Id: @Ninja.Id </div>
<div>
<a asp-page="..">Ninja List</a>
</div>
40 msdn magazine
ASP.NET Core