Не удается получить доступ к удаленному объекту. Имя объекта: ошибка «IServiceProvider» в проекте AspNet Core/EF Core

#c# #asp.net-core #dependency-injection #mediatr

Вопрос:

Я пишу статью ASP.NET Основное приложение с ядром Entity Framework. Я также использую MediatR.

Когда я запускаю обновление базы данных, будь то сохранение или удаление, я получаю эту ошибку:

Не удается получить доступ к удаленному объекту. Имя объекта: «IServiceProvider»

Иногда это происходит с первой попытки, иногда с последующих. Кажется, я не могу найти закономерность. Что мне удалось сделать, так это нажать точку останова в обработчике, который вызывает await _applicationDbContext.SaveChangesAsync(cancellationToken); , хотя на самом деле ошибка возникает в контроллере, вкл await _mediator.Send(someRequestModel); . После появления ошибки приложение переходит в режим прерывания и выходит из строя.

Я буду использовать фиктивные имена, но я думаю, что это соответствующий код:

Контроллер:

 public MyController(IMediator mediator)
{
    _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}

[HttpDelete("{id}")]
public async void Delete(string id)
{
    await _mediator.Send(new DeleteRequestModel(Guid.Parse(id))); // error thrown here
}
 

Обработчик:

 public class DeleteCommandHandler : IRequestHandler<DeleteRequestModel>
{
    private readonly ApplicationDbContext _applicationDbContext;

    public DeleteCommandHandler(ApplicationDbContext applicationDbContext)
    {
        _applicationDbContext = applicationDbContext;
    }

    public async Task<Unit> Handle(DeleteRequestModel request, CancellationToken cancellationToken)
    {
        var item = _applicationDbContext.MyData.First(x => x.Id == request.Id);
        _applicationDbContext.MyData.Remove(item);

        await _applicationDbContext.SaveChangesAsync(cancellationToken); // pretty sure this errors out

        return Unit.Value;
    }
}
 

Startup.cs:

 public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnectionString")));
    services.AddDbContext<ApplicationAspNetUsersDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnectionString")));

    services.AddDatabaseDeveloperPageExceptionFilter();

    services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationAspNetUsersDbContext>();

    services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationAspNetUsersDbContext>();

    services.AddAuthentication()
        .AddIdentityServerJwt();
    services.AddControllers();
    services.AddRazorPages();
    // In production, the Angular files will be served from this directory
    services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; });

    services.AddSwaggerDocument();

    services.AddMediatR(AppDomain.CurrentDomain.Load("MySolution.MyProject.EntityFramework"));
    services.AddValidatorsFromAssembly(AppDomain.CurrentDomain.Load("MySolution.MyProject"));
    services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorPipelineBehavior<,>));

    services.AddSingleton(x =>
        new BlobServiceClient(Configuration.GetConnectionString("AzureBlobStorageConnection")));
    services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_CONNECTIONSTRING"]);

    services.Configure<ConnectionStrings>(Configuration.GetSection("ConnectionStrings"));
    services.Configure<AzureBlobStorage>(Configuration.GetSection("AzureBlobStorage"));
    services.Configure<ApplicationInsights>(Configuration.GetSection("ApplicationInsights"));
}
 

Наконец, вот трассировка стека, на этот раз для действия по обновлению:

 at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.GetActionsForException(Type exceptionType, TRequest request, MethodInfoamp; actionMethodInfo)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.<Handle>d__2.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()   
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.<Handle>d__2.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()   
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.<Handle>d__2.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()   
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)   
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MySolution.Web.Controllers.MyController.< Patch >d__7.MoveNext() in
..ControllersMyController.cs:line 85
 

Мы будем очень признательны за любую помощь.

Комментарии:

1. Теун ван Шаген прав: "Avoid Async Void" . Вот хорошая статья, объясняющая «почему»: MSDN: Асинхронное/Ожидание — Лучшие практики асинхронного программирования . Пожалуйста, убедитесь, что изменение подписи вашего контроллера public async Task Delete(string id) решает проблему; пожалуйста, поддержите и «примите» ответ Теуна ван Шагена 🙂

2. Я, безусловно, согласился! Спасибо вам за статью.

Ответ №1:

Вы используете асинхронную пустоту в своем контроллере. Async void следует использовать только в определенных сценариях, в этом случае вы должны использовать задачу в качестве типа возвращаемого значения.

Комментарии:

1. Ага… Кроме того, в качестве конечной точки я бы подумал, что следует обрабатывать возвраты, чтобы правильно указывать статус http. хотя я не уверен, какая это версия netcore и тип проекта: вероятно, это будет Task<IActionResult> с Ok() использованием или CreatedAtAction использованием; см. Типы возвращаемых действий aspnet-core web-api , если да,