dadhi / DryIoc

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

Exception thrown when using WebOptimizer in ASP.NET Core MVC #519

Closed roncrush closed 2 years ago

roncrush commented 2 years ago

Thanks for the great library! I've hit an issue with using DryIoc in an ASP.NET Core MVC application that also happens to use the WebOptimizer library. When running the application sometimes the following exception gets thrown in the console logs or as a developer exception page. It looks like there's sometimes an issue resolving the type Microsoft.Extensions.Options.IOptionsSnapshot<WebOptimizer.WebOptimizerOptions> :

System.ArgumentException: Generic types are not valid. (Parameter 'methodInfo') at System.Reflection.Emit.DynamicILGenerator.EmitCall(OpCode opcode, MethodInfo methodInfo, Type[] optionalParameterTypes) at DryIoc.FastExpressionCompiler.LightExpression.ExpressionCompiler.EmittingVisitor.TryEmitMethodCall(Expression expr, IParameterProvider paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) in //src/DryIoc/FastExpressionCompiler.cs:line 4154 at DryIoc.FastExpressionCompiler.LightExpression.ConvertViaCastClassIntrinsicExpression`1.TryEmit(CompilerFlags config, ClosureInfo& closure, IParameterProvider paramExprs, ILGenerator il, ParentFlags parent, Int32 byRefIndex) in //src/DryIoc/Expression.cs:line 2321 at DryIoc.FastExpressionCompiler.LightExpression.ExpressionCompiler.EmittingVisitor.EmitNewArrayInit(NewArrayExpression expr, IParameterProvider paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) in //src/DryIoc/FastExpressionCompiler.cs:line 3459 at DryIoc.FastExpressionCompiler.LightExpression.ExpressionCompiler.EmittingVisitor.TryEmitNew(Expression expr, IParameterProvider paramExprs, ILGenerator il, ClosureInfo& closure, CompilerFlags setup, ParentFlags parent) in //src/DryIoc/FastExpressionCompiler.cs:line 2115 at DryIoc.FastExpressionCompiler.LightExpression.NoByRefOneArgumentNewExpression.TryEmit(CompilerFlags setup, ClosureInfo& closure, IParameterProvider paramExprs, ILGenerator il, ParentFlags parent, Int32 byRefIndex) in //src/DryIoc/Expression.cs:line 2873 at DryIoc.FastExpressionCompiler.LightExpression.ExpressionCompiler.TryCompileNestedLambda(NestedLambdaInfo nestedLambdaInfo, CompilerFlags setup) in //src/DryIoc/FastExpressionCompiler.cs:line 1613 at DryIoc.FastExpressionCompiler.LightExpression.ExpressionCompiler.TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IParameterProvider paramExprs, Type[] closurePlusParamTypes, Type returnType, CompilerFlags flags) in //src/DryIoc/FastExpressionCompiler.cs:line 496 at DryIoc.FactoryDelegateCompiler.CompileToFactoryDelegate(Expression expression, Boolean preferInterpretation) in //src/DryIoc/Container.cs:line 3936 at DryIoc.Container.TryInterpretOrCompileCachedExpression(IResolverContext r, KeyedFactoryCacheEntry cacheEntry, Rules rules, Object& result) in //src/DryIoc/Container.cs:line 572 at DryIoc.Container.ResolveAndCacheKeyed(Int32 serviceTypeHash, Type serviceType, Object serviceKey, IfUnresolved ifUnresolved, Object scopeName, Type requiredServiceType, Request preResolveParent, Object[] args) in //src/DryIoc/Container.cs:line 491 at DryIoc.Container.ResolveAndCache(Int32 serviceTypeHash, Type serviceType, IfUnresolved ifUnresolved) in //src/DryIoc/Container.cs:line 404 at DryIoc.Container.System.IServiceProvider.GetService(Type serviceType) in //src/DryIoc/Container.cs:line 338 at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.GetService(IServiceProvider sp, Type type, Type middleware) at lambda_method1(Closure , Object , HttpContext , IServiceProvider ) at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.b__2(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Reproduction Files

test/test.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="codeessentials.WebOptimizer.Dotless" Version="3.1.0" />
      <PackageReference Include="DryIoc.Microsoft.DependencyInjection" Version="6.0.2" />
    </ItemGroup>

</Project>

test/Program.cs

using DryIoc;
using DryIoc.Microsoft.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
var container = new Container(Rules.MicrosoftDependencyInjectionRules);
var dependencyInjectionFactory = new DryIocServiceProviderFactory(container);
builder.Host.UseServiceProviderFactory(dependencyInjectionFactory);
builder.Services.AddControllersWithViews();
builder.Services.AddWebOptimizer(options =>
{
    options.AddLessBundle("/css/test.css", "wwwroot/css/test.less").UseContentRoot();
});

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseWebOptimizer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

test/wwwroot/css/test.less

body {
  background: lightcyan;
}

test/Controllers/HomeController.cs

using Microsoft.AspNetCore.Mvc;

namespace test.Controllers;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}

test/Views/Home/Index.cshtml

@{
    ViewData["Title"] = "Home Page";
}

<link rel="stylesheet" href="/css/test.css"/>

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

test/Views/_ViewImports.cshtml

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
dadhi commented 2 years ago

@roncrush Wow, thanks for detailed reproductiom info! I will look.

dadhi commented 2 years ago

@roncrush Meanwhile if the exception is critical for you, you may want to switch to interpretation new Container(Rules.Default.WithUseInterpretation())

roncrush commented 2 years ago

@dadhi Thanks!

dadhi commented 2 years ago

@roncrush Reproduced the exception locally.

dadhi commented 2 years ago

@roncrush fixed at least. You have found a very sneaky beast - so thanks ;)

dadhi commented 2 years ago

DI v5.2.2 is out on NuGet

roncrush commented 2 years ago

@dadhi Awesome, thanks!