[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на C# станут решающим фактором. Переходите по ссылке 🔰.
В этой статье рассмотрим, как использовать инъекцию зависимостей (DI) в .NET. С помощью Microsoft Extensions управление DI осуществляется путем добавления служб и их конфигурирования в коллекции IServiceCollection. Интерфейс IHost раскрывает экземпляр IServiceProvider, который выступает в качестве контейнера всех зарегистрированных служб.
Создадим проекта по типу Console Application и дадим его имя: DependencyInjection.
В проект сразу же загрузим библиотеку Microsoft.Extensions.Hosting, используя Package Manager Console:
1 |
PM> Install-Package Microsoft.Extensions.Hosting |
А также библиотеку для работы с базой данных:
1 |
Install-Package Microsoft.EntityFrameworkCore.SqlServer |
В корень проекта добавим папку Models, а в нее класс User.cs, со следующим содержимым:
1 2 3 4 5 6 |
public class User { public string Id { get; set; } = Guid.NewGuid().ToString(); public string Name { get; set; } public int Age { get; set; } } |
В корень проекта, добавим папку Data, а в нее класс ApplicationContext.cs, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } = null!; public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options) { Database.EnsureDeleted(); Database.EnsureCreated(); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } } |
В корне проекта определим файл appsettings.json и пропишем конфигурацию подключения к базе данных:
1 2 3 4 5 |
{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=testdb;Trusted_Connection=True;" } } |
Строки подключения определяются в файле appsettings.json, в коде выше, представлено определение строки подключения для БД приложения GameStore. В проекте применяется версия LocalDB продукта SQL Server, которая спроектирована специально для разработчиков и не требует конфигурирования или учетных данных.
После добавления файла в Visual Studio для его копирования в каталог приложения в окне свойств необходимо установить для опции Copy to Output Directory значение «Copy if newer» (или «Copy always»).
В корне проекта добавим папку Interfaces, в которой определим интерфейс IUser.cs, со следующим содержимым:
1 2 3 4 5 6 7 8 9 |
public interface IUser { Task<IEnumerable<User>> GetUsersAsync(); Task<User> GetUserAsync(string userId); Task AddUserAsync(User user); Task UpdateUserAsync(User user); Task DeleteUserAsync(User user); } |
В корне проекта добавим папку Repository, в которой определим интерфейс UserRepository.cs, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public class UserRepository : IUser { private readonly ApplicationContext _context; public UserRepository(ApplicationContext context) { _context = context; } public async Task AddUserAsync(User user) { _context.Users.Add(user); await _context.SaveChangesAsync(); } public async Task DeleteUserAsync(User user) { _context.Users.Remove(user); await _context.SaveChangesAsync(); } public async Task<User> GetUserAsync(string userId) { return await _context.Users.FirstOrDefaultAsync(e => e.Id.Equals(userId)); } public async Task<IEnumerable<User>> GetUsersAsync() { return await _context.Users.ToListAsync(); } public async Task UpdateUserAsync(User user) { _context.Update(user); await _context.SaveChangesAsync(); } } |
Чтобы при запуске приложений в базе данных были начальные данные, определим в Data, класс DbInit.cs, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class DbInit { public async Task InitializeAsync(ApplicationContext context) { if (!context.Users.Any()) { context.Users.AddRange(new User[] { new User{ Name = "Alex", Age = 30 }, new User{ Name = "Tom", Age = 23 }, new User{ Name = "Marry", Age = 41 } }); await context.SaveChangesAsync(); } } } |
Изменим содержимое класса Program.cs, следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public class Program { static async Task Main(string[] args) { HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); IConfigurationRoot _confString = new ConfigurationBuilder(). SetBasePath(AppDomain.CurrentDomain.BaseDirectory).AddJsonFile("appsettings.json").Build(); builder.Services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(_confString.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped<IUser,UserRepository>(); using IHost host = builder.Build(); using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; try { var applicationContext = services.GetRequiredService<ApplicationContext>(); await new DbInit().InitializeAsync(applicationContext); } catch (Exception ex) { Console.WriteLine("An error occurred while seeding the database."); } } await UsersExample(host.Services); await host.RunAsync(); } static async Task UsersExample(IServiceProvider hostProvider) { var users = hostProvider.GetService<IUser>(); var allUsers = await users.GetUsersAsync(); foreach (var item in allUsers) { Console.WriteLine($"{item.Id}:{item.Name}:{item.Age}"); } } } |
В начале метода Main, создается объект HostApplicationBuilder с использованием статического метода Host.CreateApplicationBuilder, и передаются аргументы командной строки (args).
Уважаемые энтузиасты программирования на C#!
С наилучшими пожеланиями,
[Леонид / Dijix Company]
Далее создается объект _confString типа IConfigurationRoot с помощью ConfigurationBuilder. Он загружает конфигурацию из файла appsettings.json, который находится в том же каталоге, что и исполняемый файл приложения.
После, добавляется сервис для работы с базой данных. Используется DbContext типа ApplicationContext, который настроен на использование SQL Server в соответствии с конфигурацией, полученной из appsettings.json.
Далее, добавляется сервис с областью действия Scoped, который представлен интерфейсом IUser и его реализацией UserRepository. Это означает, что для каждой области действия будет создан новый экземпляр UserRepository.
Далее создается область действия (IServiceScope) с использованием host.Services.CreateScope(). Область действия предоставляет контейнер зависимостей, который содержит зарегистрированные сервисы. Получается экземпляр ApplicationContext из контейнера зависимостей. Вызывается метод InitializeAsync на объекте DbInit, передавая applicationContext. Этот метод выполняет инициализацию базы данных или выполнение других операций для подготовки приложения к работе.
Если возникает исключение во время инициализации базы данных, выводится сообщение об ошибке в консоль.
Выполняется метод UsersExample, который принимает в качестве аргумента host.Services, внутри которого получает зависимость IUser и получает всех пользователей из базы данных.
Запустим приложение и проверим удалось ли получить пользователей.
И на последок, представим что наше приложение имеет стартовую точку, имеено с которой мы начинаем работать с нашим приложением, что-то по типу контроллера по умолчанию. В корень проекта, добавим класс MainController.cs, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class MainController { private readonly IUser _users; private readonly ApplicationContext _context; public MainController(IUser users, ApplicationContext context) { _users = users; _context = context; } public async Task Start() { while (true) { var allUsers = await _users.GetUsersAsync(); Console.WriteLine("User using a Repository"); foreach (User user in allUsers) { Console.WriteLine($"Id - {user.Id}, Name - {user.Name}, Age - {user.Age}"); } Console.WriteLine(); var allUserFromAppContext = await _context.Users.ToListAsync(); Console.WriteLine("User using a ApplicationContext"); foreach (User user in allUserFromAppContext) { Console.WriteLine($"Id - {user.Id}, Name - {user.Name}, Age - {user.Age}"); } Console.WriteLine("\nTap to repite"); Console.ReadLine(); } } } |
Изменим класс Program.cs, следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
public class Program { static async Task Main(string[] args) { HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); IConfigurationRoot _confString = new ConfigurationBuilder(). SetBasePath(AppDomain.CurrentDomain.BaseDirectory).AddJsonFile("appsettings.json").Build(); builder.Services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(_confString.GetConnectionString("DefaultConnection"))); builder.Services.AddScoped<IUser,UserRepository>(); //Добавили новый класс в сервисы builder.Services.AddScoped<MainController>(); using IHost host = builder.Build(); using (var scope = host.Services.CreateScope()) { var services = scope.ServiceProvider; try { var applicationContext = services.GetRequiredService<ApplicationContext>(); await new DbInit().InitializeAsync(applicationContext); } catch (Exception ex) { Console.WriteLine("An error occurred while seeding the database."); } } //Получили новый класс из сервисов var startApplicationController = host.Services.GetService<MainController>(); //Вызвали метод для старта работы await startApplicationController.Start(); await host.RunAsync(); } } |
Запустим приложение и проверим его работу. В данному случае, класс MainController, получает 2 зависимости и в цикле получает пользователей через каждую из них, просто для демонстрации работы.
Я надеюсь, что вам понравилось читать эту статью, и она оказалась легкой для понимания. Пожалуйста, дайте мне знать, если у вас есть какие-либо комментарии или исправления.
Так же вам может быть интересна предыдущая статья — Sweetalert2 в Asp.Net Core Mvc.
Вы хотите научится писать код на языке программирования C#?
Создавать различные информационные системы, состоящие из сайтов, мобильных клиентов, десктопных приложений, телеграмм-ботов и т.д.
Переходите к нам на страницу Dijix и ознакомьтесь с условиями обучения, мы специализируемся только на индивидуальных занятиях, как для начинающих, так и для более продвинутых программистов. Вы можете взять как одно занятие для проработки интересующего Вас вопроса, так и несколько, для более плотной работы. Благодаря личному кабинету, каждый студент повысит качество своего обучения, в вашем распоряжении:
- Доступ к пройденному материалу
- Тематические статьи
- Библиотека книг
- Онлайн тестирование
- Общение в закрытых группах
Живи в своем мире, программируй в нашем.