js 개발자를 위한 초스피드 .NET, Blazor를 다루는 기술

이 게시글들은
js 개발자를 위한 초스피드 .NET, Blazor를 다루는 기술
이라는 책을 작성하기 위해 JS 개발자였던 제가 Blazor와 .NET을 학습해 나가는 과정을 차근차근 정리해 가는 팁 들입니다.

13개의 좋아요

Blazor를 사용한 웹 개발 소개

.NET

=> SSR 기반의 서버 프레임워크

Razor

=> 텍스트 기반의 CSR 을 위한 파일명(cshtml, razor 포함)

Blazor

=> .NET 및 Razor를 기반으로 하는 사용자 인터페이스 프레임워크. 클라이언트 및 서버 코드 빌드 가능. 프런트 엔드와 백 엔드 논리를 사용하여 코드와 라이브러리를 공유가능.

Blazor Server

=> ASP.NET Core 웹 개발 프레임워크의 일부로 SSR 기반의 프레임워크. 서버와 SignalR로 연겨되어 통신

Blazor WebAssembly

=> CSR 기반의 프레임워크

4개의 좋아요

[01] Blazor를 사용하여 웹앱 빌드

시작 전 좋은 책 추천

Blazor란?

Blazor 앱은 C#, HTML, CSS를 사용하여 빌드된 재사용 가능 웹 UI 구성 요소로 구성됩니다. Blazor를 통해 개발자는 C#으로 클라이언트 및 서버 코드를 빌드할 수 있습니다. 또한 프런트 엔드 클라이언트 코드와 백 엔드 논리를 사용하여 코드와 라이브러리를 공유할 수 있습니다.

WebAssembly란?

WebAssembly(WASM)는 개방형 이진 표준입니다. 웹 브라우저에서 실행되도록 설계된 프로그램의 이식 가능한 코드 형식을 정의합니다. WebAssembly는 빠른 다운로드와 네이티브에 가까운 성능을 위한 컴팩트 이진 형식의 텍스트 어셈블리 언어입니다.

한마디로 CSR 인데 따로 빌드 과정 없이 웹에서 실행 가능한 코드이다.

WebAssembly는 C, C++, Rust 등의 언어에 컴파일 대상을 제공합니다. JavaScript와 함께 실행되어 둘 다 함께 사용할 수 있도록 설계되었습니다. 또한 WebAssembly는 점진적 웹 애플리케이션을 생성하여 오프라인으로 다운로드하고 실행할 수 있습니다.

Blazor WebAssembly는 무엇인가요?

Blazor WebAssembly를 사용하면 개발자가 브라우저에서 .NET 코드를 실행할 수 있습니다. 플러그 인 또는 코드 생성을 요구하지 않고 WebAssembly 개방형 표준을 사용하는 단일 페이지 앱 프레임워크입니다.

브라우저에서 WebAssembly를 통해 실행되는 .NET 코드는 브라우저의 JavaScript 샌드박스에서 실행됩니다.

Blazor는 앱에 다운로드할 수 있는 WebAssembly 모듈에 컴파일된 .NET 런타임을 사용합니다.

Blazor 서버란?

Blazor 서버는 ASP.NET Core 앱의 서버에서 Razor 구성 요소를 호스팅할 수 있도록 지원합니다. UI 업데이트는 SignalR 연결을 통해 처리됩니다.

런타임은 서버에 유지되고 다음을 처리합니다.

  • 앱의 C# 코드를 실행합니다.
  • 브라우저에서 서버로 UI 이벤트를 보냅니다.
  • 서버에서 다시 전송되는 렌더링된 구성 요소에 UI 업데이트를 적용합니다.

Blazor Server에서 브라우저와 통신하는 데 사용하는 연결은 JavaScript interop 호출을 처리하는 데도 사용됩니다.

Blazor를 사용하여 웹앱 빌드

Razor 구성 요소란?

Razor 파일은 앱의 일부 UI를 구성하는 구성 요소를 정의합니다. Blazor의 구성 요소는 ASP.NET Web Forms의 사용자 컨트롤과 유사합니다.

프로젝트를 살펴보면 대부분의 파일이 .razor 파일인 것을 알 수 있습니다.

컴파일 시간에 각 Razor 구성 요소는 .NET 클래스로 빌드됩니다. 클래스에는 상태, 렌더링 논리, 수명 주기 메서드 및 이벤트 처리기와 같은 일반 UI 요소가 포함됩니다.

@page "/todo"

<h3>Todo ( @todos.Count(todo => !todo.IsDone) )</h3>
<ul>
	@foreach (var todo in todos)
	{
		<li>
			<input type="checkbox" @bind="todo.IsDone"/>
			<input @bind="todo.title" />
		</li>
	}
</ul>

@* bind 는 데이터 바인딩을 위한 목적, input 태그에 value와 묶여 변경을 처리 *@
<input placeholder="Something todo" @bind="newtodo"/>
<button @onclick="AddTodo">Add todo</button>

@code {
	// new() 사용시 클래스 생성자를 호출하여 객체 생성과 초기화를 한 번에 진행
	// List<> 배열은 동적 크기를 가짐. 체인 링크드 리스트 방식
	// [] 배열은 고정된 정적 크기
	private List<TodoItem> todos = new();
	//String 과 string은 차이가 없다. 그러니 자료형을 잘 표현하기 위해 나는 대문자를 쓰면 된다.
	private String newtodo;
	private void AddTodo()
	{
		if (newtodo !=null)
		{
			todos.Add(new TodoItem{title=newtodo, IsDone=true});
			newtodo = String.Empty;
		}
	}

}

Todo.razor

Blazor 웹앱에서 데이터와 상호 작용

Blazor 구성 요소 이해

Blazor는 개발자가 C# 코드를 작성하여 풍부한 대화형 UI(사용자 인터페이스)를 만드는 데 사용할 수 있는 프레임워크입니다. Blazor를 사용하면 서버 쪽과 클라이언트 쪽 모두에서 모든 코드에 동일한 언어를 사용하고 모바일 디바이스의 브라우저를 포함하여 다양한 브라우저에 표시하기 위해 렌더링할 수 있습니다.

참고
Blazor 앱에는 두 가지 코드 호스팅 모델이 있습니다.

  • Blazor Server: 이 모델에서 앱은 ASP.NET Core 앱 내의 웹 서버에서 실행됩니다. 클라이언트 쪽의 UI 업데이트, 이벤트 및 JavaScript 호출은 클라이언트와 서버 간의 SignalR 연결을 통해 전송됩니다. 이 모듈에서는 이 모델에 대해 설명하고 코딩합니다.
  • Blazor WebAssembly: 이 모델에서는 Blazor 앱, 해당 종속성 및 .NET 런타임이 다운로드되어 브라우저에서 실행됩니다.

Blazor에서는 “구성 요소”라고 하는 코드의 자체 포함 부분에서 UI를 빌드합니다. 각 구성 요소는 HTML 및 C# 코드가 혼합되어 있을 수 있습니다. 구성 요소는 코드가 @code 지시문으로 표시되는 Razor 구문을 사용하여 작성됩니다. 다른 지시문을 사용하여 변수에 액세스하고, 값에 바인딩하고, 다른 렌더링 작업을 수행할 수 있습니다. 앱이 컴파일되면 HTML 및 코드가 구성 요소 클래스로 컴파일됩니다. 구성 요소는 .razor 확장명의 파일로 작성됩니다.

참고
Razor 구문은 .NET 코드를 웹 페이지에 포함시키는 데 사용됩니다. 파일 확장명이 .cshtmlASP.NET MVC 애플리케이션에서 이 구문을 사용할 수 있습니다. Razor 구문은 Blazor에서 구성 요소를 작성하는 데 사용됩니다. 이러한 구성 요소에는 대신 .razor 확장자가 있으며 컨트롤러와 보기가 엄격하게 구분되지 않습니다.

Blazor 구성 요소에서 코드 작성


dotnet new blazorserver --no-https true -o BlazzingPizza -f net6.0

Blazor에서 UI를 빌드할 때 흔히 동일한 파일에 있는 정적 HTML 및 CSS 태그를 C# 코드와 혼합합니다. 이러한 코드 형식을 구분하기 위해 Razor 구문을 사용합니다. Razor 구문에는 C# 코드, 라우팅 매개 변수, 바인딩된 데이터, 가져온 클래스 및 기타 기능을 구분하는, @ 기호가 접두사로 추가된 지시문이 포함됩니다.

다음 예제 구성 요소를 다시 살펴보겠습니다.

@page "/index"

<h1>Welcome to Blazing Pizza</h1>

<p>@welcomeMessage</p>

@code {
  private string welcomeMessage = "However you like your pizzas, we can deliver them fast!";
}

<h1><p> 태그를 통해 HTML 태그를 알아볼 수 있습니다. 이 태그는 코드가 동적 콘텐츠를 삽입하는 페이지의 정적 프레임워크입니다. Razor 태그는 다음으로 구성됩니다.

  • @page 지시문: 이 지시문은 Blazor에 경로 템플릿을 제공합니다. 런타임에 Blazor는 이 템플릿을 사용자가 요청한 URL과 일치시켜 렌더링할 페이지를 찾습니다. 이 경우 http://yourdomain.com/index 양식의 URL과 일치시킬 수 있습니다.
  • @code 지시문: 이 지시문은 다음 블록의 텍스트가 C# 코드임을 선언합니다. 구성 요소에 필요한 만큼 코드 블록을 포함할 수 있습니다. 이러한 코드 블록에서 구성 요소 클래스 멤버를 정의하고 계산, 데이터 조회 작업 또는 기타 소스에서 해당 값을 설정할 수 있습니다. 이 경우 코드는 welcomeMessage라는 단일 구성 요소 멤버를 정의하고 해당 문자열 값을 설정합니다.
  • 멤버 액세스 지시문: 렌더링 논리에 멤버의 값을 포함하려면 @ 기호 뒤에 멤버 이름 같은 C# 식을 사용합니다. 여기서는 @welcomeMessage 지시문이

    태그에서 welcomeMessage 멤버의 값을 렌더링하는 데 사용됩니다.

Blazor 애플리케이션에서 데이터 공유

Blazor에는 구성 요소 간에 정보를 공유하는 여러 가지 방법이 포함되어 있습니다. 구성 요소 매개 변수 또는 연계 매개 변수를 사용하여 부모 구성 요소에서 자식 구성 요소로 값을 보낼 수 있습니다. AppState 패턴은 값을 저장하고 애플리케이션의 모든 구성 요소에서 액세스하는 데 사용할 수 있는 또 다른 방법입니다.

구성 요소 매개 변수를 사용하여 다른 구성 요소와 정보 공유

구성 요소가 태그의 일부만 렌더링하는 경우 이를 부모 구성 요소 내에서 자식 구성 요소로 사용해야 합니다. 자식 구성 요소는 그 안에 렌더링되는 다른 작은 구성 요소의 부모일 수도 있습니다. 자식 구성 요소를 중첩된 구성 요소라고도 합니다.

이 부모 및 자식 구성 요소 계층 구조에서는 구성 요소 매개 변수를 사용하여 구성 요소 간에 정보를 공유할 수 있습니다. 자식 구성 요소에서 이러한 매개 변수를 정의한 다음, 부모 구성 요소에서 해당 값을 설정합니다.

자식 구성 요소에서 구성 요소 매개 변수를 정의하는 것으로 시작합니다. C# 공용 속성으로 정의되고 [Parameter] 특성으로 데코레이트됩니다.

<h2>New Pizza: @PizzaName</h2>

<p>@PizzaDescription</p>

@code {
    [Parameter]
    public string PizzaName { get; set; }
    
    [Parameter]
    public string PizzaDescription { get; set; } = "The best pizza you've ever tasted."
}

구성 요소 매개 변수는 자식 구성 요소의 멤버이므로 Blazor의 예약된 @ 기호 및 해당 이름을 사용하여 HTML에서 렌더링할 수 있습니다. 또한 앞의 코드는 PizzaDescription 매개 변수의 기본값을 지정합니다. 부모 구성 요소가 값을 전달하지 않으면 이 값이 렌더링됩니다. 아니면 부모로부터 전달된 값으로 재정의됩니다.

프로젝트에서 사용자 지정 클래스를 구성 요소 매개 변수로 사용할 수도 있습니다. 토핑을 설명하는 다음 클래스를 생각해 보겠습니다.

public class PizzaTopping
{
    public string Name { get; set; }
    public string Ingredients { get; set; }
}

점 구문을 사용하여 클래스의 개별 속성에 액세스하는 매개 변수 값과 동일한 방식으로 이를 구성 요소 매개 변수로 사용할 수 있습니다.

<h2>New Topping: @Topping.Name</h2>

<p>Ingredients: @Topping.Ingredients</p>

@code {
    [Parameter]
    public PizzaTopping Topping { get; set; }
}

부모 구성 요소에서 자식 구성 요소 태그의 특성을 사용하여 매개 변수 값을 설정합니다. 간단한 구성 요소를 직접 설정합니다. 사용자 지정 클래스를 기반으로 하는 매개 변수를 사용하여 인라인 C# 코드로 해당 클래스의 새 인스턴스를 만들고 해당 값을 설정합니다.

@page "/pizzas-toppings"

<h1>Our Latest Pizzas and Topping</h1>

<Pizza PizzaName="Hawaiian" PizzaDescription="The one with pineapple" />

<PizzaTopping Topping="@(new PizzaTopping() { Name = "Chilli Sauce", Ingredients = "Three kinds of chilli." })" />

연계 매개 변수를 사용하여 정보 공유

자식의 자식이 있는 심층 계층 구조가 있는 경우 상황이 어려워집니다. 구성 요소 매개 변수는 상위 구성 요소에서 손자 구성 요소 또는 계층 구조의 하위 구성 요소로 자동으로 전달되지 않습니다.

이 문제를 자연스럽게 처리하기 위해 Blazor에는 연계 매개 변수가 포함되어 있습니다. 구성 요소에서 연계 매개 변수의 값을 설정하면 모든 깊이의 모든 하위 구성 요소에서 해당 값을 자동으로 사용할 수 있습니다.

부모 구성 요소에서 태그를 사용하면 모든 하위 항목에 계단식으로 배열할 정보가 지정됩니다. 이 태그는 기본 제공 Blazor 구성 요소로 구현됩니다. 해당 태그 내에서 렌더링되는 모든 구성 요소는 값에 액세스할 수 있습니다.

@page "/specialoffers"

<h1>Special Offers</h1>

<CascadingValue Name="DealName" Value="Throwback Thursday">
    <!-- Any descendant component rendered here will be able to access the cascading value. -->
</CascadingValue>

하위 구성 요소에서 구성 요소 멤버를 사용하고 [CascadingParameter] 특성으로 데코레이트하여 연계 값에 액세스할 수 있습니다.

<h2>Deal: @DealName</h2>

@code {
    [CascadingParameter(Name="DealName")]
    private string DealName { get; set; }
}

따라서 이 예제에서

태그는 상위 구성 요소에 의해 연계 값이 설정되었기 때문에 Deal: Throwback Thursday 콘텐츠를 갖습니다.

앞의 예제에서 연계 값은 부모의 Name 특성으로 식별되며 [CascadingParameter] 특성의 Name 값과 일치됩니다. 필요에 따라 이러한 이름을 생략할 수 있습니다. 이 경우 특성은 형식을 기준으로 일치됩니다. 이름을 누락하는 방법은 해당 형식의 매개 변수가 하나만 있는 경우에 잘 작동합니다. 서로 다른 두 문자열 값을 계단식으로 배열하려면 매개 변수 이름을 사용하여 모호성을 방지해야 합니다.

AppState를 사용하여 정보 공유

다른 구성 요소 간에 정보를 공유하는 또 다른 방법은 AppState 패턴을 사용하는 것입니다.

저장하려는 속성을 정의하고 범위가 지정된 서비스로 등록하는 클래스를 만듭니다. AppState 값을 설정 또는 사용하려는 모든 구성 요소에서 서비스를 삽입한 다음 해당 속성에 액세스할 수 있습니다. 구성 요소 매개 변수 및 연계 매개 변수와 달리 AppState의 값은 해당 값을 저장한 구성 요소의 자식이 아닌 구성 요소까지 포함하여 애플리케이션의 모든 구성 요소에서 사용할 수 있습니다.

예를 들어 매출에 대한 값을 저장하는 이 클래스를 사용하는 것이 좋습니다.

public class PizzaSalesState
{
    public int PizzasSoldToday { get; set; }
}

Program.cs 파일에서 클래스를 범위가 지정된 서비스로 추가합니다.

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

// Add the AppState class
builder.Services.AddScoped<PizzaSalesState>();
...

이제 AppState 값을 설정하거나 검색하려는 구성 요소에서 클래스를 삽입한 다음 속성에 액세스할 수 있습니다.

@page "/"
@inject PizzaSalesState SalesState

<h1>Welcome to Blazing Pizzas</h1>

<p>Today, we've sold this many pizzas: @SalesState.PizzasSoldToday</p>

<button @onclick="IncrementSales">Buy a Pizza</button>

@code {
    private void IncrementSales()
    {
        SalesState.PizzasSoldToday++;
    }
}

Blazor 애플리케이션의 컨트롤을 데이터에 바인딩

Blazor를 사용하면 변경되는 값이 UI(사용자 인터페이스)에 자동으로 표시되도록 HTML 컨트롤을 속성에 바인딩할 수 있습니다.

고객의 피자 선호에 대한 정보를 수집하는 페이지를 개발한다고 가정합니다. 데이터베이스에서 정보를 로드하고 고객이 즐겨찾는 토핑을 기록하는 등 변경을 할 수 있도록 하려고 합니다. 데이터베이스에서 사용자에 의한 변경 또는 업데이트가 있는 경우 UI에 가능한 한 빨리 새 값을 표시하려고 합니다.

데이터 바인딩이란?

HTML 요소가 값을 표시하도록 하려면 디스플레이를 변경하는 코드를 작성할 수 있습니다. 값이 변경될 때 디스플레이를 업데이트하려면 추가 코드를 작성해야 합니다. Blazor에서 데이터 바인딩을 사용하여 HTML 요소를 필드, 속성 또는 식에 연결할 수 있습니다. 이렇게 하면 값이 변경될 때 HTML 요소가 자동으로 업데이트됩니다. 업데이트는 일반적으로 변경 후 빠르게 이루어지며 업데이트 코드를 작성할 필요가 없습니다.

컨트롤을 바인딩하려면 @bind 지시문을 사용합니다.

@page "/"

<p>
    Your email address is:
    <input @bind="customerEmail" />
</p>

@code {
    private string customerEmail = "john.doe@contoso.com"
}

특정 이벤트에 요소를 바인딩

@bind 지시문은 스마트하며 사용하는 컨트롤을 이해합니다.

예를 들어 값을 <input> 텍스트 상자에 바인딩하면 value 특성이 바인딩됩니다. HTML 확인란 <input>에는 value 특성 대신 checked 특성이 있습니다. @bind 특성은 이 checked 특성을 대신 자동으로 사용합니다. 기본적으로 컨트롤은 DOM onchange 이벤트에 바인딩됩니다. 예를 들어 다음 페이지를 생각해 보세요.

@page "/"

<h1>My favorite pizza is: @favPizza</h1>

<p>
    Enter your favorite pizza:
    <input @bind="favPizza" />
</p>

@code {
    private string favPizza { get; set; } = "Margherita"
}

페이지가 렌더링되면 기본값 Margherita<h1> 요소 및 텍스트 상자 모두에 표시됩니다.

텍스트 상자에 새 즐겨찾는 피자를 입력하면 텍스트 상자 밖을 탭하거나 Enter 키를 선택할 때까지는 <h1> 요소가 변경되지 않습니다. 그 시점에 onchange DOM 이벤트가 발생하기 때문입니다.

이것이 원하는 동작인 경우가 많습니다. 하지만 텍스트 상자에 문자를 입력하는 즉시 <h1> 요소를 업데이트하려 한다고 가정합니다. 대신 oninput DOM 이벤트에 바인딩하여 이 결과를 얻을 수 있습니다. 이 이벤트에 바인딩하려면 @bind-value@bind-value:event 지시문을 사용해야 합니다.

@page "/"

<h1>My favorite pizza is: @favPizza</h1>

<p>
    Enter your favorite pizza:
    <input @bind-value="favPizza" @bind-value:event="oninput" />
</p>

@code {
    private string favPizza { get; set; } = "Margherita"
}

이 경우 텍스트 상자에 문자를 입력하는 즉시 제목이 변경됩니다.

바인딩된 값 서식 지정

사용자에게 날짜를 표시하는 경우 현지 데이터 형식을 사용할 수 있습니다. 예를 들어 요일이 앞에 오도록 날짜를 작성하는 것을 선호하는 영국 사용자를 위해 페이지를 작성한다고 가정합니다. @bind:format 지시문을 사용하여 단일 날짜 서식 문자열을 지정할 수 있습니다.

@page "/ukbirthdaypizza"

<h1>Order a pizza for your birthday!</h1>

<p>
    Enter your birth date:
    <input @bind="birthdate" @bind:format="dd-MM-yyyy" />
</p>

@code {
    private DateTime birthdate { get; set; } = new(2000, 1, 1);
}

이 문서 작성 시 서식 문자열은 날짜 값에서만 지원됩니다.

나중에 통화 형식, 숫자 형식 및 기타 형식이 추가될 수 있습니다. 바인딩 형식에 대한 최신 내용을 확인하려면 Blazor 설명서의 형식 문자열을 참조하세요.

@bind:format 지시문을 사용하는 대신 바인딩된 값의 서식을 지정하는 C# 코드를 작성할 수 있습니다. 다음 예제와 같이 멤버 정의에서 get 및 set 접근자를 사용합니다.

@page "/pizzaapproval"
@using System.Globalization

<h1>Pizza: @PizzaName</h1>

<p>Approval rating: @approvalRating</p>

<p>
    <label>
        Set a new approval rating:
        <input @bind="ApprovalRating" />
    </label>
</p>

@code {
    private decimal approvalRating = 1.0;
    private NumberStyles style = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign;
    private CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
    
    private string ApprovalRating
    {
        get => approvalRating.ToString("0.000", culture);
        set
        {
            if (Decimal.TryParse(value, style, culture, out var number))
            {
                approvalRating = Math.Round(number, 3);
            }
        }
    }
}
7개의 좋아요

DB를 local에서 만들고 연결하기

DB Helper를 달기 위해 DB 만들기

[ 환경 셋팅 ]
DBMS : Download | DBeaver Community

시작전 Base가 되는 github 파일을 받아오자

git clone GitHub - MicrosoftDocs/mslearn-interact-with-data-blazor-web-apps: Sample repo for Interact with Data for Blazor Web Apps Learn Module BlazingPizza

sqlite 기반 간단한 DB 만들기

  1. 패키지 설치
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Sqlite 
dotnet add package System.Net.Http.Json 

위 세 가지 패키지를 다운 받아주어야 한다.
우리는 Sqlite 기반의 매우 간단한 DB를 만들 계획이다.

image

간단하게 Visual Studio에서 NuGet 패키지를 검색해서 설치해도 되고

Visual Studio 콘솔창에 설치할 패키지를 입력해도 설치가 된다.

최종적으로 패키지 관리나 혹은 csproj 파일에서 위와같이 패키지가 보이면 성공이다.

  1. DB 를 만들고 데이터 삽입하기
  • DB 데이터 모델 정의
  • DB Context 정의
  • DB Controller 정의
  • DB 초기 데이터 정의
  • DB 생성 && 초기 데이터 삽입

[ DB 데이터 모델 정의 ]


DB 에서 읽고 쓰기 위해서 DB 의 데이터 형을 알고 있어야 한다. 이걸 Model 폴더안에 정의해주자. 여기에서는 PizzaSpecial.cs 파일에 내용을 작성해주었다.

[ DB Context 정의 ]
![image|690x220]

using Microsoft.EntityFrameworkCore;

namespace BlazingPizza.Data
{
    public class PizzaStoreContext : DbContext
    {
        public PizzaStoreContext(DbContextOptions options) : base(options)
        { 
        }
        public DbSet<PizzaSpecial> Specials { get; set; }
    }
}

Data/PizzaStoreContext.cs 파일 생성

C#에서 DB Context는 Entity Framework API의 중요한 클래스로, 도메인 또는 엔터티 클래스와 데이터베이스 사이의 다리 역할을 합니다. 이는 데이터를 객체로 처리하는 데 필요한 모든 작업을 수행합니다

예를 들어, DbContext 인스턴스는 다음과 같은 일반적인 작업 단위를 수행합니다

  • DbContext 인스턴스 생성
  • 컨텍스트에 따른 엔터티 인스턴스 추적
  • 비즈니스 규칙을 구현하는 데 필요하다면 추적된 엔터티에 변경 사항이 적용됩니다.
  • SaveChanges 또는 SaveChangesAsync 가 호출됩니다. EF Core는 변경 사항을 감지하고 데이터베이스에 기록합니다.
  • DbContext 인스턴스가 삭제됩니다.

또한, DbContext는 데이터베이스 연결 문자열을 사용하여 모델 속성을 데이터베이스에 연결하도록 허용합니다.
이렇게 하면 컨트롤러에서 데이터를 처리하기 위해 데이터베이스를 참조하려고 할 때 DbContext를 참조할 수 있습니다.
따라서 DbContext는 데이터베이스 작업(데이터 가져오기, 저장, 검색 등)을 수행하는 데 필요한 모든 것을 처리하는 중심 역할을 합니다.

[ DB Controller 정의 ]

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using BlazingPizza.Data;

namespace BlazingPizza.Controllers
{
    [Route("specials")]
    [ApiController]
    public class SpecialsController : Controller
    {
        private readonly PizzaStoreContext _db;
        public SpecialsController(PizzaStoreContext db)
        {
            _db = db;
        }
        [HttpGet]
        public async Task<ActionResult<List<PizzaSpecial>>> GetSpecials()
        {
            return (await _db.Specials.ToListAsync()).OrderByDescending(s => s.BasePrice).ToList();
        }
    }
}

/Controllers/SpecialsController.cs

C#에서 DB Controller는 데이터베이스와 상호작용하는 데 사용되는 클래스입니다1. 이 클래스는 데이터베이스 엔터티에 대한 CRUD (생성, 읽기, 업데이트, 삭제) 작업을 수행합니다2.

예를 들어, ASP.NET MVC 프로젝트에서는 Controller가 사용자의 요청을 처리하고, 모델에서 데이터를 가져와 뷰에 전달하는 역할을 합니다3. 이 경우, DB Controller는 특정 데이터베이스 테이블(예: Kittens)과 관련된 작업을 수행하는 메서드를 포함할 수 있습니다.

[ DB 초기 데이터 정의 ]

namespace BlazingPizza.Data
{
    public class SeedData
    {
        public static void Initialize(PizzaStoreContext db)
        {
            var specials = new PizzaSpecial[]
            {
                new PizzaSpecial()
                {
                    Name = "Basic Cheese Pizza",
                    Description = "It's cheesy and delicious. Why wouldn't you want one?",
                    BasePrice = 9.99m,
                    ImageUrl = "img/pizzas/cheese.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 2,
                    Name = "The Baconatorizor",
                    Description = "It has EVERY kind of bacon",
                    BasePrice = 11.99m,
                    ImageUrl = "img/pizzas/bacon.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 3,
                    Name = "Classic pepperoni",
                    Description = "It's the pizza you grew up with, but Blazing hot!",
                    BasePrice = 10.50m,
                    ImageUrl = "img/pizzas/pepperoni.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 4,
                    Name = "Buffalo chicken",
                    Description = "Spicy chicken, hot sauce and bleu cheese, guaranteed to warm you up",
                    BasePrice = 12.75m,
                    ImageUrl = "img/pizzas/meaty.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 5,
                    Name = "Mushroom Lovers",
                    Description = "It has mushrooms. Isn't that obvious?",
                    BasePrice = 11.00m,
                    ImageUrl = "img/pizzas/mushroom.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 7,
                    Name = "Veggie Delight",
                    Description = "It's like salad, but on a pizza",
                    BasePrice = 11.50m,
                    ImageUrl = "img/pizzas/salad.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 8,
                    Name = "Margherita",
                    Description = "Traditional Italian pizza with tomatoes and basil",
                    BasePrice = 9.99m,
                    ImageUrl = "img/pizzas/margherita.jpg",
                },
            };
            db.Specials.AddRange(specials);
            db.SaveChanges();
        }
    }
}

/Data/SeedData.cs

초기 데이터를 셋팅해준다

[ DB 생성 && 초기 데이터 삽입 ]


...

// PizzaStoreContext Init and DB make
builder.Services.AddHttpClient();
builder.Services.AddSqlite<PizzaStoreContext>("Data Source=pizza.db");

...

// Path Initialize
app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");

// DB Seed Data Initialize
var scopeFactory = app.Services.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<PizzaStoreContext>();
    if(db.Database.EnsureCreated())
    {
        SeedData.Initialize(db);
    }
}

app.Run();

Program.cs 파일을 위와같이 수정해주어서 프로그램 생성과 함께 sqlite 기반의 db가 생성될 수 있게 만들자.

[ 데이터를 가지고 오는 페이지 만들기 ]

@page "/"
@inject HttpClient HttpClient
@inject NavigationManager NavigationManager

<div class="main">
  <h1>Blazing Pizzas</h1>
  <ul class="pizza-cards">
        @if (specials != null)
        {
            @foreach (var special in specials)
            {
                <li style="background-image: url('@special.ImageUrl')">
                  <div class="pizza-info">
                      <span class="title">@special.Name</span>
                        @special.Description
                        <span class="price">@special.GetFormattedBasePrice()</span>
                  </div>
                </li>
            }
        }
  </ul>
</div>

@code {
    List<PizzaSpecial> specials = new();

    protected override async Task OnInitializedAsync()
    {
        specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
    }
}

마지막으로 데이터가 정상적으로 입력이 되었는지를 JSON 형태로 데이터를 받는 페이지도 만들어보자

이대로 ctrl + f5로 DB에 접근하여 데이터를 확인할 수 있다.

혹은 dbeaver를 이용해 sqlite를 접근해서 데이터를 보는 방법도 있다.

5개의 좋아요

와우 드디어 국내에서도 blazor 서적이 나오겠군요 화이팅

4개의 좋아요