ABP vNext와 .NET 6 기반의 웹 애플리케이션 개발 환경 구축 및 엔티티 구현

개발 환경 준비 및 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>

태그: ABP-Framework .NET-6 Blazor-WebAssembly entity-framework-core DDD

7월 21일 20:29에 게시됨