Entity Framework Core: una segunda operación comenzó en este contexto antes de que se completara una operación anterior

88

Estoy trabajando en un proyecto ASP.Net Core 2.0 usando Entity Framework Core

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0"/>

Y en uno de mis métodos de lista recibo este error:

InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

Este es mi método:

    [HttpGet("{currentPage}/{pageSize}/")]
    [HttpGet("{currentPage}/{pageSize}/{search}")]
    public ListResponseVM<ClientVM> GetClients([FromRoute] int currentPage, int pageSize, string search)
    {
        var resp = new ListResponseVM<ClientVM>();
        var items = _context.Clients
            .Include(i => i.Contacts)
            .Include(i => i.Addresses)
            .Include("ClientObjectives.Objective")
            .Include(i => i.Urls)
            .Include(i => i.Users)
            .Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search))
            .OrderBy(p => p.CompanyName)
            .ToPagedList(pageSize, currentPage);

        resp.NumberOfPages = items.TotalPage;

        foreach (var item in items)
        {
            var client = _mapper.Map<ClientVM>(item);

            client.Addresses = new List<AddressVM>();
            foreach (var addr in item.Addresses)
            {
                var address = _mapper.Map<AddressVM>(addr);
                address.CountryCode = addr.CountryId;
                client.Addresses.Add(address);
            }

            client.Contacts = item.Contacts.Select(p => _mapper.Map<ContactVM>(p)).ToList();
            client.Urls = item.Urls.Select(p => _mapper.Map<ClientUrlVM>(p)).ToList();
            client.Objectives = item.Objectives.Select(p => _mapper.Map<ObjectiveVM>(p)).ToList();
            resp.Items.Add(client);
        }

        return resp;
    }

Estoy un poco perdido, especialmente porque funciona cuando lo ejecuto localmente, pero cuando lo implemento en mi servidor de ensayo (IIS 8.5), aparece este error y funciona normalmente. El error comenzó a aparecer después de que aumenté la longitud máxima de uno de mis modelos. También actualicé la longitud máxima del modelo de vista correspondiente. Y hay muchos otros métodos de lista que son muy similares y están funcionando.

Tenía un trabajo de Hangfire en ejecución, pero este trabajo no usa la misma entidad. Eso es todo lo que puedo pensar que es relevante. ¿Alguna idea de qué podría estar causando esto?

André Luiz
fuente
1
Mira esto .
Berkay
2
@Berkay Vi eso y muchas otras preguntas similares y las probé. Mi método era asíncrono y lo sincronicé para evitar estos problemas. También trato de eliminar el mapeo, también traté de eliminar el .ToPagedList y continúa arrojando el error.
André Luiz
Sería bueno ver un seguimiento de pila completo
Evk
Y para saber si están habilitados varios resultados activos
Jay
Habiendo tenido el mismo problema, descubrí que tenía números enteros anulables en mi tabla de base de datos. tan pronto como configuré las propiedades de mi modelo de entidad para que coincidan con los int que aceptan valores NULL, todo comenzó a funcionar, así que los mensajes me engañaron ...!
AlwaysLearning

Respuestas:

87

No estoy seguro de si está utilizando IoC y Dependency Injection para resolver su DbContext donde sea que se pueda usar. Si lo hace y está utilizando IoC nativo de .NET Core (o cualquier otro contenedor de IoC) y recibe este error, asegúrese de registrar su DbContext como Transient. Hacer

services.AddTransient<MyContext>();

O

services.AddDbContext<MyContext>(ServiceLifetime.Transient);

en vez de

services.AddDbContext<MyContext>();

AddDbContext agrega el contexto según el ámbito, lo que puede causar problemas al trabajar con varios subprocesos.

Además, las operaciones asíncronas / de espera pueden causar este comportamiento cuando se utilizan expresiones lambda asíncronas.

Agregarlo como transitorio también tiene sus desventajas. No podrá realizar cambios en alguna entidad en varias clases que estén usando el contexto porque cada clase obtendrá su propia instancia de su DbContext.

La explicación simple para eso es que la DbContextimplementación no es segura para subprocesos. Puedes leer más sobre esto aquí.

alsami
fuente
1
Cuando uso transitorio, obtengo los siguientes errores de conexión (cerrados o eliminados) 'OmniService.DataAccess.Models.OmniServiceDbContext'. System.ObjectDisposedException: no se puede acceder a un objeto eliminado. Una causa común de este error es eliminar un contexto que se resolvió a partir de la inyección de dependencia y luego intentar usar la misma instancia de contexto en otra parte de su aplicación. Esto puede ocurrir si está llamando a Dispose () en el contexto o si envuelve el contexto en una declaración using. ... Nombre del objeto: 'AsyncDisposer'.
David
3
¡Hola David! Supongo que está utilizando Task.Run(async () => context.Set...)sin esperarlo o creando un contexto de base de datos con ámbito sin esperar el resultado. Esto significa que su contexto probablemente ya esté eliminado al acceder a él. Si está en Microsoft DI, debe crear un ámbito de dependencia dentro de él Task.Run. Consulte también estos enlaces. stackoverflow.com/questions/45047877/… docs.microsoft.com/en-us/dotnet/api/…
alsami
3
Como se señaló anteriormente, si no puede llamar a un método asíncrono con la palabra clave await, enfrentará este problema.
Yennefer
Eso me ayudó. Estoy inyectando dependencias en un nuevo hilo de un servicio alojado cuando recibimos un nuevo mensaje de una cola. Hacer que mi contexto sea transitorio solucionó la excepción
Cale
3
@alsami eres mi héroe. 6 horas de depuración dolorosa. Ésta fue la solución. Si alguien más está inyectando IHttpContextAccessor en DbContext y los reclamos son nulos, esta es la solución. Muchas gracias hombre
jcmontx
55

En algunos casos, este error se produce al llamar a un método asíncrono sin la awaitpalabra clave, que simplemente se puede resolver agregando awaitantes de la llamada al método. sin embargo, es posible que la respuesta no esté relacionada con la pregunta mencionada, pero puede ayudar a resolver un error similar.

Hamid Nasirloo
fuente
4
Esto me pasó a mí. Cambiar First()a await / FirstAsync()trabajado.
Guilherme
Voto a favor. Consulte también jimlynn.wordpress.com/2017/11/16/… Jim Lynn "ERROR EN EL MARCO DE LA ENTIDAD: UNA SEGUNDA OPERACIÓN INICIÓ EN ESTE CONTEXTO ANTES DE COMPLETAR UNA OPERACIÓN ANTERIOR. NO SE GARANTIZA QUE LOS MIEMBROS DE LA INSTANCIA ESTÁN SEGUROS EN EL HILO".
granadaCoder
¡Gracias por esto! Este era exactamente mi problema ... Olvidé agregar un método de espera en un método asíncrono.
AxleWack
También me pasó a mí, y este comentario me ayudó mientras buscaba donde olvidé una espera perdida. Una vez que lo encontré, el problema está resuelto.
Zion Hai
42

La excepción significa que _contextestá siendo utilizado por dos subprocesos al mismo tiempo; ya sea dos subprocesos en la misma solicitud o por dos solicitudes.

¿Es su _contextestática declarada tal vez? No debería ser así.

¿O está llamando GetClientsvarias veces en la misma solicitud desde algún otro lugar de su código?

Es posible que ya esté haciendo esto, pero idealmente, estaría usando la inyección de dependencia para su DbContext, lo que significa que lo usará AddDbContext()en su Startup.cs, y el constructor de su controlador se verá así:

private readonly MyDbContext _context; //not static

public MyController(MyDbContext context) {
    _context = context;
}

Si su código no es así, enséñenos y tal vez podamos ayudar más.

Gabriel Luci
fuente
1
Probablemente sea el trabajo que tengo. Logré resolver, mira mi respuesta. Pero estoy marcando el tuyo como el correcto
André Luiz
Mi código es exactamente así y a menudo hacemos un seguimiento de "Una segunda operación comenzó en este contexto antes de que se completara una operación asincrónica anterior. Use 'await' para asegurarse de que cualquier operación asincrónica se haya completado antes de llamar a otro método en este contexto. Los miembros de la instancia no son garantizado para ser seguro para subprocesos. - en System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered () ".
NMathur
@NMathur ¿Estás usando tu _contextobjeto en otros hilos? ¿Como dentro de un Task.Run()por ejemplo?
Gabriel Luci
@GabrielLuci todos mis métodos son asincrónicos como se muestra a continuación, ¿esto causará el problema? Mi conocimiento sobre este tema es muy reducido. ¿Puede sugerir dónde y qué debería leer en detalle para comprender estos comportamientos? public async Task <List <Item>> GetItems (int orderId) {List <Item> items = await _context.Item.Where (x => x.OrderId == orderId) .ToListAsync (); devolver los artículos; }
NMathur
@NMathur Eso se ve bien. Solo asegúrate de usar siempre awaitmétodos asincrónicos. Si no lo usa await, puede entrar involuntariamente en subprocesos múltiples.
Gabriel Luci
8
  • Resuelva mi problema usando esta línea de código en mi archivo Startup.cs.
    Agregar un servicio transitorio significa que cada vez que se solicita el servicio, se crea una nueva instancia cuando se trabaja con la inyección de dependencia

           services.AddDbContext<Context>(options =>
                            options.UseSqlServer(_configuration.GetConnectionString("ContextConn")),
                 ServiceLifetime.Transient);
    
Muhammad Armaghan
fuente
6

Tuve el mismo problema y resultó que el servicio para padres era un singelton. De modo que el contexto también se convirtió automáticamente en singelton. Aunque fue declarado como Per Life Time Scoped en DI.

Inyectando servicios con diferentes vidas útiles en otro

  1. Nunca inyecte servicios Scoped & Transient en el servicio Singleton. (Esto convierte efectivamente el servicio transitorio o de ámbito en el singleton).

  2. Nunca inyecte servicios transitorios en un servicio con ámbito (esto convierte el servicio transitorio en un servicio con ámbito).

DiPix
fuente
este era mi problema exactamente
Jonesopolis
Este también era mi problema. Estaba registrando una clase de controlador como singleton y DbContext como transitorio. Tuve que usar ServiceProvider dentro de la clase Handler para obtener una instancia transitoria del contenedor DI cada vez que se golpea al Handler
Daiana Sodré
5

Yo tenía el mismo error. Sucedió porque llamé a un método que se construyó como en public async void ...lugar de public async Task ....

Raynlaze
fuente
4

Creo que esta respuesta todavía puede ayudar a alguien y salvar muchas veces. Resolví un problema similar cambiando IQueryablea List(o matriz, colección ...).

Por ejemplo:

var list=_context.table1.where(...);

a

var list=_context.table1.where(...).ToList(); //or ToArray()...
Makhidi Masimov
fuente
2
En mi humilde opinión, esta respuesta no merece puntos negativos, simplemente está mal expresada. .ToList () de hecho resuelve la mayoría de los problemas "una segunda operación ..." debido al hecho de que obliga a la evaluación inmediata de la expresión. De esta forma no hay operaciones de contexto de cola.
vassilag
Este fue el problema en mi caso. Tenía xxx.Contains (z.prop) en una cláusula where de una consulta. Se suponía que xxx era una matriz int [] distinta resuelta a partir de una consulta anterior. Desafortunadamente, cuando llegó la segunda consulta, xxx seguía siendo un IQueryable. Agregar xxx.ToArray () antes de la segunda consulta solucionó mi problema.
Jason Butera
2

Enfrenté el mismo problema, pero el motivo no fue ninguno de los mencionados anteriormente. Creé una tarea, creé un alcance dentro de la tarea y le pedí al contenedor que obtuviera un servicio. Eso funcionó bien, pero luego utilicé un segundo servicio dentro de la tarea y me olvidé de solicitarlo también al nuevo alcance. Por eso, el segundo servicio estaba usando un DbContext que ya estaba eliminado.

Task task = Task.Run(() =>
    {
        using (var scope = serviceScopeFactory.CreateScope())
        {
            var otherOfferService = scope.ServiceProvider.GetService<IOfferService>();
            // everything was ok here. then I did: 
            productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed.
            ...
        }
    }

Debería haber hecho esto:

var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();
Francisco Goldenstein
fuente
¿No se expondría el contexto solo una vez que todo en el bloque de uso se haya completado la ejecución?
Sello Mkantjwa
Cuando se dispone la acción, todo se dispone en ese ámbito. Si tiene una tarea ejecutándose en segundo plano y esa tarea es más larga que la acción, tendrá este problema a menos que cree un nuevo alcance para la tarea, como hice en el ejemplo. Por otro lado, si su tarea puede llevar mucho tiempo o desea estar 100% seguro de que se ejecutará, es posible que deba usar una cola. Si usa Azure, puede usar las colas de Service Bus.
Francisco Goldenstein
2

Entity Framework Core no admite la ejecución de varias operaciones paralelas en la misma DbContextinstancia. Esto incluye tanto la ejecución paralela de asyncconsultas como cualquier uso simultáneo explícito de varios subprocesos. Por lo tanto, siempre await asyncllame inmediatamente o use DbContextinstancias separadas para operaciones que se ejecuten en paralelo.

Ehsan Gondal
fuente
1

Mi situación es diferente: estaba tratando de sembrar la base de datos con 30 usuarios, pertenecientes a roles específicos, así que estaba ejecutando este código:

for (var i = 1; i <= 30; i++)
{
    CreateUserWithRole("Analyst", $"analyst{i}", UserManager);
}

Esta fue una función de sincronización. Dentro de él tuve 3 llamadas a:

UserManager.FindByNameAsync(username).Result
UserManager.CreateAsync(user, pass).Result
UserManager.AddToRoleAsync(user, roleName).Result

Cuando reemplacé .Resultcon .GetAwaiter().GetResult(), este error desapareció.

Catalin
fuente
0

Recibí el mismo mensaje. Pero no tiene ningún sentido en mi caso. Mi problema es que utilicé una propiedad "NotMapped" por error. Probablemente solo signifique un error de sintaxis Linq o clase de modelo en algunos casos. El mensaje de error parece engañoso. El significado original de este mensaje es que no puede llamar a async en el mismo dbcontext más de una vez en la misma solicitud.

[NotMapped]
public int PostId { get; set; }
public virtual Post Post { get; set; }

Puede consultar este enlace para obtener más detalles, https://www.softwareblogs.com/Posts/Details/5/error-a-second-operation-started-on-this-context-before-a-previous-operation-completed

Sharon Zhou
fuente
0

Tengo un servicio en segundo plano que realiza una acción para cada entrada en una tabla. El problema es que si repito y modifico algunos datos en la misma instancia de DbContext, se produce este error.

Una solución, como se menciona en este hilo, es cambiar la vida útil de DbContext a transitoria definiéndola como

services.AddDbContext<DbContext>(ServiceLifetime.Transient);

pero debido a que hago cambios en múltiples servicios diferentes y los confirmo a la vez usando el SaveChanges()método, esta solución no funciona en mi caso.

Debido a que mi código se ejecuta en un servicio, estaba haciendo algo como

using (var scope = Services.CreateScope())
{
   var entities = scope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = scope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

para poder utilizar el servicio como si fuera una simple solicitud. Entonces, para resolver el problema, simplemente dividí el alcance único en dos, uno para la consulta y el otro para las operaciones de escritura de la siguiente manera:

using (var readScope = Services.CreateScope())
using (var writeScope = Services.CreateScope())
{
   var entities = readScope.ServiceProvider.GetRequiredService<IReadService>().GetEntities();
   var writeService = writeScope.ServiceProvider.GetRequiredService<IWriteService>();
   foreach (Entity entity in entities)
   {
       writeService.DoSomething(entity);
   } 
}

Así, efectivamente hay dos instancias diferentes del DbContext que se está utilizando.

Otra posible solución sería asegurarse de que la operación de lectura haya terminado antes de comenzar la iteración. Eso no es muy práctico en mi caso porque podría haber muchos resultados que tendrían que cargarse en la memoria para la operación que traté de evitar usando un Queryable en primer lugar.

NiPfi
fuente
0

Logré obtener ese error pasando un IQueryablemétodo que luego usó esa 'lista' IQueryable como parte de otra consulta en el mismo contexto.

public void FirstMethod()
{
    // This is returning an IQueryable
    var stockItems = _dbContext.StockItems
        .Where(st => st.IsSomething);

    SecondMethod(stockItems);
}

public void SecondMethod(IEnumerable<Stock> stockItems)
{
    var grnTrans = _dbContext.InvoiceLines
        .Where(il => stockItems.Contains(il.StockItem))
        .ToList();
}

Para evitar que eso suceda, utilicé el enfoque aquí y materialicé esa lista antes de pasarle el segundo método, cambiando la llamada SecondMethoda serSecondMethod(stockItems.ToList()

tomRedox
fuente
Esto resolvió el problema, pero ¿no ralentizará el rendimiento? ¿Existe alguna solución alternativa?
Dheeraj Kumar,
0

Primero, vote a favor (al menos) la respuesta de alsami. Eso me puso en el camino correcto.

Pero para aquellos de ustedes que hacen IoC, aquí hay un análisis un poco más profundo.

Mi error (igual que los demás)

Ocurrieron uno o más errores. (Una segunda operación se inició en este contexto antes de que se completara una operación anterior. Esto suele ser causado por diferentes subprocesos que utilizan la misma instancia de DbContext. Para obtener más información sobre cómo evitar problemas de subprocesos con DbContext, consulte https://go.microsoft.com / fwlink /? linkid = 2097913. )

Mi configuración de código. "Solo lo básico" ...

public class MyCoolDbContext: DbContext{
    public DbSet <MySpecialObject> MySpecialObjects {        get;        set;    }
}

y

public interface IMySpecialObjectDomainData{}

y (tenga en cuenta que se está inyectando MyCoolDbContext)

public class MySpecialObjectEntityFrameworkDomainDataLayer: IMySpecialObjectDomainData{
    public MySpecialObjectEntityFrameworkDomainDataLayer(MyCoolDbContext context) {
        /* HERE IS WHERE TO SET THE BREAK POINT, HOW MANY TIMES IS THIS RUNNING??? */
        this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);
    }
}

y

public interface IMySpecialObjectManager{}

y

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);
    }
}

Y finalmente, mi clase de subprocesos múltiples, que se llama desde una aplicación de consola (aplicación de interfaz de línea de comandos)

    public interface IMySpecialObjectThatSpawnsThreads{}

y

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);
    }
}

y la acumulación de DI. (Nuevamente, esto es para una aplicación de consola (interfaz de línea de comandos) ... que exhibe un comportamiento ligeramente diferente al de las aplicaciones web)

private static IServiceProvider BuildDi(IConfiguration configuration) {
    /* this is being called early inside my command line application ("console application") */

    string defaultConnectionStringValue = string.Empty; /* get this value from configuration */

    ////setup our DI
    IServiceCollection servColl = new ServiceCollection()
        ////.AddLogging(loggingBuilder => loggingBuilder.AddConsole())

        /* THE BELOW TWO ARE THE ONES THAT TRIPPED ME UP.  */
        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

    /* so the "ServiceLifetime.Transient" below................is what you will find most commonly on the internet search results */
     # 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;
}

Los que me sorprendieron fueron los (cambiar a) transitorios para

        .AddTransient<IMySpecialObjectDomainData, MySpecialObjectEntityFrameworkDomainDataLayer>()
    .AddTransient<IMySpecialObjectManager, MySpecialObjectManager>()

Tenga en cuenta que creo que debido a que IMySpecialObjectManager se estaba inyectando en "MySpecialObjectThatSpawnsThreads", esos objetos inyectados debían ser Transitorios para completar la cadena.

El punto es ....... no era solo el (Mi) DbContext que necesitaba .Transient ... sino una parte más grande del DI Graph.

Consejo de depuración:

Esta línea:

this.entityDbContext = context ?? throw new ArgumentNullException("MyCoolDbContext is null", (Exception)null);

Ponga su punto de interrupción del depurador allí. Si su MySpecialObjectThatSpawnsThreads está haciendo N número de subprocesos (digamos 10 subprocesos, por ejemplo) ... y esa línea solo se golpea una vez ... ese es su problema. Su DbContext está cruzando hilos.

PRIMA:

Sugeriría leer este artículo / URL a continuación (antiguo pero bueno) sobre las diferencias entre aplicaciones web y aplicaciones de consola

https://mehdi.me/ambient-dbcontext-in-ef6/

Aquí está el encabezado del artículo en caso de que el enlace cambie.

ADMINISTRAR DBCONTEXT DE LA MANERA CORRECTA CON ENTIDAD MARCO 6: UNA GUÍA EN PROFUNDIDAD Mehdi El Gueddari

Encontré este problema con WorkFlowCore https://github.com/danielgerlag/workflow-core

  <ItemGroup>
    <PackageReference Include="WorkflowCore" Version="3.1.5" />
  </ItemGroup>

código de muestra a continuación ... para ayudar a los futuros usuarios de Internet

 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();
                    })

                        /* bunch of other Steps here that were using IMySpecialObjectManager.. here is where my DbContext was getting cross-threaded */


                    .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));

            }
        }
    }

y

ICollection<string> workFlowGeneratedIds = new List<string>();
                for (int i = 0; i < 10; i++)
                {
                    MySpecialObjectInterviewPassThroughData currentMySpecialObjectInterviewPassThroughData = new MySpecialObjectInterviewPassThroughData();
                    currentMySpecialObjectInterviewPassThroughData.MySpecialObjectInterviewPassThroughDataSurrogateKey = i;

                    ////  private readonly IWorkflowHost workflowHost;
                    string wfid = await this.workflowHost.StartWorkflow(MySpecialObjectInterviewDefaultWorkflow.WorkFlowId, MySpecialObjectInterviewDefaultWorkflow.WorkFlowVersion, currentMySpecialObjectInterviewPassThroughData);
                    workFlowGeneratedIds.Add(wfid);
                }
granadaCoder
fuente
0

En mi caso, uso un componente de plantilla en Blazor.

 <BTable ID="Table1" TotalRows="MyList.Count()">

El problema es llamar a un método (Count) en el encabezado del componente. Para resolver el problema, lo cambié así:

int total = MyList.Count();

y después :

<BTable ID="Table1" TotalRows="total">
Ali Borjian
fuente
0

Sé que este problema se planteó hace dos años, pero acabo de tener este problema y la solución que utilicé realmente ayudó.

Si realiza dos consultas con el mismo contexto, es posible que deba eliminar el archivo AsNoTracking. Si lo usa AsNoTracking, está creando un nuevo lector de datos para cada lectura. Dos lectores de datos no pueden leer los mismos datos.

Cornelis de Jager
fuente
0

En mi caso, estaba usando un bloqueo que no permite el uso de await y no crea una advertencia del compilador cuando no esperas un async.

El problema:

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync();
}

// some other code somewhere else doing await context.SaveChangesAsync() shortly after the lock gets the concurrency error

La solución: espere el async dentro del bloqueo bloqueándolo con un .Wait ()

lock (someLockObject) {
    // do stuff
    context.SaveChangesAsync().Wait();
}
Tikall
fuente
0

Otro caso posible: si usa la conexión directa, no olvide cerrar if. Necesitaba ejecutar una consulta SQL arbitraria y leer el resultado. Esta fue una solución rápida, no quería definir una clase de datos, ni configurar una conexión SQL "normal". Así que simplemente reutilicé la conexión de la base de datos de EFC como var connection = Context.Database.GetDbConnection() as SqlConnection. Asegúrese de llamar connection.Close()antes de hacerlo Context.SaveChanges().

klenio
fuente
-1

Tengo el mismo problema cuando intento usar FirstOrDefaultAsync() el método asíncrono en el código siguiente. Y cuando lo arreglé FirstOrDefault(), ¡el problema se resolvió!

_context.Issues.Add(issue);
        await _context.SaveChangesAsync();

        int userId = _context.Users
            .Where(u => u.UserName == Options.UserName)
            .FirstOrDefaultAsync()
            .Id;
...
JuSik404
fuente
1
No está relacionado con FirstOrDefault () o FirstOrDefaultAsync () en absoluto. Se trata del uso de dbContext.
sajadre
-2

Si su método devuelve algo, puede resolver este error poniendo .Resultal final del trabajo y .Wait()si no devuelve nada.

Hasan_H
fuente
-6

Me las arreglé para hacerlo funcionar de nuevo. No tiene mucho sentido pero funcionó:

  1. Eliminar Hangfire de StartUp (estaba creando mi trabajo allí)
  2. Eliminada la base de datos de hangfire
  3. Reinició el servidor

Investigaré más adelante, pero el método que llamé con hangfire recibe un DBContext y esa es la posible causa.

André Luiz
fuente