简体   繁体   English

创建用户时如何修复System.ObjectDisposedException

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

I need to create a user telegram in IDENTITY. 我需要在IDENTITY中创建用户电报。 But when using the method _userManager.CreateAsync(appUser) , I get an error. 但是当使用_userManager.CreateAsync(appUser)方法时,出现错误。

Before that, I used IDENTITY only in the controller, from the data coming in the form. 在此之前,我仅在控制器中使用了IDENTITY,来自表单中的数据。 Now, I need to create a user from the data that comes from telegrams. 现在,我需要根据电报中的数据创建一个用户。

My user object: 我的用户对象:

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

Context: 内容:

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

AccountService: 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;
    }
}

And connecting everything in Startup.cs 并连接Startup.cs所有内容

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

I expect the user to be added to the database and return true from the method async Task<bool> TryRegisterUserAsync(User user) . 我希望将用户添加到数据库,并从async Task<bool> TryRegisterUserAsync(User user)方法返回true But in the end, I get an error at run time. 但是最后,我在运行时遇到了错误。

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

Calling Code: 呼叫代码:

var createResult = await _userManager.CreateAsync(appUser);

Updated: Messages from the Telegram server come to my controller 更新:来自电报服务器的消息到达我的控制器

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

The bot code is as follows: 机器人代码如下:

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 should return a Task derived result and not async void . Controller Action应该返回Task派生的结果,而不是async void This will cause the action to be fire and forget, which will cause the db context to be disposed of before the controller or its dependencies are finished with it. 这将导致该操作被触发并遗忘,这将导致在控制器或其依赖关系完成之前丢弃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();
    }
}

I would also advise against making blocking calls on async function in the constructor, which can lead to deadlocks. 我还建议不要在构造函数中对异步函数进行阻塞调用,否则可能导致死锁。

Hold on to the task and await it as needed when appropriate. 坚持执行任务,并在适当时根据需要等待。

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