Search code examples
c#asp.net-core.net-coredependency-injectionpiranha-cms

Unable to access services from DI on delegate in startup Configure?


I am trying to add some items to the piranha sitemap using the delegate method OnGenerateSitemaps.

In this method I am calling to a service that gets data from entity framework context and then caches it. Whenever I try to use this service in the delegate-method I get a error that the dbContext has already been disposed.

System.AggregateException: 'One or more errors occurred. (Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

I've tried making the service sync instead of async, I've tried awaiting the result and running the task sync, none of which works.

Any ideas on how to use my service in this delegate in Configure on startup?

services.AddScoped<ICachedSitemapService, CachedSitemapService>();

In startup I inject the service, which is scoped.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApi api, ICachedSitemapService cachedSitemapService)
        {

        App.Hooks.OnGenerateSitemap += (sitemap) =>
            {
                var items = await cachedSitemapService.GetCachedClinics().Result;
                sitemap.AddRange(items);

                return sitemap;
            };
}

The service that is called is DbContext to get items:

    private async Task<IEnumerable<SitemapItem>> GetSitemapClinics()
    {
        var spec = new ClinicSitemapSpecification();

        //This throws error            
        var allClinics = await _clinicRepo.ListAsync(spec);
        //code shortened for brevity, but returns a list.
        
    }

I've tried below without any luck.

                var items = await cachedSitemapService.GetCachedClinics().GetAwaiter().GetResult();
                sitemap.AddRange(items);

Solution

  • We're (the Piranha team) planning on redesigning the hook system in version 10 (has to be a major version as it will break backward compatibility) to provide DI functionality in all hooks. However, in the meantime, the following should fix your issues.

    using (var scope = app.ApplicationServices.CreateScope())
    {
      var service = scope.ServiceProvider.GetService< ICachedSitemapService>();
    }
    

    Since your service is registered to be scoped it can't be resolved directly from the root provider (like the error states). When resolving the service from a controller you are in the request scope, so the solution here is to just create a scope that will allow you to resolve it.