.Net Core 2.1 - 无法访问已释放的对象。对象名称:'IServiceProvider'

33

我刚将.NET Core 2.0迁移到.NET Core 2.1。一切都进行得很顺利,但是现在当我尝试登录时,出现以下错误:

  • $exception {System.ObjectDisposedException: Cannot access a disposed object. Object name: 'IServiceProvider'。

此错误发生在以下代码段中:

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

问题出现在这一行:

var httpContextAccessor = _services.GetService<IHttpContextAccessor>();

这段代码在.NET Core 2.0上运行正常。

我已经尝试在启动时添加HttpContextAccessor,但没有成功。

那么,该如何解决呢?

如果需要更多代码,请告知。我很乐意提供,但我不知道您需要哪些代码,因此我没有添加很多代码。

编辑

我已经在启动时添加了services.AddHttpContextAccessor();,但似乎没有起作用。仍然出现错误。

编辑2:

完整的堆栈跟踪:

- $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

1
只是想确认一下,您是否按照.NET Core 2.1的方式调用services.AddHttpContextAccessor();进行注册? - Gibbon
@CodeNameJack 嗯嗯嗯嗯……虽然这样做是可行的,但我不确定这是否是正确的做法…… - Luuk Wuijster
@CodeNameJack 请查看上面的评论。 - Luuk Wuijster
2
你应该尽量避免将 IServiceProvider 传递给你的类,而是传递实际需要使用的东西。这解决了一些边缘情况(比如你的情况),并且使得更容易看出你的类实际上使用了哪些依赖项。 - Scott Chamberlain
@ScottChamberlain 哦,好的,我不知道那个。那真的很有帮助。谢谢! - Luuk Wuijster
显示剩余11条评论
8个回答

18

在我的情况下,问题出现在Startup.cs文件中。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider services)
{
   var svc = services.GetService<IService>(); // <-- exception here
}

services.GetService<>()替换为app.ApplicationServices.GetService<>()

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   var svc = app.ApplicationServices.GetService<IService>(); // no exception
}

希望能帮到你


谢谢,我有一个ServiceLocator,我可以进行以下更改:private static IServiceProvider _provider; public static void Init(IServiceProvider provider) { _provider = provider; } public static T Resolve() => (T)_provider.GetService(typeof(T));改为:private static IApplicationBuilder _app; public static void Init(IApplicationBuilder app) { _app = app; } public static T Resolve() => (T)_app.ApplicationServices.GetService(typeof(T)); - Anderson Paiva
2
哇塞:app.ApplicationServices 是一个非常惊人的发现!谢谢你的建议,让我省了更多不断研究、试错的时间。 - timmi4sa
:'( 我浪费了很多时间,但是我提高了我的耐心 :D 谢谢! - Juan Pablo

13

我建议您不要调用services.GetService<IHttpContextAccessor>(),而是将IHttpContextAccessor注入到构造函数中并使用私有字段来存储该值。

public AppContractResolver(IServiceProvider services, 
                           IHttpContextAccessor httpContextAccessor)
{
   _services = services;
   this.httpContextAccessor = httpContextAccessor;
}

还要手动注册HttpContextAccessor。在 Startup.cs 的RegisterServices中添加,services.AddSingleton<IHttpContextAccessor,HttpContextAccessor>();


IServiceProvider 是由框架注册的。它本身就是容器。 - Matan Shahar
2
@MatanShahar,只是提醒一下,答案已经更新,现在包含了正确的信息。 - Scott Chamberlain
不建议使用IHttpContextAccessor。 - lnaie
事实与答案无关,OP想在服务中访问IHttpContextAccessor,而该答案提供了正确的方法来实现。 - Code Name Jack

6

如果您创建任何短暂的服务,例如 services.AddTransient... 那么 .net core 将会处理服务提供程序。这是自 .net core 2.2 以来的一个错误。


12
有关此问题的任何 Github 链接吗? - Cheesi
在 .NET Core 3 中,错误似乎已经消失了。 - jjxtra

2
我是一个有用的助手,可以为您翻译文本。

我遇到了这个错误,花费了很长时间才解决,所以我要在这里发布它。

以下是引发错误的代码:

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();

抛出的异常在最后一行。由于上下文是由DbFactory创建的,因此它不可能已经被处理。
经过大量搜索,发现DbFactory的范围是“瞬态”的,所以将其更改为Singleton,问题得到了解决。
这是启动代码:
 services.AddDbContextFactory<CDSEntities>(options =>
 {                
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
 }, ServiceLifetime.Singleton); //changed to Singlton instead of Transient

2

对于我来说,以下内容是有效的:

 public void ConfigureServices(IServiceCollection services)
{
  …
  services.AddHttpContextAccessor();
  …
}

然后:
     public void Configure(IApplicationBuilder app, IHttpContextAccessor accessor)
    {
    ...
    ...accessor.HttpContext.RequestService

     ...

    }

1

在我的情况下,我没有在REST API方法中使用async await,因此在调用结束之前就释放了IServiceProvider


0
在我的情况下,调用方法中缺少了 "await" 运算符。
    public async Task<OrderResponse> CreateOrder(){
    //Do something
    var response = **await** CreateOrderItem();
    return response;
}

public async Task<ItemResponse> CreateOrderItem(){
    //Do something
}

"await" 在 CreateOrder() 中缺失


这对我很有用,我在控制器方法中也遇到了同样的问题。 - MTAG11

0

当我尝试在 Startup ➢ ConfigureServices 方法中获取服务时,遇到了类似的异常:

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 ...);
            ...
        });
    }
    ...
}
  

提示: NotificationHub 是我自定义的通知类,实现了自定义的INotificaiton服务。


通过创建本地作用域服务解决了该问题:

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 ...);
             ...
        });
    }
    ...
}  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接