Blazor 서버 기본 구조
Dependency Injection, Router, _imports, Layout 등을 알아본다
Dependency Injection
이를 간단하게 알아보기 위해서 이미 존재하고있던 Data폴더에 FoodService.cs를 생성한다.
이후 이 안에 Food class를 생성해주고 프로퍼티값으로 Name, Price를 선언해준다.
그리고 cs파일을 생성하면서 생성된 FoodService class안에
public List<Food> GetFoods()
{
List<Food> foods = new List<Food>()
{
new Food() {Name = "bap", Price = 7000},
new Food() {Name = "KimBap", Price = 3000},
new Food() {Name = "ChoBap", Price = 9000}
};
return foods;
}
위와 같이 List<Food>를 반환해주는 함수를 생성해준다.
이후에 Blazor App을 생성하면서 존재하는 Index.razor파일안에 아래와 같은 코드를 추가해주면
웹 페이지에 하드코딩해서 넣어준 서비스의 목록들이 나오긴 한다.
@using BlazorApp.Data;
<div>
@foreach(var food in _foodService.GetFood())
{
<div>@food.Name</div>
<div>@food.Price</div>
}
</div>
@code{
FoodSerive _foodService= new FoodService();
}
다만, 위와 같이 코드를 작성하게 된다면 코드간의 의존성이 너무 심해진다는 문제가 발생한다.
따라서 Interface을 활용하여 이를 해결해주자.
다시 FoodService.cs로 돌아와서 Interface를 선언해주자 이렇게 해주면 이 FoodService를 사용하고싶은
사람들은 이 interface를 구현해야한다는 규칙이 생기게 된다.
public interface IFoodService
{
IEnumeralbe<Food> GetFoods();
}
public class FoodService : IFoodService
{
public IEnumeralbe<Food> GetFoods()
{
List<Food> foods = new List<Food>()
{
new Food() {Name = "bap", Price = 7000},
new Food() {Name = "KimBap", Price = 3000},
new Food() {Name = "ChoBap", Price = 9000}
};
return foods;
}
}
하지만 아직까지 razor의 컴포넌트들마다 일일이 new FoodService()를 호출해야하는 문제가 존재한다.
이를 해결하기 위해서 Dependency Injection이다.
이는 Startup.cs안에 ConfigureServices 함수안에 service.AddSingleton<IFoodService, FoodService>();로 선언하게 되면
이제 new를 통해서 선언하는 것이아닌
@inject IFoodService foodSerivce를 통해서 FoodService를 new를 통해서 생성하지 않고 사용이 가능하다.
[예시]
@using BlazorApp.Data;
@inject IFoodService foodSerivce
<div>
@foreach(var food in foodSerivce.GetFood())
{
<div>@food.Name</div>
<div>@food.Price</div>
}
</div>
하지만 이러한 방식이 전역적으로 사용되는것은 아니다.
이를 살펴보자.
public class SingletonService : IDisposable
{
public Guid ID {get; set;} //간단하게 ID를 생성하는 인터페이스이다.
public SingletonService() //cotr + tab,tab으로 해당 class의 생성자를 간단하게 생성할 수 있다.
{
ID = Guid.NewGuid();
}
public Dispose()
{
Console.WriteLine("SingletonService Disposed!");
}
}
public class TransientService : IDisposable
{
public Guid ID {get; set;} //간단하게 ID를 생성하는 인터페이스이다.
public TransientService() //cotr + tab,tab으로 해당 class의 생성자를 간단하게 생성할 수 있다.
{
ID = Guid.NewGuid();
}
public Dispose()
{
Console.WriteLine("TransientService Disposed!");
}
}
public class ScopeService : IDisposable
{
public Guid ID {get; set;} //간단하게 ID를 생성하는 인터페이스이다.
public ScopeService() //cotr + tab,tab으로 해당 class의 생성자를 간단하게 생성할 수 있다.
{
ID = Guid.NewGuid();
}
public Dispose()
{
Console.WriteLine("ScopeService Disposed!");
}
}
[생명주기]
3가지 모드를 파악해보자.
다음처럼 생성
service.AddSingleton<SingletonService>();
service.AddTransient<TransientService>();
service.AddScoped<ScopedService>();
다음 처럼 사용 (주로 상단에 선언)
@inject SingletonService singleton;
@inject TransientService transient;
@inject ScopedService scoped;
@inject 가 있는 동일페이지에서 다음 코드가 있을때 guid를 통해 id 가 페이지개 갱신 될때마다 재생성 되는 것을 보면 생명 주기를 파악 할 수 있다
<div>
<h1>Singleton</h1>
Guid: @singleton.ID
<h1>Singleton</h1>
Guid: @transient.ID
<h1>Singleton</h1>
Guid: @scoped.ID
<div>
이렇게 하고 생명주기를 살펴보면
singleton와scoped의 id는 변화하지 않고
transient의 id는 변화한다.
하지만 새로고침을 실행하면 singleton의 id는 바뀌지 않지만 나머지 두개는 변화한다.
(Balzor Server 프로젝트의 경우에는 변화가 없지만 클라이언트(Blazor WebAssembly ) 사이드같은 경우에는 singleton 방식도 guid 도 변경 된다)
즉, 변동하지 않고 모두에게 똑같이 보여야 한다면 singleton을
유저마다 갱신되어 보여야 한다면 나머지 2개를 선택하여 사용해야 하는데
Transient 는 말그래도 웹페이지의 요청이 일어날때마다 바뀌고
Scoped 는 웹에 접속할때 마다 변경된다.
SPA(single Page Application)
SPA는 기존에 존재하던 정적 페이지가 아닌 동적 페이지라고 할 수 있다
기존에는 웹서버에서 전체를 실시간으로 만들어 보내주는 방식이였지만
일부 변경되는 데이터에 따라(Dom) 모습이 달라지는 것을 동적페이지 방식이라 한다=> SPA
레이아웃
다음 과 같은 레이웃의 범위를 알아보면 아래 코드로 글자가 어디에 들어 가있는지 보면 된다 a, d , c
MainLayout.razor
@inherits LayoutComponentBase
<div class="sidebar">
<p style="color : #be0000;">
a
</p>
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
c
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<div class="content px-4">
d
@Body
</div>
</div>
_imports .razor 알아보기
이 컴포넌트 안에 사용되는 @키워드들은 같은 폴더안에 있는 모든 컴포넌트들에게 적용되게 된다.
imports.razor 의 내용을 ABC 라는 폴더에 넣어놓고 내용을 새로만든 레이아웃 @layout MainLayout2 .razor
해놓으면 해당 폴더에 있는 razor 페이지들의 기본 레이아웃은 MainLayout 이 아닌 MainLayout2 으로 변경된다
기본 레이아웃은 자체는 다음 코드를 상속받아 레이아웃 자체를 구성한다
@inherits LayoutComponentBase
반드시 하나는 이 것을 상속받는 레잉아웃이 있어야 한다 이것이 적용된 페이지가
MainLayout.razor 이다
@inherits를 사용하게되면 class를 상속해서 사용할 수 있게 된다.
@layout키워드를 사용하면 레이아웃을 바꿔서 적용할 수 있다.
키워드를 사용하지 않고 모든 레이아웃을 변경하기 위해서는 App.razor에 DefaultLayout을 변경해주면 된다.
Router : 주소/sports/55 과 같이 주소 뒤에 어떤 페이지를 보여줄지에 대한 것
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<Router 는 다음 처럼 되어 있다 Found 가 RenderFragment 로 내용을 보여주기 위한 형태인것을 알 수있다(템플릿)
그리고 Router는 상대적 기준으로 생각하고 작성해야 한다 즉 현재 경로 위쪽이 무엇인지 기본적으로 절대경로로 생각하면 안된다는것
아래코드에서
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">BlazorApp</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="user">
<span class="oi oi-list-rich" aria-hidden="true"></span> User
</NavLink>
</li>
</ul>
</div>
@code {
private bool collapseNavMenu = true;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
이 부분은
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">BlazorApp</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
이 처럼 화면이 작아지는 모바일 환경에서 메뉴표현등으로 나타내기 위한 버튼으로 화면이 큰 윈도우 환경에선 기본적으로는 화면을 줄이지 않는 이상 안보일 수 있다
NavLink : 이동 시키는 <a href > 와 유사한데 비주얼 적으로 차이가 있는데 버튼을 누를때 스타일 적인 것만 다르다
상단에 Home, FetchData 등의 버튼을 참고하면 된다
NavLink 는
<a href 를 써서 동일하게 구현할 수도 있고
NavigationManager 를 인젝션 하여
이렇게 구현하여 구현 할 수도 있다
counter 페이지가 뜰때 다음처럼 값을 받을 수도 있다 값은 CurrentCount 로 들어가게 된다
https://localhost:44337/counter/30 30을 입력하면 CurrentCount 값이 30 이 된다
ref : https://blog.naver.com/whro152/223041082396