ASP.NET MVC Tutorial
MVC pattern
- Models : 유효성 검사, 비즈니스 로직 적용, 뷰에 결과 제공
- Views : 모델 데이터 표시, UI 구성 요소
- Controllers : 브라우저 요청 처리, 모델 데이터 검색(모델에 전달), 뷰 템플릿 호출
MVC 앱 생성
1
dotnet new mvc -o HelloMvc
- 
    HelloWorldController.cs추가 후 아래 코드 입력1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 using Microsoft.AspNetCore.Mvc; using System.Text.Encodings.Web; namespace MvcMovie.Controllers; public class HelloWorldController : Controller { // // GET: /HelloWorld/ public string Index() { return "This is my default action..."; } // // GET: /HelloWorld/Welcome/ public string Welcome() { return "This is the Welcome action method..."; } } - localhost:port/HelloWorld로 접속하면 Index()가 실행됨
- https는 아래 명령어 실행해서 인증서 신뢰하도록 설정해야 함
        1 dotnet dev-certs https --trust
 
라우팅 포맷
- /[Controller]/[ActionName]/[Parameters]서식을 따름
- 
    Program.cs파일에서 설정 가능1 2 3 app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); 
- 
    Welcome()을 아래와 같이 변경:1 2 3 4 5 6 // GET: /HelloWorld/Welcome/ // Requires using System.Text.Encodings.Web; public string Welcome(string name, int numTimes = 1) { return HtmlEncoder.Default.Encode($"Hello {name}, NumTimes is: {numTimes}"); } - localhost:port/HelloWorld/Welcome?name=yang&numtimes=5와 같이 파라미터를 입력 후 실행해서 결과 나오는지 확인
 
- Welcome()을 Path Variable을 사용하도록 변경:- 1 2 3 4 - public string Welcome(string name, int ID = 1) { return HtmlEncoder.Default.Encode($"Hello {name}, ID: {ID}"); } - routing format에서 path variable은 대소문자 신경쓰지 않는 것 같음
- {id?}:- ?는- id가 optional임을 나타냄
 
View 추가
- 
    HelloWorldController의Index()도 view method를 호출하도록 변경1 2 3 4 public IActionResult Index() { return View(); } 
- 
    Views/HelloWorld/Index.cshtml추가1 2 3 4 5 6 7 @{ ViewData["Title"] = "Indextitle"; } <h2>Index</h2> <p>Hello from our View Template!</p> 
- 
    Views/Shared/_Layout.cshtml변경1 2 3 4 5 6 7 8 9 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie App</title> ... <div class="container-fluid"> <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a> ... <div class="container"> © 2023 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a> </div> - 현재는 Movies컨트롤러가 없기 때문에 Moive App 링크가 작동하지 않음
- title 끝부분이 Movie App으로 바뀐 것 확인
        - 레이아웃을 변경했기 때문에 모든 페이지가 동일하게 변경됨
            - Views/_ViewStart.cshtml에서- _Layout.cshtml을 불러오기 때문
 
 
- 레이아웃을 변경했기 때문에 모든 페이지가 동일하게 변경됨
            
 
- 현재는 
- 
    Views/HelloWorld/Index.cshtml을 아래처럼 변경1 2 3 4 5 6 @{ ViewData["Title"] = "Movie List"; } <h2>My Movie List</h2> ...  - layout template을 사용해서 Index.cshtml과Views/Shared/_Layout.cshtml을 합침
 
- layout template을 사용해서 
Controller에서 View로 데이터 전달
- Controller는 View에서 렌더링할 데이터를 제공해야 함
- HelloWorldController에서- ViewData에 데이터를 추가하고, view에서 가져다 쓰도록 구현할 예정
- HelloWorldController.cs을 아래처럼 변경- 1 2 3 4 5 6 - public IActionResult Welcome(string name, int numTimes=1) { ViewData["Message"]="Hello "+name; ViewData["NumTimes"]=numTimes; return View(); } 
- 
    Views/HelloWorld/Welcome.cshtml생성1 2 3 4 5 6 7 8 9 10 11 12 @{ ViewData["Title"] = "Welcome"; } <h2>Welcome</h2> <ul> @for (int i = 0; i < (int)ViewData["NumTimes"]!; i++) { <li>@ViewData["Message"]</li> } </ul>  - ViewData를 사용해서 컨트롤러에서 뷰로 데이터를 전달함
 
모델 추가
- 보통 모델은 EF Core와 함께 DB 접근에 사용됨
    - EF Core(Entity Framework Core) : JPA Entity 같은 ORM framework
 
- 모델 클래스 자체는 POCO(Plain Old CLR Objects)로 EF Core 종속성이 없음
    - DB에 저장되는 데이터의 속성만 정의함
 
- 예제에서는 모델 클래스, EF Core, DB 순으로 만들 예정
데이터 모델 클래스 추가
- 
    Models/Movie.cs생성1 2 3 4 5 6 7 8 9 10 11 12 13 using System.ComponentModel.DataAnnotations; namespace MvcMovie.Models; public class Movie { public int Id { get; set; } public string? Title { get; set; } [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } public string? Genre { get; set; } public decimal Price { get; set; } } - string?:- nullable을 의미함
- DataType.Date: 시간을 제외한 날짜
 
- 
    NuGet 패키지 추가 1 2 3 4 5 6 7 8 dotnet tool uninstall --global dotnet-aspnet-codegenerator dotnet tool install --global dotnet-aspnet-codegenerator dotnet tool uninstall --global dotnet-ef dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.EntityFrameworkCore.SQLite dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.SqlServer - .NET 6.0일 경우
        - dotnet-aspnet-codegenerator,- Microsoft.VisualStudio.Web.CodeGeneration.Design는 버전 맞춰줘야 함- 1 2 - dotnet tool install --global dotnet-aspnet-codegenerator --version 6.0.0 dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design --version 6.0.10 
 
 
- .NET 6.0일 경우
        
영화 페이지 스캐폴드
1
2
export PATH=$HOME/.dotnet/tools:$PATH
dotnet aspnet-codegenerator controller -name MoviesController -m Movie -dc MvcMovie.Data.MvcMovieContext --relativeFolderPath Controllers --useDefaultLayout --referenceScriptLibraries -sqlite
- 스캐폴딩 실행 후에는 아래와 같은 기능들이 추가됨
    - Controllers/MoviesController.cs
- Vies/Movies/*.cshtml: CRUD, Index 페이지에 대한 Razor 뷰 파일
- Data/MvcMovieContext.cs: DB context 클래스
 
초기 마이그레이션
- migration : Data model과 일치하는 DB를 만들고 수정할 수 있는 도구 모음
1
2
dotnet ef migrations add InitialCreate
dotnet ef database update
- 앱 실행해서 Movie App 클릭 후 정상 작동 확인
 
DB 초기화
- 
    SeedData/SeedData.cs생성1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using MvcMovie.Data; using System; using System.Linq; namespace MvcMovie.Models; public static class SeedData { public static void Initialize(IServiceProvider serviceProvider) { using (var context = new MvcMovieContext( serviceProvider.GetRequiredService< DbContextOptions<MvcMovieContext>>())) { // 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수정1 2 3 4 5 6 7 8 9 10 11 ... using MvcMovie.Models; ... using (var scope = app.Services.CreateScope()) { var services = scope.ServiceProvider; SeedData.Initialize(services); } - 다시 실행해서 시드 데이터 들어간 것 확인
 
- 
    Models/Movie.cs수정
1
2
3
4
5
6
7
8
9
10
11
12
...
using System.ComponentModel.DataAnnotations.Schema;
...
		[Display(Name ="Release Data")]
		[DataType(DataType.Date)]
		public DateTime ReleaseDate { get; set; }
		public string? Genre { get; set; }
		[Column(TypeName ="decimal(18, 2)")]
		public decimal Price { get; set; }
}
 
       
      
Leave a comment