İlk olarak, (en azından) alsami'nin cevabına olumlu oy verin. Bu beni doğru yola götürdü.
Ancak, IoC yapanlarınız için, işte biraz daha derin bir dalış.
Benim hatam (diğerleriyle aynı)
Bir veya daha fazla hata oluştu. (Önceki bir işlem tamamlanmadan önce bu bağlamda ikinci bir işlem başlatıldı. Bu genellikle aynı DbContext örneğini kullanan farklı iş parçacıklarından kaynaklanır. DbContext ile iş parçacığı sorunlarının nasıl önleneceği hakkında daha fazla bilgi için bkz.
Https://go.microsoft.com / fwlink /? linkid = 2097913. )
Kod kurulumum. "Sadece temel bilgiler" ...
public class MyCoolDbContext: DbContext{
public DbSet <MySpecialObject> MySpecialObjects { get; set; }
}
ve
public interface IMySpecialObjectDomainData{}
ve (MyCoolDbContext'in enjekte edildiğini unutmayın)
public class MySpecialObjectEntityFrameworkDomainDataLayer: IMySpecialObjectDomainData{
public MySpecialObjectEntityFrameworkDomainDataLayer(MyCoolDbContext context) {
this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
}
}
ve
public interface IMySpecialObjectManager{}
ve
public class MySpecialObjectManager: IMySpecialObjectManager
{
public const string ErrorMessageIMySpecialObjectDomainDataIsNull = "IMySpecialObjectDomainData is null";
private readonly IMySpecialObjectDomainData mySpecialObjectDomainData;
public MySpecialObjectManager(IMySpecialObjectDomainData mySpecialObjectDomainData) {
this.mySpecialObjectDomainData = mySpecialObjectDomainData ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectDomainDataIsNull, (Exception)null);
}
}
Ve son olarak, çok iş parçacıklı sınıfım bir Konsol Uygulamasından (Komut Satırı Arayüzü uygulaması) çağrılıyor
public interface IMySpecialObjectThatSpawnsThreads{}
ve
public class MySpecialObjectThatSpawnsThreads: IMySpecialObjectThatSpawnsThreads
{
public const string ErrorMessageIMySpecialObjectManagerIsNull = "IMySpecialObjectManager is null";
private readonly IMySpecialObjectManager mySpecialObjectManager;
public MySpecialObjectThatSpawnsThreads(IMySpecialObjectManager mySpecialObjectManager) {
this.mySpecialObjectManager = mySpecialObjectManager ?? throw new ArgumentNullException(ErrorMessageIMySpecialObjectManagerIsNull, (Exception)null);
}
}
ve DI birikmesi. (Yine, bu, web uygulamalarından biraz farklı davranış gösteren bir konsol uygulaması (komut satırı arayüzü) içindir)
private static IServiceProvider BuildDi(IConfiguration configuration) {
string defaultConnectionStringValue = string.Empty;
IServiceCollection servColl = new ServiceCollection()
.AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
.AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()
# if (MY_ORACLE)
.AddDbContext<ProvisioningDbContext>(options => options.UseOracle(defaultConnectionStringValue), ServiceLifetime.Transient);
# endif
# if (MY_SQL_SERVER)
.AddDbContext<ProvisioningDbContext>(options => options.UseSqlServer(defaultConnectionStringValue), ServiceLifetime.Transient);
# endif
servColl.AddSingleton <IMySpecialObjectThatSpawnsThreads, MySpecialObjectThatSpawnsThreads>();
ServiceProvider servProv = servColl.BuildServiceProvider();
return servProv;
}
Beni şaşırtanlar, geçici olanlardı
.AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
.AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()
Not, IMySpecialObjectManager "MySpecialObjectThatSpawnsThreads" içine enjekte edildiğinden, bu enjekte edilen nesnelerin zinciri tamamlamak için Geçici olması gerektiğini düşünüyorum.
Asıl nokta ....... gerekli olan sadece (My) DbContext değildi ... Geçici ... ama DI Graph'in daha büyük bir parçası.
Hata Ayıklama İpucu:
Bu hat:
this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
Hata ayıklayıcı kırılma noktanızı oraya koyun. MySpecialObjectThatSpawnsThreads, N sayıda iş parçacığı oluşturuyorsa (örneğin 10 iş parçacığı diyelim) ...... ve bu satıra yalnızca bir kez vuruluyorsa ... bu senin sorunun. DbContext'iniz iş parçacıklarını aşıyor.
BONUS:
Web uygulamaları ve konsol uygulamaları arasındaki farklar hakkında aşağıdaki url / makaleyi (eski ama güzel) okumanızı öneririm.
https://mehdi.me/ambient-dbcontext-in-ef6/
Bağlantının değişmesi ihtimaline karşı makalenin başlığı.
DBCONTEXT'İ ENTITY ÇERÇEVESİ İLE DOĞRU YÖNETME 6: DERİNLEMESİNE DAYALI BİR KILAVUZ Mehdi El Gueddari
Bu soruna WorkFlowCore https://github.com/danielgerlag/workflow-core ile ulaştım
<ItemGroup>
<PackageReference Include="WorkflowCore" Version="3.1.5" />
</ItemGroup>
Aşağıdaki örnek kod .. gelecekteki İnternet araştırmacılarına yardımcı olmak için
namespace MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Workflows
{
using System;
using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Constants;
using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.MySpecialObjectInterview.Glue;
using MyCompany.Proofs.WorkFlowCoreProof.BusinessLayer.Workflows.WorkflowSteps;
using WorkflowCore.Interface;
using WorkflowCore.Models;
public class MySpecialObjectInterviewDefaultWorkflow : IWorkflow<MySpecialObjectInterviewPassThroughData>
{
public const string WorkFlowId = "MySpecialObjectInterviewWorkflowId";
public const int WorkFlowVersion = 1;
public string Id => WorkFlowId;
public int Version => WorkFlowVersion;
public void Build(IWorkflowBuilder<MySpecialObjectInterviewPassThroughData> builder)
{
builder
.StartWith(context =>
{
Console.WriteLine("Starting workflow...");
return ExecutionResult.Next();
})
.Then(lastContext =>
{
Console.WriteLine();
bool wroteConcreteMsg = false;
if (null != lastContext && null != lastContext.Workflow && null != lastContext.Workflow.Data)
{
MySpecialObjectInterviewPassThroughData castItem = lastContext.Workflow.Data as MySpecialObjectInterviewPassThroughData;
if (null != castItem)
{
Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete :) {0} -> {1}", castItem.PropertyOne, castItem.PropertyTwo);
wroteConcreteMsg = true;
}
}
if (!wroteConcreteMsg)
{
Console.WriteLine("MySpecialObjectInterviewDefaultWorkflow complete (.Data did not cast)");
}
return ExecutionResult.Next();
}))
.OnError(WorkflowCore.Models.WorkflowErrorHandling.Retry, TimeSpan.FromSeconds(60));
}
}
}
ve
ICollection<string> workFlowGeneratedIds = new List<string>();
for (int i = 0; i < 10; i++)
{
MySpecialObjectInterviewPassThroughData currentMySpecialObjectInterviewPassThroughData = new MySpecialObjectInterviewPassThroughData();
currentMySpecialObjectInterviewPassThroughData.MySpecialObjectInterviewPassThroughDataSurrogateKey = i;
string wfid = await this.workflowHost.StartWorkflow(MySpecialObjectInterviewDefaultWorkflow.WorkFlowId, MySpecialObjectInterviewDefaultWorkflow.WorkFlowVersion, currentMySpecialObjectInterviewPassThroughData);
workFlowGeneratedIds.Add(wfid);
}