EF Core araçları (dotnet ef migrations add, database update ve benzerleri) modelinizi öğrenmek için tasarım zamanında türettiğiniz DbContext'ten bir örnek oluşturmak zorundadır. Bunu üç yolla dener: projede IDesignTimeDbContextFactory<TContext> uygulayan bir sınıf varsa doğrudan onu kullanır; yoksa başlangıç projesinin host'unu kurup context'i uygulamanın servis sağlayıcısından ister; o da olmazsa context'i parametresiz kurucusuyla oluşturmaya çalışır. "Araçlar context'i oluşturamadı" türündeki hataların neredeyse hepsi bu üç yolun hiçbirinin sizin projenizde çalışmamasından kaynaklanır ve en güvenilir çözüm bir design-time factory yazmaktır.
Bu yazı, Entity Framework Core (EF Core) belgelerinin "Design-time DbContext Creation" sayfasını, ayrı migration projesi sayfasını ve araç başvurularındaki ilgili bölümleri birlikte ele alıyor: araçlar context'i neden oluşturur, her yöntem hangi koşulda çalışır, factory nasıl yazılır ve neye dikkat edilir, komut satırı argümanları factory'ye nasıl ulaşır, platforma özgü projelerde ne yapılır ve tasarım zamanı servisleri ne işe yarar. Komutların kendisi dotnet ef komutları yazısında, çalışma zamanındaki context yapılandırması ise DbContext yapılandırma yazısında anlatılıyor.
Araçlar neden DbContext oluşturur?

Migration komutları gibi bazı EF Core araç komutları, uygulamanızın entity türleri ve bunların veritabanı şemasına nasıl eşlendiği hakkında ayrıntı toplamak için türetilmiş DbContext'inizin bir örneğine ihtiyaç duyar. Model, context'in OnModelCreating yapılandırmasından, konvansiyonlardan ve kullandığınız sağlayıcıdan oluştuğu için araçlar onu ancak context'i gerçekten oluşturarak elde edebilir. Bağlantı dizesi de aynı yoldan gelir: database update hangi veritabanına bağlanacağını, context'e verdiğiniz yapılandırmadan öğrenir.
Belgelerin vurguladığı nokta şudur: çoğu durumda tasarım zamanında oluşturulan context'in, çalışma zamanında yapılandırıldığına benzer biçimde yapılandırılması istenir. Çalışma zamanında context'e yapılandırma vermenin sayısız yolu vardır ve hepsi çalışır; ancak tasarım zamanında context'i kullanan araçlar yalnızca sınırlı sayıda deseni tanıyabilir. Araçların başlangıç projesini derleyip çalıştırmasının sebebi de budur (hedef ve başlangıç projesi farkı için bkz. dotnet ef komutları).
1. yol: Uygulama servislerinden
Başlangıç projeniz ASP.NET Core Web Host ya da .NET Generic Host kullanıyorsa araçlar context'i uygulamanın servis sağlayıcısından almaya çalışır. Belgelere göre araçlar önce Program.CreateHostBuilder() metodunu çağırır, ardından Build() ile host'u kurar ve Services özelliğine erişir. Belgelerdeki örnek bu kancanın klasik biçimidir:
public class Program
{
public static void Main(string[] args)
=> CreateHostBuilder(args).Build().Run();
// EF Core uses this method at design time to access the DbContext
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder => webBuilder.UseStartup<Startup>());
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
=> services.AddDbContext<ApplicationDbContext>();
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
}
}
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}Belgeler yeni bir ASP.NET Core uygulaması oluşturduğunuzda bu kancanın varsayılan olarak geldiğini not eder. Bu yolun çalışması için context'in kendisinin ve kurucusundaki tüm bağımlılıkların uygulamanın servis sağlayıcısına servis olarak kayıtlı olması gerekir. Bunun en kolay yolu, context'e DbContextOptions<TContext> alan bir kurucu yazmak ve onu AddDbContext<TContext> ile kaydetmektir.
Bu yolun pratik sonucu önemlidir: araçlar host'u kurarken uygulamanızın başlangıç kodunu çalıştırır. Yapılandırma, ortam (ASP.NET Core projelerinde Development, Production gibi) ve servis kayıtları bu sırada devreye girer. Belgelere göre tasarım zamanı araçları, ne ASPNETCORE_ENVIRONMENT ne de DOTNET_ENVIRONMENT ayarlıysa Development ortamını kullanır; dolayısıyla araç, aksini söylemediğiniz sürece geliştirme yapılandırmanızdaki bağlantı dizesiyle çalışır.
2. yol: Parametresiz kurucu
Context uygulama servis sağlayıcısından alınamazsa araçlar proje içinde türetilmiş DbContext türünü arar ve onu parametresiz bir kurucuyla oluşturmaya çalışır. Context OnConfiguring metoduyla yapılandırılıyorsa bu, varsayılan kurucunun kendisi olabilir. İlk EF Core uygulaması yazısındaki console örneği tam olarak bu yolla çalışır: BloggingContext parametresiz bir kurucuya sahiptir ve sağlayıcıyla bağlantı dizesini OnConfiguring içinde kendisi ayarlar.
Bu yol basit projelerde iş görür ama bir sınırı vardır: context'in yapılandırması tamamen kendi içinde olmalıdır. Context yapılandırmasını yalnızca DI üzerinden alıyorsa, yani tek kurucusu DbContextOptions<TContext> parametreli ise ve uygulama servisleri de araçlar tarafından kurulamıyorsa, araçların context'i oluşturmasının yolu kalmaz.
3. yol: Design-time factory (önerilen)

Araçlara context'i nasıl oluşturacaklarını açıkça söylemek için IDesignTimeDbContextFactory<TContext> arayüzünü uygularsınız. Belgelere göre bu arayüzü uygulayan bir sınıf, türetilmiş DbContext ile aynı projede ya da uygulamanın başlangıç projesinde bulunursa araçlar diğer tüm oluşturma yollarını atlar ve doğrudan bu factory'yi kullanır. Belgelerdeki örnek şudur:
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Data Source=blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}Factory'nin tek görevi, CreateDbContext içinde yapılandırılmış bir context örneği döndürmektir. Örnekte seçenekler bir DbContextOptionsBuilder<BloggingContext> ile oluşturulup context'in seçenek alan kurucusuna verilir; bu, DbContext yapılandırma yazısında anlatılan "seçenekleri açıkça oluşturma" deseninin aynısıdır. Context sınıfınızın bu yüzden DbContextOptions<BloggingContext> alan bir kurucusu olmalıdır.
Factory ne zaman gerekir?
Belgeler design-time factory'yi iki durum için önerilen desen olarak gösterir: ayrı bir migration projesi kullandığınızda ve uygulamanızın başlangıç projesi platforma özgü olduğunda. Bunlara ek olarak factory şu durumlarda özellikle işe yarar:
- Context'in kurucusunda DI'a kayıtlı olmayan bağımlılıklar varsa,
- uygulamanızda dependency injection hiç kullanmıyorsanız,
- uygulamanın başlangıç projesi araçlar tarafından çalıştırılamıyorsa.
Factory'nin bir başka değeri de, araçların uygulamanızın başlangıç kodunu çalıştırmasına gerek bırakmamasıdır. Ayrı migration projesi belgeleri bunu açıkça söyler: factory, araçların context'i uygulama projesini çalıştırmadan oluşturmasını sağlar ve migration projesini hem hedef hem başlangıç projesi olarak kullanmak, araçların uygulama başlangıç kodunu yürütmesini engeller. Context'in hangi sağlayıcı ve hangi bağlantıyla oluşturulacağı da böylece tek bir sınıfta, açıkça okunabilir hâle gelir.
Factory yazarken dikkat edilecekler
Belgelerin bu konudaki uyarısı açıktır: tasarım zamanında, uygulamanın çalışma zamanında kullandığı aynı sağlayıcıyı, aynı model seçeneklerini ve aynı migrations assembly ayarını yapılandırın. Aksi hâlde araçlar, uygulamanın kullandığından farklı bir model için migration iskeleti üretebilir. Örneğin çalışma zamanında SQL Server kullanırken factory'de SQLite yapılandırırsanız, üretilen migration'lar SQLite'a göre olur ve üretim veritabanınızla uyuşmaz.
İkinci uyarı argümanlarla ilgilidir: isteğe bağlı bir komut satırı argümanının her zaman verileceğini varsaymayın. Argümanları doğrulayın ve argüman yoksa uygun bir geliştirme varsayılanı veya bir yapılandırma kaynağı kullanın. Bir sonraki bölümdeki örnek bunu nasıl yapacağınızı gösteriyor.
Komut satırı argümanları (args)
Hem IDesignTimeDbContextFactory<TContext>.CreateDbContext hem de Program.CreateHostBuilder komut satırı argümanlarını alır. Bu argümanları araçlardan şöyle iletirsiniz: .NET CLI'da -- işaretinden sonra yazılan her şey uygulamaya iletilir; dotnet ef bunları kendi seçeneği olarak ayrıştırmaya çalışmaz. Package Manager Console'da aynı iş -Args parametresiyle yapılır.
dotnet ef database update -- --environment ProductionUpdate-Database -Args '--environment Production'Ayrı migration projesi belgelerindeki factory, bu argümanları bağlantı dizesi için kullanır. İlk argüman verilmişse onu, verilmemişse yerel bir geliştirme bağlantısını kullanır ve migration'ların bulunduğu derlemeyi açıkça belirtir:
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
var connectionString = args.FirstOrDefault()
?? @"Server=(localdb)\mssqllocaldb;Database=WebApplication1;Trusted_Connection=True";
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlServer(
connectionString,
sqlServer => sqlServer.MigrationsAssembly(typeof(ApplicationDbContextFactory).Assembly.GetName().Name))
.Options;
return new ApplicationDbContext(options);
}
}Bu factory ile dotnet ef database update -- "<bağlantı dizesi>" biçiminde bir çağrı, bağlantı dizesini args dizisinin ilk elemanı olarak factory'ye ulaştırır. Argüman verilmediğinde ise geliştirme veritabanı kullanılır; belgelerin istediği "argüman yoksa makul bir varsayılan" kuralı tam olarak budur. Yalnızca bağlantıyı değiştirmek istiyorsanız birçok komutun kendi --connection seçeneği de vardır (bkz. dotnet ef komutları).
Ayrı migration projesi ve factory
Migration'ları context'ten ayrı bir projede tutmak, belgelere göre uygulama projesi platforma özgü olduğunda (WinUI, .NET MAUI, Blazor WebAssembly, Azure Functions gibi) veya belirli bir runtime identifier (RID) hedeflediğinde önerilir; birden fazla migration setini yönetmek için de kullanılabilir. Belgelerdeki örnek yerleşim üç projeden oluşur:
| Proje | Sorumluluğu | Referansları |
|---|---|---|
| WebApplication1.Data | DbContext ve entity türleri | EF Core sağlayıcısı |
| WebApplication1.Migrations | Migration'lar, model snapshot ve tasarım zamanı context oluşturma | Data projesi, sağlayıcı ve Microsoft.EntityFrameworkCore.Design |
| WebApplication1 | Uygulamayı çalıştırır | Data projesi ve migration projesi |
Bu yerleşimde factory migration projesine konur. Böylece araçlar context'i uygulama projesini hiç çalıştırmadan oluşturabilir. Migration projesi hem hedef hem başlangıç projesi olarak kullanılır; belgelere göre bu, araçların uygulamanın başlangıç kodunu çalıştırmasını engeller:
dotnet ef migrations add NewMigration \
--project WebApplication1.Migrations \
--startup-project WebApplication1.MigrationsÇalışma zamanında da context'i kaydederken aynı migrations assembly'yi belirtmeniz gerekir; belgelerdeki örnek bunu x => x.MigrationsAssembly("WebApplication1.Migrations") ile yapar. Uygulama migration'ları çalışma zamanında keşfediyor veya uyguluyorsa (örneğin Migrate çağırıyorsa) migration projesine normal bir proje referansı vermelidir; migration'lar yalnızca bir dağıtım çıktısıyla uygulanıyorsa bu referansa gerek yoktur. Data projesi ise migration projesine referans vermemelidir, çünkü migration projesi zaten data projesine referans verir ve bu döngüsel bir bağımlılık oluşturur. Bu yerleşimin migration tarafındaki ayrıntıları migration özelleştirme yazısında.
services.AddDbContext<ApplicationDbContext>(
options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"),
x => x.MigrationsAssembly("WebApplication1.Migrations")));Platforma özgü projeler ve işlemci mimarisi
Belgeler, platforma özgü bir uygulama projesinin EF araçları için başlangıç projesi olarak kullanılmamasını açıkça söyler. Mobil, tarayıcı, masaüstü, function ve RID'e özgü projeler, dotnet ef'in çalıştıramayacağı bir iş yükü veya yerel host gerektirebilir. .NET MAUI, WinUI, Blazor WebAssembly, Azure Functions ve benzerleri için önerilen düzen şudur: context ve entity türlerini paylaşılan bir data projesine koyun; migration'ları ve IDesignTimeDbContextFactory<TContext> uygulamasını sıradan, platformlar arası bir .NET projesine koyun; araçları bu projeyi hem hedef hem başlangıç projesi yaparak çalıştırın; uygulamadan migration projesine yalnızca uygulama migration'ları çalışma zamanında yüklüyor veya uyguluyorsa referans verin.
İşlemci mimarisi de benzer bir engeldir. Araçları çalıştıran işlem tüm tasarım zamanı derlemelerini yükleyebilmelidir: 64 bit bir Visual Studio veya .NET işlemi yalnızca x86 için derlenmiş bir başlangıç derlemesini yükleyemez ve aynı kısıt Arm64 ve diğer mimariler için de geçerlidir. Belgeler AnyCPU bir migration projesini tercih etmeyi, tasarım zamanı bağımlılıkları belirli bir mimari gerektiriyorsa eşleşen bir .NET SDK'sını açıkça çağırmayı önerir. Tasarım zamanındaki işlem mimarisi dağıtım hedefinden ayrıdır: bir bundle oluştururken dağıtım RID'i için --target-runtime kullanılır, örneğin linux-x64 ya da linux-arm64.
EF Core 11 için belgelerde, platforma özgü bir başlangıç projesi kullanıldığında araçların uyarı vereceği belirtilir; EF Core 11 geliştirme aşamasındadır ve bu davranış EF Core 10'da yoktur.
MSBuild entegrasyonunda factory zorunluluğu
Compiled model ve önceden derlenmiş sorguları derleme sırasında üreten deneysel MSBuild entegrasyonu da factory ile yakından ilgilidir. Belgelerdeki sınırlamalara göre bu yöntemde farklı bir başlangıç projesi belirtilemez, çünkü bu ters yönlü bir derleme bağımlılığı oluşturur. Bu yüzden context projesinin yapılandırma açısından kendi kendine yetmesi gerekir: uygulamanız context'i normalde başka bir projedeki host builder ile yapılandırıyorsa, context projesinde IDesignTimeDbContextFactory<TContext> uygulamanız gerekir. MSBuild entegrasyonu ve NativeAOT desteği belgelerde deneysel ve henüz üretime uygun değil olarak işaretlidir.
Tasarım zamanı servisleri (IDesignTimeServices)
Factory, araçların context'i nasıl oluşturacağını belirler; tasarım zamanı servisleri ise araçların ne ürettiğini özelleştirmenizi sağlar. Araçların kullandığı bazı servisler yalnızca tasarım zamanında kullanılır ve uygulamanızla birlikte yayına gitmemeleri için çalışma zamanı servislerinden ayrı yönetilir. Bunlardan birini, örneğin migration dosyalarını üreten servisi değiştirmek için başlangıç projenize bir IDesignTimeServices uygulaması eklersiniz:
internal class MyDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
=> services.AddSingleton<IMigrationsCodeGenerator, MyMigrationsCodeGenerator>();
}Belgelerdeki servis listesi; migration kodunu üreten IMigrationsCodeGenerator, migration dosyalarını yöneten IMigrationsScaffolder, çoğul ve tekil kelime üreten IPluralizer, veritabanından model okuyan IDatabaseModelFactory, model kodunu üreten IModelCodeGenerator, OnConfiguring kodunu üreten IProviderConfigurationCodeGenerator ve compiled model ile önceden derlenmiş sorgu üreticileri gibi servisleri içerir. Bu türlere kodunuzdan erişebilmek için Microsoft.EntityFrameworkCore.Design paketinin PackageReference meta verisini değiştirmeniz gerekir; varsayılan kurulumda paket bir DevelopmentDependency olduğu için türlerine referans veremezsiniz (ayrıntı EF Core kurulumu yazısında). Belgeler ayrıca AddEntityFrameworkDesignTimeServices ve AddDbContextDesignTimeServices extension metotlarıyla bu servisleri içeren bir servis sağlayıcı kurup tasarım zamanı iş akışınızın bir kısmını otomatikleştiren kendi araçlarınızı yazabileceğinizi gösterir.
Sık karşılaşılan sorunlar ve çözümleri

- Araçlar context'i oluşturamıyor: Context'in yalnızca DI üzerinden yapılandırıldığı ama başlangıç projesinin host'unun araçlar tarafından kurulamadığı durumlarda görülür. Bir
IDesignTimeDbContextFactory<TContext>ekleyin. - Kurucuda kayıtlı olmayan bağımlılık: Context kurucusu DI'a kayıtlı olmayan bir servis istiyorsa uygulama servisleri yolu başarısız olur. Ya servisi kaydedin ya da factory yazın.
- Factory bulunmuyor: Factory sınıfı ya context ile aynı projede ya da başlangıç projesinde olmalıdır; başka bir projeye koyduğunuz factory'yi araçlar görmez.
- Migration'lar beklenen veritabanına göre değil: Factory'deki sağlayıcı veya model seçenekleri çalışma zamanındakinden farklıdır. Belgelerin kuralı: aynı sağlayıcı, aynı model seçenekleri, aynı migrations assembly.
- Argüman yokken hata: Factory,
argsdizisinin dolu olduğunu varsayıyordur. Argümanı doğrulayın ve bir geliştirme varsayılanına düşün. - Araçlar yanlış veritabanına bağlanıyor: Ortam belirtilmediğinde araçlar
Developmentkullanır. Ortamı-- --environmentile ya da ortam değişkeniyle açıkça verin. - Platforma özgü başlangıç projesi: MAUI, WinUI, Blazor WebAssembly veya Azure Functions projesini başlangıç projesi yapmayın; ayrı, platformlar arası bir migration projesi kullanın.
- Mimari uyuşmazlığı: Yalnızca x86 derlenen bir başlangıç projesi 64 bit araç işlemine yüklenemez; AnyCPU bir migration projesi tercih edin.
Sık Sorulan Sorular
ASP.NET Core projemde factory yazmam gerekir mi?
Genellikle hayır. Belgelere göre yeni ASP.NET Core uygulamalarında araçların context'i servis sağlayıcıdan almasını sağlayan kanca varsayılan olarak gelir; context AddDbContext ile kayıtlı ve kurucusu DbContextOptions<TContext> alıyorsa araçlar onu bulur. Factory, migration'ları ayrı bir projeye taşıdığınızda veya host kurulumu araçlar tarafından çalıştırılamadığında gerekir.
Factory varken diğer yollar da denenir mi?
Hayır. Belgelere göre IDesignTimeDbContextFactory<TContext> uygulayan bir sınıf bulunursa araçlar diğer oluşturma desenlerini atlar ve factory'yi kullanır.
Factory uygulama çalışırken de kullanılır mı?
Bu arayüz araçların tasarım zamanında context oluşturması içindir. Uygulamanın çalışma zamanında context'i nasıl aldığı ayrı bir konudur: AddDbContext, AddDbContextFactory veya new desenleri DbContext yapılandırma yazısında anlatılıyor. Önemli olan, iki tarafın aynı sağlayıcı ve model seçenekleriyle yapılandırılmasıdır.
Factory'ye ortam bilgisini nasıl veririm?
CreateDbContext metodu araçlardan gelen argümanları args dizisi olarak alır. .NET CLI'da -- işaretinden sonra, PMC'de -Args parametresiyle verdiğiniz değerler bu diziye ulaşır; factory içinde bunları doğrulayıp kullanabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: EF Core öğrenme rehberi · dotnet ef komutları · DbContext yapılandırma · Migration özelleştirme