0

In an ASP.NET Webforms application on .NET 4.0 and a Web API, I attempt to add an order and orderRow to the database, but I get this error:

Error: new transactions are not allowed because there are other running threads in the session

From the client, I run an Ajax post to the controller, which has the following code for inserting a value into the database:

private readonly MyDatabaseEntities _ctx;

public ComponibileController()
{
    _ctx = new MyDatabaseEntities(@"xxx");
}

[HttpPost]
public void Post([FromBody] ComponibileCreate model)
{
    if (!ModelState.IsValid) return;

    var taskWork = System.Threading.Tasks.Task.Run(() => SaveOnDatabase(model, utente));

    ...query
    SendMailToUser(...);

    taskWork.Wait();
}

public void SaveOnDatabase(ComponibileCreate model, string utente)
{
    try
    {
        using (_ctx)
        {
            var ordine = new COM_ORDINI
            {
                ..,
            };

            foreach (var item in model.Righe.ToList())
            {
                var righe = new COM_RIGHE
                {
                   ...
                };
                ordine.COM_RIGHE.Add(righe);
            }

            _ctx.COM_ORDINI.Add(ordine);
            _ctx.SaveChanges();
        }
    }
    catch (Exception e)
    {
    }
}
  • I'm pretty sure the for each loop is causing the problem (especially the .ToList()). It is further described over here: https://stackoverflow.com/a/3902790/10551193 – swforlife May 08 '19 at 15:10
  • don't run it in a task – Daniel A. White May 08 '19 at 15:11
  • if i could use async/ await i had no error but how can solve? – gigiLaTrottola May 08 '19 at 15:16
  • Don't use a Task. *Don't* try to use the same context from different threads. It's not thread-safe, it's not meant to live long, just like database connections. It shouldn't be stored in a field either, unless multiple methods need to use the same instance with the same cached data – Panagiotis Kanavos May 08 '19 at 15:34
  • In fact, this code can easily lead to other exceptions. If for example `SaveOnDatabase` completes too quickly, the context could get disposed *before* the other queries run, resulting in an `ObjectDisposedException`. If you want to perform multiple operations in parallel, create and use new DbContext instances – Panagiotis Kanavos May 08 '19 at 15:35
  • Furthermore, the only thing that would require async execution in `SaveOnDatabase` is the call to `SaveChanges`. All other operations are local. – Panagiotis Kanavos May 08 '19 at 15:37

1 Answers1

1

instead System.Threading.Tasks.Task.Run(() => SaveOnDatabase(model, utente)); , use

async Task SaveOnDatabase(ComponibileCreate model, string utente) {
...
await _ctx.SaveChangesAsync();
}

and call await SaveOnDatabase(model, utente) in action

Lapenkov Vladimir
  • 3,066
  • 5
  • 26
  • 37