Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collection Expressions-y Injections #1408

Closed
TonyValenti opened this issue Jan 27, 2024 · 13 comments
Closed

Collection Expressions-y Injections #1408

TonyValenti opened this issue Jan 27, 2024 · 13 comments

Comments

@TonyValenti
Copy link

Problem Statement

AutoFac cannot create immutable or frozen collections.

Desired Solution

AutoFac should use rules/processes similar to what is outlined in collection expressions to create collections of the specified types.

Alternatives You've Considered

Additional Context

@tillig
Copy link
Member

tillig commented Jan 27, 2024

Is this the same as #1372?

@TonyValenti
Copy link
Author

This would eliminate the need for it as this would be a general solution to that specific case.

@tillig
Copy link
Member

tillig commented Jan 27, 2024

Then I'll close the other as duplicate. No need to address the same request twice.

@tillig
Copy link
Member

tillig commented Jan 27, 2024

to create collections of the specified types

Can you provide a specific list of types you think qualify here? "Just know about all the types" isn't specific or feasible. Put another way, if we were to write unit tests to make sure this is "done," what would we test to verify it's done and we can close the issue?

Also, FYI, "Autofac" - no cap F 😉

@tillig tillig added enhancement pending-input Pending input or update labels Feb 3, 2024
@MaQy
Copy link

MaQy commented May 17, 2024

Hi,

It seems a recent change in the 8.0.300 SDK made this more urgent. We are unable to run our application with the latest SDK as it's using a new type called ReadOnlySingleElementList that seems to be used for collection expressions of one element: https://github.com/dotnet/dotnet/blob/84c07ba732cfaf598d5691c1203041af91993b7c/src/roslyn/src/Compilers/CSharp/Portable/Symbols/Synthesized/ReadOnlyListType/SynthesizedReadOnlyListTypeSymbol.cs#L21

This is the kind of errors we are getting now:

Autofac.Core.DependencyResolutionException : An exception was thrown while activating λ:Microsoft.Extensions.Hosting.IHost -> Microsoft.Extensions.Hosting.Internal.ApplicationLifetime -> Microsoft.Extensions.Logging.Logger`1[[Microsoft.Extensions.Hosting.Internal.ApplicationLifetime, Microsoft.Extensions.Hosting, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] -> Microsoft.Extensions.Logging.LoggerFactory -> Microsoft.Extensions.Options.OptionsMonitor`1[[Microsoft.Extensions.Logging.LoggerFilterOptions, Microsoft.Extensions.Logging, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] -> Microsoft.Extensions.Options.OptionsFactory`1[[Microsoft.Extensions.Logging.LoggerFilterOptions, Microsoft.Extensions.Logging, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] -> <>z__ReadOnlySingleElementList`1[[Microsoft.Extensions.Options.IPostConfigureOptions`1[[Microsoft.Extensions.Logging.LoggerFilterOptions, Microsoft.Extensions.Logging, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]], Microsoft.Extensions.Options, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].
---- Autofac.Core.DependencyResolutionException : None of the constructors found on type '<>z__ReadOnlySingleElementList`1[Microsoft.Extensions.Options.IPostConfigureOptions`1[Microsoft.Extensions.Logging.LoggerFilterOptions]]' can be invoked with the available services and parameters:
Cannot resolve parameter 'Microsoft.Extensions.Options.IPostConfigureOptions`1[Microsoft.Extensions.Logging.LoggerFilterOptions] item' of constructor 'Void .ctor(Microsoft.Extensions.Options.IPostConfigureOptions`1[Microsoft.Extensions.Logging.LoggerFilterOptions])'.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating ?:Microsoft.Extensions.Hosting.IHost -> Microsoft.Extensions.Hosting.Internal.ConsoleLifetime -> Microsoft.Extensions.Options.UnnamedOptionsManager`1[[Microsoft.Extensions.Hosting.ConsoleLifetimeOptions, Microsoft.Extensions.Hosting, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] -> Microsoft.Extensions.Options.OptionsFactory`1[[Microsoft.Extensions.Hosting.ConsoleLifetimeOptions, Microsoft.Extensions.Hosting, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] -> <>z__ReadOnlySingleElementList`1[[Microsoft.Extensions.Options.IConfigureOptions`1[[Microsoft.Extensions.Hosting.ConsoleLifetimeOptions, Microsoft.Extensions.Hosting, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]], Microsoft.Extensions.Options, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].
 ---> Autofac.Core.DependencyResolutionException: None of the constructors found on type '<>z__ReadOnlySingleElementList`1[Microsoft.Extensions.Options.IConfigureOptions`1[Microsoft.Extensions.Hosting.ConsoleLifetimeOptions]]' can be invoked with the available services and parameters:
Cannot resolve parameter 'Microsoft.Extensions.Options.IConfigureOptions`1[Microsoft.Extensions.Hosting.ConsoleLifetimeOptions] item' of constructor 'Void .ctor(Microsoft.Extensions.Options.IConfigureOptions`1[Microsoft.Extensions.Hosting.ConsoleLifetimeOptions])'.

Could you please look into it?

@alistairjevans
Copy link
Member

@MaQy, can you please raise a new issue for reporting this issue rather than adding to a feature request?

Please ensure you include a minimal reproducible code example that causes the failure on 8.0.300. A public repo with an example is ideal.

@MaQy
Copy link

MaQy commented May 18, 2024

Hi again,

It took me a while to pinpoint the issue as I was not able to reproduce it in an isolated way. The problem was actually partially in our code, though I think Microsoft is also to be blamed for the sudden change they did. As mentioned above, it seems they have introduced new collections for collection expressions:

int[] a = [1];

This now gets compiled into an auto-generated collection that is inserted into the assembly where that code is located. The name of the class is <>z__ReadOnlySingleElementList. This class is not marked as compiler generated with the CompilerGeneratedAttribute attribute. We have the typical "catch all" method for generic interfaces for some of our assemblies, and this type was suddenly getting registered for IEnumerable. That caused problems with the Autofac resolution when an IEnumerable was requested to find all existing registrations.

I'm sorry for the off-topic and the false alarm, but I wanted to leave this somewhere as a word of warning in case anyone else encounters this issue.

@ArnaudB88
Copy link

@MaQy what was the solution for the issue with <>z__ReadOnlySingleElementList?

@MaQy
Copy link

MaQy commented Aug 6, 2024

I just put a filter to exclude IEnumerable implementations from being registered:

public static IEnumerable<Type> GetOpenGenericTypes(params Assembly[] assemblies)
{
    return assemblies.SelectMany(assembly => assembly.GetTypes()
        .Where(type => type is { IsClass: true, IsGenericTypeDefinition: true, IsAbstract: false } 
            && !IsCompilerGenerated(type) 
            && !IsDelegate(type) 
            && !type.IsAssignableToGenericInterface(typeof(IEnumerable<>))));
}

private static bool IsCompilerGenerated(Type type) => Attribute.GetCustomAttribute(type, typeof(CompilerGeneratedAttribute)) is not null;

private static bool IsDelegate(Type type) => typeof(Delegate).IsAssignableFrom(type);

public static bool IsAssignableToGenericInterface(this Type givenType, Type genericInterfaceType)
{
    var interfaceTypes = givenType.GetInterfaces();

    foreach (var it in interfaceTypes)
    {
        if (it.IsGenericType && it.GetGenericTypeDefinition() == genericInterfaceType)
        {
            return true;
        }
    }

    return false;
}

I already had the IsCompilerGenerated filter in place, but Microsoft is not marking those types as compiler generated (even though they are). In any case, I don't see a use case for binding IEnumerable, and that conflicts with obtaining multiple implementations, so it's safer to explicitly exclude them.

@TonyValenti
Copy link
Author

You should post in the appropriate forum about the compiler generated types. That sounds like a bug.

@MaQy
Copy link

MaQy commented Aug 7, 2024

@TonyValenti it seems this has already been reported by @ArnaudB88: dotnet/runtime#104372 (comment)

@TonyValenti
Copy link
Author

bug resolved:

dotnet/roslyn#74676 (comment)

@tillig
Copy link
Member

tillig commented Sep 5, 2024

Given this has been pending input for about six months I'm going to close the issue. The request, as a concept, has merit, but the title ("Collection Expressions-y Injections") and the somewhat ambiguous description (basically "inject this basic kind of thing" without an actual described universe of things - we can't "just know" about every collection type, we need to have a set of types or interfaces folks desire) leaves this in a place where no action can be taken.

I think if this is a feature folks want, we'll need some fairly specific info on the actual need so we can, at the very least, determine when we're "done" implementing it, or maybe whether it's not possible.

@tillig tillig closed this as completed Sep 5, 2024
@tillig tillig removed the pending-input Pending input or update label Sep 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants