How to Web API .Net Core Basics to Advanced Part 4 Service Layer

Service Layer
Welcome back!

In How to Web API .Net Core Basics to Advanced Part 2 Data Access Layer article we talked about separation of concern and how to isolate our application in different layers based on their domain and we implimented Data Acc…


This content originally appeared on DEV Community and was authored by Manik

Service Layer
Welcome back!

In How to Web API .Net Core Basics to Advanced Part 2 Data Access Layer article we talked about separation of concern and how to isolate our application in different layers based on their domain and we implimented Data Access Layer by using Repository pattern. In this article we are going to Impliment Business Layer.

Asp.Net 5 Web API Service Layer

To impliment our Business/Service layer we will also make use of Dtos to pass data from our Entities/Models to our presentation layer (Controller) which further isolate our front end.

*Question is what is a service layer? *
Service layer is the middle layer between presentation layer and data layer (Repository). It abstracts business logic and data access.This provides easier management, better abstraction and scalability.

Asp.Net 5 Web API Service Layer

We can start with creating five folders in our project, first one Service to keep our CompanyService.cs class file, at the same time let us create Contract folder inside Service folder to keep our interface class file ICompanyService.cs next, we can create a folder Dtos and create another folder called Company to keep our Company Dtos and the last folder ServiceResponder to keep our ServiceResponse.cs file which we will use to wrap our API response to provide a more meaningful response when a request is sent to our API.

Let us start by creating our Dtos

CompanyDto.cs

public class CompanyDto
    {

        public int Id { get; set; }
        public Guid GUID { get; set; }
        [Required]
        [RegularExpression(@"[a-zA-Z0-9._@+-]{2,150}",
              ErrorMessage = "The {0} must be 1 to 150 valid characters which are any digit, any letter and -._@+.")]
        [StringLength(150, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 2)]
        [Display(Name = "CompanyName")]
        public string CompanyName { get; set; }
        public DateTimeOffset CreatedDate { get; set; }
        public bool IsEnabled { get; set; }
        public bool IsDeleted { get; set; }
    }

CreateCompanyDto.cs

public class CreateCompanyDto
    {
        [Required(ErrorMessage = "Company name is required")]
        [MinLength(2, ErrorMessage = "Company Name can not be less than two characters")]
        [MaxLength(150, ErrorMessage = "Company Name to long")]
        public string CompanyName { get; set; }

    }

UpdateCompanyDto.cs

public class UpdateCompanyDto
    {
        public Guid GUID { get; set; }
        [Required]
        public string CompanyName { get; set; }        
        public bool IsEnabled { get; set; }
        public bool IsDeleted { get; set; }
    }

Once we are happy with our Dtos we can create our generic API response wrapper.

public class ServiceResponse<T>
     /// <summary>
    /// Generic wrapper for web api response.       
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ServiceResponse<T>
    {

        public T Data { get; set; }
        public bool Success { get; set; } = true;
        public string Message { get; set; } = null;
        public string Error { get; set; } = null;
        public List<string> ErrorMessages { get; set; } = null;
    }

Now we can start writing code in our ICompanyService.cs and CompanyService.cs files.

ICompanyService.cs

    public interface ICompanyService
    {
        /// <summary>
        /// Return list of companies which are not marked as deleted.
        /// </summary>
        /// <returns>List Of CompanyDto</returns>
        Task<ServiceResponse<List<Dtos.Company.CompanyDto>>> GetCompaniesAsync();
        /// <summary>
        /// Return company record.
        /// </summary>
        /// <param name="Id"></param>
        /// <returns>CompanyDto</returns>
        Task<ServiceResponse<Dtos.Company.CompanyDto>> GetByIdAsync(int Id);
        /// <summary>
        /// Return company record.
        /// </summary>
        /// <param name="guid"></param>
        /// <returns>CompanyDto</returns>
        Task<ServiceResponse<Dtos.Company.CompanyDto>> GetByGUIDAsync(Guid guid);
        /// <summary>
        /// Add new company record in db
        /// </summary>
        /// <param name="createCompanyDto"></param>
        /// <returns>CompanyDto</returns>
        Task<ServiceResponse<Dtos.Company.CompanyDto>> AddCompanyAsync(Dtos.Company.CreateCompanyDto createCompanyDto);
        /// <summary>
        /// Update company record
        /// </summary>
        /// <param name="updateCompanyDto"></param>
        /// <returns>CompanyDto</returns>
        Task<ServiceResponse<Dtos.Company.CompanyDto>> UpdateCompanyAsync(Dtos.Company.UpdateCompanyDto updateCompanyDto);
        /// <summary>
        /// Mark the company record as deleted
        /// </summary>
        /// <param name="guid"></param>
        /// <returns>bool</returns>
        Task<ServiceResponse<string>> SoftDeleteCompanyAsync(Guid guid);

    }

And here our CompanyService.cs file.


public class CompanyService : ICompanyService
    {
        private readonly ICompanyRepository _compRepo;
        private readonly IMapper _mapper;

        public CompanyService(ICompanyRepository companyRepository, IMapper mapper)
        {
            this._compRepo = companyRepository;
            this._mapper = mapper;
        }
        public async Task<ServiceResponse<CompanyDto>> AddCompanyAsync(CreateCompanyDto createCompanyDto)
        {
            ServiceResponse<CompanyDto> _response = new();
            try
            {


                //Check If company exist
                if (await _compRepo.CompanyExistAsync(createCompanyDto.CompanyName))
                {
                    _response.Message = "Exist";
                    _response.Success = false;
                    _response.Data = null;
                    return _response;

                }

                Entities.Company _newCompany = new()
                {

                    CompanyName = createCompanyDto.CompanyName,
                    GUID = Guid.NewGuid(),
                    CreatedDate = DateTimeOffset.UtcNow,
                    IsEnabled = true,
                    IsDeleted = true
                };

                //Add new record
                if (!await _compRepo.CreateCompanyAsync(_newCompany))
                {
                    _response.Error = "RepoError";
                    _response.Success = false;
                    _response.Data = null;
                    return _response;
                }

                _response.Success = true;
                _response.Data = _mapper.Map<CompanyDto>(_newCompany);
                _response.Message = "Created";

            }
            catch (Exception ex)
            {
                _response.Success = false;
                _response.Data = null;
                _response.Message = "Error";
                _response.ErrorMessages = new List<string> { Convert.ToString(ex.Message) };

            }
            return _response;
        }

        public async Task<ServiceResponse<CompanyDto>> GetByGUIDAsync(Guid CompanyGUID)
        {
            ServiceResponse<CompanyDto> _response = new();

            try
            {

                var _Company = await _compRepo.GetCompanyByGUIDAsync(CompanyGUID);

                if (_Company == null)
                {
                    _response.Success = false;
                    _response.Message = "NotFound";
                    return _response;
                }

                var _CompanyDto = _mapper.Map<CompanyDto>(_Company);

                _response.Success = true;
                _response.Message = "ok";
                _response.Data = _CompanyDto;


            }
            catch (Exception ex)
            {
                _response.Success = false;
                _response.Data = null;
                _response.Message = "Error";
                _response.ErrorMessages = new List<string> { Convert.ToString(ex.Message) };
            }

            return _response;
        }

        public async Task<ServiceResponse<CompanyDto>> GetByIdAsync(int Id)
        {
            ServiceResponse<CompanyDto> _response = new();

            try
            {


                var _Company = await _compRepo.GetCompanyByIDAsync(Id);

                if (_Company == null)
                {

                    _response.Success = false;
                    _response.Message = "Not Found";
                    return _response;
                }

                var _CompanyDto = _mapper.Map<CompanyDto>(_Company);

                _response.Success = true;
                _response.Message = "ok";
                _response.Data = _CompanyDto;

            }
            catch (Exception ex)
            {
                _response.Success = false;
                _response.Data = null;
                _response.Message = "Error";
                _response.ErrorMessages = new List<string> { Convert.ToString(ex.Message) };
            }

            return _response;
        }

        public async Task<ServiceResponse<List<CompanyDto>>> GetCompaniesAsync()
        {
            ServiceResponse<List<CompanyDto>> _response = new();

            try
            {

                var CompaniesList = await _compRepo.GetCompaniesAsync();

                var CompanyListDto = new List<CompanyDto>();

                foreach (var item in CompaniesList)
                {
                    CompanyListDto.Add(_mapper.Map<CompanyDto>(item));
                }

                //OR 
                //CompanyListDto.AddRange(from item in CompaniesList select _mapper.Map<CompanyDto>(item));
                _response.Success = true;
                _response.Message = "ok";
                _response.Data = CompanyListDto;

            }
            catch (Exception ex)
            {
                _response.Success = false;
                _response.Data = null;
                _response.Message = "Error";
                _response.ErrorMessages = new List<string> { Convert.ToString(ex.Message) };
            }

            return _response;
        }

        public async Task<ServiceResponse<string>> SoftDeleteCompanyAsync(Guid CompanyGUID)
        {
            ServiceResponse<string> _response = new();

            try
            {
                //check if record exist
                var _existingCompany = await _compRepo.CompanyExistAsync(CompanyGUID);

                if (_existingCompany == false)
                {
                    _response.Success = false;
                    _response.Message = "NotFound";
                    _response.Data = null;
                    return _response;

                }

                if (!await _compRepo.SoftDeleteCompanyAsync(CompanyGUID))
                {
                    _response.Success = false;
                    _response.Message = "RepoError";
                    return _response;
                }



                _response.Success = true;
                _response.Message = "SoftDeleted";

            }
            catch (Exception ex)
            {

                _response.Success = false;
                _response.Data = null;
                _response.Message = "Error";
                _response.ErrorMessages = new List<string> { Convert.ToString(ex.Message) };
            }
            return _response;
        }

        public async Task<ServiceResponse<CompanyDto>> UpdateCompanyAsync(UpdateCompanyDto updateCompanyDto)
        {
            ServiceResponse<CompanyDto> _response = new();

            try
            {
                //check if record exist
                var _existingCompany = await _compRepo.GetCompanyByGUIDAsync(updateCompanyDto.GUID);

                if (_existingCompany == null)
                {
                    _response.Success = false;
                    _response.Message = "NotFound";
                    _response.Data = null;
                    return _response;

                }

                //Update
                _existingCompany.CompanyName = updateCompanyDto.CompanyName;
                _existingCompany.IsEnabled = updateCompanyDto.IsEnabled;
                _existingCompany.IsDeleted = updateCompanyDto.IsDeleted;

                if (!await _compRepo.UpdateCompanyAsync(_existingCompany))
                {
                    _response.Success = false;
                    _response.Message = "RepoError";
                    _response.Data = null;
                    return _response;
                }

                //Map updateCompanyDto To Company
                var _companyDto = _mapper.Map<CompanyDto>(_existingCompany);
                _response.Success = true;
                _response.Message = "Updated";
                _response.Data = _companyDto;

            }
            catch (Exception ex)
            {

                _response.Success = false;
                _response.Data = null;
                _response.Message = "Error";
                _response.ErrorMessages = new List<string> { Convert.ToString(ex.Message) };
            }
            return _response;
        }
    }


Well done! We managed to get our service layer up and running, time to move on and set up our presentation layer which is controllers. In the next article we are going to set up our first controller.

Part 5 Controllers/Get/Put/Post/Delete coming soon....

<<<Part 3 How to Web API Core set up Data Access Layer
<<<Part 2 How to Web API Core set up Database Context
<<<Part 1 How to set up Web API core project


This content originally appeared on DEV Community and was authored by Manik


Print Share Comment Cite Upload Translate Updates
APA

Manik | Sciencx (2021-07-12T14:29:12+00:00) How to Web API .Net Core Basics to Advanced Part 4 Service Layer. Retrieved from https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/

MLA
" » How to Web API .Net Core Basics to Advanced Part 4 Service Layer." Manik | Sciencx - Monday July 12, 2021, https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/
HARVARD
Manik | Sciencx Monday July 12, 2021 » How to Web API .Net Core Basics to Advanced Part 4 Service Layer., viewed ,<https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/>
VANCOUVER
Manik | Sciencx - » How to Web API .Net Core Basics to Advanced Part 4 Service Layer. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/
CHICAGO
" » How to Web API .Net Core Basics to Advanced Part 4 Service Layer." Manik | Sciencx - Accessed . https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/
IEEE
" » How to Web API .Net Core Basics to Advanced Part 4 Service Layer." Manik | Sciencx [Online]. Available: https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/. [Accessed: ]
rf:citation
» How to Web API .Net Core Basics to Advanced Part 4 Service Layer | Manik | Sciencx | https://www.scien.cx/2021/07/12/how-to-web-api-net-core-basics-to-advanced-part-4-service-layer/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.