Я хочу автоматизировать добавление сервисов в контейнер di. Здесь, в моем классе ServiceRegistration:
builder.Services.AddScoped<ICategoryService, CategoryService>();
builder.Services.AddScoped<IProductDetailService, ProductDetailService>();
builder.Services.AddScoped<IProductImageService, ProductImageService>();
builder.Services.AddScoped<IProductService, ProductService>();
...
Я не хочу добавлять подобное, я хочу пометить каждый из моих классов обслуживания атрибутом, найти этот класс, найти интерфейс, который реализует найденный мной класс, и автоматически добавить его в контейнер di. Как мне это сделать? Или у вас есть лучшее решение?
Я не хочу добавлять свои услуги вручную, я хочу делать это автоматически
Вы можете использовать отражение:
var components =
from type in typeof(CategoryService).Assembly.GetTypes()
where type.Name.EndsWith("Service")
where !type.IsAbstract && !type.IsGenenicTypeDefinition
where type.GetInterfaces().Count() == 1
select { Service = type.GetInterfaces().Single(), Implementation = type };
foreach (var component in components)
{
services.AddScoped(component.Service, component.Implementation);
}
Также доступны расширения для MS.DI, которые могут упростить эту задачу, например Scrutor.
«Разве использование отражения не обойдется мне здесь дорого?» Много чего?
Мне нужно использовать его в большом проекте. Не приводит ли отражение к уязвимостям безопасности, проблемам с производительностью и увеличению использования памяти? Генерация кода статически во время компиляции с помощью генератора исходного кода показалась мне более предпочтительной, но мне хотелось бы узнать ваше мнение.
«Не является ли отражение причиной уязвимостей безопасности» — Нет, это не так.
«Проблемы с производительностью». Вам придется измерить это, справедливо ли это в вашем случае, но будьте осторожны, чтобы измерить полную разницу во времени запуска между явной регистрацией и этой (основанной на отражении) автоматической регистрацией. Хотя накладные расходы, безусловно, существуют, они обычно меньше, чем вы думаете.
«больше использования памяти». Во время запроса объектов с использованием отражения память будет временно использоваться больше, но после этапа запуска разницы в использовании памяти нет. В случае сомнений: измерьте.
«Мне показалось, что статическая генерация кода во время компиляции с помощью генератора исходного кода». Генерация этого кода с помощью генератора кода, безусловно, возможна и иногда приводит к более быстрому запуску, но вы потеряете гибкость в отличие от использования этого динамического способа регистрации вещей на основе среды выполнения. Также обратите внимание, что зрелые DI-контейнеры в .NET используют этот подход на основе отражения уже почти два десятилетия, в то время как генерация кода во время компиляции для регистрации зависимостей является довольно новой.
Хотя это хороший ответ, я думаю, вам, вероятно, следует упомянуть и о некоторых подводных камнях. Подобные отражения лишают вас возможности использовать AOT. Но более серьезные проблемы, подобные этой, не удастся решить, если какая-либо из служб реализует более одного интерфейса или если службы находятся в нескольких сборках.
@DavidG, кажется, ты только что упомянул AOT :-). Конечно, этот показанный пример очень ограничен. Однако то, как писать запросы автоматической регистрации, во многом зависит от соглашений, которые применяет приложение. Этот контекст полностью отсутствует в вопросе. Вопрос очень широкий, и мой ответ, следовательно, такой же. Идея состоит в том, чтобы дать ФП представление о том, как решить эту проблему и учесть потребности. Изменение этого параметра для поддержки нескольких интерфейсов и нескольких сборок не должно составить труда для опытного разработчика C#.
Конечно, но вы не предоставили никакого контекста в своем ответе, поэтому люди будут слепо приходить и не иметь ни малейшего представления, почему они могут не захотеть поступать таким образом. Если бы я написал этот ответ, я, возможно, начал бы со слов: «Не делайте этого, если вы действительно не знаете, что делаете, и не имеете передовой опыт». Что касается добавления строки AOT, мы все знаем, что комментарии здесь довольно эфемерны и могут исчезнуть в любой момент, не говоря уже о том факте, что большинство людей вообще их не читают.
@DavidG, точка зрения принята. Обычно я предоставляю больше контекста в своих ответах здесь, на SO. Если вы опубликуете свой собственный ответ, я обязательно проголосую за него, как я часто делаю с вашими ответами.
спасибо большое, мой Стивен. У меня есть еще один вопрос; не будет ли мне здесь дорого стоить использование отражения? Было бы правильно вместо этого создать SourceGenerator? Я создал генератор исходного кода, но он не дает необходимого ответа во время компиляции. Спасибо за ваш ответ.