When I do a POST to a controller, I intermittently get threading errors - though a lot of the time everything will work perfectly. These are the most common two:
New transaction is not allowed because there are other threads running in the session.
The transaction operation cannot be performed because there are pending requests working on this transaction.
I have read multiple replies on why this happens. Such as this one and this one, but I can't say I understand. I know just posting code is horrible practice on SO, and I generally do my best to avoid it, but I really don't know what to ask past "Can you please take a look and let me know if you see any obvious problems."
// POST: api/CheckOuts
[AccessType(AccessType.Create)]
[HttpPost, Route("")]
[ResponseType(typeof(CheckOut))]
public async Task<IHttpActionResult> PostCheckOut(TransactionViewModel<CheckOut> tx)
{
//check if tx is a valid CheckOut Model Object
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
tx.Transaction.OrganizationId = SelectedOrganizationID;
tx.Transaction.OfficeId = SelectedOfficeID;
tx.Transaction.CheckedOutById = UserId;
tx.Transaction.Date = DateTime.UtcNow;
var items = tx.Transaction.Items.ToList();
long checkedOutStatus = db.Statuses.First( a => a.Name == "Checked Out" ).Id;
long checkedInStatus = db.Statuses.First( a => a.Name == "Checked In" ).Id;
//check item status
if( !items.TrueForAll( i=> i.StatusId == checkedInStatus ) )
{
return BadRequest("Not all items are in 'Checked In' state.");
}
var mongoItems = GetMongoCollection<BsonDocument>(MongoConstants.ItemsCollection);
items.ForEach(async item =>
{
var builder = Builders<BsonDocument>.Update;
var update = builder.Set("StatusId", checkedOutStatus)
.Set("CustodianId", tx.Transaction.TakenById)
.Set<BsonDocument, int?>("LocationId", null)
.Set<BsonDocument, string>("Location", null);
await mongoItems.FindOneAndUpdateAsync(
Builders<BsonDocument>.Filter.Eq("_id", item.Id),
update);
await AddItemHistory(item, UserId);
var primaryKeyOfTheItemId = db.ItemIds.Single(i => i.Item_Id == item.Id);
tx.Transaction.ItemIds.Add(primaryKeyOfTheItemId);
});
//add item
db.CheckOuts.Add(tx.Transaction);
await db.SaveChangesAsync(UserId);
return CreatedAtRoute("DefaultApi", new {controller = "checkouts", id = tx.Transaction.Id }, tx.Transaction);
}
Note: I am 100% sure this has to do with async
and is not MongoDb specific. The code below is equivalent of saving something to SQL with EF. I am sure the other Mongo bits are completely irrelevant to the question.
await mongoItems.FindOneAndUpdateAsync(
Builders<BsonDocument>.Filter.Eq("_id", item.Id),
update);
db
is our Entity Framework dbContext (just normal dbContext used with SQL, we have two databases - Mongo and SQL).