【问题标题】:Property injection in to Web Api controller using Autofac使用 Autofac 将属性注入到 Web Api 控制器
【发布时间】:2020-06-02 17:37:04
【问题描述】:

我正在尝试将System.Web.Http.ApiController 上的属性设置为已解析IServerPackageRepository 的值。控制器在HttpSelfHostServer 中运行,DependencyResolver 已设置为AutofacWebApiDependencyResolver。这是来自Autofac.Module.Load 方法的代码

...

builder.RegisterType<ServerPackageRepository>()
    .As<IServerPackageRepository>()
    .SingleInstance()
    .WithParameter("path", this.StoragePath);

builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
    .PropertiesAutowired();

ApiController 控制器本身具有类型属性

public IServerPackageRepository Repository { get; set; }

但从未解决。

我正在尝试这样做,因为ApiController 除了默认构造函数之外什么都不会。有关如何使用 Autofac 以正确方式执行此操作的任何建议?

【问题讨论】:

  • RegisterApiControllers()的实现是什么?
  • @Aliostad RegisterApiControllers() 是 Autofac 贡献项目的 Autofac.Integration.WebApi 中的扩展方法。

标签: asp.net-web-api autofac


【解决方案1】:

如果ApiController 仅使用默认构造函数,则听起来好像没有调用依赖解析器,并且可能没有正确注册到 Web API。这是一个使用构造函数注入进行自托管的工作示例。

依赖项(在本例中是一个简单的记录器):

public interface ILogger
{
    void Log(string text);
}

public class Logger : ILogger
{
    public void Log(string text)
    {
        Debug.WriteLine(text);
    }
}

一个依赖于记录器的简单控制器:

public class ValuesController : ApiController
{
    readonly ILogger _logger;

    public ValuesController(ILogger logger)
    {
        _logger = logger;
    }

    // GET api/values
    public IEnumerable<string> Get()
    {
        _logger.Log("GET api/values");

        return new string[] { "value1", "value2" };
    }
}

控制台应用程序:

class Program
{
    static void Main(string[] args)
    {
        var configuration = new HttpSelfHostConfiguration("http://localhost:8080");

        configuration.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
            );

        var builder = new ContainerBuilder();

        // Register API controllers using assembly scanning.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // Register API controller dependencies.
        builder.Register<ILogger>(c => new Logger()).SingleInstance();

        var container = builder.Build();

        // Set the dependency resolver implementation.
        var resolver = new AutofacWebApiDependencyResolver(container);
        configuration.DependencyResolver = resolver;

        // Open the HTTP server and listen for requests.
        using (var server = new HttpSelfHostServer(configuration))
        {
            server.OpenAsync().Wait();

            Console.WriteLine("Hosting at http://localhost:8080/{controller}");
            Console.ReadLine();
        }
    }
}

使用以下方式点击控制器操作:

http://localhost:8080/api/values

请对此进行测试,如果您有任何问题,请告诉我。

【讨论】:

  • 我只是做了同样的事情,除了我有 2 个模块:一个用于记录器,如果你愿意从你的例子中,另一个用于初始化主机。一切正常,就像宣传的那样。这与我在主应用程序中进行的设置几乎相同,但涉及更多。所以像往常一样,责任落在了我的肩上,我要去调试和测试更多。感谢 Alex 和 @tugberk 付出的时间和努力。我将把这个交给 Alex,以提供一个完整的工作示例。
  • 所以我遇到的问题是我在一个Autofac.Module 中做了一些HttpSelfHostConfiguration,在另一个HttpSelfHostServer 中做了一些,依赖于配置,最后,在构建容器之后main 方法,设置DependencyResolver。重新排序几行可以解决我最初的问题。现在的问题是,理想情况下,我想在Module 中完全配置主机,但不能因为AutofacWebApiDependencyResolver 依赖于容器。有什么建议可以解决这个问题吗?
【解决方案2】:

不确定这是否是您想要的,但您可以创建自己的基本控制器并将IServerPackageRepository 注入其中。

public class MyApiController : ApiController { 

    public IServerPackageRepository ServerPackageRepository { get; set; }

    public MyApiController(IServerPackageRepository serverPackageRepository) { 

        ServerPackageRepository = serverPackageRepository;
    }
}

然后,将其用作您的基本控制器:

public class ProductsController : MyApiController { 

    public ProductsController(IServerPackageRepository serverPackageRepository) 
        : base(serverPackageRepository) { 
    }

    public IEnumerable<Product> Get() { 

        ServerPackageRepository.DoWork();

        //...
    }
}

【讨论】:

  • 我看不出有什么理由不这样做。无论如何,我最终会得到我自己的基本控制器。我只是想知道这是实现这一目标的最佳方法还是唯一方法?在记录 Autofac Web Api 扩展使用的博客的其他地方,我读到我不需要基本控制器。唉,我无法让构造函数或属性注入在任何 ApiController 中工作。
  • 无论哪种方式,我都无法运行它,因为 Autofac 不会在任何 ApiController 的属性或构造函数上发挥其注入魔法。我得到的只是通常的例外,即控制器可能没有空的默认 ctor。我确实像往常一样注册了我的类型。我确实将 DependencyResolver 设置为 AutofacWebApiDependencyResolver。我还需要配置什么才能使其正常工作吗?
  • @KarlO 很奇怪。我敢打赌,您的代码中某处存在错误。你确定你的控制器在Assembly.GetExecutingAssembly()下吗?
  • 是的,绝对确定。 Assembly.GetExecutingAssembly()typeof(PackagesController).Assembly 没有区别。
  • @KarlO。 Alex Meyer-Gleaves 在他的回答中提供了一个完整的例子。我认为它会帮助您查看缺少的内容。
【解决方案3】:

另一种方法是将您的依赖项直接连接到属性,如下所示:

var repo = new ServerPackageRepository(path: this.StoragePath);

builder.RegisterInstance(repo)
    .SingleInstance();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly())
    .WithProperty("Repository", repo)
    .PropertiesAutowired();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    相关资源
    最近更新 更多