Проблемы установки контейнера Lamar IoC

Я пытался заставить Ламара работать на нашу инъекцию зависимости, но мой недостаток опыта заставил меня испытать некоторое горе.

У меня есть простой фиктивный контроллер:

[Route("[controller]")]
public class TestController : Controller
{
    [HttpGet]
    public int GetRandom()
    {
        TestService service = new TestService();
        int value = service.GetRandomNumber();


        return value;
    }
}

Внутри TestService находится репозиторий интерфейса, в котором я хотел бы применить DI.

Я добавил UseLamar в мой Program.cs, и мой startup.cs выглядит так:

    public void ConfigureContainer(ServiceRegistry services)
    {
        services.AddMvc();
        services.Scan(s =>
        {
            s.Assembly("Test.Components");
            s.WithDefaultConventions();
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Invalid");
        });

        app.UseMvc();
    }

Из прочтения документации я считаю, что Lamar должен автоматически сопоставить мой интерфейс с моим типом, так как они имеют одинаковое имя (IRepository -> Repository), хотя это не то, что я вижу.

Я уверен, что что-то пропустил, но я перебрал документацию и пытался поискать реальные примеры безрезультатно. Есть ли строки, которые мне не хватает в Startup.cs? Нужен ли моему Сервису конструктор для установки репозитория?

1 ответ

Вообще говоря, вы хотите внедрить свои зависимости через конструктор. Есть случаи, когда вы могли бы использовать другой подход, но в моем опыте более чем 90% случаев - это внедрение через конструктор.

Таким образом, вы действительно хотите добавить IRepository в ваш конструктор TestService. Однако из вашего кода похоже, что вам не хватает чего-то более фундаментального в том, как работает внедрение зависимостей.

TestService service = new TestService();

Когда вы используете new для создания объекта, вы управляете жизненным циклом и областью действия этого объекта. Смысл использования инфраструктуры внедрения зависимостей состоит в том, чтобы позволить ей (структуре / контейнеру) управлять зависимостями и их областью действия / жизненным циклом. Если вы создаете экземпляр объекта с помощью контейнера внедрения зависимостей, он разрешает зависимости этого объекта для вас - он также управляет зависимостями этих зависимостей, и так далее, так что вы можете иметь цепочку зависимостей, которые разрешаются без проработка сложностей инициализации большого графа объектов вручную (используя "новый").

Чтобы решить ваш непосредственный вопрос, вы можете сделать что-то вроде (это плохой код - не рекомендуется!):

TestService service = container.Resolve<ITestService>();

Контейнер будет контейнером lamar, где вы регистрируете свои типы - я не знаком с lamar, поэтому синтаксис Resolve() может выглядеть немного иначе. Это разрешило бы TestService и добавило бы репозиторий и все аргументы конструктора класса TestService.

Предпочтительный способ сделать это - разрешить цепочку зависимостей на границе (точке входа) вашего приложения, которым является сам ваш контроллер. Таким образом, ваш контроллер должен принять ITestService в качестве аргумента конструктора, а контейнер / инфраструктура разрешит TestController => TestService => Репозиторий.

Вам нужно немного поработать, чтобы это заработало. Как я уже сказал, я не знаю lamar, поэтому я не уверен, как заставить это работать с Asp.net Core.

В Asp.Net Framework WebAPI это выглядело бы примерно так с использованием Unity для DI:

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new UnityControllerActivator(container));

Этот код запускается при запуске приложения и сообщает платформе ASP.Net: при поступлении запроса разрешите соответствующий контроллер и все его зависимости, используя предоставленный контейнер.

Другие вопросы по тегам