🔸 1. 프로젝트 개요 및 목표

Blazor Server 환경에서 RankingApp을 개발하여 사용자 인증 기반의 CRUD 기능을 학습합니다. 해당 프로젝트는 다음과 같은 목적을 가집니다:

  • Entity Framework Core를 통한 ORM 기반 DB 연동 학습
  • 개별 사용자 인증 시스템 구현
  • Blazor의 Razor Component를 사용한 CRUD 화면 구현

🔸 2. 프로젝트 생성 및 설정

▶ Blazor Server 프로젝트 생성

  • 이름: RankingApp
  • 템플릿: Blazor Server App
  • 인증 유형: 개별 사용자 계정 (Register, Login 기능 포함)

▶ appsettings.json 수정

"ConnectionStrings": {
  "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=RankingDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}

▶ SQL Server 개체 탐색기에서 DB 생성

  • 새 데이터베이스 이름: RankingDB
  • 생성 후 연결 문자열 복사 가능 (속성 탭 -> 연결 문자열)

🔸 3. 모델링 및 DB 연동 설정

▶ GameResult 모델 생성 (Data/Models/GameResult.cs)

public class GameResult
{
    public int Id { get; set; }
    public int UserID { get; set; }
    public string UserName { get; set; }
    public int Score { get; set; }
    public DateTime Date { get; set; }
}

▶ ApplicationDbContext.cs 설정

public class ApplicationDbContext : IdentityDbContext
{
    public DbSet<GameResult> GameResultList { get; set; }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
}
  • DbSet<GameResult>를 통해 ORM 기반 DB 테이블 자동 생성

▶ Startup.cs 또는 Program.cs 설정

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

builder.Services.AddScoped<RankingService>();

▶ 마이그레이션 명령어 실행

PM> Add-Migration RankingService
PM> Update-Database

🔸 4. RankingService.cs 구현 (Data/Services)

public class RankingService
{
    private readonly ApplicationDbContext _context;
    public RankingService(ApplicationDbContext context) { _context = context; }

    public Task<List<GameResult>> GetGameResultAsync()
    {
        var results = _context.GameResultList.OrderByDescending(x => x.Score).ToList();
        return Task.FromResult(results);
    }

    public Task<GameResult> AddGameResult(GameResult gameResult)
    {
        _context.GameResultList.Add(gameResult);
        _context.SaveChanges();
        return Task.FromResult(gameResult);
    }

    public Task<bool> UpdateGameResult(GameResult gameResult)
    {
        var result = _context.GameResultList.FirstOrDefault(x => x.Id == gameResult.Id);
        if (result == null) return Task.FromResult(false);
        result.UserName = gameResult.UserName;
        result.Score = gameResult.Score;
        _context.SaveChanges();
        return Task.FromResult(true);
    }

    public Task<bool> DeleteGameResult(GameResult gameResult)
    {
        var result = _context.GameResultList.FirstOrDefault(x => x.Id == gameResult.Id);
        if (result == null) return Task.FromResult(false);
        _context.GameResultList.Remove(result);
        _context.SaveChanges();
        return Task.FromResult(true);
    }
}

🔸 5. Ranking.razor 컴포넌트 구현 (Pages/Ranking.razor)

@page "/ranking"
@using RankingApp.Data.Models;
@using RankingApp.Data.Services;
@inject RankingService RankingService

<h3>Ranking</h3>

<AuthorizeView>
<Authorized>
    @if (_gameResultList == null)
    {
        <p>Loading...</p>
    }
    else
    {
        <table class="table">
            <thead>
                <tr>
                    <th>UserName</th>
                    <th>Score</th>
                    <th>Date</th>
                    <th></th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
                @foreach (var result in _gameResultList)
                {
                    <tr>
                        <td>@result.UserName</td>
                        <td>@result.Score</td>
                        <td>@result.Date</td>
                        <td><button class="btn btn-primary" @onclick="() => EditGameResult(result)">Edit</button></td>
                        <td><button class="btn btn-danger" @onclick="() => DeleteGameResult(result)">Delete</button></td>
                    </tr>
                }
            </tbody>
        </table>

        <button class="btn btn-success" @onclick="AddGameResult">Add</button>

        @if (_showPopup)
        {
            <div class="modal" style="display:block">
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h3 class="modal-title">Add/Update GameResult</h3>
                            <button type="button" class="close" @onclick="ClosePopup">X</button>
                        </div>
                        <div class="modal-body">
                            <label>UserName</label>
                            <input class="form-control" @bind-value="_gameResult.UserName" />
                            <label>Score</label>
                            <input class="form-control" @bind-value="_gameResult.Score" />
                            <button class="btn btn-primary" @onclick="SaveGameResult">Save</button>
                        </div>
                    </div>
                </div>
            </div>
        }
    }
</Authorized>
<NotAuthorized>
    <p>You are not authorized to view this page.</p>
</NotAuthorized>
</AuthorizeView>

@code {
    List<GameResult> _gameResultList;
    GameResult _gameResult;
    bool _showPopup = false;

    protected override async Task OnInitializedAsync()
    {
        await ReadGameResults();
    }

    async Task ReadGameResults()
    {
        _gameResultList = await RankingService.GetGameResultAsync();
    }

    void AddGameResult()
    {
        _showPopup = true;
        _gameResult = new GameResult { Id = 0 };
    }

    void EditGameResult(GameResult gameResult)
    {
        _showPopup = true;
        _gameResult = gameResult;
    }

    async Task DeleteGameResult(GameResult gameResult)
    {
        await RankingService.DeleteGameResult(gameResult);
        await ReadGameResults();
    }

    async Task SaveGameResult()
    {
        if (_gameResult.Id == 0)
        {
            _gameResult.Date = DateTime.Now;
            await RankingService.AddGameResult(_gameResult);
        }
        else
        {
            await RankingService.UpdateGameResult(_gameResult);
        }
        _showPopup = false;
        await ReadGameResults();
    }
}

🔸 6. NavMenu.razor에 링크 추가

<NavLink class="nav-link" href="ranking">
    <span class="oi oi-list-rich" aria-hidden="true"></span> Ranking
</NavLink>

profile
李家네_공부방

0개의 댓글