Azunt.Components 패키지 만들기
Reusable Blazor UI Component Library (Step-by-Step Guide)
이 문서는 Blazor에서 공통 UI 컴포넌트(SearchBox, SortOrderArrow, Pager 등)를 RCL(Razor Class Library)로 만들어 NuGet 패키지로 배포하고, 실제 Blazor 앱에서 사용하는 전 과정을 안내합니다.
GitHub에 리포지토리 만들기: Azunt.Components
이 단계에서는 만든 RCL 프로젝트를 GitHub에 업로드하고 오픈소스로 관리하는 방법을 안내합니다. URL은 다음과 같습니다:
🔗 https://github.com/VisualAcademy/Azunt.Components
✅ 1단계: Git 초기화
git init
git add .
git commit -m "Initialize Azunt.Components project"
✅ 2단계: GitHub 리포지토리 생성
- https://github.com/VisualAcademy 로 이동
Azunt.Components
라는 이름으로 New repository 생성- 공개(Public) 여부 선택 후 생성
✅ 3단계: 원격 연결 및 푸시
git remote add origin https://github.com/VisualAcademy/Azunt.Components.git
git branch -M main
git push -u origin main
✅ 4단계: .gitignore
및 README.md
추가 (선택)
프로젝트 루트에 다음 파일들을 추가하세요:
.gitignore
bin/
obj/
*.user
*.suo
*.userosscache
*.sln.docstates
README.md
# Azunt.Components
Reusable Blazor UI Components (SearchBox, SortOrderArrow, Pager)
Packaged as a Razor Class Library (RCL) and published on NuGet.
NuGet: [https://www.nuget.org/packages/Azunt.Components](https://www.nuget.org/packages/Azunt.Components)
git add .gitignore README.md
git commit -m "Add README and .gitignore"
git push
✅ 5단계: GitHub Topics 및 설명 추가
GitHub 리포지토리 상단에서 다음 정보 입력:
- Description: Reusable Blazor UI Component Library (Search, Sort, Paging)
- Topics:
blazor
,razor-components
,nuget
,ui-library
,azunt
1. RCL(Razor Class Library) 프로젝트 생성
dotnet new razorclasslib -n Azunt.Components
cd Azunt.Components
.csproj
수정:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RazorLangVersion>8.0</RazorLangVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.0" />
</ItemGroup>
</Project>
🔧
net8.0
을 사용해야 최신 Blazor 기능과 호환됩니다.
2. 프로젝트 구조 만들기
mkdir -p Paging Search Sorting
touch _Imports.razor
Azunt.Components/
├─ Paging/
│ ├─ Pager.razor
│ └─ PagerBase.cs
├─ Search/
│ ├─ SearchBox.razor
│ └─ SearchBox.razor.cs
├─ Sorting/
│ └─ SortOrderArrow.razor
├─ Azunt.Components.csproj
├─ _Imports.razor
3. 페이징 컴포넌트 만들기 (Paging)
Paging/PagerBase.cs
namespace Azunt.Components.Paging;
public class PagerBase
{
public string Url { get; set; } = "";
public int PageCount { get; set; } = 5;
public int RecordCount { get; set; } = 50;
public int PageSize { get; set; } = 10;
public int PageIndex { get; set; } = 0;
public int PageNumber { get; set; } = 1;
public int PagerButtonCount { get; set; } = 3;
public bool SearchMode { get; set; } = false;
public string SearchField { get; set; } = "";
public string SearchQuery { get; set; } = "";
}
Paging/Pager.razor
@using Azunt.Components.Paging
@namespace Azunt.Components.Paging
<div class="d-flex">
<ul class="pagination pagination-sm mx-auto">
@if (Model.PageNumber > 1)
{
<li class="page-item"><a class="page-link" @onclick="@(() => PagerClicked(1))">FIRST</a></li>
<li class="page-item"><a class="page-link" @onclick="@(() => PagerClicked(Model.PageNumber - 1))">PREV</a></li>
}
else
{
<li class="page-item disabled"><span class="page-link">FIRST</span></li>
<li class="page-item disabled"><span class="page-link">PREV</span></li>
}
@{
int start = (Model.PageIndex / Model.PagerButtonCount) * Model.PagerButtonCount + 1;
int end = Math.Min(start + Model.PagerButtonCount - 1, Model.PageCount);
}
@for (int i = start; i <= end; i++)
{
if (i == Model.PageNumber)
{
<li class="page-item active"><span class="page-link">@i</span></li>
}
else
{
<li class="page-item"><a class="page-link" @onclick="@(() => PagerClicked(i))">@i</a></li>
}
}
@if (Model.PageNumber < Model.PageCount)
{
<li class="page-item"><a class="page-link" @onclick="@(() => PagerClicked(Model.PageNumber + 1))">NEXT</a></li>
<li class="page-item"><a class="page-link" @onclick="@(() => PagerClicked(Model.PageCount))">LAST</a></li>
}
else
{
<li class="page-item disabled"><span class="page-link">NEXT</span></li>
<li class="page-item disabled"><span class="page-link">LAST</span></li>
}
</ul>
</div>
@code {
[Parameter, EditorRequired] public PagerBase Model { get; set; } = default!;
[Parameter] public EventCallback<int> PageIndexChanged { get; set; }
protected override Task OnParametersSetAsync()
{
Model.PageCount = (Model.RecordCount == 0) ? 1 : Convert.ToInt32(Math.Ceiling(Model.RecordCount / (double)Model.PageSize));
return base.OnParametersSetAsync();
}
private void PagerClicked(int pageNumber)
{
Model.PageNumber = pageNumber;
Model.PageIndex = pageNumber - 1;
PageIndexChanged.InvokeAsync(Model.PageIndex);
}
}
4. 검색 컴포넌트 만들기 (Search)
Search/SearchBox.razor
@namespace Azunt.Components.Search
<div class="input-group mb-3">
<input class="form-control form-control-sm"
type="search"
placeholder="Search..."
aria-describedby="btnSearch"
@attributes="AdditionalAttributes"
@bind="SearchQuery"
@bind:event="oninput" />
<div class="input-group-append">
<button class="btn btn-sm btn-success" type="submit" @onclick="Search" id="btnSearch">Search</button>
</div>
</div>
Search/SearchBox.razor.cs
using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic;
using System.Timers;
namespace Azunt.Components.Search;
public partial class SearchBox : ComponentBase, IDisposable
{
private string searchQuery = "";
private Timer? debounceTimer;
[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; } = new Dictionary<string, object>();
[Parameter]
public EventCallback<string> SearchQueryChanged { get; set; }
[Parameter]
public int Debounce { get; set; } = 300;
public string SearchQuery
{
get => searchQuery;
set
{
searchQuery = value;
debounceTimer?.Stop();
debounceTimer?.Start();
}
}
protected override void OnInitialized()
{
debounceTimer = new Timer { Interval = Debounce, AutoReset = false };
debounceTimer.Elapsed += SearchHandler!;
}
protected void Search() => SearchQueryChanged.InvokeAsync(SearchQuery);
protected async void SearchHandler(object? source, ElapsedEventArgs e)
{
await InvokeAsync(() => SearchQueryChanged.InvokeAsync(SearchQuery));
}
public void Dispose() => debounceTimer?.Dispose();
}
5. 정렬 화살표 컴포넌트 만들기 (Sorting)
Sorting/SortOrderArrow.razor
@namespace Azunt.Components.Sorting
<span style="color: silver; margin-left: 7px; font-weight: bold; float: right;">@arrow</span>
@code {
[Parameter] public string SortColumn { get; set; } = "";
[Parameter] public string SortOrder { get; set; } = "";
private string arrow = "↕";
protected override void OnParametersSet()
{
if (string.IsNullOrWhiteSpace(SortOrder))
{
arrow = "↕";
}
else if (SortOrder.Contains(SortColumn) && SortOrder.Contains("Desc"))
{
arrow = "↓";
}
else if (SortOrder.Contains(SortColumn))
{
arrow = "↑";
}
else
{
arrow = " ";
}
}
}
6. NuGet 패키지로 만들기
패키지 생성
dotnet pack -c Release
NuGet 게시 (API Key 필요)
dotnet nuget push bin/Release/Azunt.Components.X.Y.Z.nupkg -k {API_KEY} -s https://api.nuget.org/v3/index.json
7. Blazor 앱에서 사용하기
- NuGet에서
Azunt.Components
설치 _Imports.razor
에 다음 추가:
@using Azunt.Components.Search
@using Azunt.Components.Sorting
@using Azunt.Components.Paging
- Razor 페이지에서 사용:
<SearchBox SearchQueryChanged="OnSearch" />
<SortOrderArrow SortColumn="Name" SortOrder="@sortOrder" />
<Pager Model="pagerModel" PageIndexChanged="OnPageChanged" />
추천 자료: ASP.NET Core 인증 및 권한 부여
추천 자료: .NET Blazor에 대해 알아보시겠어요? .NET Blazor 알아보기를 확인해보세요!