Pertama, beri suara positif (setidaknya) jawaban alsami. Itu membuat saya berada di jalan yang benar.
Namun bagi Anda yang melakukan IoC, berikut adalah penjelasan yang lebih mendalam.
Kesalahan saya (sama seperti yang lain)
Terjadi satu atau lebih kesalahan. (Operasi kedua dimulai pada konteks ini sebelum operasi sebelumnya selesai. Hal ini biasanya disebabkan oleh utas yang berbeda menggunakan contoh DbContext yang sama. Untuk informasi selengkapnya tentang cara menghindari masalah threading dengan DbContext, lihat
https://go.microsoft.com / fwlink /? linkid = 2097913. )
Pengaturan kode saya. "Hanya dasar-dasarnya" ...
public class MyCoolDbContext: DbContext{
public DbSet <MySpecialObject> MySpecialObjects { get; set; }
}
dan
public interface IMySpecialObjectDomainData{}
dan (catatan MyCoolDbContext sedang diinjeksi)
public class MySpecialObjectEntityFrameworkDomainDataLayer: IMySpecialObjectDomainData{
public MySpecialObjectEntityFrameworkDomainDataLayer(MyCoolDbContext context) {
this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
}
}
dan
public interface IMySpecialObjectManager{}
dan
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);
}
}
Dan akhirnya, kelas multi utas saya, dipanggil dari Aplikasi Konsol (aplikasi Antarmuka Baris Perintah)
public interface IMySpecialObjectThatSpawnsThreads{}
dan
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);
}
}
dan penumpukan DI. (Sekali lagi, ini untuk aplikasi konsol (antarmuka baris perintah) ... yang menunjukkan perilaku yang sedikit berbeda dari aplikasi web)
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;
}
Yang mengejutkan saya adalah (perubahan ke) sementara untuk
.AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
.AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()
Catatan, saya pikir karena IMySpecialObjectManager disuntikkan ke "MySpecialObjectThatSpawnsThreads", objek yang disuntikkan itu harus Transient untuk menyelesaikan rantai.
Intinya adalah ....... bukan hanya Konteks Db (Saya) yang membutuhkan .Transient ... tetapi sebagian besar Grafik DI.
Tip Debugging:
Garis ini:
this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
Tempatkan break point debugger Anda di sana. Jika MySpecialObjectThatSpawnsThreads Anda membuat N jumlah utas (katakanlah 10 utas misalnya) ...... dan baris itu hanya terkena sekali ... itu masalah Anda. DbContext Anda melintasi utas.
BONUS:
Saya akan menyarankan membaca ini di bawah url / artikel (lama tapi bagus) tentang perbedaan aplikasi web dan aplikasi konsol
https://mehdi.me/ambient-dbcontext-in-ef6/
Berikut adalah tajuk artikel jika tautan berubah.
MENGELOLA DBCONTEXT DENGAN BENAR DENGAN KERANGKA ENTITY 6: PANDUAN DALAM KEDALAMAN Mehdi El Gueddari
Saya mengalami masalah ini dengan WorkFlowCore https://github.com/danielgerlag/workflow-core
<ItemGroup>
<PackageReference Include="WorkflowCore" Version="3.1.5" />
</ItemGroup>
contoh kode di bawah .. untuk membantu pencari internet di masa mendatang
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));
}
}
}
dan
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);
}