ABP Framework ile Adım Adım Yazılım Geliştirme – Bölüm 5: Application Layer Geliştirme
Application Layer (Uygulama Katmanı), uygulamanın kullanım senaryolarını (use cases) ve kullanıcı hikayelerini yönetir. Domain katmanındaki işlevleri kullanarak kullanıcı arayüzünden gelen isteklere yanıt verir ve sunum katmanı ile domain katmanı arasındaki bir köprü görevi görür. Bu bölümde, uygulama katmanının temel bileşenlerini ve geliştirme pratiklerini ele alacağız.
Application Service’ler Oluşturma
Application Service (Uygulama Servisi), dış dünyadan (UI, API) gelen isteklere doğrudan yanıt veren bir sınıftır. Genellikle bir senaryoyu (örn. “Yeni Kitap Oluştur”, “Kitap Listesini Getir”) veya bir CRUD (Create, Read, Update, Delete) işlemini temsil eder. Uygulama servisleri, domain katmanındaki entity’leri ve domain servislerini kullanarak iş mantığını koordine eder.
ABP’de bir uygulama servisi oluşturmak için Volo.Abp.Application.Services.ApplicationService
sınıfından türetilir:
C#
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using MyProject.Books;
using MyProject.Application.Contracts.Books; // DTO'lar burada tanımlanır
namespace MyProject.Application.Services
{
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IRepository<Book, Guid> _bookRepository;
private readonly BookManager _bookManager; // Domain servislerini de enjekte edebiliriz
public BookAppService(IRepository<Book, Guid> bookRepository, BookManager bookManager)
{
_bookRepository = bookRepository;
_bookManager = bookManager;
}
public async Task<BookDto> GetAsync(Guid id)
{
var book = await _bookRepository.GetAsync(id);
return ObjectMapper.Map<Book, BookDto>(book); // AutoMapper kullanımı
}
public async Task<List<BookDto>> GetListAsync()
{
var books = await _bookRepository.GetListAsync();
return ObjectMapper.Map<List<Book>, List<BookDto>>(books);
}
public async Task<BookDto> CreateAsync(CreateUpdateBookDto input)
{
var book = await _bookManager.CreateBookAsync(
input.Name,
input.Type,
input.PublishDate,
input.Price
);
return ObjectMapper.Map<Book, BookDto>(book);
}
public async Task UpdateAsync(Guid id, CreateUpdateBookDto input)
{
var book = await _bookRepository.GetAsync(id);
// Güncelleme mantığı (Domain Service veya direkt entity üzerinde)
await _bookRepository.UpdateAsync(book);
}
public async Task DeleteAsync(Guid id)
{
await _bookRepository.DeleteAsync(id);
}
}
}
ApplicationService
sınıfı, temel özellikler (örn.ObjectMapper
(AutoMapper),Logger
,CurrentUser
) ve bağımlılık enjeksiyonu için kolaylıklar sağlar.- Uygulama servisleri
IApplicationService
arayüzünü implemente etmelidir. Bu, ABP’nin otomatik API denetleyicileri gibi özelliklerini kullanmak için önemlidir.
DTO (Data Transfer Object) Tasarımı
DTO (Data Transfer Object), uygulama katmanı ile sunum katmanı arasında veri taşımak için kullanılan basit veri yapısı sınıflarıdır. DTO’lar, entity’leri doğrudan ifşa etmekten kaçınır ve istemciye sadece ihtiyaç duyduğu veriyi sunar.
BookDto
: Bir kitap bilgilerini istemciye sunmak için.CreateUpdateBookDto
: Yeni bir kitap oluşturmak veya mevcut bir kitabı güncellemek için istemciden gelen verileri almak için.
BookDto.cs
(MyProject.Application.Contracts projesinde):
C#
using System;
using Volo.Abp.Application.Dtos;
namespace MyProject.Application.Contracts.Books
{
public class BookDto : AuditedEntityDto<Guid> // Audited bilgileri de içerir
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
CreateUpdateBookDto.cs
(MyProject.Application.Contracts projesinde):
C#
using System;
using System.ComponentModel.DataAnnotations;
namespace MyProject.Application.Contracts.Books
{
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
public BookType Type { get; set; } = BookType.Undefined; // Varsayılan değer
[Required]
public DateTime PublishDate { get; set; }
[Range(0, float.MaxValue)]
public float Price { get; set; }
}
}
- DTO’lar, UI katmanına bağlı olarak ek doğrulama (validation) nitelikleri içerebilir (
[Required]
,[StringLength]
,[Range]
).
CRUD Operasyonları Implementasyonu
Uygulama servisleri genellikle entity’ler üzerinde temel CRUD operasyonlarını implemente eder. ABP’nin IRepository
arayüzü ve AutoMapper entegrasyonu sayesinde bu operasyonlar oldukça basittir.
GetAsync
: Tek bir entity’yi ID’sine göre getirir ve DTO’ya dönüştürür.GetListAsync
: Entity listesini getirir ve DTO listesine dönüştürür.CreateAsync
: Bir DTO alır, entity’ye dönüştürür, kaydeder ve yeni entity’yi DTO olarak geri döndürür.UpdateAsync
: Bir DTO alır, mevcut entity’yi günceller ve güncellenmiş entity’yi DTO olarak geri döndürür.DeleteAsync
: Bir entity’yi ID’sine göre siler.
AutoMapper Profilleri ile Entity-DTO Dönüşümleri
ABP, AutoMapper’ı otomatik olarak yapılandırır. Entity ve DTO’lar arasındaki eşleştirmeleri tanımlamak için Profile
sınıfları oluşturulur ve YourProjectNameApplicationModule
içinde yapılandırılır.
MyProjectApplicationAutoMapperProfile.cs
(MyProject.Application projesinde):
C#
using AutoMapper;
using MyProject.Books;
using MyProject.Application.Contracts.Books;
namespace MyProject.Application
{
public class MyProjectApplicationAutoMapperProfile : Profile
{
public MyProjectApplicationAutoMapperProfile()
{
/* You can configure your AutoMapper mapping configurations here.
* Alternatively, you can split your mapping configurations
* into multiple profile classes for a better organization. */
CreateMap<Book, BookDto>();
CreateMap<CreateUpdateBookDto, Book>(); // DTO'dan Entity'ye dönüşüm
}
}
}
IApplicationService Interface Kullanımı
IApplicationService
arayüzü, bir sınıfın bir uygulama servisi olduğunu belirtir. Bu arayüzü implemente eden sınıflar, ABP’nin otomatik bağımlılık enjeksiyonu ve Auto API Controller (Bkz. Bölüm 6) özellikleri için uygundur.
C#
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using MyProject.Application.Contracts.Books;
namespace MyProject.Application.Contracts.Books
{
public interface IBookAppService : IApplicationService
{
Task<BookDto> GetAsync(Guid id);
Task<List<BookDto>> GetListAsync();
Task<BookDto> CreateAsync(CreateUpdateBookDto input);
Task UpdateAsync(Guid id, CreateUpdateBookDto input);
Task DeleteAsync(Guid id);
}
}
Validasyonlar ve İş Kurallarının Uygulanması
Uygulama katmanında, istemciden gelen verilerin doğru formatta ve geçerli olduğundan emin olmak için validasyonlar yapılır. Bu validasyonlar genellikle DTO’lar üzerinde veri açıklaması (data annotations) nitelikleri kullanılarak veya FluentValidation gibi kütüphanelerle uygulanır.
Ayrıca, bazı iş kuralları (ancak domain katmanında olması gerekenler değil) uygulama katmanında da uygulanabilir. Örneğin, bir kullanıcının belirli bir işlemi yapmaya yetkisi olup olmadığını kontrol etmek.
ABP Features ve Özellik Kontrolü
ABP Framework, uygulamanızda Features (Özellikler) adı verilen bir mekanizma sunar. Bu, belirli işlevlerin veya modüllerin uygulamanızın farklı sürümlerinde veya farklı kiracılar için etkinleştirilip devre dışı bırakılmasını sağlar. Örneğin, bir “Premium Özellik” sadece belirli bir abonelik seviyesine sahip kullanıcılara sunulabilir.
- Özellik Tanımlama:
IFeatureDefinitionContext
kullanarak özellikler tanımlanır (genellikle birModule
sınıfında). - Özellik Kullanımı:
IFeatureChecker
servisi aracılığıyla uygulamanızın herhangi bir yerinde (uygulama servisi, UI vb.) bir özelliğin etkin olup olmadığı kontrol edilir.
C#
// Özelliği tanımlama (YourProjectNameModule.cs'de)
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpFeaturesConfigurationOptions>(options =>
{
options.AddGroup(
new FeatureGroupDefinition(
"MyFeatures",
"My Features"
).AddFeature(
"MyProject.PremiumFeature",
"false", // Varsayılan değer
"This is a premium feature."
)
);
});
}
// Uygulama servisinde özelliği kontrol etme
private readonly IFeatureChecker _featureChecker;
public async Task DoPremiumOperation()
{
if (!await _featureChecker.IsEnabledAsync("MyProject.PremiumFeature"))
{
throw new BusinessException(MyProjectDomainErrorCodes.PremiumFeatureRequired);
}
// Premium işlem mantığı
}
Uygulama katmanı, uygulamanızın kullanım senaryolarını açıkça tanımlayarak ve domain katmanından bağımsız kalarak, daha temiz ve bakımı kolay bir kod tabanı oluşturmanıza yardımcı olur.