Передайте параметр при инициализации внедрения зависимостей в ядре ASP.NET

У меня есть простой класс, который выглядит так:

public class TestClass1
{
    private string testString = "Should be set by DI";

    public TestClass1(string testString)
    {
        this.testString = testString;
    }
    public string GetData()
    {
        return testString + DateTime.Now;
    }
}

Я хочу внедрить его с помощью встроенного DI в простое основное веб-приложение ASP.NET, но с параметром testString, установленным при инициализации внедрения зависимостей.

Я попытался установить следующее в startup.cs, но во время выполнения это не работает, потому что TestClass1 не имеет конструктора без параметров:

services.AddScoped(provider => new TestClass1("Success!")); 

person Rasmus Hansen    schedule 13.07.2016    source источник
comment
Ваш вопрос не имеет смысла; код, который вы разместили, будет работать нормально. Возможно, вам не хватает какой-то важной информации в вашем вопросе, но я не могу определить, что вам не хватает. Опубликуйте полученные сведения об исключении (тип исключения, сообщение, трассировка стека и сведения о внутреннем исключении).   -  person Steven    schedule 13.07.2016
comment
Вы действительно вводите этот класс, пытаетесь ли вы инициализировать его «новым», как в new TestClass()? ДИ так не работает   -  person Tseng    schedule 13.07.2016
comment
Не могли бы вы опубликовать свой метод ConfigureServices?   -  person adem caglin    schedule 13.07.2016
comment
@Tseng: конечно, иногда вам нужно напрямую зарегистрировать экземпляр типа. Итак, это распространенный сценарий. Как уже написал Стивен, это должно работать так.   -  person Juergen Gutsch    schedule 13.07.2016
comment
@JuergenGutsch: Нет, вы не используете ключевое слово new при получении экземпляра. Вы всегда вводите его через конструктор. DI — это не какая-то магия компилятора, это просто CLR/OOP с небольшим количеством отражений или ExpressionTrees. Я подозреваю, что он делает new TestClass() в своем коде (обратите внимание на новое ключевое слово и отсутствие параметра). ДИ работает не так. Скорее вы передаете его через конструктор, например public MyService(TestClass injectedTestCass)   -  person Tseng    schedule 13.07.2016
comment
Как упоминал @Tseng, я не должен использовать ключевое слово new, потому что DI должен обрабатывать создание экземпляра класса. Но я понятия не имею, как написать строку services.AddScoped с параметрами, если я не использую ключевое слово new   -  person Rasmus Hansen    schedule 13.07.2016
comment
Покажите код, где вы хотите использовать сервис, вот где ошибка. Ваши регистрации выглядят нормально   -  person Tseng    schedule 13.07.2016
comment
@Tseng, может быть, мы неправильно поняли друг друга. Если регистрация кажется нормальной (как вы написали в последнем комментарии), регистрация экземпляра (созданного с помощью new, как я написал в своем комментарии) тоже подходит, верно? ;) Я думаю, что хорошо знаю IoC :) В любом случае, такая регистрация довольно хороша и должна работать :)   -  person Juergen Gutsch    schedule 14.07.2016
comment
Это не то, что я сказал в своем комментарии. См. Первый раздел кода ниже в моем ответе. Я говорил о получении экземпляра за пределами корня композиции, поскольку многие люди, плохо знакомые с DI/IoC, считают, что они могут вызывать new MyClass() в любом месте своего кода, чтобы разрешить зависимость без передачи параметров, и это первое, что пришло мне в голову. когда он получил ошибку, нет конструктора без параметров. Я просто пропустил случай, когда модели создаются инфраструктурой MVC при вызове действий контроллера, что было в случае, когда OP пытался использовать его в   -  person Tseng    schedule 14.07.2016


Ответы (1)


Я подозреваю, что вы просто пропустили важнейшую часть кода, и ваше использование DI просто неправильно, а не регистрация.

public class MyController 
{
    private readonly MyClass myClass;

    public MyController()
    {
        // This doesn't work and do not involve DI at all
        // It will fail because MyClass has no parameterles constructor
        this.myClass = new MyClass(); 
    }
}

Вышеприведенное не сработает, потому что DI не является магией компилятора, которая позволяет вам волшебным образом внедрять зависимости при вызове new для типа.

public class MyController 
{
    private readonly MyClass myClass;

    public MyController(MyClass myClass)
    {
        // This should work, because the IoC/DI Container creates the instance
        // and pass it into the controller
        this.myClass = myClass;
    }
}

Когда вы используете DI/IoC, вы позволяете конструктору генерировать и создавать экземпляры объектов, поэтому вы никогда не вызываете new в своих классах обслуживания. Просто скажите в конструкторе, что вам нужен экземпляр какого-то типа или его интерфейс.

Изменить:

Раньше это работало в предыдущих версиях (бета-версиях) ASP.NET Core. Должен по-прежнему работать, но ограничен параметрами:

public class MyController 
{
    public IActionResult Index([FromServices]MyClass myClass)
    {
    }
}
person Tseng    schedule 13.07.2016
comment
Спасибо большое. Я попробовал ваш фрагмент кода, и, конечно, он сработал. Затем я проверил свой собственный код, и моя ошибка заключалась в том, что я поместил TestClass testClass в метод ActionResult вместо метода конструктора контроллера. А также спасибо @steven за то, что указал мне правильное направление :) - person Rasmus Hansen; 13.07.2016
comment
Вы должны были добавить свой вариант использования и рассматриваемый пример кода в ответ, тогда это было бы намного быстрее, чем угадывать, в чем может быть ошибка. Для действий раньше тоже был метод внедрения, используя атрибут [FromServices] в параметре. docs.asp.net/ en/latest/mvc/controllers/ Это было изменено несколько раз (т.е. удалено из свойств и контроллера), как указано в этой проблеме GitHub github.com/aspnet/Mvc/issues/3578. Я не знаю, работает ли он по-прежнему с параметрами действия. - person Tseng; 13.07.2016