Less handler fails in conjunction with 'Microsoft.Extensions.DependencyInjection' v8
julealgon opened this issue · 5 comments
The Less request handler (BundleTransformer.Less.HttpHandlers.LessAssetHandler
) defines 2 public constructors:
This breaks when attempting to resolve the handler through DI when using Microsoft.Extensions.DependencyInjection v8, as a breaking change was introduced that now throws an InvalidOperationException
when multiple valid constructors are found.
Section of a stacktrace from our WebForms app which uses Autofac through MEDI:
Exception information:
Exception type: InvalidOperationException
Exception message: Multiple constructors accepting all given argument types have been found in type 'BundleTransformer.Less.HttpHandlers.LessAssetHandler'. There should only be one applicable constructor.
at bool Microsoft.Extensions.DependencyInjection.ActivatorUtilities.TryFindMatchingConstructor(Type instanceType, Type[] argumentTypes, out ConstructorInfo matchingConstructor, out Nullable[] parameterMap)
at void Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, out ConstructorInfo matchingConstructor, out Nullable[] matchingParameterMap)
at object Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, object[] parameters)
at object OutProject.DependencyInjection.AutofacWebObjectActivator.GetService(Type serviceType) in ....
And how we are configuring the handler in the web.config
:
<system.web>
<pages>
<httpHandlers>
<add path="*.less" verb="GET" type="BundleTransformer.Less.HttpHandlers.LessAssetHandler, BundleTransformer.Less" />
...
</httpHandlers>
...
</pages>
</system.web>
Here is the documentation regarding the breaking change in MEDI v8 that explains the issue in more detail:
This likely breaks with other containers or setups as well since depending on the DI adapter implementation, it could just call directly into a build-up method in the DI library and many DI libraries will choke when multiple public constructors are found.
In our setup, we should be able to workaround this issue by manually registering the handler using a factory registration, but you might still want to reconsider the design here and opt to have just a single constructor (and maybe move the second one into a factory class).
Hello, Juliano!
Bundle Transformer and Microsoft.Extensions.DependencyInjection are things from different worlds. I do not recommend that you even try to create a instances of the Bundle Transformer's types through DI.
I got feeling that you are trying to use the LessAssetHandler
separately from the Bundle Transformer's infrastructure. If this is case, then perhaps your best solution would be to use a dotless library.
Hello, Juliano!
Bundle Transformer and Microsoft.Extensions.DependencyInjection are things from different worlds. I do not recommend that you even try to create a instances of the Bundle Transformer's types through DI.
I would've agreed with you a few years ago, but not anymore. As you can see, we have a WebForms project that leverages your Less handler via standard web.config setup, and then we added dependency injection support to that project once it became available.
WebForms with DI enabled will attempt to resolve every object through the DI container, including ones defined via configuration like this.
I got feeling that you are trying to use the
LessAssetHandler
separately from the Bundle Transformer's infrastructure. If this is case, then perhaps your best solution would be to use a dotless library.
I'm not sure I understand what you are saying there (to be fair, I don't know the precise history of when/how this handler was added to our project, it was probably a very long time ago), but I've since resolved the problem with a modification to our implementation of the IServiceProvider
by manually filtering out types with multiple constructors and skipping those in favor of the standard Activator.CreateInstance
instead of relying on the containers
ActivatorUtilities.CreateInstance`. I wish that wasn't necessary but it was a simple enough fix.
The only reason I decided to create this issue was to make you aware of the problem (I do consider it a problem), but if you disagree, do feel free and close the issue.
WebForms with DI enabled will attempt to resolve every object through the DI container, including ones defined via configuration like this.
Could you please provide a link to the documentation or article that describes this approach in ASP.NET Web Forms.
WebForms with DI enabled will attempt to resolve every object through the DI container, including ones defined via configuration like this.
Could you please provide a link to the documentation or article that describes this approach in ASP.NET Web Forms.
This is a blog post from back when it was first made available. It uses the Unity container but you can use any other container (we use Autofac on our side, for instance):
And this is the relevant bits that I mentioned:
Areas that Dependency Injection can be used
There are many areas you can use Dependency Injection in WebForms applications now. Here is a complete list.
- Pages and controls
- WebForms page
- User control
- Custom control
- IHttpHandler and IHttpHandlerFactory
- IHttpModule
- Providers
- BuildProvider
- ResourceProviderFactory
- Health monitoring provider
- Any ProviderBase based provider created by System.Web.Configuration.ProvidersHelper.InstantiateProvider. e.g. custom sessionstate provider
Thanks for information!