'.Net Core 2.1 - Cannot access a disposed object.Object name: 'IServiceProvider'
I just migrated .NET Core 2.0 to .NET Core 2.1. Everything went fine, but when I try to login now I get the folowing error:
- $exception {System.ObjectDisposedException: Cannot access a disposed object. Object name: 'IServiceProvider'.
This happens in this bit of code:
public class AppContractResolver : DefaultContractResolver
{
private readonly IServiceProvider _services;
public AppContractResolver(IServiceProvider services)
{
_services = services;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var httpContextAccessor = _services.GetService<IHttpContextAccessor>();
var user = httpContextAccessor.HttpContext.User;
List<JsonProperty> properies = base.CreateProperties(type, memberSerialization).ToList();
properies = FilterOneClaimGranted(type, properies, user);
return properies;
}
It happens on this line:
var httpContextAccessor = _services.GetService<IHttpContextAccessor>();
This did work on .NET Core 2.0
I have tried adding the HttpContextAccessor
to my startup, but that did not work.
So, how do I fix this?
Let me know if you need more code. I will happily provide more, but I don't know what you might or might not need, so therefor I did not add a lot of code.'
EDIT
I have added services.AddHttpContextAccessor();
to my startup, but that does not seem to work. Still getting the error.
EDIT 2:
Full stacktrace:
- $exception {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.GetService[T](IServiceProvider provider)
at WebAPI.Extensions.AppContractResolver.CreateProperties(Type type, MemberSerialization memberSerialization) in C:\Users\luukw\Desktop\stage\blacky-api\Blacky\Extensions\Resolver\AppContractResolver.cs:line 25
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.GetContractSafe(Type type)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
at Microsoft.AspNetCore.Mvc.Formatters.JsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)} System.ObjectDisposedException
Solution 1:[1]
I would suggest that instead of calling
services.GetService<IHttpContextAccessor>()
, inject IHttpContextAccessor
to the constructor and use aprivate field to store the value.
public AppContractResolver(IServiceProvider services,
IHttpContextAccessor httpContextAccessor)
{
_services = services;
this.httpContextAccessor = httpContextAccessor;
}
Also HttpContextAccessor has to be registered manually.
In RegisterServices in Startup.cs
add, services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Solution 2:[2]
In my case issue was in Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider services)
{
var svc = services.GetService<IService>(); // <-- exception here
}
just replace services.GetService<>()
with app.ApplicationServices.GetService<>()
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var svc = app.ApplicationServices.GetService<IService>(); // no exception
}
hope it helps
Solution 3:[3]
If you create any transient service, such as services.AddTransient... then .net core will dispose the service provider. This is a bug as of .net core 2.2.
Solution 4:[4]
For me it works with:
public void ConfigureServices(IServiceCollection services)
{
…
services.AddHttpContextAccessor();
…
}
and then:
public void Configure(IApplicationBuilder app, IHttpContextAccessor accessor)
{
...
...accessor.HttpContext.RequestService
...
}
Solution 5:[5]
I was getting this error and it took a long time to resolve, so I am going to post it here.
Here is the code that was throwing the error:
using var context = this.DbFactory.CreateDbContext();
SqlParameter[] parameter =
{
new SqlParameter("@ord_cust_id", ordCustId)
};
products = await context.GetProduct.FromSqlRaw<ProductEntity>($"{spName} @ord_cust_id", parameter).AsNoTracking().ToListAsync();
The exception that was thrown was on the last line. It made no sense as the context was being created by the DbFactory, and so there is no way that it could be disposed already.
After a lot of searching, the scope of the DbFactory was found to be "Transient" so that was changed to Singleton, and the exception was resolved.
This is the code in startup:
services.AddDbContextFactory<CDSEntities>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
}, ServiceLifetime.Singleton); //changed to Singlton instead of Transient
Solution 6:[6]
I was getting a similar exception when trying to get service inside the Startup ? ConfigureServices
method:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<INotification>(provider =>
{
var hubContext = (IHubContext<NotificationHub>)provider
.GetService(typeof(IHubContext<NotificationHub>));
// ??? Exception: cannot access a disposed object. Object name: 'IServiceProvider'.
var mediator = (IMediator)provider.GetService(typeof(IMediator));
hubContext.SetListener(() =>
mediator.Send(new ...);
...
});
}
...
}
FYI: NotificationHub
is my custom notification class implementing the custom INotificaiton
service.
Solved the problem by creating a local scoped service:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<INotification>(provider =>
{
var hubContext = (IHubContext<NotificationHub>)provider
.GetService(typeof(IHubContext<NotificationHub>));
var myScope = provider.CreateScope(); // <<< creating a scoped sertvice
var mediator = (IMediator)myScope.ServiceProvider.GetService(typeof(IMediator));
hubContext.SetListener(() =>
mediator.Send(new ...);
...
});
}
...
}
Solution 7:[7]
In my case, "await" operator was missing in the caller method.
public async Task<OrderResponse> CreateOrder(){
//Do something
var response = **await** CreateOrderItem();
return response;
}
public async Task<ItemResponse> CreateOrderItem(){
//Do something
}
"await" was missing in CreateOrder()
Solution 8:[8]
In my case I didn't have the async await on the rest API method, so it was disposing the IServiceProvider before the end of the call.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Chris Missal |
Solution 2 | Denis Olifer |
Solution 3 | |
Solution 4 | user3198116 |
Solution 5 | Greg Gum |
Solution 6 | Arsen Khachaturyan |
Solution 7 | prags9 |
Solution 8 | Daniel Lobo |