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
If you have a transient service constructor that takes an IServiceProvider, the service provider will be disposed. This is a bug in . NET core. Work-around is to manage your own transient life-cycle in a pooling class.
The IServiceProvider is responsible for resolving instances of types at runtime, as required by the application. These instances can be injected into other services resolved from the same dependency injection container. The ServiceProvider ensures that resolved services live for the expected lifetime.
: '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.
In the context of C#, dispose is an object method invoked to execute code required for memory cleanup and release and reset unmanaged resources, such as file handles and database connections.
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
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>();
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.
For me it works with:
public void ConfigureServices(IServiceCollection services)
{
…
services.AddHttpContextAccessor();
…
}
and then:
public void Configure(IApplicationBuilder app, IHttpContextAccessor accessor)
{
...
...accessor.HttpContext.RequestService
...
}
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With