Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ObjectDisposedException: Cannot access a disposed object. Object name: 'IServiceProvider' #19

Open
ikyslyi opened this issue Jan 3, 2025 · 1 comment

Comments

@ikyslyi
Copy link

ikyslyi commented Jan 3, 2025

Trying to run multiple parallel requests to GetCustomers, even without any logic inside

public async Task<GetCustomersResponse> Handle(GetCustomers request, CancellationToken cancellationToken)
{
    await Task.Delay(300, cancellationToken);
    var customer = new CustomerReadDto { Id = Guid.NewGuid(), CustomerId = 1, City = "New York" };
    return new GetCustomersResponse(new ListResultModel<CustomerReadDto>(new List<CustomerReadDto>(){ customer }, 10, 1, 10));
}

and getting such exception:

[13:47:46 ERR] HTTP GET /api/v1/customers responded 500 in 908.3350 ms
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at MediatR.ServiceFactoryExtensions.GetInstances[T](ServiceFactory factory)
at MediatR.Wrappers.RequestHandlerWrapperImpl2.Handle(IRequest1 request, ServiceFactory serviceFactory, CancellationToken cancellationToken)
at MediatR.Mediator.Send[TResponse](IRequest1 request, CancellationToken cancellationToken) at BuildingBlocks.Core.CQRS.Query.QueryProcessor.SendAsync[TResponse](IQuery1 query, CancellationToken cancellationToken) in C:\Users\xxx\Projects\etc\ecommerce-modular-monolith\src\BuildingBlocks\BuildingBlocks.Core\CQRS\Query\QueryProcessor.cs:line 16
at FoodDelivery.Modules.Customers.Customers.Features.GettingCustomers.GetCustomersEndpoint.HandleAsync(GetCustomersRequest request, CancellationToken cancellationToken) in C:\Users\xxx\Projects\etc\ecommerce-modular-monolith\src\Modules\Customers\FoodDelivery.Modules.Customers\Customers\Features\GettingCustomers\GetCustomersEndpoint.cs:line 40
at lambda_method548(Closure, Object)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Prometheus.GrpcRequestCountMiddleware.Invoke(HttpContext context)
at Prometheus.HttpMetrics.HttpRequestDurationMiddleware.Invoke(HttpContext context)
at Prometheus.HttpMetrics.HttpRequestCountMiddleware.Invoke(HttpContext context)
at Prometheus.HttpMetrics.HttpInProgressMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Serilog.AspNetCore.RequestLoggingMiddleware.Invoke(HttpContext httpContext)

Code to reproduce the issue:

class Program
{
static async Task Main(string[] args)
{
// Endpoint URL
string urlGet = "http://localhost:5000/api/v1/customers?Page=1&PageSize=10";
// Number of parallel requests
int numberOfRequests = 100;
// List to hold tasks
List tasks = new List();
using (HttpClient client = new HttpClient())
{
for (int i = 0; i < numberOfRequests; i++)
{
tasks.Add(SendGetRequest(client, urlGet));
}
// Wait for all requests to complete
await Task.WhenAll(tasks);
}
Console.WriteLine("All requests completed.");
}
static async Task SendGetRequest(HttpClient client, string url)
{
try
{
HttpResponseMessage response = await client.GetAsync(url);
string responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Response: {response.StatusCode} - {responseString}");
}
catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); }
}
}

@ikyslyi
Copy link
Author

ikyslyi commented Jan 3, 2025

A possible reason is described here
The solution that helped me is described here

to me, the fastest way was to create a new Mediator instance in QueryProcessor/CommandProcessor directly from IServiceScopeFactory

public class QueryProcessor : IQueryProcessor
{
private readonly IMediator _mediator;
public QueryProcessor(IServiceScopeFactory serviceScopeFactory)
{
var serviceProvider = serviceScopeFactory.CreateScope().ServiceProvider;
_mediator = new Mediator(serviceProvider);
}
public Task SendAsync(IQuery query,
CancellationToken cancellationToken = default)
{
return _mediator.Send(query, cancellationToken);
}
public IAsyncEnumerable SendAsync(IStreamQuery query,
CancellationToken cancellationToken = default)
{
return _mediator.CreateStream(query, cancellationToken);
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant