.Net Core'un duyurulmasıyla birlikte microsoft .Net Framework çatısı altında geliştirmekte olduğu bütün ürünlerin -core versiyonlarını geliştirmeye devam ediyor ve Entity Framework Core da bunlardan bir tanesi. En son 2.1 versiyonu ile birlikte benchmark testlerinde en hızlı orm olarak karşımıza çıktı. Bizde bu yazımızda entity framework 2.1 kullanarak Generic Repository Pattern ile birlikte bir Asp.Net Core 2.1 WebApi uygulaması geliştireceğiz.
Proje Oluşturulması
İlk olarak vs'da EfCoreWithWebApiSample adında versiyon olarak Asp.Net Core 2.1 seçerek bir Web Api Application oluşturalım.
Not: Geliştirmeye başlamadan önce makinanızda .Net Core sdk 2.1.3 rc1 ve host edebilmemizi sağlayan .Net hosting 2.1.0 rc1 kurulumlarının olması gerekmekte.
DbContext-Entity Tanımlaması
Api projemizde bir ProductDbContext'i ile product database'inde bulunan ürünler için CRUD işlemlerini içeren api end-point'leri yer alacaktır. Bunun için ilk olarak projemizde ProductDbContext'ini ve Product entity sınıfını oluşturalım.
public class ProductDbContext : DbContext
{
public ProductDbContext(DbContextOptions<ProductDbContext> options) : base(options) { }
public DbSet<Product> Product { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
public class Product
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
}
Yukarıda görüldüğü üzre context ve entity tanımlamalarını yaptık şimdi ise ProductDbContext'i Startup.cs içerisinde service olarak ekleme işlemini yapalım. Bunun için projemizde yer alan appsettings.json dosyasına connstring'i aşağıdaki gibi tanımlayalım ve sonrasında Startup.cs'de yer alan ConfigureServices metodu içerisinde context'i servislere ekleyelim.
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ProductDbConnString": "Server=.;Initial Catalog=productdb;Persist Security Info=False;User ID=productuser;Password=qwerty135-;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ProductDbContext>(options =>
options.UseSqlServer(Configuration.GetSection("ProductDbConnString")));
services.AddMvc();
}
Generic Repository Oluşturulması
Repository katmanı doğrudan context'i constructor injection yöntemi ile alarak database CRUD işlemlerini yapmamızı sağlayacak olan katman. Bunun için ilk olarak IGenericRepository adında bir interface tanımlayalım.
public interface IGenericRepository<T> where T : class, IEntity
{
Guid Save(T entity);
T Get(Guid id);
void Update(T entity);
void Delete(Guid id);
IQueryable<T> All();
IQueryable<T> Find(Expression<Func<T, bool>> predicate);
}
Bu interface'e ait abstract GenericRepository sınıfını aşağıdaki gibi IGenericRepository interface'inden implement ederek metotlarını oluşturalım.
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, IEntity
{
private readonly ProductDbContext _dbContext;
private readonly DbSet<T> _dbSet;
protected GenericRepository(ProductDbContext dbContext)
{
this._dbContext = dbContext;
this._dbSet = _dbContext.Set<T>();
}
public Guid Save(T entity)
{
entity.Id = Guid.NewGuid();
_dbSet.Add(entity);
return entity.Id;
}
public T Get(Guid id)
{
return _dbSet.Find(id);
}
public void Update(T entity)
{
_dbSet.Attach(entity);
_dbContext.Entry(entity).State = EntityState.Modified;
}
public void Delete(Guid id)
{
var entity = Get(id);
_dbSet.Remove(entity);
}
public IQueryable<T> All()
{
return _dbSet.AsNoTracking();
}
public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
{
return _dbSet.Where(predicate);
}
}
Generic Repository için gerekli olan base sınıf ve interface'i yukarıdaki gibi tanımladık. Şimdi sırada Product entity'si için kullanacağımız ProductRepository ve onun interface'i var.
public interface IProductRepository : IGenericRepository<Product>
{ }
public class ProductRepository : GenericRepository<Product>, IProductRepository
{
public ProductRepository(ProductDbContext dbContext) : base(dbContext)
{
}
}
Service Layer Oluşturulması
Service layer controller ile repository arasında kullanacağımız katman olacak ve uygula için business'ların bulunduğu katmanda diyebiliriz. Bunun için aşağıdaki gibi IProductService ve onun implementasyonu ile birlikte request-response dto sınıflarını oluşturalım.
public interface IProductService
{
GetAllProductResponse GetAllProducts();
void AddProduct(AddProductRequest reqModel);
}
public class ProductService : IProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public GetAllProductResponse GetAllProducts()
{
var result = _productRepository.All();
var mappedList = new List<ProductDto>();
foreach (var item in result)
{
mappedList.Add(new ProductDto { Id = item.Id, Name = item.Name });
}
return new GetAllProductResponse
{
ProductList = mappedList
};
}
public void AddProduct(AddProductRequest reqModel)
{
_productRepository.Save(new Product { Name = reqModel.Name });
}
}
Controller'a geçmeden şu ana kadar oluşturduğumuz dependency'leri inject edelim. Bunun için Startup.cs içerisinde yer alan ConfigureServices metodu içerisinde aşağıdaki tanımlamaları yapalım.
services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<IProductService, ProductService>();
Api Controller Oluşturulması
Son adım olarak ise service'de yer alan bu iki metot için end-ponit'leri oluşturmak var. Bunun için projede yer alan Controller klasörü içerisine ProductController adında bir Controller ekleyelim ve aşağıdaki 2 end-point'i tanımlayalım.
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
private readonly IProductService _productService;
public ProductController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
public ActionResult<GetAllProductResponse> GetAll()
{
var response = _productService.GetAllProducts();
return Ok(response);
}
[HttpPost]
public ActionResult Post([FromBody] AddProductRequest reqModel)
{
_productService.AddProduct(reqModel);
return Ok();
}
}
Geliştirmelerimiz bu kadardı. Entity Framework Core ve Asp.Net Core Web Api kullanarak uçtan uca bir ProductApi oluşturduk ve data access layer için Generic Repository Pattern'den faydalandık.
Yukarıda da bahsettiğim gibi Entity Framework Core benchmark testlerinde en performanslı orm olarak karşımıza çıkmakta ve microsoft'un core çatısı altında en çok önem verdiği ürünlerin başında gelmekte. Sizlerde bu yazımızda olduğu gibi hızlı bir şekilde uçtan uca bir api projesi geliştirebilirsiniz.