question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IDataListSource only supports injection of singletons?

See original GitHub issue

Which Contentment version are you using?

4.1.1

Which Umbraco version are you using? For example: 8.14.1 - don’t just write v8

10.0.1

Bug summary

When using a custom .NET datasource (ie. a class implementing IDataListSource) if I try to inject a class into the constructor that isn’t a singleton then I get a boot error telling me:

Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: DataSources.AtsTeamDataSource Lifetime: Singleton ImplementationType: DataSources.AtsTeamDataSource': Cannot consume scoped service 'Services.IJobBoardDataService' from singleton 'DataSources.AtsTeamDataSource'.)

From what I gather it is because my custom IDataListSource called AtsTeamDataSource is injecting (via constructor) the service IJobBoardDataService which is a scoped service. If I register IJobBoardDataSource as a singleton then it works (but I can’t really do that as this service cannot be a singleton).

public class AtsTeamDataSource : IDataListSource
{
     private readonly IJobBoardDataService dataService;

     public AtsTeamDataSource(IJobBoardDataService dataService)
     {
         this.dataService = dataService;
     }
}

In my IComposer I’m doing:

services.AddScoped<IJobBoardDataService, JobBoardDataService>();

Steps to reproduce

Create a NET datasource that implements IDataListSource

In the constructor of this data source inject a service that is not scoped as a singleton.

Expected result / actual result

I’d expect to be able to inject services that are either scoped or transient.

I’m not quite sure where the AtsTeamDataSource gets registered from? I’m not registering it as a singleton, so I assume Contentment is. I did try looking in the source, but couldn’t really figure out. I guess I’m looking for whether there is a way it could be registered as transient or something? Any ideas?

Do you have Umbraco ModelsBuilder enabled?

  • Yes, it is enabled.

What browsers are you seeing the problem on?

Chrome

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
patrickdemooij9commented, Aug 24, 2022

Hi! Wanted to time in and offer another way of doing this instead of using the Lazy<> way. If you want to retrieve non-singleton classes then you can also inject IServiceScopeFactory in your constructer and use it like this when you need to retrieve the service:

using (var scope = _serviceScopeFactory.CreateScope())
            {
                var smartSheetService = scope.ServiceProvider.GetService<SmartSheetService>();
            }

This would then work for all lifecycles without needing any changes from @leekelleher.

Ofcourse we can also change the interface to accept a IServiceProvider, but that would then be a breaking change. I also don’t think this happens that often although I could be wrong.

Or maybe you can take a look at how Middleware currently functions. By default, you use the Task Invoke(HttpContext context) and then then do your stuff and continue the middleware train. However, middlewares are also singletons and suffer from the same problem that Dan is having here. But with middleware you are able to use DI in your Invoke method (https://github.com/patrickdemooij9/SeoToolkit.Umbraco/blob/4155a59ff7300a37981c6c0efb2935d635d3f923/src/SeoToolkit.Umbraco.Sitemap.Core/Middleware/SitemapMiddleware.cs#L30) so that you can retrieve your scoped/transient services.

0reactions
leekellehercommented, Sep 12, 2022

Closing this ticket off, as I’m unsure if there’s anything I could do within Contentment’s ContentmentListItemCollectionBuilder to resolve or workaround this.

Looking at @patrickdemooij9’s comment above, I recalled that I am already taking a similar approach with the Umbraco Tags data-source, e.g. using HttpContext.RequestServices.GetRequiredService<ITagQuery>() to get the scoped service. ref: https://github.com/leekelleher/umbraco-contentment/blob/4.0.0/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoTagsDataListSource.cs#L76

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found