11.05.2023

Моя цель — изучить C# и поделиться своими знаниями с людьми. Я упомянул примеры с кодами комментариев.

Мы продолжим RentCarProject(ReCapProject)

Требования:

1. -Создайте таблицу CarImages (Id, CarId, ImagePath, Date). Каждый автомобиль может иметь более 1 фотографии.

2. -Прописать систему в API, когда будем добавлять Фото Авто…

3. -Изображения будут храниться в папке вашего проекта. Изображения будут сохранены с идентификатором GUID, который вы сами предоставите, а не с именем, которое они загружают.

4. -Добавить метод фотографий = Удалить, Обновить

5. -1 машина может иметь 5 фотографий.

6. -Когда добавлены фотографии автомобиля, затем сохранены фотографии, которые были добавлены, тогда мы можем увидеть в системе это…

7. -Создайте систему для списка фотографий автомобилей.

8. -Создайте систему. Если по умолчанию выбраны фотографии автомобилей, система может отображать фотографии по умолчанию. Это означает логотип компании (список одного элемента).

1-)

Сначала я создал как сущность в EntityLayer

namespace Entities.Concrete
{
    public class CarImage : IEntity
    {
        public int Id { get; set; }
        public int CarId { get; set; }
        public string ImagePath { get; set; }
        public DateTime ImageDate { get; set; }

    }
}

Некоторые классы с кодами, но некоторые классы без кода, но позже я добавлю коды, потому что некоторое время мы должны следовать методу блок-схемы, чтобы упорядочить классы. Но некоторые классы не нуждаются в рефакторинге, поэтому я буду делиться с кодами. можете увидеть их коды с комментариями ниже. Также вы можете понять с пространством имен, какой слой и классы…

namespace DataAccess.Abstract
{
    //CarImage is generic and it will use as a entity...
    public interface ICarImageDal : IEntityRepository <CarImage>
    {

    }
}

namespace DataAccess.Concrete.EntityFramework
{
    public class EfCarImageDal : EfEntityRepositoryBase<CarImage,CarContext>,ICarImageDal
    {

    }
}

И Первые Требования закончены…

2-) Мы хотим добавить фотографии автомобилей, тогда нам нужно написать коды в бизнес-уровне классов Service и Manager. Теперь я напишу просто метод Add, а затем позже я добавлю другие операции, это означает операцию CRUD в других требования…

Давайте сначала напишем в ICarImageService

namespace Business.Abstract
{
    public interface ICarImageService
    {
        IResult Add(CarImage carImage);
    }

Я добавлю другие операции, которые хочу сначала показать, по какому пути мы идем.

namespace Business.Concrete
{
    public class CarImageManager : ICarImageService
    {
        ICarImageDal _carImageDal;

        public CarImageManager(ICarImageDal carImageDal)
        {
            _carImageDal = carImageDal;
        }

        public IResult Add(CarImage carImage)
        {
            _carImageDal.Add(carImage);
            return new SuccessResult(Messages.ImageAdded);
        }
    }
}



Теперь мы можем создать операцию добавления WepAPI…

Давайте напишем метод Add в этом классе CarImagesController WebAPI…

namespace WebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CarImagesController : ControllerBase
    {
        //Firstly Let's create the Loosely Coopled...
        ICarImageService _carImageService;

        public CarImagesController(ICarImageService carImageService)
        {
            _carImageService = carImageService;
        }

        //Used add naming to understand
        [HttpPost("add")]
        //Used CarImage to added entity for database
        public IActionResult Add(CarImage carImage)
        {
            //carimage coming from UI then added the system
            var result = _carImageService.Add(carImage);
            if (result.Success)
            {
                //http 200 code
                return Ok(result);
            }
            //http 400 code
            return BadRequest(result);
        }
    }
}

Затем мы также должны добавить экземпляр и серверную часть в API, поэтому мы должны добавить ссылки на сервисы…

В классе OutofacBusinessModule.

            builder.RegisterType<CarImageManager>().As<ICarImageService>().SingleInstance();
            builder.RegisterType<EfCarImageDal>().As<ICarImageDal>().SingleInstance();

            builder.RegisterType<FileHelperManager>().As<IFileHelperService>().SingleInstance();

Завершите 2.Требования…

3–4-)

Давайте добавим GUID…

GUID = глобальный уникальный идентификатор

CreatGuid() может создавать случайный GUID, а также возвращает этот GUID, преобразовывая его в строку.

GUID имеет 128-битные случайные идентификаторы, поэтому они не могут быть найдены. Его можно использовать для базы данных, веб-сайтов, электронной почты, идентификатора файла и т. Д., Мы можем использовать множество областей для их идентификатора.

Почему мы используем этот метод, потому что мы можем легко и безопасно найти файл или электронную почту.

namespace Core.Utilities.Helpers.GuidHelpers
{
    public class GuidHelpers
    {
        public static string CreatGuid()
        {
            return Guid.NewGuid().ToString();
        }
    }
}

Создан файл FileHelper и созданы FileHelperService и FileHelperManager, чтобы найти файл для сохранения фотографий…

namespace Core.Utilities.Helpers.FileHelper
{
    public interface IFileHelperService
    {
        //IFormFile Http protocol to which file will upload,Root is which way will follow...
        string Upload(IFormFile file, string root);
        void Delete(string filepath);
        string Update(IFormFile file, string filePath, string root);


    }
}

Затем менеджер мы можем управлять ими в этом классе с комментариями.

namespace Core.Utilities.Helpers.FileHelper
{
    //in this Class we will do CRUD(Create,Read,Update,Delete) operations for file.

    public class FileHelperManager : IFileHelperService
    {




        //We can upload the File in this root(in this way)
        //filepath is coming from ICarImageManager ,root is =jpeg it means way,which type of file
        public string Upload(IFormFile file, string root)
        {
            //if File Length is 0 return the null
            //it has a byte it means... it has a memory or no checking
            if (file.Length > 0)
            {
                //it is checking .jpeg have or no doesnt have it will create the way.
                if (!Directory.Exists(root))
                {
                    //this one is for UI memory working like that.firstly checking (random way=we created for photos in manager) have or no then
                    //dont have then again create the way for IU to save file in the service
                    Directory.CreateDirectory(root);
                }
                //extension is defined the extention variables file name
                string extension = Path.GetExtension(file.FileName);

               //which way will use the system we created random file way like that for safe.and guid was defined the this random numbers in the jpeg.
                string guid = GuidHelpers.GuidHelpers.CreatGuid();
                //then filepath was defined the total name and which way
                string filePath = guid + extension;

                //root and filepath created with IDısposable pattern
               //it means after do that then  will deleted with garbage collector
                using (FileStream fileStream = File.Create(root + filePath))
                {
                    //it is defined the with copy method in file full name
                    file.CopyTo(fileStream);
                    //then delete the flush in memory to new something.
                    fileStream.Flush();

                    return filePath;
                }
            }
            return null;
        }
        //filepath is coming from ICarImageManager 
        public void Delete(string filePath)
        {//if filepath way has a same file then we can delete the filePath
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }
        }
        public string Update(IFormFile file, string filePath, string root)
        {
            //firstly We are checking file have or no than if it has firstly delete it then Upload the new file with way(root) 
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }
            return Upload(file, root);
        }
    }
}

Также мы хотим добавить правила в операцию CRUD, поэтому мы используем BusinessRules. Давайте создадим его.

Почему мы используем бизнес-правила на основном уровне, потому что они могут обеспечить устойчивость, и мы можем проверить все правила в операции CRUD. Также мы использовали полиморфизм, чтобы использовать больше, чем правила, там вы можете увидеть внизу коды с комментариями…!

namespace Core.Utilities.Business
{
    //if we create the Service it will be overdesign...
    public class BusinessRules
    {
        public static IResult Run(params IResult[] logics)
        {

            foreach ( var logic in logics)
            {
                //if logic unsuccess then it will give us the error.
                if (!logic.Success)
                {
                    return logic;
                }
               
            }
            //if succes it can do operations.
            return null;
        }
    }
}

Теперь мы можем добавить правила в менеджере.

Нам нужен ConstantsPath для файлов Давайте создадим его…

namespace Business.Constants
{
    public class PathConstants
    {
        public const string CarImagesPath = "root\\Uploads\\CarImages";
    }
}

5,6,7,8)

Сначала добавлены все сервисы в BusinessLayer…

Все операции Crud и бизнес-правила внизу

public interface ICarImageService
    {


        IDataResult<List<CarImage>> GetImagesByCarId(int id);
        IDataResult<List<CarImage>> GetAll();
        IDataResult<CarImage> GetById(int id);
        IResult Add(IFormFile file,CarImage carImage);
        IResult Update(IFormFile file,CarImage carImage);
        IResult Delete(CarImage carImage);

    }

Затем работает в ManagerClass для CarImage на бизнес-уровне.

namespace Business.Concrete
{
    public class CarImageManager : ICarImageService
    {
        ICarImageDal _carImageDal;
        IFileHelperService _fileHelperService;


        public CarImageManager(ICarImageDal carImageDal,IFileHelperService fileHelperService)
        {
            _carImageDal = carImageDal;
            _fileHelperService = fileHelperService;

        }

        
        //IFormFile it means for HTTP protocol for file to request.
        public IResult Add(IFormFile file, CarImage carImage)
        {
            //used the Polymorphism to use rules. I wrote the rule method at below side
            IResult result = BusinessRules.Run(CheckForCarImageLimit(carImage.CarId));
            if (result != null)
            {
                return result;
            }
            carImage.ImagePath = _fileHelperService.Upload(file, PathConstants.CarImagesPath);
            carImage.ImageDate = DateTime.Now;

            _carImageDal.Add(carImage);
            return new SuccessResult(Messages.ImageAdded);

        }

        public IResult Delete(CarImage carImage)
        {
            //for safety we added each other after that we can find the way then we can delete it.
            _fileHelperService.Delete(PathConstants.CarImagesPath + carImage.ImagePath);
            //then we delete the in dataBase.
            _carImageDal.Delete(carImage);

            return new SuccessResult(Messages.CarImageDeleted);

        }

        public IDataResult<CarImage> GetById(int id)
        {
            return new SuccessDataResult<CarImage>(_carImageDal.Get(i => i.Id == id), Messages.ImagesListedById);
          
        }

        public IResult Update(IFormFile file, CarImage carImage)
        {
            //Firstly Update the ImageFilePath
            carImage.ImagePath = _fileHelperService.Update(file, PathConstants.CarImagesPath + carImage.ImagePath, 
                PathConstants.CarImagesPath);
           //Then Update the Upload time for image.When they uploaded in the system.
            carImage.ImageDate = DateTime.Now;
            //Then Update the Database ImageFilePath
            _carImageDal.Update(carImage);
            //everything Success result messages
            return new SuccessResult(Messages.ImageUpdated);
        }
        public IDataResult<List<CarImage>> GetAll()
        {
            return new SuccessDataResult<List<CarImage>>(_carImageDal.GetAll(), Messages.ImagesListed);
        }

        public IDataResult<List<CarImage>> GetImagesByCarId(int id)
        {
            IResult result = BusinessRules.Run(CheckImageExists(id));
            if (result != null)
            {
                return new ErrorDataResult<List<CarImage>>(GetDefaultImage(id).Data);
            }

            return new SuccessDataResult<List<CarImage>>(_carImageDal.GetAll(c => c.CarId == id), Messages.ImagesListedByCarId);
        }

        //ImageLimit can not more 5 photos...
        private IResult CheckForCarImageLimit(int carId)
        {
            var result = _carImageDal.GetAll(i => i.CarId == carId).Count;
            if (result > 5)
            {
                return new ErrorResult(Messages.CarImageLimitReached);
            }
            return new SuccessResult();

        }

        private IResult CheckImageExists(int carId)
        {
            var result = _carImageDal.GetAll(i => i.CarId == carId).Count;

            if (result > 0)
            {
                return new ErrorResult(Messages.CarImageAlreadyHave);
            }
            return new SuccessResult();

        }
        private IDataResult<List<CarImage>> GetDefaultImage(int carId)
        {

            List<CarImage> carImages = new List<CarImage>();

            carImages.Add(new CarImage { CarId = carId, ImageDate = DateTime.Now, ImagePath = "DefaultImage.jpg" });

            return new SuccessDataResult<List<CarImage>>(carImages);
        }

    }

}

Также, когда мы подключаемся к серверу PostgreSql, выдается ошибка времени, поэтому мы должны сопоставить время

Затем я ищу и могу найти подобное решение времени.

И подключитесь к базе данных для CarImage

namespace DataAccess.Concrete.EntityFramework
{
    //Context is matching Db files and project classes...
    public class CarContext:DbContext
    {
        //we are selecting the which database
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseNpgsql(@"Host = localhost; Username = postgres; Password = 1234; Database = RentCarDB; Pooling = true;");
            //Connection String..
            //for time enable to working with together time.
            AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

        }
        //which object in sql server match which object in project we are doint it
        public DbSet<Car> Cars { get; set; }
        public DbSet<Brand> Brands { get; set; }
        public DbSet<Color> Colors { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Rental> Rentals { get; set; }
        public DbSet<CarImage> CarImages { get; set; }



    }
}

Затем я добавил всю операцию CRUD для файла изображения в webAPI, давайте посмотрим коды с комментариями…

namespace WebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CarImagesController : ControllerBase
    {
        //Firstly Let's create the Loosely Coopled...
        ICarImageService _carImageService;

        public CarImagesController(ICarImageService carImageService)
        {
            _carImageService = carImageService;
        }



        //Used add naming to understand
        [HttpPost("add")]
        //Used CarImage to added entity for database
        public IActionResult Add([FromForm] IFormFile file, [FromForm] CarImage carImage)
        {
            //carimage coming from UI then added the system
            var result = _carImageService.Add(file,carImage);
            if (result.Success)
            {
                //http 200 code
                return Ok(result);
            }
            //http 400 code
            return BadRequest(result);
        }
        [HttpPost("update")]
        public IActionResult Update([FromForm] IFormFile file , [FromForm] CarImage carImage)
        {
            var result = _carImageService.Update(file, carImage);
            if (result.Success)
            {
                return Ok(result);

            }
            return BadRequest(result);
        }

        [HttpPost("delete")]
        public IActionResult Delete(CarImage carImage)
        {
            //We find the which Id in DataBase
            var carDeleteImage = _carImageService.GetById(carImage.Id).Data;
            //then we deleted in the database
            var result = _carImageService.Delete(carDeleteImage);

            if (result.Success)
            {
                return Ok(result);
            }
            return BadRequest(result);
        }

        [HttpGet("getall")]
        public IActionResult GetAll()
        {
            var result = _carImageService.GetAll();

            if (result.Success)
            {
                return Ok(result);
            }
            return BadRequest(result);
        }
        [HttpGet("getbyid")]
        public IActionResult GetbyId(int id)
        {
            var result = _carImageService.GetById(id);

            if (result.Success)
            {
                return Ok(result);
            }
            return BadRequest(result);
        }
        [HttpGet("getimagebycarid")]
        public IActionResult GetImagesByCarId(int carId)
        {
            var result = _carImageService.GetImagesByCarId(carId);
            if (result.Success)
            {
                return Ok(result);
            }
            return BadRequest(result);
        }


    }
}

Давайте попробуем в Postman

файл должен выбрать параметры файла, а затем добавить jpeg с ПК.

Затем мы можем добавить их в Postman.

GitHup=https://github.com/muratozeee/ReCapProject