diff --git a/Birdmap.API/Controllers/ServiceController.cs b/Birdmap.API/Controllers/ServiceController.cs new file mode 100644 index 0000000..b68f955 --- /dev/null +++ b/Birdmap.API/Controllers/ServiceController.cs @@ -0,0 +1,103 @@ +using AutoMapper; +using Birdmap.API.DTOs; +using Birdmap.BLL.Interfaces; +using Birdmap.DAL.Entities; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Runtime.InteropServices.ComTypes; +using System.Threading.Tasks; + +namespace Birdmap.API.Controllers +{ + [Authorize] + [ApiController] + [Route("api/[controller]")] + public class ServiceController : ControllerBase + { + private readonly IServiceService _service; + private readonly IMapper _mapper; + private readonly ILogger _logger; + + public ServiceController(IServiceService service, IMapper mapper, ILogger logger) + { + _service = service; + _mapper = mapper; + _logger = logger; + } + + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + public async Task>> GetAsync() + { + _logger.LogInformation($"Getting all services from db..."); + var serviceInfos = (await _service.GetAllServicesAsync()) + .Select(s => new ServiceInfo { Service = _mapper.Map(s) }); + + var client = new HttpClient(); + foreach (var si in serviceInfos) + { + try + { + _logger.LogInformation($"Sending a request to service '{si.Service.Name}' with url '{si.Service.Uri}'..."); + var response = await client.GetAsync(si.Service.Uri); + si.StatusCode = response.StatusCode; + si.Response = await response.Content.ReadAsStringAsync(); + } + catch (Exception ex) + { + _logger.LogWarning($"Requesting service '{si.Service.Name}' faulted."); + si.StatusCode = System.Net.HttpStatusCode.ServiceUnavailable; + si.Response = ex.ToString(); + } + } + + return serviceInfos.ToList(); + } + + [HttpPost] + [ProducesResponseType(StatusCodes.Status201Created)] + public async Task> PostAsync(ServiceRequest request) + { + _logger.LogInformation($"Creating service {request.Name}..."); + var created = await _service.CreateServiceAsync( + _mapper.Map(request)); + + _logger.LogInformation($"Created service [{created.Id}]."); + + return CreatedAtAction( + nameof(GetAsync), + _mapper.Map(created)); + } + + [HttpPut] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task PutAsync(ServiceRequest request) + { + _logger.LogInformation($"Updating service {request.Name}..."); + var service = _mapper.Map(request); + service.IsFromConfig = false; + + await _service.UpdateServiceAsync(service); + + return NoContent(); + } + + [HttpDelete("{id}")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + public async Task DeleteAsync(int id) + { + _logger.LogInformation($"Deleting service [{id}]..."); + + await _service.DeleteServiceAsync(id); + + return NoContent(); + } + } +} diff --git a/Birdmap.API/DTOs/ServiceInfo.cs b/Birdmap.API/DTOs/ServiceInfo.cs new file mode 100644 index 0000000..2150eaf --- /dev/null +++ b/Birdmap.API/DTOs/ServiceInfo.cs @@ -0,0 +1,11 @@ +using System.Net; + +namespace Birdmap.API.DTOs +{ + public class ServiceInfo + { + public ServiceRequest Service { get; set; } + public HttpStatusCode StatusCode { get; set; } + public string Response { get; set; } + } +} diff --git a/Birdmap.API/DTOs/ServiceRequest.cs b/Birdmap.API/DTOs/ServiceRequest.cs new file mode 100644 index 0000000..ca99642 --- /dev/null +++ b/Birdmap.API/DTOs/ServiceRequest.cs @@ -0,0 +1,9 @@ +namespace Birdmap.API.DTOs +{ + public class ServiceRequest + { + public int Id { get; set; } + public string Name { get; set; } + public string Uri { get; set; } + } +} diff --git a/Birdmap.API/MapperProfiles/BirdmapProfile.cs b/Birdmap.API/MapperProfiles/BirdmapProfile.cs index 1955f38..f2132a0 100644 --- a/Birdmap.API/MapperProfiles/BirdmapProfile.cs +++ b/Birdmap.API/MapperProfiles/BirdmapProfile.cs @@ -1,5 +1,7 @@ using AutoMapper; +using Birdmap.API.DTOs; using Birdmap.DAL.Entities; +using System; namespace Birdmap.API.MapperProfiles { @@ -7,10 +9,31 @@ namespace Birdmap.API.MapperProfiles { public BirdmapProfile() { - CreateMap() + CreateMap().ConvertUsing(); + CreateMap().ConvertUsing(); + + CreateMap() .ForMember(m => m.Username, opt => opt.MapFrom(m => m.Name)) .ForMember(m => m.UserRole, opt => opt.MapFrom(m => m.Role)) .ReverseMap(); + + CreateMap() + .ReverseMap(); + } + + private class UriToStringConverter : ITypeConverter, ITypeConverter + { + public string Convert(Uri source, string destination, ResolutionContext context) + { + destination = source.ToString(); + return destination; + } + + public Uri Convert(string source, Uri destination, ResolutionContext context) + { + Uri.TryCreate(source, UriKind.Absolute, out destination); + return destination; + } } } } diff --git a/Birdmap.BLL/Interfaces/IServiceService.cs b/Birdmap.BLL/Interfaces/IServiceService.cs new file mode 100644 index 0000000..7db279b --- /dev/null +++ b/Birdmap.BLL/Interfaces/IServiceService.cs @@ -0,0 +1,15 @@ +using Birdmap.DAL.Entities; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Birdmap.BLL.Interfaces +{ + public interface IServiceService + { + Task> GetAllServicesAsync(); + Task GetServiceAsync(int id); + Task CreateServiceAsync(Service service); + Task DeleteServiceAsync(int id); + Task UpdateServiceAsync(Service service); + } +} diff --git a/Birdmap.BLL/Services/ServiceService.cs b/Birdmap.BLL/Services/ServiceService.cs new file mode 100644 index 0000000..04c63ea --- /dev/null +++ b/Birdmap.BLL/Services/ServiceService.cs @@ -0,0 +1,55 @@ +using Birdmap.BLL.Exceptions; +using Birdmap.BLL.Interfaces; +using Birdmap.DAL; +using Birdmap.DAL.Entities; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Birdmap.BLL.Services +{ + public class ServiceService : IServiceService + { + private readonly BirdmapContext _context; + + public ServiceService(BirdmapContext context) + { + _context = context; + } + + public async Task CreateServiceAsync(Service service) + { + _context.Services.Add(service); + await _context.SaveChangesAsync(); + + return service; + } + + public Task DeleteServiceAsync(int id) + { + var service = _context.Services.Find(id); + if (service == null) + return Task.CompletedTask; + + _context.Services.Remove(service); + return _context.SaveChangesAsync(); + } + + public Task> GetAllServicesAsync() + { + return _context.Services.ToListAsync(); + } + + public async Task GetServiceAsync(int id) + { + return await _context.Services.SingleOrDefaultAsync(s => s.Id == id) + ?? throw new EntityNotFoundException($"Cannot find service with id: {id}."); + } + + public Task UpdateServiceAsync(Service service) + { + _context.Services.Update(service); + return _context.SaveChangesAsync(); + } + } +} diff --git a/Birdmap.BLL/Startup.cs b/Birdmap.BLL/Startup.cs index e6f3dd3..a3b9480 100644 --- a/Birdmap.BLL/Startup.cs +++ b/Birdmap.BLL/Startup.cs @@ -11,6 +11,7 @@ namespace Birdmap.BLL { services.AddTransient(); services.AddTransient(); + services.AddTransient(); return services; } diff --git a/Birdmap.DAL/DbInitializer.cs b/Birdmap.DAL/DbInitializer.cs index 6f85bd1..b578247 100644 --- a/Birdmap.DAL/DbInitializer.cs +++ b/Birdmap.DAL/DbInitializer.cs @@ -2,7 +2,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.Linq; using static Birdmap.Common.PasswordHelper;