개발 환경 준비 및 ABP 프레임워크 설정
ABP vNext 프레임워크를 사용하여 프로젝트를 시작하기 위해 .NET 6.0 SDK와 Visual Studio 2022를 설치해야 합니다. 개발 도구가 준비되면 ABP CLI를 설치하거나 최신 버전으로 업데이트하여 프로젝트 생성을 준비합니다.
// ABP CLI 설치
dotnet tool install -g Volo.Abp.Cli
// 이미 설치된 경우 업데이트
dotnet tool update -g Volo.Abp.Cli
프로젝트 템플릿은 Blazor WebAssembly, Entity Framework Core(EF Core), SQL Server 조합을 선택하여 생성합니다. 초기 데이터베이스 구성을 위해 DbMigrator 프로젝트를 실행하며, 이 과정에서 .NET SDK 환경이 올바르게 설정되어 있어야 합니다.
도메인 엔티티(Domain Entity) 정의
도메인 계층(Domain Project)에 실제 비즈니스 데이터를 담을 엔티티 클래스를 생성합니다. ABP의 BasicAggregateRoot를 상속받아 기본 키 형식을 지정합니다.
using System;
using Volo.Abp.Domain.Entities;
namespace MyTodoApp.Domain
{
public class TaskItem : BasicAggregateRoot<Guid>
{
public string Title { get; set; }
public bool IsCompleted { get; set; }
}
}
Entity Framework Core를 이용한 데이터베이스 매핑
EntityFrameworkCore 프로젝트 내의 DbContext 클래스에서 생성한 엔티티를 DbSet으로 등록하고, OnModelCreating 메서드에서 테이블 매핑 규칙을 설정합니다.
public class MyProjectDbContext : AbpDbContext<MyProjectDbContext>
{
public DbSet<TaskItem> TaskItems { get; set; }
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<TaskItem>(b => {
b.ToTable("AppTaskItems");
b.ConfigureByConvention(); // 기본 설정 적용
b.Property(x => x.Title).IsRequired().HasMaxLength(256);
});
}
}
매핑 설정을 완료한 후, 패키지 관리자 콘솔(PMC) 또는 CLI를 통해 마이그레이션을 생성하고 데이터베이스를 업데이트합니다.
// CLI 사용 시
dotnet ef migrations add Added_TaskItem
dotnet ef database update
// PMC 사용 시
Add-Migration Added_TaskItem
Update-Database
애플리케이션 서비스 및 DTO 구현
계층 간 데이터 전송을 위해 Application.Contracts 프로젝트에 DTO(Data Transfer Object)와 서비스 인터페이스를 정의합니다. 인터페이스는 IApplicationService를 상속받아야 종속성 주입 시스템에 자동 등록됩니다.
public interface ITaskAppService : IApplicationService
{
Task<List<TaskDto>> GetTasksAsync();
Task<TaskDto> CreateTaskAsync(string title);
Task DeleteTaskAsync(Guid id);
}
public class TaskDto
{
public Guid Id { get; set; }
public string Title { get; set; }
}
Application 프로젝트에서는 위 인터페이스를 실제로 구현합니다. IRepository를 주입받아 데이터베이스 작업을 수행하며, 엔티티와 DTO 간의 변환 로직을 작성합니다.
public class TaskAppService : ApplicationService, ITaskAppService
{
private readonly IRepository<TaskItem, Guid> _taskRepository;
public TaskAppService(IRepository<TaskItem, Guid> taskRepository)
{
_taskRepository = taskRepository;
}
public async Task<List<TaskDto>> GetTasksAsync()
{
var items = await _taskRepository.GetListAsync();
return items.Select(x => new TaskDto { Id = x.Id, Title = x.Title }).ToList();
}
public async Task<TaskDto> CreateTaskAsync(string title)
{
var newItem = await _taskRepository.InsertAsync(new TaskItem { Title = title });
return new TaskDto { Id = newItem.Id, Title = newItem.Title };
}
public async Task DeleteTaskAsync(Guid id)
{
await _taskRepository.DeleteAsync(id);
}
}
Blazor WebAssembly 사용자 인터페이스(UI) 구성
Blazor 프로젝트의 Razor 컴포넌트에서 위에서 작성한 서비스를 호출하여 화면을 구성합니다. [Inject] 속성을 사용하여 서비스를 주입받습니다.
// Index.razor.cs
public partial class Index
{
[Inject]
private ITaskAppService TaskService { get; set; }
private List<TaskDto> TaskList { get; set; } = new();
private string InputTitle { get; set; }
protected override async Task OnInitializedAsync()
{
TaskList = await TaskService.GetTasksAsync();
}
private async Task AddTask()
{
var result = await TaskService.CreateTaskAsync(InputTitle);
TaskList.Add(result);
InputTitle = string.Empty;
}
}
Razor 마크업 파일에서는 다음과 같이 바인딩 및 이벤트 핸들러를 설정합니다.
<div class="container">
<div class="card">
<div class="card-body">
<form @onsubmit="AddTask">
<input type="text" @bind="InputTitle" class="form-control" placeholder="할 일 입력..." />
<button type="submit" class="btn btn-success">등록</button>
</form>
<ul class="list-group mt-3">
@foreach (var task in TaskList)
{
<li class="list-group-item d-flex justify-content-between">
@task.Title
<button class="btn btn-danger btn-sm" @onclick="() => TaskService.DeleteTaskAsync(task.Id)">삭제</button>
</li>
}
</ul>
</div>
</div>
</div>