【问题标题】:Why is my context disposed before I can use it?为什么我的上下文在我可以使用之前就被处理掉了?
【发布时间】:2021-07-29 14:02:10
【问题描述】:

我在 .Net 5 项目中使用 HotChocolate GraphQL 库实现了一个非常简单的查询。我一直在关注 HotChocolate GitHub 存储库中的 tutorial series,但在我的项目中,我不希望 GraphQL 直接访问上下文,而是希望它访问通过上下文管理数据库访问的存储库。

我在这个项目中与 GraphQL 一起构建了一些 REST 端点,并且这个存储库模式在那里可以正常工作。但是,当我从 GraphQL 调用这些存储库方法时,上下文会在存储库方法使用它之前被释放。

我猜测 HotChocolate 使用上下文的方式导致它比我预期的更早被处理,但我无法弄清楚它何时/何​​处被处理以及如何防止它被处理,因此我的存储库方法会工作的。

ContentRepository.cs

namespace BLL.Repository
{
    public class ContentRepository : IRepository<Content>
    {
        private readonly CmsContext _dbContext;

        public ContentRepository(CmsContext dbContext)
        {
            _dbContext = dbContext;
        }

        public virtual List<Content> GetContent()
        {
            return _dbContext.Content.ToList();
        }
    }
}

Query.cs

namespace Web.GraphQL
{
    public class Query
    {
        private readonly IContentRepository _contentRepository;

        public Query(IContentRepository contentRepository)
        {
            _contentRepository = contentRepository;
        }
        
        public List<Content> GetContent()
        {
            return _contentRepository.GetContent() as List<Content>;
        }
    }
}

Startup.cs

namespace Web
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddControllers().AddNewtonsoftJson();
            
            services.AddDbContext<CmsContext>(options =>
                options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), ServerVersion.AutoDetect(Configuration.GetConnectionString("DefaultConnection"))));
            
            services
                .AddGraphQLServer()
                .ModifyRequestOptions(options => options.IncludeExceptionDetails = true)
                .AddQueryType<Query>();

            services.AddScoped<IRepository<Content>, ContentRepository>();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment()) app.UseDeveloperExceptionPage();

            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute("default", "/{controller}/{action}",
                    new {controller = "Default", action = "Index"});
            });

            app.UseEndpoints(endpoints => endpoints.MapGraphQL());

            app.UseGraphQLVoyager(new VoyagerOptions
            {
                GraphQLEndPoint = "/graphql"
            }, "/graphql-voyager");
        }
    }
}

在调试和单步执行代码时,一旦到达ContentRepository.cs 中的GetContent 方法,它就会抛出ObjectDisposedException

我需要做些什么来确保CmsContext 在从 GraphQL 查询中调用时仍然可供 ContentRepository 使用?

【问题讨论】:

  • 不要使用构造函数注入,使用带有[Service]属性的参数注入。 github.com/ChilliCream/hotchocolate/blob/develop/templates/…
  • 你是如何进入 ContentRepository 的呢?此外,这些存储库/查询类过于复杂,没有任何好处。除此之外,Query 还知道它不应该知道的存储库中的实现细节(转换为 List&lt;T&gt;
  • @CamiloTerevinto 我同意 DbContext 的不必要抽象,但 IList/ICollection/IReadonlyListList 并不算太糟糕。
  • @abdusco 哎呀,忽略最后一点,我看到演员表并立即想到IEnumerable&lt;T&gt;List&lt;T&gt;(我经常看到)
  • @abdusco 解决了我的问题。如果你把它作为一个答案,我会接受它。感谢您的帮助

标签: c# asp.net-core hotchocolate


【解决方案1】:

只能使用构造函数注入with HotChocolate v11

services
    .AddScoped<IUserRepository, UserRepository>()
    .AddScoped<Query>()
    .AddGraphQLServer()
    .AddQueryType<Query>()

public class Query
{
    public Query(IUserRepository repository)
    {

    }

    // code omitted for brevity
}

如果您使用的是 HotChocolate v10,则需要 use parameter injection[Service] 属性:

public class Query
{
    public string Bar(ISchema schema, [Service]MyCustomService service)
    {
        return "foo";
    }
}

参考文献

【讨论】:

    【解决方案2】:

    根据文档,在构造函数中您还可以像这样获得服务:

    public class Query
        {
            private readonly IEntityRepository _entityRepository;
      
            public Query([Service] IEntityRepository entityRepository)  
            {  
                _entityRepository= entityRepository;  
            }
      
            public IQueryable<Entity> Entities=> _entityRepository.GetAll();
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2015-03-19
      • 2014-01-14
      • 2020-09-12
      • 2015-06-01
      • 1970-01-01
      • 2019-05-31
      相关资源
      最近更新 更多