khellang / Scrutor

Assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
MIT License
3.5k stars 231 forks source link

"Value cannot be null" ArgumentNullException on .Net Framework 4.8 #109

Open dcuccia opened 4 years ago

dcuccia commented 4 years ago

Hi! I'm running into an issue with Scrutor 3.1 when multitargeting .Net 4.8 and .Net Core 3.0. The offending code is occurring in a .Net Standard 2.0 library:

var collection = new ServiceCollection()
    .Scan(scan =>
        scan.FromApplicationDependencies()
            .AddClasses(classes => classes.AssignableTo<IMyInterface>())
            .AsSelfWithInterfaces()
            .WithTransientLifetime()
        );

This code works fine for the .Net Core 3.0 runtime, but fails on 4.8 with a "Value cannot be null" ArgumentNullException. Are there possibly additional explicit Scrutor dependencies I need to add for .Net Framework 4.8?

The source for this project is here. The multitargeted test project contains the following:

<PropertyGroup>
    <TargetFrameworks>netcoreapp3.0;net48</TargetFrameworks>
</PropertyGroup>

the exception details with partial stack trace are below:

System.ArgumentNullException HResult=0x80004003 Message=Value cannot be null. Parameter name: assembly Source=Scrutor StackTrace: at Scrutor.Preconditions.NotNull[T](T value, String parameterName) at Scrutor.TypeSourceSelector.FromAssemblyDependencies(Assembly assembly) at Scrutor.TypeSourceSelector.FromApplicationDependencies(Func2 predicate) at Scrutor.TypeSourceSelector.FromApplicationDependencies() at Vts.MonteCarlo.DetectorInputProvider.<>c.<get_ServiceProvider>b__2_0(ITypeSourceSelector scan) in C:\Projects\dcuccia-vts\src\Vts\MonteCarlo\DataStructures\DetectorInputProvider.cs:line 23 at Microsoft.Extensions.DependencyInjection.ServiceCollectionExtensions.Scan(IServiceCollection services, Action1 action)

I'm quite new to this tool, so it's likely I'm just not setting things up properly. Let me know if there's more information I can provide to help resolve.

Thanks! David

dcuccia commented 4 years ago

Following up on this. I cloned Scrutor and added the .csproj to my project directly.

It seems that both 'try' and 'catch' paths are failing in TypeSourceSelector.FromApplicationDependencies:

1) DependencyContext.Default from Microsoft.Extensions.DependencyModel is null 2) Assembly.GetEntryAssembly() is returning null

Feels like there is some .Net Framework bootstrapping I might be missing...

khellang commented 4 years ago

Hi @dcuccia! 👋

Thanks for filing this issue. Can you try adding <PreserveCompilationContext>true</PreserveCompilationContext> to a PropertyGroup in your project file and see if it makes a difference? 🤔

dcuccia commented 4 years ago

No problem, thanks for your reply. Tried that line in either the Scrutor-containing netstandard2.0 library, or the netcoreapp3.0 consuming library, or both with no luck - same issue.

dcuccia commented 4 years ago

Hi @khellang, any thoughts on how I might debug this further?

khellang commented 4 years ago

Not really, I've never seen Assembly.GetEntryAssembly() return null before. I mean; how can you even run an assembly without an entrypoint? 🤔

304NotModified commented 4 years ago

I can also confirm I get a nullreference exception in FromApplicationDependencies

khellang commented 4 years ago

NullReferenceException? 🤔

304NotModified commented 4 years ago

I will recheck and add the full stacktrace for the error :angel:

dcuccia commented 4 years ago

Confirming I'm still seeing this on 3.2

khellang commented 4 years ago

There hasn't been any attempts at fixing this as I have no clue how to reproduce it. I'm afraid I have to require more information or even better; a pull request to fix this 😞

dcuccia commented 4 years ago

@khellang understood, thanks. I will try at least to repro.

dcuccia commented 4 years ago

@khellang I can now reproduce the error in isolation. See my repro code here:

https://github.com/dcuccia/ScrutorArgumentNullExceptionDemo

(currently requires a parallel checked-out Scrutor source tree for easy debugging)

What was driving me nuts is that I was unable to reproduce with a command-line exe, thinking maybe there was something to do with the complexity of my original project. Then, I added a simple unit test and BANG - you can see that the test passes with netcoreapp3.0, but fails with net48. Maybe related to this issue:

https://github.com/dotnet/sdk/issues/5654

I'll keep digging to see if there's a simple work-around, but if you have time let me know what you think.

Thanks!

dcuccia commented 4 years ago

See also: https://github.com/dotnet/sdk/issues/6239

Seems like it's related to an assembly name equality check. Setting <PreserveCompilationContext>true</PreserveCompilationContext> doesn't seem to fix it for me.

dcuccia commented 4 years ago

Didn't say this explicitly, but it appears that this is only an issue when running inside other tooling, e.g. Resharper or VS Test environments (and only for net48).