无法在.NET Core 3.1中使用Lamar(IOC)解析API控制器依赖项。

huangapple go评论72阅读模式
英文:

Can't get Lamar (IOC) to resolve API Controller Dependencies in .NET Core 3.1

问题

I am getting an error when trying to call the controller below using Lamar to resolve the dependencies at runtime.

我在尝试使用Lamar在运行时解析依赖项时遇到错误。

I have tried .AddControllersAsServices() and without and still get the same result.

我尝试过.AddControllersAsServices()和不使用,但仍然得到相同的结果。

Using

使用

  • ASP.NET Core: 3.1

  • Lamar

  • ASP.NET Core: 3.1

  • Lamar

Container.GetInstance<IDataAccess>() works inside the watch window but will not resolve at runtime

Container.GetInstance<IDataAccess>()在监视窗口内工作,但在运行时不会解析

Container.WhatDoIHave() also shows that the dependency is there

Container.WhatDoIHave()还显示依赖项已经存在

Question?
What am I missing in Lamar configuration to resolve the controllers?

问题?
我在Lamar配置中漏掉了什么以解析控制器?

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly IDataAccess _dataAccess;
    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(IDataAccess dataAccess, ILogger<WeatherForecastController> logger)
    {
        _dataAccess = dataAccess;
    }

    [HttpGet]
    public IEnumerable<string> Get()
    {
        return _dataAccess.GetAll();
    }
}

Startup.cs


public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public IContainer Container { get; private set; }

    public void ConfigureContainer(ServiceRegistry services)
    {
        Container = new Container(cfg =>
        {
            cfg.Scan(scanner =>
            {
                scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
                    a.FullName.Contains("Test3.1"));
                scanner.WithDefaultConventions();
                scanner.SingleImplementationsOfInterface();
            });
        });

        services
            .AddControllers(options =>
            {
                // Disable automatic fallback to JSON
                options.ReturnHttpNotAcceptable = true;

                // Honor browser's Accept header (e.g. Chrome)
                options.RespectBrowserAcceptHeader = true;
            })
            .AddControllersAsServices();

        services.AddMvc()
            .AddControllersAsServices();

        Container.WhatDidIScan();
        Container.WhatDoIHave();

        Console.Write("Container Instantiated");
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();
        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Program.cs


public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseLamar()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseIISIntegration()
                    .UseStartup<Startup>();
                
            });
}

> An unhandled exception occurred while processing the request.
>
>LamarException: Cannot build registered instance weatherForecastController of 'Test3._1.Controllers.WeatherForecastController':
Cannot fill the dependencies of any of the public constructors
Available constructors:new WeatherForecastController(IDataAccess dataAccess, ILogger<Test3._1.Controllers.WeatherForecastController> logger)

  • IDataAccess is not registered within this container and cannot be auto discovered by any missing family policy

> 在处理请求时发生未处理的异常。
>
>LamarException: 无法构建已注册的实例WeatherForecastController 'Test3._1.Controllers.WeatherForecastController':
无法填充任何公共构造函数的依赖项
可用构造函数:new WeatherForecastController(IDataAccess dataAccess, ILogger<Test3._1.Controllers.WeatherForecastController> logger)

  • IDataAccess未在此容器中注册,并且无法通过任何缺失的family策略进行自动发现
英文:

I am getting an error when trying to call the controller below using Lamar to resolve the dependencies at runtime.

I have tried .AddControllersAsServices() and without and still get the same result.

Using

  • ASP.NET Core: 3.1
  • Lamar

Container.GetInstance<IDataAccess>() works inside the watch window but will not resolve at runtime

Container.WhatDoIHave() also shows that the dependency is there

Question?
What am I missing in Lamar configuration to resolve the controllers?

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly IDataAccess _dataAccess;
    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(IDataAccess dataAccess, ILogger<WeatherForecastController> logger)
    {
        _dataAccess = dataAccess;
    }

    [HttpGet]
    public IEnumerable<string> Get()
    {
        return _dataAccess.GetAll();
    }
}

Startup.cs


public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public IContainer Container { get; private set; }

    public void ConfigureContainer(ServiceRegistry services)
    {
        Container = new Container(cfg =>
        {
            cfg.Scan(scanner =>
            {
                scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
                    a.FullName.Contains("Test3.1"));
                scanner.WithDefaultConventions();
                scanner.SingleImplementationsOfInterface();
            });
        });

        services
            .AddControllers(options =>
            {
                // Disable automatic fallback to JSON
                options.ReturnHttpNotAcceptable = true;

                // Honor browser's Accept header (e.g. Chrome)
                options.RespectBrowserAcceptHeader = true;
            })
            .AddControllersAsServices();

        services.AddMvc()
            .AddControllersAsServices();

        Container.WhatDidIScan();
        Container.WhatDoIHave();

        Console.Write("Container Instantiated");
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();
        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Program.cs


public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .UseLamar()
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseIISIntegration()
                    .UseStartup<Startup>();
                
            });
}

> An unhandled exception occurred while processing the request.
>
>LamarException: Cannot build registered instance weatherForecastController of 'Test3._1.Controllers.WeatherForecastController':
Cannot fill the dependencies of any of the public constructors
Available constructors:new WeatherForecastController(IDataAccess dataAccess, ILogger<Test3._1.Controllers.WeatherForecastController> logger)

  • IDataAccess is not registered within this container and cannot be auto discovered by any missing family policy

答案1

得分: 2

错误消息表明容器无法解析控制器的依赖项。确保这些依赖项已在容器中注册,以便在激活控制器时知道如何解析它们。

这是因为在 Startup 中配置了不同的容器,而框架使用的容器不知道 IDataAccess,因为没有将 Scan 应用于其容器。

参考 Lamar - 与 ASP.Net Core 集成

public class Startup {

    public Startup(IConfiguration configuration) {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    //REMOVED IContainer. It is not needed

    public void ConfigureContainer(ServiceRegistry services) {

        //Apply scan to the registry used by framework so container is aware of types.
        services.Scan(scanner => {
            scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
                a.FullName.Contains("Test3.1"));
            scanner.WithDefaultConventions();
            scanner.SingleImplementationsOfInterface();
        });

        services
            .AddControllers(options => {
                // Disable automatic fallback to JSON
                options.ReturnHttpNotAcceptable = true;
                // Honor browser's Accept header (e.g. Chrome)
                options.RespectBrowserAcceptHeader = true;
            })
            .AddControllersAsServices();

        services.AddMvc()
            .AddControllersAsServices();

        services.WhatDidIScan();
        services.WhatDoIHave();

        Console.Write("Container Instantiated");
    }

    //...omitted for brevity
}
英文:

The error message indicates that the container can't resolve the controller's dependencies. Make sure those dependencies are registered with the container so it knows how to resolve them when activating controllers.

This is because separate containers are being configured in Startup and the one used by the framework is unaware of IDataAccess as the Scan was not applied to its container.

Reference Lamar - Integration with ASP.Net Core

public class Startup {

    public Startup(IConfiguration configuration) {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    //REMOVED IContainer. It is not needed

    public void ConfigureContainer(ServiceRegistry services) {

        //Apply scan to the registry used by framework so container is aware of types.
        services.Scan(scanner => {
            scanner.AssembliesAndExecutablesFromApplicationBaseDirectory(a =>
                a.FullName.Contains("Test3.1"));
            scanner.WithDefaultConventions();
            scanner.SingleImplementationsOfInterface();
        });

        services
            .AddControllers(options => {
                // Disable automatic fallback to JSON
                options.ReturnHttpNotAcceptable = true;
                // Honor browser's Accept header (e.g. Chrome)
                options.RespectBrowserAcceptHeader = true;
            })
            .AddControllersAsServices();

        services.AddMvc()
            .AddControllersAsServices();

        services.WhatDidIScan();
        services.WhatDoIHave();

        Console.Write("Container Instantiated");
    }

    //...omitted for brevity
}

huangapple
  • 本文由 发表于 2020年1月6日 22:24:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/59613776.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定