تعریف موجودیت و DbSet تصاویر یک اتاق هتل
برای اینکه بتوان اطلاعات تصاویر آپلودی را در بانک اطلاعاتی ثبت کرد، نیاز است یک رابطهی یک به چند را بین یک اتاق و تصاویر مرتبط با آن برقرار کرد. به همین جهت ابتدا به پروژهی BlazorServer.Entities.csproj مراجعه کرده و موجودیت ثبت اطلاعات تصاویر را تعریف میکنیم:
using System.ComponentModel.DataAnnotations.Schema; namespace BlazorServer.Entities { public class HotelRoomImage { public int Id { get; set; } public string RoomImageUrl { get; set; } [ForeignKey("RoomId")] public virtual HotelRoom HotelRoom { get; set; } public int RoomId { get; set; } } }
namespace BlazorServer.Entities { public class HotelRoom { // ... public virtual ICollection<HotelRoomImage> HotelRoomImages { get; set; } } }
namespace BlazorServer.DataAccess { public class ApplicationDbContext : DbContext { public DbSet<HotelRoomImage> HotelRoomImages { get; set; } // ... } }
dotnet tool update --global dotnet-ef --version 5.0.3 dotnet build dotnet ef migrations --startup-project ../BlazorServer.App/ add Init --context ApplicationDbContext dotnet ef --startup-project ../BlazorServer.App/ database update --context ApplicationDbContext
تعریف مدل UI متناظر با هر تصویر
همانطور که در قسمت 13 نیز عنوان شد، در حین کار با رابط کاربری برنامه، با موجودیتهای بانک اطلاعاتی، به صورت مستقیم کار نخواهیم کرد و بر اساس نیازهای برنامه، یکسری کلاس DTO را تعریف میکنیم. بنابراین به پروژهی BlazorServer.Models مراجعه کرده و DTO متناظر با HotelRoomImage را به صورت زیر اضافه میکنیم:
namespace BlazorServer.Models { public class HotelRoomImageDTO { public int Id { get; set; } public int RoomId { get; set; } public string RoomImageUrl { get; set; } } }
using AutoMapper; using BlazorServer.Entities; namespace BlazorServer.Models.Mappings { public class MappingProfile : Profile { public MappingProfile() { // ... CreateMap<HotelRoomImageDTO, HotelRoomImage>().ReverseMap(); // two-way mapping } } }
تعریف سرویس کار با HotelRoomImage
در اینجا نیز همانند سرویسی که برای انجام عملیات تجاری مرتبط با یک اتاق هتل، در قسمت 13 پیاده سازی کردیم، سرویس دیگری را در پروژهی BlazorServer.Services برای کار با تصاویر اتاقها تهیه میکنیم:
namespace BlazorServer.Services { public interface IHotelRoomImageService { Task<int> CreateHotelRoomImageAsync(HotelRoomImageDTO imageDTO); Task<int> DeleteHotelRoomImageByImageIdAsync(int imageId); Task<int> DeleteHotelRoomImageByRoomIdAsync(int roomId); Task<List<HotelRoomImageDTO>> GetHotelRoomImagesAsync(int roomId); } }
namespace BlazorServer.Services { public class HotelRoomImageService : IHotelRoomImageService { private readonly ApplicationDbContext _dbContext; private readonly IMapper _mapper; private readonly IConfigurationProvider _mapperConfiguration; public HotelRoomImageService(ApplicationDbContext dbContext, IMapper mapper) { _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); _mapperConfiguration = mapper.ConfigurationProvider; } public async Task<int> CreateHotelRoomImageAsync(HotelRoomImageDTO imageDTO) { var image = _mapper.Map<HotelRoomImage>(imageDTO); await _dbContext.HotelRoomImages.AddAsync(image); return await _dbContext.SaveChangesAsync(); } public async Task<int> DeleteHotelRoomImageByImageIdAsync(int imageId) { var image = await _dbContext.HotelRoomImages.FindAsync(imageId); _dbContext.HotelRoomImages.Remove(image); return await _dbContext.SaveChangesAsync(); } public async Task<int> DeleteHotelRoomImageByRoomIdAsync(int roomId) { var imageList = await _dbContext.HotelRoomImages.Where(x => x.RoomId == roomId).ToListAsync(); _dbContext.HotelRoomImages.RemoveRange(imageList); return await _dbContext.SaveChangesAsync(); } public Task<List<HotelRoomImageDTO>> GetHotelRoomImagesAsync(int roomId) { return _dbContext.HotelRoomImages .Where(x => x.RoomId == roomId) .ProjectTo<HotelRoomImageDTO>(_mapperConfiguration) .ToListAsync(); } } }
namespace BlazorServer.App { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddScoped<IHotelRoomImageService, HotelRoomImageService>(); // ...
تهیه سرویسی برای آپلود فایلهای یک برنامهی Blazor Server به سرور
جهت ساده سازی کار آپلود، در برنامههای Blazor Server، سرویس جدید FileUploadService را به پروژهی BlazorServer.Services اضافه میکنیم:
using Microsoft.AspNetCore.Components.Forms; using System.Threading.Tasks; namespace BlazorServer.Services { public interface IFileUploadService { void DeleteFile(string fileName, string webRootPath, string uploadFolder); Task<string> UploadFileAsync(IBrowserFile inputFile, string webRootPath, string uploadFolder); } }
using Microsoft.AspNetCore.Components.Forms; using System; using System.IO; using System.Threading.Tasks; namespace BlazorServer.Services { public class FileUploadService : IFileUploadService { private const int MaxBufferSize = 0x10000; public void DeleteFile(string fileName, string webRootPath, string uploadFolder) { var path = Path.Combine(webRootPath, uploadFolder, fileName); if (File.Exists(path)) { File.Delete(path); } } public async Task<string> UploadFileAsync(IBrowserFile inputFile, string webRootPath, string uploadFolder) { createUploadDir(webRootPath, uploadFolder); var (fileName, imageFilePath) = getOutputFileInfo(inputFile, webRootPath, uploadFolder); using (var outputFileStream = new FileStream( imageFilePath, FileMode.Create, FileAccess.Write, FileShare.None, MaxBufferSize, useAsync: true)) { using var inputStream = inputFile.OpenReadStream(); await inputStream.CopyToAsync(outputFileStream); } return $"{uploadFolder}/{fileName}"; } private static (string FileName, string FilePath) getOutputFileInfo( IBrowserFile inputFile, string webRootPath, string uploadFolder) { var fileName = Path.GetFileName(inputFile.Name); var imageFilePath = Path.Combine(webRootPath, uploadFolder, fileName); if (File.Exists(imageFilePath)) { var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); var fileExtension = Path.GetExtension(fileName); fileName = $"{fileNameWithoutExtension}-{Guid.NewGuid()}{fileExtension}"; imageFilePath = Path.Combine(webRootPath, uploadFolder, fileName); } return (fileName, imageFilePath); } private static void createUploadDir(string webRootPath, string uploadFolder) { var folderDirectory = Path.Combine(webRootPath, uploadFolder); if (!Directory.Exists(folderDirectory)) { Directory.CreateDirectory(folderDirectory); } } } }
همچنین برای دسترسی به IBrowserFile در یک سرویس، نیاز است وابستگی زیر را نیز به پروژهی سرویسها اضافه کرد:
<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="5.0.3" /> </ItemGroup> </Project>
namespace BlazorServer.App { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddScoped<IFileUploadService, FileUploadService>(); // ...
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-16.zip