dadhi / DryIoc

DryIoc is fast, small, full-featured IoC Container for .NET
MIT License
982 stars 122 forks source link

troubleshooting sudden ArgumentException at TryInterpretSingletonAndUnwrapContainerException #635

Open ssteiner opened 4 months ago

ssteiner commented 4 months ago

I'm using a mix of MS and DryIOC in my app. I've recently gone through some refactoring, and just before rolling out in prod, I noticed I'm getting an ArgumentException at TryInterpretSingletonAndUnwrapContainerException. The exception happens when I start my app host, so it's somewhere deep down in the MS app host stack, no chance to figure out where.

The full stacktrace is

   at DryIoc.Interpreter.TryInterpretSingletonAndUnwrapContainerException(IResolverContext r, Expression expr, ImMapEntry`1 itemRef, Object& result) in /_/src/DryIoc/Container.cs:line 3110
   at DryIoc.Factory.ApplyReuse(Expression serviceExpr, Request request) in /_/src/DryIoc/Container.cs:line 11136
   at DryIoc.Factory.GetExpressionOrDefault(Request request) in /_/src/DryIoc/Container.cs:line 11055
   at DryIoc.ReflectionFactory.CreateExpressionOrDefault(Request request) in /_/src/DryIoc/Container.cs:line 12082
   at DryIoc.Factory.GetExpressionOrDefault(Request request) in /_/src/DryIoc/Container.cs:line 11038
   at DryIoc.WrappersSupport.GetArrayExpression(Request request) in /_/src/DryIoc/Container.cs:line 5187
   at DryIoc.WrappersSupport.<>c.<BuildSupportedWrappers>b__9_0(Request r) in /_/src/DryIoc/Container.cs:line 5027
   at DryIoc.ExpressionFactory.CreateExpressionOrDefault(Request request) in /_/src/DryIoc/Container.cs:line 12551
   at DryIoc.Factory.GetExpressionOrDefault(Request request) in /_/src/DryIoc/Container.cs:line 11038
   at DryIoc.Container.ResolveAndCache(Int32 serviceTypeHash, Type serviceType, IfUnresolved ifUnresolved) in /_/src/DryIoc/Container.cs:line 426
   at DryIoc.Container.System.IServiceProvider.GetService(Type serviceType) in /_/src/DryIoc/Container.cs:line 344
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Start(IHost host)
   at UnifiedUCProvisioning.AudmOperationFrontEnd.InitializeApiHost() in D:\Repos\AUDM\UnifiedProvisioning\UnifiedProvisioningLibCore\AudmOperationFrontEnd.cs:line 578

The exception message is Specified argument was out of the range of valid values. (Parameter 'value')' which isn't particularly helpful (name of the argument? type? value?)

Line 578 is the call to host.Start() and the host is build like this (abbreviated)

var builder = Host.CreateDefaultBuilder()
    .UseServiceProviderFactory(new DryIocServiceProviderFactory(tenantNull.IocContainer)) 
    // configuration here
var host = builder.Build();

Is there any chance to figure out what kind of type it was trying to resolve and with what arguments?

dadhi commented 4 months ago

What version are you using? Could you try DryIoc.Microsoft.DependencyInjection v8.0.0-preview-01?

ssteiner commented 4 months ago

I'm using version 6.2.0.

I finally figured out the culprit. In my Startup.cs 's ConfigureServices I have this:

services.AddServerSentEvents(options =>
{
    options.ReconnectInterval = 5000;
    options.KeepaliveInterval = startupConfig.SseKeepAliveInterval;
    options.KeepaliveMode = startupConfig.SseKeepAliveInterval > 0 ? ServerSentEventsKeepaliveMode.Always : ServerSentEventsKeepaliveMode.Never;
});

That's based on a package

When startupConfig.SseKeepAliveInterval was 0, then problem would occurr, when it was > 0, no problem. AddServerSentEvents is an extension that comes from the Lib.AspNetCore.ServerSentEvents nuget package.

I'll give the preview a try - just found it very confusing that it errors out in what seems to be DryIoc.

dadhi commented 4 months ago

@ssteiner You are getting the errors because it resolves (creates or gets) service via DryIoc. The service is Singleton based on the stack trace. DryIoc has done its work and is calling to the service constructor or factory method. A service may fail its creation, usually wrapping the original exception in the TargetInvocationException. DryIoc will unwrap and re-throw the exception, trying to preserve a stack trace.