[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на 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 і ознайомтеся з умовами навчання, ми спеціалізуємося тільки на індивідуальних заняттях, як для початківців, так і для просунутих програмістів. Ви можете взяти як одне заняття для опрацювання питання, що вас цікавить, так і кілька, для більш щільної роботи. Завдяки особистому кабінету, кожен студент підвищить якість свого навчання, у вашому розпорядженні:
- Доступ до пройденого матеріалу
- Тематичні статті
- Бібліотека книг
- Онлайн тестування
- Спілкування в закритих групах