OrchardCMS / OrchardCore

Orchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.
https://orchardcore.net
BSD 3-Clause "New" or "Revised" License
7.42k stars 2.39k forks source link

Cannot access a disposed object 'IServiceProvider' with TaxonomyIndexProvider #3191

Closed numgithub closed 6 months ago

numgithub commented 5 years ago

When trying to add a taxonomy content item via a recipe I get this error. I noted it occurs when adding the taxonomy first in the recipe, if I added after some other content it might not occur.

System.ObjectDisposedException HResult=0x80131622 Message=Cannot access a disposed object. Object name: 'IServiceProvider'. Source=Microsoft.Extensions.DependencyInjection StackTrace: 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 Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at OrchardCore.Taxonomies.Indexing.TaxonomyIndexProvider.Describe(DescribeContext1 context) in C:\src\Orchard.Core\src\OrchardCore.Modules\OrchardCore.Taxonomies\Indexing\TaxonomyIndex.cs:line 39 at YesSql.Indexes.IndexProvider1.YesSql.Indexes.IIndexProvider.Describe(IDescriptor context) at YesSql.Store.CreateDescriptors(Type target, String collection, IEnumerable`1 indexProviders) at YesSql.Session.GetDescriptors(Type t) at YesSql.Session.d__42.MoveNext()

This is an extract of the recipe json I used:

"steps": [
    {
      "name": "content",
      "Data": [

        {
          "AliasPart": { "Alias": "taxonomy" },
          "ContentItemId": "[js: uuid()]",
          "ContentType": "Taxonomy",
          "taxonomyPart": {
            "termContentType": "Taxonomy"
          },
          "DisplayText": "Taxonomy",
          "Latest": true,
          "Published": true,
          "Owner": "[js: parameters('AdminUsername')]",
          "Author": "[js: parameters('AdminUsername')]"
        }
      ]
    }
  ]

I found if I updated the code like so it works, not sure if this is right?

       public TaxonomyIndexProvider(IServiceProvider serviceProvider, IContentDefinitionManager contentDefinitionManager)
        {
            _serviceProvider = serviceProvider;
            _contentDefinitionManager = contentDefinitionManager;
        }
sebastienros commented 5 years ago

/cc @jtkech tell me this is because we have RecipeExecutor from DI again

jtkech commented 5 years ago

No, i think it's the same issue we saw in #3133 with a dynamic scoped index using scoped services.

When disposing, the session may use some services which are already disposed.

The workaround was to add a _session.CommitAsync(), see here.

Intended to be fixed in my working branch related to shell scopes where you can do a RegisterBeforeDispose() e.g to commit the session before disposing the shell scope.

jtkech commented 5 years ago

@numgithub can you try it again with the dev branch where we now commit the session automatically before disposing the shell scope.

PiemP commented 5 years ago

I would like to say sorry for my written english.

I'm working on beta 3 Nuget package version 71077 with .NET Core version 2.2.203

I've created a controller that use ContentManager to filter some ContentType by taxonomy term with it's view to present filtered items. Now I want to use it as a widget and add it to a page. I've a couple a question: It's right use ContentManager to filter item by taxonomy term's Id or there is another way? How can I convert this view in a widget?

I tried to give me an answer to the 2nd question I've make a custom content part and in its ContentPartDisplayDriver class with the code used previous in the controller class cited before:

 Func<IQuery<ContentItem, TaxonomyIndex>, IQuery<ContentItem>> query = q => q.Where(x => x.ContentType == "News").Take(10);
      var contentItems = await query(_session.Query<ContentItem, TaxonomyIndex>(x => x.TermContentItemId == "4ndtj77t1rwvh53c1n5xvp7z5r")).ListAsync();

When I run my dev site I found this error log:

Microsoft.AspNetCore.Server.Kestrel|ERROR|Connection id "0HLOV7IURFB8R", Request id "0HLOV7IURFB8R:00000001": An unhandled exception was thrown by the application. 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 Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at OrchardCore.Taxonomies.Indexing.TaxonomyIndexProvider.<Describe>b__4_0(ContentItem contentItem) in C:\projects\orchardcore\src\OrchardCore.Modules\OrchardCore.Taxonomies\Indexing\TaxonomyIndex.cs:line 54
   at YesSql.Indexes.IndexDescriptor`3.<>c__DisplayClass10_0.<Map>b__0(T x)
   at YesSql.Indexes.IndexDescriptor`3.<YesSql.Indexes.IDescribeFor.GetMap>b__17_0(Object x)
   at YesSql.Session.MapNew(Document document, Object obj)
   at YesSql.Session.UpdateEntityAsync(Object entity)
   at YesSql.Session.FlushAsync()
   at YesSql.Session.Dispose()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.Dispose()
   at OrchardCore.Hosting.ShellBuilders.ShellContext.ServiceScopeWrapper.Dispose() in C:\projects\orchardcore\src\OrchardCore\OrchardCore.Abstractions\Shell\Builders\ShellContext.cs:line 272
   at OrchardCore.Modules.ModularTenantContainerMiddleware.Invoke(HttpContext httpContext) in C:\projects\orchardcore\src\OrchardCore\OrchardCore\Modules\ModularTenantContainerMiddleware.cs:line 86
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)    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 Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at OrchardCore.Taxonomies.Indexing.TaxonomyIndexProvider.<Describe>b__4_0(ContentItem contentItem) in C:\projects\orchardcore\src\OrchardCore.Modules\OrchardCore.Taxonomies\Indexing\TaxonomyIndex.cs:line 54
   at YesSql.Indexes.IndexDescriptor`3.<>c__DisplayClass10_0.<Map>b__0(T x)
   at YesSql.Indexes.IndexDescriptor`3.<YesSql.Indexes.IDescribeFor.GetMap>b__17_0(Object x)
   at YesSql.Session.MapNew(Document document, Object obj)
   at YesSql.Session.UpdateEntityAsync(Object entity)
   at YesSql.Session.FlushAsync()
   at YesSql.Session.Dispose()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.Dispose()
   at OrchardCore.Hosting.ShellBuilders.ShellContext.ServiceScopeWrapper.Dispose() in C:\projects\orchardcore\src\OrchardCore\OrchardCore.Abstractions\Shell\Builders\ShellContext.cs:line 272
   at OrchardCore.Modules.ModularTenantContainerMiddleware.Invoke(HttpContext httpContext) in C:\projects\orchardcore\src\OrchardCore\OrchardCore\Modules\ModularTenantContainerMiddleware.cs:line 86
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

I hope to be useful.

jtkech commented 5 years ago

Yes, thanks.

It clearly shows that the session does a map on the TaxonomyIndexProvider after having disposed the shell scope (and its service provider). This has been fixed in the dev branch by committing the session before disposing the shell scope.

Piedone commented 6 months ago

This isn't an issue anymore.