簡體   English   中英

創建用戶時如何修復System.ObjectDisposedException

[英]How to fix System.ObjectDisposedException while creating user

我需要在IDENTITY中創建用戶電報。 但是當使用_userManager.CreateAsync(appUser)方法時,出現錯誤。

在此之前,我僅在控制器中使用了IDENTITY,來自表單中的數據。 現在,我需要根據電報中的數據創建一個用戶。

我的用戶對象:

public class AppUser : IdentityUser
{
    public int TelegramId { get; set; }
    public bool IsBot { get; set; }
    public string TelegramFirstName { get; set; }
    public string TelegramLangCode { get; set; }
}

內容:

public class AppIdentityContext : IdentityDbContext<AppUser>
{
    public AppIdentityContext(DbContextOptions<AppIdentityContext> options)
        : base(options) {}
}

AccountService:

public class Account : IAccount
{
    private readonly UserManager<AppUser> _userManager;

    public Account(UserManager<AppUser> userManager)
        => _userManager = userManager;

    public async Task<bool> TryRegisterUserAsync(User user)
    {
       // User - telegram user object
        var appUser = new AppUser
        {
            IsBot = user.IsBot,
            TelegramId = user.Id,
            UserName = user.Username,
            TelegramFirstName = user.FirstName,
            TelegramLangCode = user.LanguageCode
        };

        var createResult = await _userManager.CreateAsync(appUser);

        return createResult;
    }
}

並連接Startup.cs所有內容

...
services.AddDbContext<AppIdentityContext>(optios => optios.UseSqlServer(Configuration.GetConnectionString("UserIdentityConnection")));
services.AddIdentity<AppUser, IdentityRole>().AddEntityFrameworkStores<AppIdentityContext>();
services.AddTransient<IAccount, Account>();
...

我希望將用戶添加到數據庫,並從async Task<bool> TryRegisterUserAsync(User user)方法返回true 但是最后,我在運行時遇到了錯誤。

System.ObjectDisposedException
  HResult=0x80131622
  Message=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.
  ObjectDisposed_ObjectName_Name
  Source=Microsoft.EntityFrameworkCore

呼叫代碼:

var createResult = await _userManager.CreateAsync(appUser);

更新:來自電報服務器的消息到達我的控制器

[Route("bot/[controller]")]
    [ApiController]
    public class UpdatesController : ControllerBase
    {
        private readonly IBot _bot;
        private readonly IUpdatesRouter _updateRoute;

        public UpdatesController(IBot bot, IUpdatesRouter updateRoute)
        {
            _bot = bot;
            _updateRoute = updateRoute;
        }

        [HttpPost]
        public async void Post([FromBody] Update update)
        {
            if (_updateRoute.IsText(update))
            {
                await _bot.HandleTextCommandAsync(update.Message);
            }

            //if (_updateRoute.IsCallback(update))
            //{
            //    await bot.HandleCallbackAsync(update.CallbackQuery);
            //}
        }
    }

機器人代碼如下:

public class Bot : IBot
    {
        private readonly ITelegramBotClient _botClient;
        private readonly IOptions<BotConfig> _options;
        private readonly IAccount _account;

        public Bot(IOptions<BotConfig> options, 
                    ITextCommands txtCommands,
                    IAccount account)
        {
            _options = options;
            _account = account;

            _botClient = new TelegramBotClient(_options.Value.Token);
            SetWebhookAsync().GetAwaiter().GetResult();
        }

        private async Task SetWebhookAsync() =>
            await _botClient.SetWebhookAsync(
                string.Format(_options.Value.WebhookHost,
                               _options.Value.WebhookUrl));

        public async Task HandleTextCommandAsync(Message message)
        {
            bool regResult = await _account.TryRegisterUserAsync(message.From);
            // to do
        }
    }

Controller Action應該返回Task派生的結果,而不是async void 這將導致該操作被觸發並遺忘,這將導致在控制器或其依賴關系完成之前丟棄db上下文。

[Route("bot/[controller]")]
[ApiController]
public class UpdatesController : ControllerBase {
    private readonly IBot _bot;
    private readonly IUpdatesRouter _updateRoute;

    public UpdatesController(IBot bot, IUpdatesRouter updateRoute) {
        _bot = bot;
        _updateRoute = updateRoute;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] Update update) {
        if (_updateRoute.IsText(update)) {
            await _bot.HandleTextCommandAsync(update.Message);
        }
        return Ok();
    }
}

我還建議不要在構造函數中對異步函數進行阻塞調用,否則可能導致死鎖。

堅持執行任務,並在適當時根據需要等待。

public class Bot : IBot {
    private readonly ITelegramBotClient _botClient;
    private readonly BotConfig botConfig;
    private readonly IAccount _account;
    private Task setWebhookTask;

    public Bot(IOptions<BotConfig> options, ITextCommands xtCommands, IAccount account) {
        botConfig = options.Value;
        _account = account;

        _botClient = new TelegramBotClient(botConfig.Token);
        setWebhookTask = SetWebhookAsync();
    }

    private Task SetWebhookAsync() =>
        _botClient.SetWebhookAsync(
            string.Format(botConfig.WebhookHost, botConfig.WebhookUrl)
        );

    public async Task HandleTextCommandAsync(Message message) {
        await setWebhookTask;
        bool regResult = await _account.TryRegisterUserAsync(message.From);
        // to do
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM