[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на C# станут решающим фактором. Переходите по ссылке 🔰.
В этой статьей, мы рассмотрим пример простого Asp.Net Mvc Crud приложения, в двух вариантах: с использованием EF Core и обычной коллекции.
Операции будут основаны на модели User, представляющую обычного пользователя.
При работе с базой данных, ожидаю от вас минимальные знания концепций Entity Framework Core, поэтому в некоторых местах, вдаваться в подробности не стану.
Приложение Asp.Net Mvc Crud
Добавление контроллера и представления
Хранение данных с Entity Framework Core
Создание и настройка проекта
Чтобы создать проект Users, запустите Visual Studio и выберите в меню File (Файл) — New Project (Создать Проект). Укажите шаблон проекта ASP.NET Core Web Application (Веб-приложение ASP.NET Core). Введите UsersCrud, в поле Name, на следующей странице укажите Framework .Net 7.0 и нажмите кнопку Create:
Модель и Репозиторий
Модель для приложения UsersCrud будет основана на списке пользователей. Создайте папку Models и добавьте в нее файл класса по имени User.cs со следующим содержимым:
1 2 3 4 5 6 7 |
public class User { public string Id { get; set; } = Guid.NewGuid().ToString(); public string Email { get; set; } public string? Name { get; set; } public int Age { get; set; } } |
Мне нравится обеспечивать согласованный доступ к данным в приложении с использованием паттерна «Хранилище» (Repository), в котором интерфейс определяет свойства и методы, предназначенные для доступа к данным, а для работы с механизмом хранения данных применяется класс реализации. Преимущество использования паттерна «Хранилище» связано с облегчением модульного тестирования части MVC приложения, а также с тем, что детали, касающиеся хранения данных, скрыты от остальных частей приложения.
Чтобы создать интерфейс хранилища, создайте папку Interfaces и добавьте в нее файл интерфейса по имени IUser.cs со следующим содержимым:
1 2 3 4 5 6 7 8 9 |
public interface IUser { IEnumerable<User> GetAllUsers(); User GetUser(string id); void AddUser(User user); void UpdateUser(User user); void DeleteUser(string id); } |
Метод GetAllUsers() будет предоставлять доступ только по чтению ко всем пользователям, известным приложению. Метод AddUser() будет использоваться для добавления новых пользователей.
На данном этапе мы собираемся хранить объекты модели в памяти, а немного позже заменим это инфраструктурой Entity Framework Core. Создайте папку 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 38 39 40 41 42 43 44 45 46 47 48 |
public class UserRepository : IUser { private List<User> _users; public UserRepository() { _users = new List<User>() { new User { Name = "Alex", Age = 30, Email = "alex@gmail.com"}, new User { Name = "Marry", Age = 19, Email = "marry@gmail.com"}, new User { Name = "Tom", Age = 27, Email = "tom@gmail.com"}, new User { Name = "Karen", Age = 38, Email = "karen@gmail.com"}, new User { Name = "John", Age = 41, Email = "john@gmail.com"} }; } public void AddUser(User user) { user.Id = Guid.NewGuid().ToString(); _users.Add(user); } public void DeleteUser(string id) { _users.Remove(GetUser(id)); } public IEnumerable<User> GetAllUsers() { return _users; } public User GetUser(string id) { return _users.FirstOrDefault(e => e.Id.ToString().Equals(id)); } public void UpdateUser(User user) { var currentUser = _users.FirstOrDefault(e => e.Id.ToString().Equals(user.Id)); if (currentUser != null) { currentUser.Name = user.Name; currentUser.Email = user.Email; currentUser.Age = user.Age; } } } |
Класс UserRepository реализует интерфейс IUser и применяет экземпляр List для отслеживания объектов User, т.е. в случае остановки или перезапуска приложения данные будут утрачиваться. Постоянное хранилище будет введено в позже, а хранилища в памяти вполне достаточно для приведения в работоспособное состояние части ASP.NET Core МVС проекта, прежде чем добавлять часть EntityFramework Core.
Добавьте в класс Program оператор следующий оператор, чтобы зарегистрировать класс UserRepository как реализацию для использования в качестве зависимостей интерфейса IUser:
1 |
builder.Services.AddSingleton<IUser, UserRepository>(); |
Данная строка кода, регистрирует класс UserRepository с применением метода AddSingleton. В результате при распознавании зависимости интерфейса IUserв первый раз создается одиночный объект, который будет использоваться для всех последующих зависимостей.
При добавлении и редактировании пользователей, нам необходимо сосредоточиться на процессе валидации модели, для этого в корне проекта, определим папку ViewModels, в которую добавим класс UserViewModel, со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class UserViewModel { [Key] public string? Id { get; set; } [Required] [DataType(DataType.EmailAddress)] public string? Email { get; set; } public string? Name { get; set; } [Required] [Range(10,120)] public int Age { get; set; } } |
Модель данных служит для передачи данных между представлением (отображением) и контроллером. Модель UserViewModel содержит набор свойств, которые будут использоваться для передачи данных о пользователе между клиентской стороной (веб-страницей) и серверной стороной (контроллером).
Указан атрибут [Required], который также требует наличие значения, и атрибут [Range(10, 120)], который ограничивает диапазон возраста от 10 до 120.
Добавление контроллера и представления
Основной акцент в рассматриваемом примере приложения сделан на управлении пользователи, потому что это создает великолепную возможность для демонстрации различных средств работы с данными. Нам нужен контроллер, который будет получать НТTP-запросы и транслировать их в операции над объектами User, так что создайте папку Controllers, добавьте в нее файл по имени HomeController.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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
public class HomeController : Controller { private readonly IUser _users; public HomeController(IUser users) { _users = users; } [HttpGet] public IActionResult Index() { return View(_users.GetAllUsers()); } [HttpGet] public IActionResult CreateOrUpdate(string? userId) { if (userId != null) { var currentUser = _users.GetUser(userId); if (currentUser != null) { return View(new UserViewModel { Id = currentUser.Id, Name = currentUser.Name, Email = currentUser.Email, Age = currentUser.Age }); } } return View(); } [HttpPost] [AutoValidateAntiforgeryToken] public IActionResult CreateOrUpdate(UserViewModel uvm) { if (ModelState.IsValid) { var user = new User { Id = uvm.Id, Name = uvm.Name, Email = uvm.Email, Age = uvm.Age }; if (uvm.Id is null) { _users.AddUser(user); } else { _users.UpdateUser(user); } return RedirectToAction(nameof(Index)); } return View(uvm); } [HttpPost] [AutoValidateAntiforgeryToken] public IActionResult Delete(string userId) { _users.DeleteUser(userId); return RedirectToAction(nameof(Index)); } } |
Метод действия Index() передает коллекцию объектов User из хранилища своему представлению, которое отобразит пользователю экранную таблицу с данными. Метод AddUser() сохраняет новые объекты Product, которые основаны на данных, полученных в НТTP-запросе POST и т.д.
Далее создайте папку Views/Home и поместите в нее файл по имени Index.cshtml со следующим содержимым:
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 45 |
@{ ViewData["Title"] = "All Users"; } @model IEnumerable<User> <div class="text-center"> <h1 class="display-4">All Users</h1> <div class="row g-4 py-5 row-cols-1"> <div> <a asp-controller="Home" asp-action="CreateOrUpdate" class="btn btn-primary">Create User</a> </div> </div> @if (Model.Count() == 0) { <div class="row"> <div class="col text-center p-2">No data</div> </div> } else { <div class="p-5 mb-4 bg-light rounded-3 ovx"> <table class="table table-hover"> <tr><th>Id</th><th>Name</th><th>Email</th><th>Age</th><th></th><th></th></tr> @foreach (User user in Model) { <tr> <td>@user.Id</td> <td>@user.Name</td> <td>@user.Email</td> <td>@user.Age</td> <td> <a class="btn btn-sm btn-primary" asp-controller="Home" asp-action="CreateOrUpdate" asp-route-userId="@user.Id">Update</a> </td> <td> <form asp-controller="Home" asp-action="Delete" asp-route-userId="@user.Id" method="post"> <button type="submit" class="btn btn-sm btn-danger">Delete</button> </form> </td> </tr> } </table> </div> } </div> |
Данное представление, отображает список пользователей, используя данные модели User, и предоставляет возможности для обновления и удаления записей о пользователях.
В папку Views/Home, поместите файл по имени CreateOrUpdate.cshtml со следующим содержимым:
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 45 46 47 48 49 |
@using UsersCrud.ViewModels; @{ ViewData["Title"] = "Create / Update User"; } @model UserViewModel <div class="container px-4 py-5" id="hanging-icons"> <h2 class="pb-2 border-bottom">Create / Update User</h2> <a asp-controller="Home" asp-action="Index">Home</a> <div class="row g-4 py-5 row-cols-1"> <div class="p-5 mb-4 bg-light rounded-3 "> <form asp-controller="Home" asp-action="CreateOrUpdate" method="post"> <div asp-validation-summary="All" class="text-danger"></div> <input type="hidden" asp-for="Id" /> <div class="form-group"> <label asp-for="Name" class="control-label"></label> <input type="text" asp-for="Name" class="form-control" /> <span asp-validation-for="Name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Email" class="control-label"></label> <input type="text" asp-for="Email" class="form-control" /> <span asp-validation-for="Email" class="text-danger"></span> </div> <div class="form-group mb-3"> <label asp-for="Age" class="control-label"></label> <input type="text" asp-for="Age" class="form-control" /> <span asp-validation-for="Age" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Save" class="btn btn-primary" /> </div> </form> </div> </div> </div> |
Это представление предоставляет интерфейс для создания нового пользователя или обновления существующего. Поля формы связаны с свойствами модели UserViewModel, что позволяет передавать и обрабатывать данные между представлением и контроллером.
Запустите приложение и проверьте его работу:
Пример работы с коллекцией пользователей завершен.
Хранение данных с Entity Framework Core
Теперь добавим инфраструктуру Entity Framework Core в проект, что бы увидеть как легко работать с базой данных, при это внеся минимум изменений в текущую структуру проекта.
Для начала загрузим библиотеку Entity Framework Core Sql Server:
Или через Package Manager Console:
1 |
Install-Package Microsoft.EntityFrameworkCore.SqlServer |
Перейдем в файл appsettings.json и пропишем конфигурацию подключения и логирования (если файла нет, создайте его в корне проекта):
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=usersCrudDb;Trusted_Connection=True;" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Information" } }, "AllowedHosts": "*" } |
Строки подключения определяются в файле appsettings.json, в коде выше, представлено определение строки подключения для БД приложения GameStore. В проекте применяется версия LocalDB продукта SQL Server, которая спроектирована специально для разработчиков и не требует конфигурирования или учетных данных.
Вы обязаны обеспечить, чтобы строка подключения была единственной неразрывной строкой. Формат строки подключения специфичен для каждого сервера баз данных.
Даже в проекте, сохраняющем лишь небольшой объем данных, важно понимать запросы и команды SQL, которые инфраструктура Entity Framework Core посылает серверу баз данных.
В корне проекта, определим папку Data, в которую добавим класс ApplicationContext, со следующим содержимым:
1 2 3 4 5 6 7 8 |
public class ApplicationContext : DbContext { public ApplicationContext(DbContextOptions<ApplicationContext> context) : base(context) { } public DbSet<User> Users{ get; set; } } |
Теперь пора обновить класс реализации хранилища, чтобы обращаться к данным через класс контекста, определенный ранее. Изменим код класса UserRepository, следующим образом:
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 |
public class UserRepository : IUser { private readonly ApplicationContext _context; public UserRepository(ApplicationContext context) { _context = context; } public void AddUser(User user) { user.Id = Guid.NewGuid().ToString(); _context.Users.Add(user); _context.SaveChanges(); } public void DeleteUser(string id) { _context.Users.Remove(new User { Id = id }); _context.SaveChanges(); } public IEnumerable<User> GetAllUsers() { return _context.Users.ToList(); } public User GetUser(string id) { return _context.Users.FirstOrDefault(e => e.ToString().Equals(id)); } public void UpdateUser(User user) { _context.Users.Update(user); _context.SaveChanges(); } } |
В приложении ASP.NET Core MVC, доступ к объектам контекста данных управляется с использованием внедрения зависимостей и потому в класс UserRepository был добавлен конструктор, принимающий объект ApplicationContext, который будет предоставлен средством внедрения зависимостей во время выполнения.
Свойство Users, определенное интерфейсом хранилища, может быть реализовано путем возвращения свойства DbSet<User>, которое определено в классе контекста. Аналогично метод AddUser() реализовать легко, потому что объект DbSet<Product> определяет метод Add(), который принимает объекты User и сохраняет их на постоянной основе.
Добавьте в класс Program.cs операторы конфигурации, чтобы сообщить инфраструктуре Entity Framework Core о том, каким образом использовать строку подключения, которую должен применять поставщик БД, и как управлять классом контекста:
1 2 3 4 5 6 |
builder.Services.AddTransient<IUser, UserRepository>(); builder.Services.AddDbContext<ApplicationContext>(opts => { opts.UseSqlServer( builder.Configuration["ConnectionStrings:DefaultConnection"]); }); |
Не забудьте убрать старую строку или просто изменить ее жизненный цикл:
1 |
builder.Services.AddSingleton<IUser, UserRepository>(); |
Инфраструктура Entity Framework Core управляет базами данных через средство, называемое миграциями, которые представляют собой наборы изменений, создающих или модифицирующих БД с целью ее синхронизации с моделью данных.
Для работы с миграцией, необходимо скачать следующую библиотеку — Microsoft.EntityFrameworkCore.Tools
Или через Package Manager Console:
1 |
Install-Package Microsoft.EntityFrameworkCore.Tools |
Для создания миграции в окне Package Manager Console введите следующую команду:
1 |
Add-Migration Init |
Init или Initial — общепринятое имя, используемое для миграции, которая производит первоначальную подготовку БД.
При выполнении команды, инфраструктура Entity Framework Сoге инспектирует проект, находит класс контекста и применяет его для создания миграции. В результате в окне Solution Explorer появится папка Migrations, содержащая файлы классов, операторы которых подготовят БД.
Просто создать миграцию, которая представляет собой всего лишь набор инструкций, недостаточно. Инструкции миграции должны быть выполнены, чтобы создать БД, которая сможет хранить данные приложения. Для выполнения инструкций миграции, в окне Package Manager Console выполните команду:
1 |
Update-Database |
Инфраструктура Entity Fгamework Core подключится к серверу баз данных, указанному в строке подключения, и выполнит операторы в миграции. Результатом будет БД, которую можно использовать для хранения объектов User.
Запустите проект и проверьте его работу. Проект был немного упрощен, для того что бы начинающему разработчику было легче разобраться, некоторые вещи я реализовал не так, как делал бы в реальном проекте.
Я надеюсь, что вам понравилось читать эту статью, и она оказалась легкой для понимания. Пожалуйста, дайте мне знать, если у вас есть какие-либо комментарии или исправления.
Так же вам может быть интересна предыдущая статья — Прием платежей через Liqpay Api в Asp.Net Core.
Вы хотите научится писать код на языке программирования C#?
Создавать различные информационные системы, состоящие из сайтов, мобильных клиентов, десктопных приложений, телеграмм-ботов и т.д.
Переходите к нам на страницу Dijix и ознакомьтесь с условиями обучения, мы специализируемся только на индивидуальных занятиях, как для начинающих, так и для более продвинутых программистов. Вы можете взять как одно занятие для проработки интересующего Вас вопроса, так и несколько, для более плотной работы. Благодаря личному кабинету, каждый студент повысит качество своего обучения, в вашем распоряжении:
- Доступ к пройденному материалу
- Тематические статьи
- Библиотека книг
- Онлайн тестирование
- Общение в закрытых группах
Живи в своем мире, программируй в нашем.
Очень просто и интересно, благодарю!
Можно ли соединить данное приложение с авторизацией, к примеру как в вашей статье — https://dijix.com.ua/blog/kak-sdelat-avtorizacziyu-v-asp-net-c/
Вы планируете в дальнейшем сделать что-то подобное ?
Спасибо
Спасибо огромное!