Внедрение зависимостей в C# — это спасение при организации зависимостей, особенно в более сложных приложениях ASP.NET Core. А если вы уже знакомы с IServiceCollection или просто хотите максимально приблизиться к уже предоставленным предложениям DI, Scrutor на C# станет отличным усовершенствованием.
В этой статье я предоставлю вам общий обзор внедрения зависимостей и Scrutor в C#. Но далее мы сразу перейдем к трем советам, которые вы можете использовать со Scrutor и которые могут оказаться очень полезными в вашем приложении!
Scrutor — это мощный пакет NuGet на C#, который расширяет возможности внедрения зависимостей. Он упрощает регистрацию и разрешение зависимостей, упрощая управление и организацию кода.
Внедрение зависимостей — популярный подход к настройке приложений, который способствует слабой связи и улучшает тестируемость и удобство обслуживания. Он предполагает внедрение зависимостей в класс, а не непосредственное их создание внутри класса. Это означает, что ответственность за создание зависимости лежит не на классе, которому она требуется, а на ком-то из верхнего стека вызовов. В конечном итоге это приводит к тому, что почти все создание зависимостей приходится на точку входа приложения, что делает его громоздким. Однако фреймворки внедрения зависимостей помогают очистить и упорядочить всю эту логику .
Scrutor развивает эту концепцию на шаг дальше, предоставляя простой и интуитивно понятный способ регистрации и разрешения зависимостей. Благодаря Scrutor вам больше не нужно вручную регистрировать каждую зависимость одну за другой. Вместо этого вы можете использовать соглашения и атрибуты для автоматизации процесса.
Чтобы проиллюстрировать, как использовать Scrutor на C# для регистрации и разрешения, давайте рассмотрим простой сценарий. Представьте, что у нас есть приложение, которое требует использования разных репозиториев данных, таких как UserRepository и ProductRepostiory.
Сначала нам нужно установить пакет Scrutor NuGet в наш проект. Откройте консоль диспетчера пакетов и выполните следующую команду:
Install-Package Scrutor
Далее нам нужно определить наши репозитории и соответствующие им интерфейсы. Этот пример по сути пустой, но мы вернемся к ним через мгновение:
public interface IUserRepository { // Interface methods } public class UserRepository : IUserRepository { // Implementation } public interface IProductRepository { // Interface methods } public class ProductRepository : IProductRepository { // Implementation }
Теперь давайте подключим наши зависимости с помощью Scrutor. В код запуска (например, в методе ConfigurationServices в ASP.NET Core) добавьте следующий код:
services.Scan(scan => scan .FromAssemblyOf<Startup>() .AddClasses(classes => classes.AssignableToAny( typeof(IUserRepository), typeof(IProductRepository))) .AsImplementedInterfaces() .WithScopedLifetime());
Этот код использует метод Scan из Scrutor для сканирования сборки, содержащей класс Startup. Затем он отфильтровывает классы, которые можно назначить интерфейсам IUserRepository или IProductRepository. Наконец, он отображает реализации этих интерфейсов и регистрирует их в соответствующих интерфейсах.
Теперь мы можем внедрить эти зависимости в наши классы. Например, предположим, что у нас есть класс UserService, которому требуется IUserRepository:
public class UserService { private readonly IUserRepository _userRepository; public UserService(IUserRepository userRepository) { _userRepository = userRepository; } // Rest of the class implementation }
Объявив IUserRepository как зависимость в конструкторе, Scrutor вместе с IServiceCollection автоматически разрешит и внедрит для нас экземпляр UserRepository.
Представьте, что у вас есть сервисный интерфейс IService
и реализация MyService
. Вы хотите регистрировать вход и выход каждого вызова метода в MyService
, не загрязняя его бизнес-логику проблемами ведения журнала.
Сначала определите интерфейс IService
и его реализацию:
public interface IService { void DoWork(); } public class MyService : IService { public void DoWork() { // Business logic here } }
Затем создайте класс декоратора LoggingDecorator
, реализующий IService
. Этот класс обернет реальную службу и добавит ведение журнала вокруг вызовов делегированных методов:
public class LoggingDecorator : IService { private readonly IService _decorated; private readonly ILogger<LoggingDecorator> _logger; public LoggingDecorator(IService decorated, ILogger<LoggingDecorator> logger) { _decorated = decorated; _logger = logger; } public void DoWork() { _logger.LogInformation("Starting work."); _decorated.DoWork(); _logger.LogInformation("Finished work."); } }
Теперь используйте Scrutor, чтобы зарегистрировать свой сервис и его декоратор в Startup.cs
или там, где вы настраиваете свои сервисы:
public void ConfigureServices(IServiceCollection services) { // Register the base service services.AddScoped<IService, MyService>(); // Use Scrutor to apply the decorator services.Decorate<IService, LoggingDecorator>(); // Make sure to register the ILogger or ILogger<T> dependencies if not already done }
В этой настройке Scrutor используется для обертывания регистрации IService
с помощью LoggingDecorator
. При разрешении IService
контейнер DI предоставит экземпляр LoggingDecorator
, который, в свою очередь, является оболочкой экземпляра MyService
. Этот подход обеспечивает разделение задач, сохраняя логику журналирования вне вашей бизнес-логики.
Когда мы создаем сложные системы, часто бывают случаи, когда нам нужно ввести что-то вроде флагов функций. Это позволяет нам использовать разные пути кода в зависимости от конфигурации и не перекомпилировать и развертывать все приложение. В некоторых ситуациях речь идет не просто о выборе другого пути кода, а о замене всей реализации чего-либо!
Давайте попробуем пример вместе! Предположим, у вас есть интерфейс IFeatureService
с несколькими реализациями: NewFeatureService
(новая экспериментальная функция) и StandardFeatureService
(текущая стабильная функция). Вы хотите переключаться между этими реализациями во время выполнения на основе флага конфигурации.
Сначала определите интерфейс IFeatureService
и его реализации:
public interface IFeatureService { void ExecuteFeature(); } public class NewFeatureService : IFeatureService { public void ExecuteFeature() { // New feature logic } } public class StandardFeatureService : IFeatureService { public void ExecuteFeature() { // Standard feature logic } }
Далее вам нужен способ определить, какую реализацию использовать на основе настройки переключения функций. Это может быть значение в appsettings.json
, параметр базы данных или любой другой источник конфигурации.
Теперь используйте Scrutor для динамической регистрации соответствующей реализации сервиса на основе переключения функции:
public void ConfigureServices(IServiceCollection services) { // Assume GetFeatureToggleValue() retrieves the current feature toggle setting var useNewFeature = GetFeatureToggleValue("UseNewFeature"); // Dynamically register the appropriate implementation based on the feature toggle if (useNewFeature) { services.AddScoped<IFeatureService, NewFeatureService>(); } else { services.AddScoped<IFeatureService, StandardFeatureService>(); } // Optional: You could combine this with the previous example // to use the decorator pattern too! // services.Decorate<IFeatureService, FeatureServiceProxy>(); } private bool GetFeatureToggleValue(string featureName) { // This method would typically check your // configuration source to determine if the feature is enabled // For simplicity, this is just a placeholder return false; // or true based on actual configuration }
Такой подход может помочь нам:
В этой статье я предоставил вам 3 простых совета по внедрению зависимостей с помощью Scrutor в C#. После краткого обзора того, что такое внедрение зависимостей и как Scrutor в него вписывается, мы сразу перешли к нашим примерам. Мы увидели сканирование сборок, как декорировать зависимости и даже как помечать функции целыми реализациями!
Внедрение зависимостей — это то, что может значительно упростить ваши приложения по мере их усложнения, и Scrutor может оказаться огромным подспорьем, если вы хотите придерживаться встроенного предложения IServiceCollection от Microsoft . Если вы нашли это полезным и ищете дополнительные возможности для обучения, рассмотрите возможность подписки на мой бесплатный еженедельный информационный бюллетень по разработке программного обеспечения и посмотрите мои бесплатные видеоролики на YouTube ! Присоединяйтесь ко мне и другим участникам сообщества в Discord !
Также опубликовано здесь.