944 messaggi dal 11 febbraio 2013
ciao
perdonate ma ho provato da solo a capire ma nulla

Quando lancio un metodo che legge le tabelle da un database ottengo un errore che dice:

System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'CompanyDbContext'.

uso la DI di asp.net core per passare il contesto e non faccio io il dispose

startup:

services.AddDbContextPool<ApplicationDbContext>((serviceProvider, options) =>
            {
                options.UseSqlite(Configuration.GetConnectionString("appDbConnection"));
            });
services.AddDbContextPool<CompanyDbContext>(options =>
                options.UseSqlite(Configuration.GetConnectionString("companyDbConnection")));


Controller e metodo
 public SyncTablesController(CompanyDbContext companyContext,
            ApplicationDbContext applicationDbContext, IMapper mapper, IQueue queue, IHubContext<JobProgressHub> hubContext)
        {
            this._companyContext = companyContext;
            this._applicationContext = applicationDbContext;
            this._mapper = mapper;
            ...
        }

private async Task SyncTablesJobAsync(string jobId, ICollection<string> tables)
        {
            var taskList = new List<Task>();
            try
            {
                foreach (var table in tables)
                {
                    switch (table)
                    {
                        case "agenti":
                            var agenti = FillAgenti();
                            taskList.Add(agenti);
                            break;
                        ...
                    }
                    await _hubContext.Clients.Group(jobId).SendAsync("progress", numerTablesProcessed / tables.Count);
                    await Task.WhenAll(taskList);                
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

private async Task FillAgenti()
        {
            var agents = await new Agent(_companyContext).GetAgentsAsync();
            var agenteRepository = new AgenteRepository(_applicationContext, _mapper);
            await agenteRepository.RemoveAllAgentiAsync();
            await agenteRepository.AddAgentiAsync(
                await agenteRepository.FillAgentiFromCompanyAsync(agents));

            numerTablesProcessed++;
        }


Anche nei repository uso la DI e passo al costruttore CompanyDbContext

ho fatto il debug tante volte ma non capisco dove chiudo il contesto
Se l'errore è evidente fatemi sapere per favore
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
riesci a vedere dallo stack trace in che riga di codice si genera l'errore?

Non è che per caso fai il Dispose del DbContext da una delle classi a cui lo passi? Tipo Agent o AgenteRepository?

ciao,
Moreno

Enjoy learning and just keep making
944 messaggi dal 11 febbraio 2013
Non ci sono blocchi using e l'errore è segnalato qui:
private readonly CompanyDbContext _context;

        public Agent(CompanyDbContext context)
        {
            _context = context;
        }

        [Key]
        public string Codice { get; set; }
        public string Nome { get; set; }


        public async Task<IEnumerable<Agent>> GetAgentsAsync()
        {
            return await _context.Agents.AsNoTracking().ToListAsync(); <=== *** ERRORE
        }

Se nel metodo fillAgente commento il codice per far eseguire AgenteRepository ho lo stesso errore
Modificato da jjchuck il 15 maggio 2019 10:51 -
944 messaggi dal 11 febbraio 2013
questo codice viene eseguito
[HttpPost]
        public async Task<IActionResult> test(ICollection<string> tables)
        {
            var taskList = new List<Task>();
            foreach (var table in tables)
            {
                switch (table)
                {
                    case "agenti":
                       var agenti = FillAgenti();
                            taskList.Add(agenti);
                            break;
                    case "rubrica":
                        var rubrica = FillRubrica();
                            taskList.Add(rubrica);
                            break;
                     ...
                }
                await Task.WhenAll(taskList);
            }
            return View("Index");
        }


L'unica differenza con l'altro che eseguo da coravel e che la firma ha Task<IActionResult> anziche
Task ... percui il contesto viene rimosso per questo?
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,


L'unica differenza con l'altro che eseguo da coravel

Beh, se lo esegui da Coravel vuol dire che il lavoro viene fatto in un task in background, che perdura anche dopo il termine della richiesta HTTP, momento in cui il DbContext viene "distrutto".

Il task lanciato su Coravel dovrebbe ottenere una propria istanza del DbContext. Lo puoi fare ottenendo il riferimento al servizio IServiceScopeFactory di ASP.NET Core, crearti uno scope e all'interno di quello scope ottenere il riferimento al DbContext.

Lo puoi vedere qui proprio in fondo all'articolo, al paragrafo "Understanding scope lifetime".
https://wildermuth.com/2016/08/07/ASP-NET-Core-Dependency-Injection

Questo non l'ho mai usato in combinazione con il DbContextPool, quindi fammi sapere se funziona :D

ciao,
Moreno

Enjoy learning and just keep making
944 messaggi dal 11 febbraio 2013
SMARRAMBA cit. OttoDisk

Ci sono riuscito...grazie a te

private async Task SyncTablesJobAsync(string jobId, ICollection<string> tables)
        {
            double processed = 0;
            try
            {
                using (var scope = _scopeFactory.CreateScope())
                {
                    var appDbCtx = scope.ServiceProvider.GetService<ApplicationDbContext>();
                    var companyDbCtx = scope.ServiceProvider.GetService<CompanyDbContext>();

                    foreach (var table in tables)
                    {
                        switch (table)
                        {
                            case "agenti":
                                await FillAgenti(appDbCtx, companyDbCtx);
                                processed++;
                                break;
                            case "rubrica":
                                await FillRubrica(appDbCtx, companyDbCtx);
                                processed++;
                                break;
                            ...
                        }

                        await _hubContext.Clients.Group(jobId).SendAsync("progress", (processed / tables.Count) * 100);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

tutto funge
grazie ancora
Modificato da jjchuck il 18 maggio 2019 22:02 -
Modificato da jjchuck il 18 maggio 2019 23:40 -
944 messaggi dal 11 febbraio 2013
Ho provato a eseguire i task simultaneamente ma ottengo errori tipo
Un secondo task è iniziato sul contesto mentre un altro è in esecuzione.

Ho capito che Efcore non è thrase safe

Come posso eseguire il metodo in maniera corretta con due contesti usando Task.whenAll?

Grazie
944 messaggi dal 11 febbraio 2013
Nessuno ha usato EFcore in un contesto multitread?

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.