Closed luizfbicalho closed 4 years ago
I changed the code to make more tests I created this controller
`public class TestController : Controller { public TestController(IServiceProvider provider, Unity.IUnityContainer container) { Provider = provider; }
public IServiceProvider Provider { get; }
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2"};
}
` and changed the program.cs like this
` Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseUnityServiceProvider(GetContainer())
.UseStartup<Startup>();
});`
And the controller can't be constructed because it can't create the container
Why do you need to inject IUnityContainer in your controller?
The purpose of this package is to provide an implementation of IServiceProvider with Unity to invert the dependencies and depend on IServiceProvider instead of IUnityContainer.
thanks for the very fast answer @Jeromino Inject the unity container was a way to prove that the service provider doesn't have the container registrations, to simplify my example. the problem is that everything that is registered in the unity container is not available in the controller
Here is a complete example TesteUnity.zip
It could be a problem with the execution order of the bootstrap steps. It works for me if I call BuildServiceProvider (IServiceCollection extension) with my IUnityContainer instance in Startup.Configure(IApplicationBuilder app, IApplicationLifetime lifetime) where the IServiceProvider is assigned to app.ApplicationServices.
The latest version has a few open issues so I am using these packages:
Unity.Abstractions 4.1.1 Unity.Container 5.10.0 Unity.Microsoft.DependencyInjection 5.10.0
I also had to fix 'Ambiguous constructor' InvalidOperationExceptions by manually registering dependencies for ILoggerFactory, ISwaggerProvider and ISchemaRegistryFactory and I posted the container registrations that were required on another open issue of this project.
Can you please show the code @Jeromino ? Are you in .net core 3 preview 6?
I can't package an example right now but I could try to look at your example tomorrow. It took me a while to get this working and only the BuildServiceProvider IServiceCollection extension method worked for me after assigning the IServiceProvider to IApplicationBuilder.ApplicationServices.
The important bit is in the implementation of Startup.Configure(IApplicationBuilder app, IApplicationLifetime lifetime):
var container = new UnityContainer();
app.ApplicationServices = services.BuildServiceProvider(container);
The services instance is assigned in Startup.ConfigureServices(IServiceCollection services) that is called by the framework so I had to keep it as a variable in the Startup class.
I am on .NET Core 2.2.3.
I think the net core 3 preview 6 is the real issue
@Jeromino Your code worked half of the way. I put `app.ApplicationServices = Program.GetContainer().BuildServiceProvider(Services);
`
if I test with app.ApplicationServices.GetService(typeof(Unity.IUnityContainer)) it return the container OK.
but in the controller
public TesteController(IServiceProvider provider) { Provider = provider; }
if I test
provider.GetService(typeof(Unity.IUnityContainer))
it returns null.
After calling BuildServiceProvider can you see the IUnityContainer registrations in the IServiceCollection?
The BuildServiceProvider IServiceCollection extension I use takes an IUnityContainer parameter so I don't know which BuildServiceProvider method you used above.
its the same method, one is in the container receiving the service provider, and the other is in the provider receiving the container
I changed my createwebhostbuilder and now it's working, i'm going to make more tests
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }).UseServiceProviderFactory<IServiceCollection>(x => new Unity.Microsoft.DependencyInjection.ServiceProviderFactory(GetContainer()));
I found some errors in this solution, i'm trying to work around it
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.
at Unity.Microsoft.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatingPointTypeModelBinderProvider.GetBinder(ModelBinderProviderContext context)
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinderCoreUncached(DefaultModelBinderProviderContext providerContext, Object token)
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.GetParameterBindingInfo(IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.CreateBinderDelegate(ParameterBinder parameterBinder, IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory.<>c__DisplayClass7_0.
This is an open issue.
I already looked into and I think I know how it should be fixed but I just didn't have time to make the PR yet. In the meantime I downgraded to the versions I posted above yesterday.
I downgraded the unity and the first request worked amazing, the second request doesn't work, no matter the order I execute the requests.
if I execute again the first url it works fine.
System.InvalidOperationException: No service for type 'Microsoft.Extensions.Logging.ILoggerFactory' has been registered. at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatingPointTypeModelBinderProvider.GetBinder(ModelBinderProviderContext context) at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinderCoreUncached(DefaultModelBinderProviderContext providerContext, Object token) at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context) at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.GetParameterBindingInfo(IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions) at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.CreateBinderDelegate(ParameterBinder parameterBinder, IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext) at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory.<>c__DisplayClass7_0.<CreateRequestDelegate>b__0(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
TesteUnity.zip I reproduced the problem in a small project
the steps to reproduce are
1) make a request to /api/test/get1/5555 this will return ok 2) make a request to /api/test/get2/5555 this will return the No service for type 'Microsoft.Extensions.Logging.ILoggerFactory' error
doesn't matter if you register the ilogger factory on the unity, or on de the service collection the problem seems to be related with the parameters on the request
if you change the order of the steps, the error changes to the first url called on the second time
I downgraded the unity and the first request worked amazing, the second request doesn't work, no matter the order I execute the requests.
if I execute again the first url it works fine.
As mentioned before this is another known issue for which I posted the workaround I used under this issue that was surprisingly closed without any fix.
Could you please post the example you just provided in the related issue as the repository owner asked to reopen the issue?
I've also had the same problem with Swagger dependencies. I wonder how other DI frameworks manage to solve the resolution of ambiguous constructors like that though...
what do you think of this issue @ENikS ? Is this related with the issue #43 I think that it's something new, it only happens in WebApis requests with parameters
You are missing the internal UnityContainer exception that is ignored in an empty try catch in ServiceProvider. The original exception is because the UnityContainer doesn't know which constructor to use to create the ILoggerFactory dependency.
The exception you get is definitely related to issue #43 and you should be able to reproduce it with the resolution of any type that depends on the ILogger Interface.
I am not sure if this fix should be done in this package that doesn't need to know about those logging dependencies though.
private static IUnityContainer GetContainer() { var retorno = new UnityContainer(); retorno.RegisterType<IServiceX, MyServiceX>(); retorno.RegisterType<ILoggerFactory, LoggerFactory>(new ContainerControlledLifetimeManager(), new InjectionConstructor(new ResolvedParameter<IEnumerable<ILoggerProvider>>())); return retorno; }
And I still get the same error
There is a question here, if it only happens on the second request, the registration is correct on the first one, something else happens on the second request, can it be related to the child container?
Not understanding what is causing this makes me crazy.
OK it must be a different problem then. Can you try to log the first chance exception (by subscribing to this event) to get more diagnostic details from the internal exception that must be thrown by the UnityContainer?
Not sure how this will help.
Value cannot be null. (Parameter 'container') at Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)
Environment.StackTrace
at System.Environment.get_StackTrace()
at TesteUnity.Program.FirstChanceHandler(Object sender, FirstChanceExceptionEventArgs e) in C:\Temp\TesteUnity\TesteUnity\Program.cs:line 28
at Unity.Microsoft.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatingPointTypeModelBinderProvider.GetBinder(ModelBinderProviderContext context)
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinderCoreUncached(DefaultModelBinderProviderContext providerContext, Object token)
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.GetParameterBindingInfo(IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.CreateBinderDelegate(ParameterBinder parameterBinder, IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory.<>c__DisplayClass7_0.1 application) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox1.ExecutionContextCallback(Object s) at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox1.MoveNext(Thread threadPoolThread) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox`1.ExecuteFromThreadPool(Thread threadPoolThread)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
After that is the
No service for type 'Microsoft.Extensions.Logging.ILoggerFactory' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at System.Environment.get_StackTrace()
at TesteUnity.Program.FirstChanceHandler(Object sender, FirstChanceExceptionEventArgs e) in C:\Temp\TesteUnity\TesteUnity\Program.cs:line 28
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.FloatingPointTypeModelBinderProvider.GetBinder(ModelBinderProviderContext context)
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinderCoreUncached(DefaultModelBinderProviderContext providerContext, Object token)
at Microsoft.AspNetCore.Mvc.ModelBinding.ModelBinderFactory.CreateBinder(ModelBinderFactoryContext context)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.GetParameterBindingInfo(IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.CreateBinderDelegate(ParameterBinder parameterBinder, IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, ControllerActionDescriptor actionDescriptor, MvcOptions mvcOptions)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerCache.GetCachedResult(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvokerProvider.OnProvidersExecuting(ActionInvokerProviderContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionInvokerFactory.CreateInvoker(ActionContext actionContext)
at Microsoft.AspNetCore.Mvc.Routing.ActionEndpointFactory.<>c__DisplayClass7_0.1 application) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox1.ExecutionContextCallback(Object s) at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox1.MoveNext(Thread threadPoolThread) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox`1.ExecuteFromThreadPool(Thread threadPoolThread)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
and then the same exception
at System.Environment.get_StackTrace()
at TesteUnity.Program.FirstChanceHandler(Object sender, FirstChanceExceptionEventArgs e) in C:\Temp\TesteUnity\TesteUnity\Program.cs:line 28
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Hosting.HostingApplication.ProcessRequestAsync(Context context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication1 application) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox1.ExecutionContextCallback(Object s) at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox1.MoveNext(Thread threadPoolThread) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder
1.AsyncStateMachineBox`1.ExecuteFromThreadPool(Thread threadPoolThread)
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
You are going through all the same problems I've had to deal with too.
It looks like it's because the IUnityContainer instance is being disposed in the ServiceProvider as explained in this open issue.
What package version are you now using?
I am not sure to understand as this version should contain this workaround where the container was not set to null anymore.
If I was you I would clone the repository to be able to debug or try to use SourceLink to step into the code. I just looked at the nuspec and the repository is referenced so this could work after turning on the required options in Visual Studio.
Thanks @Jeromino for all your help, but I think I'll have to find another way to solve this, maybe change the container, if unity won't be anytime soon compatible with aspnet core 3, I have a project that is starting in a week and my research time is almost over. I'm using unity in all my projects for almost 8 years.
I am sorry to learn you couldn't get it working with ASP.NET Core 3.0. I would also switch to another container if we didn't depend on the Unity.Interception package so heavily for AOP though.
I am still planning to look into the open issues if they are not yet fixed before we get to upgrade our solutions to .NET Core 3.0 but I don't know when I'll have time to get to it.
I also have some extensions in unity that I'll have to change
The extension will be updated once Core 3 is released
Unity extension will be updated to support core 3 once it is released.
But preview 7 is able to production
I don’t have bandwidth to fix it multiple times. I’ll wait for the final version
Now that .NET Core 3 has been released, when will a fix for this be released?
I am working on it
I copied this code and changed to solve this problem.
` public static class HostingExtension2 { private static ServiceProviderFactory _factory;
if NETCOREAPP1_1
else
endif
But after the start, the service provider doesn't have the unity anymore, so I think something changed and needs more than this changes.
`Host.CreateDefaultBuilder(args) .UseUnityServiceProvider(GetContainer())
Are there plans to update this package to the latest aspnet core ?