Angelo11292
Angelo11292

Reputation: 25

asp net core get user async fails

I have a model that contains the id of the current user, every after create/edit the user it includes its id

Model code:

public class Document
{
    public int Id { get; set; }

    [Required, StringLength(2)]
    public string DocumentCode { get; set; }

    public string DocumentName { get; set; }

    public DateTime DateUpdated { get; set; } = DateTime.Now;

    //Id of the current logged user
    public string UpdatedBy { get; set; }
}

Controller code:

// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("Id,DocumentCode,DocumentName")] Document document)
    {
        if (id != document.Id)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            try
            {
                document.UpdatedBy = _userManager.GetUserAsync(HttpContext.User).Id.ToString();
                _context.Update(document);
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!DocumentExists(document.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return RedirectToAction(nameof(Index));
        }
        return View(document);
    }

Error after Edit more than twice.

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

How can I possibly fix this issue? First click is ok, but second is not. The error both occurs in Create and Edit function.

Upvotes: 0

Views: 1836

Answers (2)

Serg
Serg

Reputation: 7475

You should call it with await keyword:

document.UpdatedBy = (await _userManager.GetUserAsync(HttpContext.User)).Id.ToString();

In simple words when you call an async method without async keyword your code doesn't wait for the asynchronous GetUserAsync method to finish. So it keeps running when you call the next method but your data is not ready yet.

https://learn.microsoft.com/en-us/dotnet/csharp/async

Upvotes: 1

aleha_84
aleha_84

Reputation: 8539

Suppose, that GetUserAsync returns Task<User> object, then it should be awaited first. Then access its properties.

document.UpdatedBy = await (_userManager.GetUserAsync(HttpContext.User)).Id.ToString();

Will be better to check for null here.

document.UpdatedBy = await (_userManager.GetUserAsync(HttpContext.User))?.Id.ToString() ?? string.empty;

Upvotes: 1

Related Questions