Skip to content

Developing Application Layer

Mehmet Özkaya edited this page Mar 25, 2019 · 1 revision

Developing Application Layer

When we finished to Infrastructure layer operations its good to continue with Application Layer in order to implement our business logics, use case operations. The first point of implementation is definition of Dtos.

Its not mandatory to create and implement Dto classes, You can use direct Core entities but its good to seperate entity and application required objects.

 public class ProductDto : BaseDto
    {
        public string ProductName { get; set; }
        public string QuantityPerUnit { get; set; }
        public decimal? UnitPrice { get; set; }
        public short? UnitsInStock { get; set; }
        public short? UnitsOnOrder { get; set; }
        public short? ReorderLevel { get; set; }
        public bool Discontinued { get; set; }
        public int? CategoryId { get; set; }
        public CategoryDto Category { get; set; }
    }
public class CategoryDto : BaseDto
    {
        public string CategoryName { get; set; }
        public string Description { get; set; }        
        public ICollection<ProductDto> Products { get; set; }
    }

As you can see that these Dto classes inherit BaseDto.cs.

Application Interfaces and Implementations

The use case of projects should be handled by Application layer. So we are creating Interface and Implementation classes as below way.

Interfaces ;

public interface IProductAppService
    {
        Task<IEnumerable<ProductDto>> GetProductList();
        Task<ProductDto> GetProductById(int productId);
        Task<IEnumerable<ProductDto>> GetProductByName(string productName);
        Task<IEnumerable<ProductDto>> GetProductByCategory(int categoryId);
        Task<ProductDto> Create(ProductDto entityDto);
        Task Update(ProductDto entityDto);
        Task Delete(ProductDto entityDto);
    }
public interface ICategoryAppService
    {
        Task<IEnumerable<CategoryDto>> GetCategoryList();
    }

Implementations ;

public class ProductAppService : IProductAppService
    {
        private readonly IProductRepository _productRepository;
        private readonly IAppLogger<ProductAppService> _logger;

        public ProductAppService(IProductRepository productRepository, IAppLogger<ProductAppService> logger)
        {
            _productRepository = productRepository ?? throw new ArgumentNullException(nameof(productRepository));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public async Task<IEnumerable<ProductDto>> GetProductList()
        {
            var productList = await _productRepository.GetProductListAsync();
            var mapped = ObjectMapper.Mapper.Map<IEnumerable<ProductDto>>(productList);
            return mapped;
        }

        public async Task<ProductDto> GetProductById(int productId)
        {
            var product = await _productRepository.GetByIdAsync(productId);
            var mapped = ObjectMapper.Mapper.Map<ProductDto>(product);
            return mapped;
        }

        public async Task<IEnumerable<ProductDto>> GetProductByName(string productName)
        {
            var productList = await _productRepository.GetProductByNameAsync(productName);
            var mapped = ObjectMapper.Mapper.Map<IEnumerable<ProductDto>>(productList);
            return mapped;
        }

        public async Task<IEnumerable<ProductDto>> GetProductByCategory(int categoryId)
        {
            var productList = await _productRepository.GetProductByCategoryAsync(categoryId);
            var mapped = ObjectMapper.Mapper.Map<IEnumerable<ProductDto>>(productList);
            return mapped;
        }

        public async Task<ProductDto> Create(ProductDto entityDto)
        {
            await ValidateProductIfExist(entityDto);

            var mappedEntity = ObjectMapper.Mapper.Map<Product>(entityDto);
            if (mappedEntity == null)
                throw new ApplicationException($"Entity could not be mapped.");

            var newEntity = await _productRepository.AddAsync(mappedEntity);
            _logger.LogInformation($"Entity successfully added - AspnetRunAppService");

            var newMappedEntity = ObjectMapper.Mapper.Map<ProductDto>(newEntity);
            return newMappedEntity;
        }

        public async Task Update(ProductDto entityDto)
        {
            ValidateProductIfNotExist(entityDto);

            var mappedEntity = ObjectMapper.Mapper.Map<Product>(entityDto);
            if (mappedEntity == null)
                throw new ApplicationException($"Entity could not be mapped.");

            await _productRepository.UpdateAsync(mappedEntity);
            _logger.LogInformation($"Entity successfully updated - AspnetRunAppService");
        }

        public async Task Delete(ProductDto entityDto)
        {
            ValidateProductIfNotExist(entityDto);

            var mappedEntity = ObjectMapper.Mapper.Map<Product>(entityDto);
            if (mappedEntity == null)
                throw new ApplicationException($"Entity could not be mapped.");

            await _productRepository.DeleteAsync(mappedEntity);
            _logger.LogInformation($"Entity successfully deleted - AspnetRunAppService");
        }

        private async Task ValidateProductIfExist(ProductDto entityDto)
        {
            var existingEntity = await _productRepository.GetByIdAsync(entityDto.Id);
            if (existingEntity != null)
                throw new ApplicationException($"{entityDto.ToString()} with this id already exists");
        }

        private void ValidateProductIfNotExist(ProductDto entityDto)
        {
            var existingEntity = _productRepository.GetByIdAsync(entityDto.Id);
            if (existingEntity == null)
                throw new ApplicationException($"{entityDto.ToString()} with this id is not exists");
        }
    }
public class CategoryAppService : ICategoryAppService
    {
        private readonly ICategoryRepository _categoryRepository;
        private readonly IAppLogger<CategoryAppService> _logger;

        public CategoryAppService(ICategoryRepository categoryRepository, IAppLogger<CategoryAppService> logger)
        {
            _categoryRepository = categoryRepository ?? throw new ArgumentNullException(nameof(categoryRepository));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public async Task<IEnumerable<CategoryDto>> GetCategoryList()
        {
            var category = await _categoryRepository.GetAllAsync();
            var mapped = ObjectMapper.Mapper.Map<IEnumerable<CategoryDto>>(category);
            return mapped;
        }        
        
    }

All validation , authorization, logging, exception handling etc. -- this kind of cross cutting activities should be handled by these classes.

Clone this wiki locally