2021年12月13日 星期一

[研究]使用 ASP.NET Core 建立 Razor Page web 應用程式

[研究]使用 ASP.NET Core 建立 Razor Page web 應用程式

2021-12-13

本篇只是實測、摘錄重點、學習,參考這篇

教學課程: Razor 使用 ASP.NET Core 建立頁面 web 應用程式
https://docs.microsoft.com/zh-tw/aspnet/core/tutorials/razor-pages/?view=aspnetcore-6.0

Tutorial: Create a Razor Pages web app with ASP.NET Core
https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/?view=aspnetcore-6.0

官方網頁的中文網頁內容,似乎是系統自動翻譯的,所以有時候翻譯怪怪,甚至把要建立的英文目錄名稱也翻譯掉了,這要注意。

例如:教學課程: Razor 使用 ASP.NET Core 建立頁面 web 應用程式 (Tutorial: Create a Razor Pages web app with ASP.NET Core) = > 感覺應該翻成:使用 ASP.NET Core 建立 Razor Page 網頁應用程式

********************************************************************************

開始使用







********************************************************************************
新增模型

新增 Models  目錄,目錄下新增 Movie 模型 (Movie.cs 類別檔案)






Movie.cs 內容

using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; } = string.Empty;

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; } = string.Empty;
        public decimal Price { get; set; }
    }
}








注意,官方網頁上說資料夾名為電影
根據實際畫面,是誤翻譯了,應該用 Movies。把不該翻譯的翻譯了。








執行兩個命令
Add-Migration InitialCreate
Update-Database
  

測試

加入 /movies 目錄測試

使用 Entity Framework (CRUD) 的 Razor 頁面,
會自動建立 Create、Delete、Details 和 Edit 頁面,說明詳見

********************************************************************************

使用資料庫

appsettings.json內容   


{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-6eee0c6c-7e48-4c89-ae3e-4fe1796add92;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

敝人慣用Microsoft SQL Server 2019 Standard,故改為   


{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    //"RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-6eee0c6c-7e48-4c89-ae3e-4fe1796add92;Trusted_Connection=True;MultipleActiveResultSets=true"
    "RazorPagesMovieContext": "Server=.;Database=MovieDB;User Id=sa;Password=P@ssw0rd;"
  }
}

另外直接啟動SQL Server Management Studio 18.10 ( SMSS) 建立資料庫和資料表

建立資料庫



USE [master]
GO

/****** Object:  Database [MovieDB]    Script Date: 2021/12/13 下午 01:48:27 ******/
CREATE DATABASE [MovieDB]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'MovieDB', FILENAME = N'D:\DATABASE\MovieDB.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
 LOG ON 
( NAME = N'MovieDB_log', FILENAME = N'D:\DATABASE\MovieDB_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
 WITH CATALOG_COLLATION = DATABASE_DEFAULT
GO

IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [MovieDB].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO

ALTER DATABASE [MovieDB] SET ANSI_NULL_DEFAULT OFF 
GO

ALTER DATABASE [MovieDB] SET ANSI_NULLS OFF 
GO

ALTER DATABASE [MovieDB] SET ANSI_PADDING OFF 
GO

ALTER DATABASE [MovieDB] SET ANSI_WARNINGS OFF 
GO

ALTER DATABASE [MovieDB] SET ARITHABORT OFF 
GO

ALTER DATABASE [MovieDB] SET AUTO_CLOSE OFF 
GO

ALTER DATABASE [MovieDB] SET AUTO_SHRINK OFF 
GO

ALTER DATABASE [MovieDB] SET AUTO_UPDATE_STATISTICS ON 
GO

ALTER DATABASE [MovieDB] SET CURSOR_CLOSE_ON_COMMIT OFF 
GO

ALTER DATABASE [MovieDB] SET CURSOR_DEFAULT  GLOBAL 
GO

ALTER DATABASE [MovieDB] SET CONCAT_NULL_YIELDS_NULL OFF 
GO

ALTER DATABASE [MovieDB] SET NUMERIC_ROUNDABORT OFF 
GO

ALTER DATABASE [MovieDB] SET QUOTED_IDENTIFIER OFF 
GO

ALTER DATABASE [MovieDB] SET RECURSIVE_TRIGGERS OFF 
GO

ALTER DATABASE [MovieDB] SET  DISABLE_BROKER 
GO

ALTER DATABASE [MovieDB] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 
GO

ALTER DATABASE [MovieDB] SET DATE_CORRELATION_OPTIMIZATION OFF 
GO

ALTER DATABASE [MovieDB] SET TRUSTWORTHY OFF 
GO

ALTER DATABASE [MovieDB] SET ALLOW_SNAPSHOT_ISOLATION OFF 
GO

ALTER DATABASE [MovieDB] SET PARAMETERIZATION SIMPLE 
GO

ALTER DATABASE [MovieDB] SET READ_COMMITTED_SNAPSHOT OFF 
GO

ALTER DATABASE [MovieDB] SET HONOR_BROKER_PRIORITY OFF 
GO

ALTER DATABASE [MovieDB] SET RECOVERY FULL 
GO

ALTER DATABASE [MovieDB] SET  MULTI_USER 
GO

ALTER DATABASE [MovieDB] SET PAGE_VERIFY CHECKSUM  
GO

ALTER DATABASE [MovieDB] SET DB_CHAINING OFF 
GO

ALTER DATABASE [MovieDB] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) 
GO

ALTER DATABASE [MovieDB] SET TARGET_RECOVERY_TIME = 60 SECONDS 
GO

ALTER DATABASE [MovieDB] SET DELAYED_DURABILITY = DISABLED 
GO

ALTER DATABASE [MovieDB] SET ACCELERATED_DATABASE_RECOVERY = OFF  
GO

ALTER DATABASE [MovieDB] SET QUERY_STORE = OFF
GO

ALTER DATABASE [MovieDB] SET  READ_WRITE 
GO


建立資料表



USE [MovieDB]
GO
/****** Object:  Table [dbo].[Movie]    Script Date: 2021/12/13 下午 01:33:24 ******/
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Movie]') AND type in (N'U'))
DROP TABLE [dbo].[Movie]
GO
/****** Object:  Table [dbo].[Movie]    Script Date: 2021/12/13 下午 01:33:24 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Movie](
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[Genre] [nvarchar](max) NULL,
	[Price] [decimal](18, 2) NOT NULL,
	[ReleaseDate] [datetime2](7) NOT NULL,
	[Title] [nvarchar](max) NULL,
 CONSTRAINT [PK_Movie] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Movie] ON 
GO



SeedData.cs內容改為   


using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;

namespace RazorPagesMovie.Models
{
    public class SeedData
    {
        public static void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new RazorPagesMovieContext(
                serviceProvider.GetRequiredService<
                    DbContextOptions<RazorPagesMovieContext>>()))
            {
                if (context == null || context.Movie == null)
                {
                    throw new ArgumentNullException("Null RazorPagesMovieContext");
                }

                //Look for any movies.
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
}

Program.cs新增黃色區域部分   (官方網頁寫 程式.cs 是把不該翻譯的檔案名稱翻譯掉了)


using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

builder.Services.AddDbContext<RazorPagesMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("RazorPagesMovieContext")));

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    SeedData.Initialize(services);
}

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

F5執行,目錄加上 /movies


********************************************************************************

更新頁面

https://docs.microsoft.com/zh-tw/aspnet/core/tutorials/razor-pages/da1?view=aspnetcore-6.0

把Create.cshtml, Delete.cshtml, Details.cshtml, Edit.cshtml 的   

@page 

改為   

@page "{id:int}"

會強制檢查傳入的 id 參數是否為整數,不是則傳回 HTTP 404錯誤。


********************************************************************************

新增搜尋

https://docs.microsoft.com/zh-tw/aspnet/core/tutorials/razor-pages/search?view=aspnetcore-6.0

Pages/Movies/Index.cshtml.cs內容新增黃色部分


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;

namespace RazorPagesMovie.Pages.Movies
{
    public class IndexModel : PageModel
    {
        private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;

        public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
        {
            _context = context;
        }

        public IList<Movie> Movie { get;set; }
        [BindProperty(SupportsGet = true)]
        public string SearchString { get; set; }
        public SelectList Genres { get; set; }
        [BindProperty(SupportsGet = true)]
        public string MovieGenre { get; set; }

        //public async Task OnGetAsync()
        //{
        //    Movie = await _context.Movie.ToListAsync();
        //}
        public async Task OnGetAsync()
        {
            var movies = from m in _context.Movie
                         select m;
            if (!string.IsNullOrEmpty(SearchString))
            {
                movies = movies.Where(s => s.Title.Contains(SearchString));
            }

            Movie = await movies.ToListAsync();
        }
    }
}


網址改為下面 ( port 可能不同)   

https://localhost:5001/Movies?searchString=Ghost

********************************************************************************

新增搜尋2

Pages/Movies/Index.cshtml內容第一行

@page                      
改為
@page "{searchString?}"    

網址可改成路由查詢方式

********************************************************************************
新增搜尋3

Pages/Movies/Index.cshtml 內容新增黃色區域部分

   
@page "{searchString?}"
@model RazorPagesMovie.Pages.Movies.IndexModel

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

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<form>
    <p>
        Title: <input type="text" asp-for="SearchString" />
        <input type="submit" value="Filter" />
    </p>
</form>
<table class="table">           


********************************************************************************
新增搜尋4 - 依內容類型

Pages/Movies/Index.cshtml.cs 的 OnGetAsync() 換為下面

   
public async Task OnGetAsync()
{
    // Use LINQ to get list of genres.
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;

    var movies = from m in _context.Movie
                 select m;

    if (!string.IsNullOrEmpty(SearchString))
    {
        movies = movies.Where(s => s.Title.Contains(SearchString));
    }

    if (!string.IsNullOrEmpty(MovieGenre))
    {
        movies = movies.Where(x => x.Genre == MovieGenre);
    }
    Genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    Movie = await movies.ToListAsync();
}       

Pages/Movies/Index.cshtml 內容新增黃色區域部分

   
<form>
    <p>
        <select asp-for="MovieGenre" asp-items="Model.Genres">
            <option value="">All</option>
        </select>
        Title: <input type="text" asp-for="SearchString" />
        <input type="submit" value="Filter" />
    </p>
</form>        



********************************************************************************
新增欄位


參考其他欄位,修改下面內容

Models/Movie.cs

Pages/Movies/Create.cshtml
Pages/Movies/Delete.cshtml
Pages/Movies/Details.cshtml
Pages/Movies/Edit.cshtml

到 Visual Studio 2022 的「工具」下拉選單,選「NuGet套件管理員」下的「套件管理器主控台」。
在 PowerShell 執行下面兩個指令

Add-Migration Rating
Update-Database

或到 SMSS 中砍掉資料庫,在 PowerShell 執行下面指令

Update-Database

********************************************************************************
新增欄位驗證規則


法規名稱:資通安全責任等級分級辦法 EN
修正日期:民國 110 年 08 月 23 日
附檔:附表十 資通系統防護基準.PDF
構面:系統與資訊完整性
措施內容:軟體及資訊完整性
控制措施:二、使用者輸入資料合法性檢查應置放於應用系統伺服器端。

於前端實作欄位驗證的方式就不特別研究了,而且直接顯示於網頁的訊息,有時候對某些使用者而言,不夠明顯,他們比較喜歡彈出式的對話盒視窗 (JavaScript Alert Dialog)。

********************************************************************************

(完)

相關

RazorASP.NET Core 中的頁面簡介 | Microsoft Docs
https://docs.microsoft.com/zh-tw/aspnet/core/razor-pages/?view=aspnetcore-6.0&tabs=visual-studio
Introduction to Razor Pages in ASP.NET Core
2021-12-02
https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-6.0&tabs=visual-studio

教學課程: Razor 使用 ASP.NET Core 建立頁面 web 應用程式 | Microsoft Docs
https://docs.microsoft.com/zh-tw/aspnet/core/tutorials/razor-pages/?view=aspnetcore-6.0
Tutorial: Create a Razor Pages web app with ASP.NET Core
2021-10-15
https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/?view=aspnetcore-6.0

在錯誤中學習ASP.NET MVC系列 第 16 篇 - 認識View - Razor基本語法
https://ithelp.ithome.com.tw/users/20091626/ironman/893?page=2

Microsoft - UAC195 使用ASP.NET Core Razor Page開發網站https://www.uuu.com.tw/Course/Show/1784/%E4%BD%BF%E7%94%A8ASP-NET-Core-Razor-Page%E9%96%8B%E7%99%BC%E7%B6%B2%E7%AB%99

Razor ASP.NET Core 中的頁面與 Entity Framework Core-教學課程 1/8
https://docs.microsoft.com/zh-tw/aspnet/core/data/ef-rp/intro?view=aspnetcore-6.0&tabs=visual-studio

Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial 1 of 8
https://docs.microsoft.com/en-us/aspnet/core/data/ef-rp/intro?view=aspnetcore-6.0&tabs=visual-studio

沒有留言:

張貼留言