DI : Conditional Registration ve Open Generic Registration
Conditional Registration (Config’e Göre Kayıt)
DI : Conditional Registration ve Open Generic Registration
Conditional Registration (Config’e Göre Kayıt)
Dependency Injection(DI) ile servis kayıtlarımızı yaparken, belli koşullara göre farklı servis kayıtları yapmamız gerekebilir.
// appsettings.json
{
"Features": {
"UseRedisCache": true,
"UseSqlServerLogging": false
}
}
// Program.cs
var useRedis = builder.Configuration.GetValue<bool>("Features:UseRedisCache");
if (useRedis)
{
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
});
services.AddSingleton<ICacheService, RedisCacheService>();
}
else
{
services.AddMemoryCache();
services.AddSingleton<ICacheService, MemoryCacheService>();
}
// Kullanım - Controller'da fark etmez
public class ProductController
{
private readonly ICacheService _cache; // Redis veya Memory olabilir
public ProductController(ICacheService cache)
{
_cache = cache;
}
}
Open Generic Registration (Generic Interface Kaydetme)
Generic tipleri kullanarak servis kayıtlarında entity ler için generic servislerin hepsinin tek satırda kayıt edilmesini sağlayabilirsiniz. (Bu baya hoşunuza gidecek) 😅
// Generic interface
public interface IRepository<T> where T : class
{
Task<T> GetById(int id);
Task Save(T entity);
}
// Generic implementation
public class Repository<T> : IRepository<T> where T : class
{
private readonly AppDbContext _db;
public Repository(AppDbContext db) => _db = db;
public async Task<T> GetById(int id) => await _db.Set<T>().FindAsync(id);
public async Task Save(T entity) => await _db.Set<T>().AddAsync(entity);
}
// Program.cs - Tek satırda tüm entity'ler için!
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
// Kullanım
public class ProductService
{
private readonly IRepository<Product> _productRepo;
private readonly IRepository<Category> _categoryRepo;
// Otomatik olarak Repository<Product> ve Repository<Category> gelir!
public ProductService(
IRepository<Product> productRepo,
IRepository<Category> categoryRepo)
{
_productRepo = productRepo;
_categoryRepo = categoryRepo;
}
}
Aslında burada otomatik olarak kendisi tek tek entity class ları derleme koduna yazarak kodu derliyor gibi geliyor ama işin arkaplanı öyle değil.
Aslında tüm entity’leri bilmiyor, lazy registration yapıyor!
Nasıl Çalışıyor?
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
// Bu satır şunu söylüyor:
// "Biri IRepository<X> isterse, ona Repository<X> ver"
// X ne olursa olsun!
Runtime’da çözülüyor.
public class ProductService
{
// Constructor'da IRepository<Product> istedi
public ProductService(IRepository<Product> productRepo)
{
// DI şunu yapıyor:
// 1. "IRepository<Product> isteniyor"
// 2. "Kayıtlara bak: IRepository<> → Repository<> var"
// 3. "Product'ı yerine koy: Repository<Product> oluştur"
// 4. Inject et!
}
}
public class CategoryService
{
// Farklı entity istedi
public CategoryService(IRepository<Category> categoryRepo)
{
// DI yine aynı kayıttan Repository<Category> oluşturur
}
}
Yani önceden tüm entity’ler için kayıt yapmıyor, talep gelince oluşturuyor!
Hariç Tutma Nasıl Yapılır?
Yöntem 1: Özel Entity İçin Override
// Genel kayıt
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
// Product için özel implementation
services.AddScoped<IRepository<Product>, ProductRepositoryWithCache>();
// DI önce spesifik olanı arar:
// IRepository<Product> istendi → ProductRepositoryWithCache gelir
// IRepository<Category> istendi → Repository<Category> gelir
Yöntem 2: Interface ile Sınırlama
// Sadece IEntity implement eden classlar için
public interface IEntity
{
int Id { get; set; }
}
public interface IRepository<T> where T : class, IEntity
{
Task<T> GetById(int id);
}
public class Repository<T> : IRepository<T> where T : class, IEntity
{
// Sadece IEntity olan classlar kullanabilir
}
// Kullanım
public class Product : IEntity { } // ✅ Çalışır
public class RandomClass { } // ❌ Çalışmaz
services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
Yöntem 3: Manuel Filtreleme (Advanced)
public static class RepositoryExtensions
{
public static IServiceCollection AddRepositories(this IServiceCollection services)
{
var entityTypes = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsClass
&& !t.IsAbstract
&& t.Namespace == "MyApp.Entities" // Sadece Entities namespace'i
&& t.Name != "AuditLog") // AuditLog hariç
.ToList();
foreach (var entityType in entityTypes)
{
var repositoryInterface = typeof(IRepository<>).MakeGenericType(entityType);
var repositoryImplementation = typeof(Repository<>).MakeGenericType(entityType);
services.AddScoped(repositoryInterface, repositoryImplementation);
}
return services;
}
}
// Program.cs
services.AddRepositories();
Yöntem 4: Attribute ile İşaretleme
[AttributeUsage(AttributeTargets.Class)]
public class RepositoryEnabledAttribute : Attribute { }
[RepositoryEnabled] // Bu entity için repository oluştur
public class Product { }
public class TempData { } // Bu entity için repository oluşturma
// Registration
public static IServiceCollection AddRepositories(this IServiceCollection services)
{
var entityTypes = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.GetCustomAttribute<RepositoryEnabledAttribute>() != null)
.ToList();
foreach (var entityType in entityTypes)
{
var repoInterface = typeof(IRepository<>).MakeGenericType(entityType);
var repoImpl = typeof(Repository<>).MakeGenericType(entityType);
services.AddScoped(repoInterface, repoImpl);
}
return services;
}
Dikkat: Generic Constraint’ler Önemli! ⚠️
// ❌ YANLIŞ - Herhangi bir class için repository
public interface IRepository<T> where T : class { }
public class MyService
{
// Bu da çalışır ama mantıksız!
public MyService(IRepository<string> repo) { }
}
// ✅ DOĞRU - Sadece entity'ler için
public interface IRepository<T> where T : class, IEntity { }
public class MyService
{
public MyService(IRepository<string> repo) { } // ❌ Compile error!
public MyService(IRepository<Product> repo) { } // ✅ OK
}
Özetle;
- Tüm entity’leri önceden kaydediyor mu? → ❌ Hayır, lazy (talep gelince)
- Hangi entity’lere uygulanır? → Generic constraint’e uyan her class
- Hariç tutma nasıl? → Override, interface constraint, attribute
- Performans sorunu var mı? → ❌ Hayır, ilk kullanımda resolve edilir.
Görüşmek üzere.. 👋
메타데이터
- post_id
- d7bc9fa881cc
- slug
- dependency-injection-conditional-registration-ve-open-generic-registration-d7bc9fa881cc
- url
- https://medium.com/@muratbaseren/dependency-injection-conditional-registration-ve-open-generic-registration-d7bc9fa881cc
- canonical_url
- https://medium.com/@muratbaseren/dependency-injection-conditional-registration-ve-open-generic-registration-d7bc9fa881cc
- author_url
- https://medium.com/@muratbaseren
- status
- ok
- fetched_at
- 2026-07-09 04:10:03