CRUD операции с Blazor, .Net 6.0 и Entity Framework Core

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

В этой статье мы создадим веб-приложение, используя Blazor, .Net 6.0 и Entity Framework Core для выполнения CRUD операций на базе Asp.Net Core.

В этом руководстве мы будем использовать Visual Studio 2022 и SQL Server 2014.

Создание таблицы

Для выполнения CRUD операций мы будем использовать таблицу “userdetails”. Откройте SQL Server и создайте таблицу “userdetails”, используя запрос, приведенный ниже.

CREATE TABLE [dbo].[userdetails](
    [userid] [int] IDENTITY(1,1) NOT NULL,
    [username] [nvarchar](100) NULL,
    [address] [nvarchar](500) NULL,
    [cellnumber] [nvarchar](50) NULL,
    [emailid] [nvarchar](50) NULL,
    CONSTRAINT [PK_userdetails] PRIMARY KEY CLUSTERED
    (
        [userid] ASC
    )
)

Создание веб-приложения Blazor

Сейчас мы перейдем к созданию нового проекта, используя приложение Blazor WebAssembly и .Net 6.0. Откройте Visual Studio 2022 и следуйте этой пошаговой инструкции.

Шаг 1

Шаг 2

На этом шаге выбираем тип проекта “Blazor WebAssembly App”.

Шаг 3

Шаг 4

Выберите тип Framework’а - .NET 6.0, и вариант развертки - ASP.NET Core.

Таким образом будет создано приложение Blazor, и структура папок в Solution Explorer будет выглядеть, как показано на изображении ниже.

На изображении мы также видим 3 файла проекта, которые созданы внутри солюшена “BlazorApp”.

  • BlazorApp.Client — содержит клиентский код и страницы, которые будут отображаться в браузере.

  • BlazorApp.Server — содержит серверный код, такой как подключение к базе данных, операции и веб-API.

  • BlazorApp.Shared — содержит общий код, к которому есть доступ как у клиента, так и у сервера.

Если запустить приложение на данном этапе, нажав F5, мы увидим главную страницу приложения, похожую на изображенную ниже.

Установка необходимых Nuget-пакетов

Перейдите в пункт меню “Tools”, выберите NuGet Package Manager > Package Manager Console

а затем выполните приведенные ниже команды, чтобы добавить поставщика базы данных и инструменты Entity Framework.

=> Install-Package Microsoft.EntityFrameworkCore.SqlServer

=> Install-Package Microsoft.EntityFrameworkCore.Tools

Добавление модели в приложение

Теперь мы создадим класс Model, который будет содержать свойства модели User.

Для этого кликните правой кнопкой мыши на проект “BlazorApp.Shared” и добавьте новую папку с названием “Models”.

Затем кликните правой кнопкой мыши на папку “Models” и добавьте класс “User.cs”.

Откройте файл “User.cs” и вставьте в него код, приведенный ниже:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlazorApp.Shared.Models
{
    public class User
    {
        public int Userid { get; set; }
        public string Username { get; set; } = null!;
        public string Address { get; set; } = null!;
        public string Cellnumber { get; set; } = null!;
        public string Emailid { get; set; } = null!;
    }
}

Добавление уровня доступа к данным в приложение

А теперь мы создадим класс “DatabaseContext.cs”, в котором определим подключение к базе данных. Для этого кликните правой кнопкой мыши проект “BlazorApp.Server” и добавьте папку “Models”. Добавьте файл “DatabaseContext.cs” в папку “Models” и перенесите в него приведенный ниже код:

using BlazorApp.Shared.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorApp.Server.Models
{
    public partial class DatabaseContext : DbContext
    {
        public DatabaseContext()
        {
        }
        public DatabaseContext(DbContextOptions<DatabaseContext> options)
            : base(options)
        {
        }
        public virtual DbSet<User> Users { get; set; } = null!;
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>(entity =>
            {
                entity.ToTable("userdetails");
                entity.Property(e => e.Userid).HasColumnName("Userid");
                entity.Property(e => e.Username)
                    .HasMaxLength(100)
                    .IsUnicode(false);
                entity.Property(e => e.Address)
                    .HasMaxLength(500)
                    .IsUnicode(false);
                entity.Property(e => e.Cellnumber)
                    .HasMaxLength(50)
                    .IsUnicode(false);
                entity.Property(e => e.Emailid)
                    .HasMaxLength(50)
                    .IsUnicode(false);
            });
            OnModelCreatingPartial(modelBuilder);
        }
        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

Далее, необходимо будет создать еще две папки “Interfaces” и “Services” для обработки операций, связанных с базой данных.

Для этого кликните правой кнопкой мыши проект “BlazorApp.Server” и добавьте две новые папки “Interfaces” и “Services”.

Добавьте интерфейс в папку “Interfaces”, назовите его “IUser.cs” и перенесите в него приведенный ниже код:

using BlazorApp.Shared.Models;
namespace BlazorApp.Server.Interfaces
{
    public interface IUser
    {
        public List<User> GetUserDetails();
        public void AddUser(User user);
        public void UpdateUserDetails(User user);
        public User GetUserData(int id);
        public void DeleteUser(int id);
    }
}

Добавьте класс “UserManager.cs” в папку “Services”, который реализует интерфейс “IUser”, и перенесите в него приведенный ниже код:

using BlazorApp.Server.Interfaces;
using BlazorApp.Server.Models;
using BlazorApp.Shared.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorApp.Server.Services
{
    public class UserManager : IUser
    {
        readonly DatabaseContext _dbContext = new();
        public UserManager(DatabaseContext dbContext)
        {
            _dbContext = dbContext;
        }
        //Для получения всех данных о пользователе
        public List<User> GetUserDetails()
        {
            try
            {
                return _dbContext.Users.ToList();
            }
            catch
            {
                throw;
            }
        }
        //Для добавления новой записи пользователя
        public void AddUser(User user)
        {
            try
            {
                _dbContext.Users.Add(user);
                _dbContext.SaveChanges();
            }
            catch
            {
                throw;
            }
        }
        //Для обновления записи конкретного пользователя
        public void UpdateUserDetails(User user)
        {
            try
            {
                _dbContext.Entry(user).State = EntityState.Modified;
                _dbContext.SaveChanges();
            }
            catch
            {
                throw;
            }
        }
        //Для получения информации о конкретном пользователе
        public User GetUserData(int id)
        {
            try
            {
                User? user = _dbContext.Users.Find(id);
                if (user != null)
                {
                    return user;
                }
                else
                {
                    throw new ArgumentNullException();
                }
            }
            catch
            {
                throw;
            }
        }
        //Для удаления записи конкретного пользователя
        public void DeleteUser(int id)
        {
            try
            {
                User? user = _dbContext.Users.Find(id);
                if (user != null)
                {
                    _dbContext.Users.Remove(user);
                    _dbContext.SaveChanges();
                }
                else
                {
                    throw new ArgumentNullException();
                }
            }
            catch
            {
                throw;
            }
        }
    }
}

Теперь необходимо добавить ссылки на “DatabaseContext”, “IUser” и “UserManager” в файл Program.cs проекта “BlazorApp.Server”.

Откройте файл “Program.cs” и перенесите в него приведенный ниже код:

using BlazorApp.Server.Interfaces;
using BlazorApp.Server.Models;
using BlazorApp.Server.Services;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Добавляем сервисы в контейнер.
//Не забудьте добавить ConnectionStrings как 
"DefaultConnection" в файл appsetting.json
builder.Services.AddDbContext<DatabaseContext>
    (options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddTransient<IUser, UserManager>();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseWebAssemblyDebugging();
}
else
{
    app.UseExceptionHandler("/Error");
   // Дефолтное значение HSTS — 30 дней. Вы можете изменить это, см. https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();

Добавление веб-API контроллера в приложение

Кликните правой кнопкой мыши по папке “BlazorApp.Server/Controllers” и выберите “Add”, затем “New Item”. Откроется диалоговое окно “Add New Item”. Выберите “ASP.NET” на левой панели, затем выберите “API Controller - Empty” из шаблонов и назовите класс контроллера “UserController.cs”. Нажмите Add, чтобы создать контроллер.

Откройте файл “UserController.cs” и перенесите в него приведенный ниже код:

using BlazorApp.Server.Interfaces;
using BlazorApp.Shared.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace BlazorApp.Server.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly IUser _IUser;
        public UserController(IUser iUser)
        {
            _IUser = iUser;
        }
        [HttpGet]
        public async Task<List<User>> Get()
        {
            return await Task.FromResult(_IUser.GetUserDetails());
        }
        [HttpGet("{id}")]
        public IActionResult Get(int id)
        {
            User user = _IUser.GetUserData(id);
            if (user != null)
            {
                return Ok(user);
            }
            return NotFound();
        }
        [HttpPost]
        public void Post(User user)
        {
            _IUser.AddUser(user);
        }
        [HttpPut]
        public void Put(User user)
        {
            _IUser.UpdateUserDetails(user);
        }
        [HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            _IUser.DeleteUser(id);
            return Ok();
        }
    }
}

Добавление Razor View в приложение

Добавим три страницы в проект “BlazorApp.Client”. Для просмотра записей пользователей добавляем страницу “UserDetails.razor”, страницу “AddUser.razor” для добавления и редактирования сведений о пользователе и страницу “DeleteUser.razor” для удаления пользователя.

Кликните правой кнопкой мыши по папке “Pages” проекта “BlazorApp.Client” и выберите “Add”, затем “New Item”. Откроется диалоговое окно “Add New Item”. Выберите “Web” на левой панели, затем выберите “Razor Component” из шаблонов и введите имя “UserDetails.razor”. По этому же принципу добавляем еще две страницы “AddUser.razor” и “DeleteUser.razor” в проект “BlazorApp.Client”.

Откройте файл “UserDetails.razor” и перенесите в него приведенный ниже код:

@page "/fetchuserdetails"
@using BlazorApp.Shared.Models
@inject HttpClient Http
<h1>User Data</h1>
<p>Blazor CRUD operation</p>
<div class="row">
    <div class="col-md-6">
        <a href='/user/add' class="btn btn-primary" role="button">
            <i class="fas fa-user-plus"></i>
            Add User
        </a>
    </div>
    <div class="input-group col">
        <input type="text" class="form-control" placeholder="Search user by name"
               @bind="SearchString" @bind:event="oninput" @onkeyup="FilterUser" />
        @if (SearchString.Length > 0)
        {
            <div class="input-group-append">
                <button class="btn btn-danger" @onclick="ResetSearch">
                    <i class="fas fa-times"></i>
                </button>
            </div>
        }
    </div>
</div>
<br />
@if (userList == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table table-striped align-middle table-bordered">
        <thead class="table-success">
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Address</th>
                <th>Department</th>
                <th>Cell No</th>
                <th>E-mail</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var user in userList)
            {
                <tr>
                    <td>@user.Userid</td>
                    <td>@user.Username</td>
                    <td>@user.Address</td>
                    <td>@user.Cellnumber</td>
                    <td>@user.Emailid</td>
                    <td>
                        <a href='/user/edit/@user.Userid' class="btn btn-outline-dark" role="button">
                            Edit
                        </a>
                        <a href='/user/delete/@user.Userid' class="btn btn-outline-danger" role="button">
                            Delete
                        </a>
                    </td>
                </tr>
            }
        </tbody>

    </table>
}
@code {
    protected List<User> userList = new();
    protected List<User> searchUserData = new();
    protected User user = new();
    protected string SearchString { get; set; } = string.Empty;
    protected override async Task OnInitializedAsync()
    {
        await GetUser();
    }
    protected async Task GetUser()
    {
        userList = await Http.GetFromJsonAsync<List<User>>("api/User");
        searchUserData = userList;
    }
    protected void FilterUser()
    {
        if (!string.IsNullOrEmpty(SearchString))
        {
            userList = searchUserData
                .Where(x => x.Username.IndexOf(SearchString, StringComparison.OrdinalIgnoreCase) != -1)
                .ToList();
        }
        else
        {
            userList = searchUserData;
        }
    }
    protected void DeleteConfirm(int userID)
    {
        user = userList.FirstOrDefault(x => x.Userid == userID);
    }
    public void ResetSearch()
    {
        SearchString = string.Empty;
        userList = searchUserData;
    }
}

Откройте страницу “AddUser.razor” и перенесите приведенный ниже код, где мы можем добавить нового пользователя, а также изменить о нем сведения.

@page "/user/add"
@page "/user/edit/{userId:int}"
@using BlazorApp.Shared.Models
@inject HttpClient Http
@inject NavigationManager NavigationManager
<h1>@Title User</h1>
<hr />
<EditForm Model="@user" OnValidSubmit="SaveUser">
    <DataAnnotationsValidator />
    <div class="mb-3">
        <label for="Name" class="form-label">Name</label>
        <div class="col-md-4">
            <InputText class="form-control" @bind-Value="user.Username" />
        </div>
        <ValidationMessage For="@(() => user.Username)" />
    </div>
    <div class="mb-3">
        <label for="Address" class="form-label">Address</label>
        <div class="col-md-4">
            <InputText class="form-control" @bind-Value="user.Address" />
        </div>
        <ValidationMessage For="@(() => user.Address)" />
    </div>
    <div class="mb-3">
        <label for="Cellnumber" class="form-label">Cell No</label>
        <div class="col-md-4">
            <InputText class="form-control" @bind-Value="user.Cellnumber" />
        </div>
        <ValidationMessage For="@(() => user.Cellnumber)" />
    </div>
    <div class="mb-3">
        <label for="Emailid" class="form-label">E-mail</label>
        <div class="col-md-4">
            <InputText class="form-control" @bind-Value="user.Emailid" />
        </div>
        <ValidationMessage For="@(() => user.Emailid)" />
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Save</button>
        <button class="btn btn-light" @onclick="Cancel">Cancel</button>
    </div>
</EditForm>
@code {
    [Parameter]
    public int userId { get; set; }
    protected string Title = "Add";
    protected User user = new();
    protected override async Task OnParametersSetAsync()
    {
        if (userId != 0)
        {
            Title = "Edit";
            user = await Http.GetFromJsonAsync<User>("api/User/" + userId);
        }
    }
    protected async Task SaveUser()
    {
        if (user.Userid != 0)
        {
            await Http.PutAsJsonAsync("api/User", user);
        }
        else
        {
            await Http.PostAsJsonAsync("api/User", user);
        }
        Cancel();
    }
    public void Cancel()
    {
        NavigationManager.NavigateTo("/fetchuserdetails");
    }
}

Откройте страницу “DeleteUser.razor” и вставьте приведенный ниже код.

@page "/user/delete/{userId:int}"
@using BlazorApp.Shared.Models
@inject HttpClient Http
@inject NavigationManager NavigationManager
<h2>Delete User</h2>
<br />
<div class="form-group">
    <h4>Do you want to delete this user?</h4>
    <table class="table">
        <tbody>
            <tr>
                <td>Name</td>
                <td>@user.Username</td>
            </tr>
            <tr>
                <td>Address</td>
                <td>@user.Address</td>
            </tr>
            <tr>
                <td>Cell No</td>
                <td>@user.Cellnumber</td>
            </tr>
            <tr>
                <td>E-mail</td>
                <td>@user.Emailid</td>
            </tr>
        </tbody>
    </table>
</div>
<div class="form-group">
    <input type="submit" value="Delete" @onclick="(async () => await RemoveUser(user.Userid))" class="btn btn-danger" />
    <input type="submit" value="Cancel" @onclick="(() => Cancel())" class="btn btn-warning" />
</div>
@code {
    [Parameter]
    public int userId { get; set; }
    User user = new User();
    protected override async Task OnInitializedAsync()
    {
        user = await Http.GetFromJsonAsync<User>("/api/User/" + Convert.ToInt32(userId));
    }
    protected async Task RemoveUser(int userID)
    {
        await Http.DeleteAsync("api/User/" + userID);
        NavigationManager.NavigateTo("/fetchuserdetails");
    }
    void Cancel()
    {
        NavigationManager.NavigateTo("/fetchuserdetails");
    }
}

Добавьте ссылку “User Details” в меню навигации. Для этого откройте файл BlazorApp.Client/Shared/ NavMenu.razor” и перенесите в него приведенный ниже код:

<div class="top-row ps-3 navbar navbar-dark">
    <div class="container-fluid">
        <a class="navbar-brand" href="">BlazorApp</a>
        <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
            <span class="navbar-toggler-icon"></span>
        </button>
    </div>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchuserdetails">
                <span class="oi oi-list-rich" aria-hidden="true"></span> User Details
            </NavLink>
        </div>
    </nav>

</div>
@code {
    private bool collapseNavMenu = true;
    private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

Давайте запустим приложение. После запуска приложения, мы увидим навигационную ссылку “User Details” под ссылкой “Fetch Data” с левой стороны, как показано на изображении ниже.

Когда мы кликаем User Details в меню навигации, оно перенаправляет нас на страницу User Details и отображает все данные пользователя.

На странице “User Details” мы можем найти кнопку “Add User”. Нажав ее, мы будем перенаправлены на страницу “Add User”, где мы можем добавить нового пользователя.

Если мы хотим отредактировать или удалить существующую запись пользователя, нажмите ссылку “Edit” или “Delete” этой текущей записи. Откроется соответствующее представление (редактирование/удаление), как показано ниже, где мы можем редактировать или удалять пользовательские данные.

Вот и все. В этой статье мы показали создание приложения ASP.NET Core с использованием Blazor Entity Framework и .NET 6.0, а также выполнили CRUD операцию.


Перевод материала подготовлен в рамках набора учащихся на новый поток курса «C# ASP.NET Core разработчик». Скоро в рамках курса пройдет открытый demo-урок на тему «Пишем свой API: SignalR Core». На занятии разберем написание своего API: используем библиотеку SignalR для реализациии асинхронного обмена данными между сервером и клиентом на примере простого чата. Если интересно — записывайтесь.

Источник: https://habr.com/ru/company/otus/blog/649585/


Интересные статьи

Интересные статьи

Команда Community Toolkit рада объявить о первых предварительных выпусках двух новых наборов инструментов .NET Multi-platform App UI (.NET MAUI): CommunityToolkit.Maui и CommunityToolkit.Maui.Markup.К...
ПРИВЕТСТВИЕ Всем привет! Хочу поделиться с общественностью библиотекой, на основе которой в данный момент множество серверов, обслуживают тысячи клиентов в различных серверных системах...
В этой статье мы расскажем, как оптимизировать крупный проект в «Битрикс24» и увеличить его производительность в 3 раза, изменяя настройки MySQL и режим питания CPU. Дано Корпоративн...
Вообще-то смотреть какого цвета потроха у Rust я не собирался. Ковырнул хобби-проект на Go, пошел на GitHub посмотреть состояние fasthttp: развивается ли? Ну хотя бы поддерживается? Вспрокрастину...
Уже, наверное, раза три подбираюсь к ASP.NET MVC. После десяти лет с ASP.NET WebForms немного сложно переходить именно к технологии MVC, поскольку отличий столько, что скорее проще перечислить, ч...