Compare commits

..

2 Commits

Author SHA1 Message Date
c805ce20a8 working customer post, get and delete 2023-06-07 14:47:00 +02:00
ad998e0499 remove example controller 2023-06-07 14:46:17 +02:00
28 changed files with 448 additions and 188 deletions

View File

@ -8,11 +8,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\AB.API\AB.API.csproj" /> <ProjectReference Include="..\AB.API\AB.API.csproj" />
<ProjectReference Include="..\AB.Persistence\AB.Persistence.csproj" />
<ProjectReference Include="..\AB.Services\AB.Services.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,33 +0,0 @@
using Microsoft.AspNetCore.Mvc;
namespace AB_API.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

View File

@ -1,3 +1,12 @@
using AB.Domain.Repositories;
using AB.Persistence;
using AB.Persistence.Repos;
using AB.Services;
using AB.Services.Abstractions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
@ -5,7 +14,17 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers().AddApplicationPart(typeof(AB.API.AssemblyReference).Assembly); builder.Services.AddControllers().AddApplicationPart(typeof(AB.API.AssemblyReference).Assembly);
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(); builder.Services.AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "AB-API", Version = "v1" , Description = "An Api for the AB-Application"}));
builder.Services.AddScoped<ICustomerService, CustomerService>();
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
builder.Services.AddDbContextPool<RepoDbContext>(builder =>
{
builder.UseInMemoryDatabase("test");
});
var app = builder.Build(); var app = builder.Build();

View File

@ -1,13 +0,0 @@
namespace AB_API
{
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@ -0,0 +1,51 @@
using AB.Contracts;
using AB.Services.Abstractions;
using Microsoft.AspNetCore.Mvc;
namespace AB.API.Controllers.BusinessPartner;
[ApiController]
[Route("api/customers")]
public class CustomerController : ControllerBase
{
private readonly ICustomerService _customerService;
public CustomerController(ICustomerService customerService)
{
_customerService = customerService;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<CustomerDto>>> GetCustomers(CancellationToken cancellationToken)
{
var customers = await _customerService.GetAllAsync(cancellationToken);
return Ok(customers);
}
[HttpGet("{customerId:guid}")]
public async Task<ActionResult<CustomerDto>> GetCustomerById(Guid customerId, CancellationToken cancellationToken)
{
var customer = await _customerService.GetByIdAsync(customerId, cancellationToken);
return Ok(customer);
}
[HttpPost]
public async Task<CreatedAtActionResult> CreateCustomer([FromBody] CustomerForCreationDto customerForCreation)
{
var customerDto = await _customerService.CreateAsync(customerForCreation);
return CreatedAtAction(nameof(CreateCustomer), new { customerId = customerDto.Id }, customerDto);
}
[HttpDelete("{customerId:guid}")]
public async Task<NoContentResult> DeleteCustomer(Guid customerId, CancellationToken cancellationToken)
{
await _customerService.DeleteAsync(customerId, cancellationToken);
return NoContent();
}
}

View File

@ -0,0 +1,48 @@
using AB.Contracts;
using AB.Services.Abstractions;
using Microsoft.AspNetCore.Mvc;
namespace AB.API.Controllers.BusinessPartner;
[ApiController]
[Route("api/suppliers")]
public class SupplierController : ControllerBase
{
public readonly ISupplierService _supplierService;
[HttpGet]
public async Task<ActionResult<IEnumerable<SupplierDto>>> GetSupplieres(CancellationToken cancellationToken)
{
var suppliers = await _supplierService.GetAllAsync(cancellationToken);
return Ok(suppliers);
}
[HttpGet("{supplierId:guid}")]
public async Task<ActionResult<SupplierDto>> GetSupplierById(Guid supplierId, CancellationToken cancellationToken)
{
var supplierDto = await _supplierService.GetSupplierByIdAsync(supplierId, cancellationToken);
return Ok(supplierDto);
}
[HttpPost]
public async Task<CreatedAtActionResult> CreateSupplier([FromBody] SupplierForCreationDto supplierForCreation)
{
var supplierDto = await _supplierService.CreateAsync(supplierForCreation);
return CreatedAtAction(nameof(CreateSupplier), new { id = supplierDto.Id }, supplierDto);
}
[HttpDelete("{supplierId:guid}")]
public async Task<NoContentResult> DeleteSupplier(Guid supplierId, CancellationToken cancellationToken)
{
await _supplierService.DeleteAsync(supplierId, cancellationToken);
return NoContent();
}
}

View File

@ -1,53 +0,0 @@
using AB.Contracts;
using AB.Services.Abstractions;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.API.Controllers
{
[ApiController]
[Route("api/customers")]
public class CustomerController : ControllerBase
{
private readonly ICustomerService _customerService;
[HttpGet]
public async Task<IActionResult> GetCustomers(CancellationToken cancellationToken)
{
var customers = await _customerService.GetAllAsync(cancellationToken);
return Ok(customers);
}
[HttpGet("{customerId:guid}")]
public async Task<IActionResult> GetCustomerById(Guid customerId, CancellationToken cancellationToken)
{
var customer = await _customerService.GetByIdAsync(customerId, cancellationToken);
return Ok(customer);
}
[HttpPost]
public async Task<IActionResult> CreateCustomer([FromBody] CustomerForCreationDto customerForCreation)
{
var customerDto = await _customerService.CreateAsync(customerForCreation);
return CreatedAtAction(nameof(CreateCustomer), new {customerId = customerDto.Id}, customerDto);
}
[HttpDelete("{customerId:guid}")]
public async Task<IActionResult> DeleteCustomer(Guid customerId, CancellationToken cancellationToken)
{
await _customerService.DeleteAsync(customerId, cancellationToken);
return NoContent();
}
}
}

View File

@ -1,15 +1,20 @@
using System; namespace AB.Contracts;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.Contracts public class CustomerDto
{ {
public class CustomerDto
{
public Guid Id { get; set; } public Guid Id { get; set; }
public string Salutaion { get; set; }
public string Name1 { get; set; }
public string Name2 { get; set; }
public string Email { get; set; }
public string Iban { get; set; }
public string PhoneNumber { get; set; }
}
} }

View File

@ -1,12 +1,27 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Contracts namespace AB.Contracts;
public class CustomerForCreationDto
{ {
public class CustomerForCreationDto [Required]
{ public string Salutaion { get; set; }
}
[Required]
public string Name1 { get; set; }
public string? Name2 { get; set; }
public string? Email { get; set; }
public string? Iban { get; set; }
public string? PhoneNumber { get; set; }
} }

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.Contracts;
public class SupplierDto
{
public Guid Id { get; set; }
}

View File

@ -4,9 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Contracts namespace AB.Contracts;
public class SupplierForCreationDto
{ {
public class SupplierForCreationDto
{
}
} }

View File

@ -4,11 +4,23 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Entities namespace AB.Domain.Entities;
{
public class Customer public class Customer
{ {
Guid coutomerId;
public Guid CustomerId { get; set; }
public string Salutation { get; set; }
public string Name1 { get; set; }
public string Name2 { get; set; }
public string Email { get; set; }
public string Iban { get; set; }
public string PhoneNumber { get; set; }
}
} }

View File

@ -4,11 +4,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Entities namespace AB.Domain.Entities;
{
public class Product public class Product
{ {
Guid productId; public Guid ProductId { get; set; }
}
} }

View File

@ -4,11 +4,10 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Entities namespace AB.Domain.Entities;
{
public class Supplier
{
Guid supplierId; public class Supplier
} {
public Guid SupplierId { get; set; }
} }

View File

@ -4,14 +4,13 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Exceptions namespace AB.Domain.Exceptions;
public class BusinessPartnerNotFoundException : NotFoundException
{ {
public class BusinessPartnerNotFoundException : NotFoundException
{
public BusinessPartnerNotFoundException(Guid businessPartnerId) public BusinessPartnerNotFoundException(Guid businessPartnerId)
: base ($"The BusinessPartner with the indetifier {businessPartnerId} was not found.") : base ($"The BusinessPartner with the indetifier {businessPartnerId} was not found.")
{ } { }
}
} }

View File

@ -4,17 +4,16 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Exceptions namespace AB.Domain.Exceptions;
{
[Serializable]
public abstract class NotFoundException : Exception [Serializable]
{ public abstract class NotFoundException : Exception
public NotFoundException() { } {
public NotFoundException(string message) : base(message) { } public NotFoundException() { }
public NotFoundException(string message, Exception inner) : base(message, inner) { } public NotFoundException(string message) : base(message) { }
protected NotFoundException( public NotFoundException(string message, Exception inner) : base(message, inner) { }
System.Runtime.Serialization.SerializationInfo info, protected NotFoundException(
System.Runtime.Serialization.StreamingContext context) : base(info, context) { } System.Runtime.Serialization.SerializationInfo info,
} System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
} }

View File

@ -1,12 +1,16 @@
using System; using AB.Domain.Entities;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Repositories namespace AB.Domain.Repositories;
public interface ICustomerRepository
{ {
public class ICustomerRepository public Task<IEnumerable<Customer>> GetAllAsync(CancellationToken cancellationToken);
{ Task<Customer> GetByIdAsync(Guid customerId, CancellationToken cancellationToken);
} void Insert(Customer customer);
void Remove(Customer customer);
} }

View File

@ -4,9 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Domain.Repositories namespace AB.Domain.Repositories;
public class ISupplierRepository
{ {
public class ISupplierRepository
{
}
} }

View File

@ -1,12 +1,6 @@
using System; namespace AB.Domain.Repositories;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.Domain.Repositories public interface IUnitOfWork
{ {
public class IUnitOfWork public Task<int> SaveChangesAsync(CancellationToken cancellationToken);
{
}
} }

View File

@ -6,4 +6,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AB.Domain\AB.Domain.csproj" />
</ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,25 @@
using AB.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.Persistence;
public sealed class RepoDbContext : DbContext
{
public RepoDbContext(DbContextOptions options)
: base (options)
{
}
public DbSet<Customer> Customers { get; set; }
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<Product> Products { get; set; }
}

View File

@ -0,0 +1,36 @@
using AB.Domain.Entities;
using AB.Domain.Repositories;
using Microsoft.EntityFrameworkCore;
namespace AB.Persistence.Repos;
public class CustomerRepository : ICustomerRepository
{
private readonly RepoDbContext _dbContext;
public CustomerRepository(RepoDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<IEnumerable<Customer>> GetAllAsync(CancellationToken cancellationToken)
{
return await _dbContext.Customers.ToListAsync(cancellationToken);
}
public async Task<Customer> GetByIdAsync(Guid customerId, CancellationToken cancellationToken)
{
return await _dbContext.Customers.FirstOrDefaultAsync(x => x.CustomerId == customerId, cancellationToken);
}
public void Insert(Customer customer)
{
_dbContext.Customers.Add(customer);
}
public void Remove(Customer customer)
{
_dbContext.Customers.Remove(customer);
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.Persistence.Repos;
public class SupplierRepository
{
}

View File

@ -0,0 +1,19 @@
using AB.Domain.Repositories;
namespace AB.Persistence.Repos;
public class UnitOfWork : IUnitOfWork
{
private readonly RepoDbContext _dbContext;
public UnitOfWork(RepoDbContext dbContext)
{
_dbContext = dbContext;
}
public Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
return _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -5,13 +5,12 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace AB.Services.Abstractions namespace AB.Services.Abstractions;
public interface ICustomerService
{ {
public interface ICustomerService Task<CustomerDto> CreateAsync(CustomerForCreationDto customerForCreation, CancellationToken cancellationToken = default);
{ Task DeleteAsync(Guid customerId, CancellationToken cancellationToken);
Task<CustomerDto> CreateAsync(CustomerForCreationDto customerForCreation); Task<IEnumerable<CustomerDto>> GetAllAsync(CancellationToken cancellationToken);
Task DeleteAsync(Guid customerId, CancellationToken cancellationToken); Task<CustomerDto> GetByIdAsync(Guid customerId, CancellationToken cancellationToken);
Task<IEnumerable<CustomerDto>> GetAllAsync(CancellationToken cancellationToken);
Task<CustomerDto> GetByIdAsync(Guid customerId, CancellationToken cancellationToken);
}
} }

View File

@ -0,0 +1,11 @@
using AB.Contracts;
namespace AB.Services.Abstractions;
public interface ISupplierService
{
Task<SupplierDto> CreateAsync(SupplierForCreationDto supplierForCreation);
Task DeleteAsync(Guid supplierId, CancellationToken cancellationToken);
Task<IEnumerable<SupplierDto>> GetAllAsync(CancellationToken cancellationToken);
Task<SupplierDto> GetSupplierByIdAsync(Guid supplierId, CancellationToken cancellationToken);
}

View File

@ -7,6 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\AB.Domain\AB.Domain.csproj" />
<ProjectReference Include="..\AB.Services.Abstractions\AB.Services.Abstractions.csproj" /> <ProjectReference Include="..\AB.Services.Abstractions\AB.Services.Abstractions.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -1,15 +1,99 @@
using AB.Contracts; using AB.Contracts;
using AB.Domain.Entities;
using AB.Domain.Exceptions;
using AB.Domain.Repositories;
using AB.Services.Abstractions; using AB.Services.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AB.Services namespace AB.Services;
public class CustomerService : ICustomerService
{ {
internal class CustomerService : ICustomerService
private readonly ICustomerRepository _customerRepository;
private readonly IUnitOfWork _unitOfWork;
public CustomerService(ICustomerRepository customerRepository, IUnitOfWork unitOfWork)
{
_customerRepository = customerRepository;
_unitOfWork = unitOfWork;
}
public async Task<CustomerDto> CreateAsync(CustomerForCreationDto customerForCreation, CancellationToken cancellationToken = default)
{ {
var customer = new Customer
{
Salutation = customerForCreation.Salutaion,
Name1 = customerForCreation.Name1,
Name2 = (customerForCreation.Name2 is null) ? string.Empty : customerForCreation.Name2,
Email = (customerForCreation.Email is null) ? string.Empty : customerForCreation.Email,
PhoneNumber = (customerForCreation.PhoneNumber is null) ? string.Empty : customerForCreation.PhoneNumber,
Iban = (customerForCreation.Iban is null) ? string.Empty : customerForCreation.Iban,
};
_customerRepository.Insert(customer);
await _unitOfWork.SaveChangesAsync(cancellationToken);
var customerDto = ConvertToCustomerDto(customer);
return customerDto;
}
public async Task DeleteAsync(Guid customerId, CancellationToken cancellationToken)
{
var customer = await _customerRepository.GetByIdAsync(customerId, cancellationToken);
if (customer == null)
{
throw new BusinessPartnerNotFoundException(customerId);
}
_customerRepository.Remove(customer);
await _unitOfWork.SaveChangesAsync(cancellationToken);
}
public async Task<IEnumerable<CustomerDto>> GetAllAsync(CancellationToken cancellationToken)
{
var customers = await _customerRepository.GetAllAsync(cancellationToken);
var customerDtoList = customers.Select(customer =>
{
return ConvertToCustomerDto(customer);
});
return customerDtoList;
}
public async Task<CustomerDto> GetByIdAsync(Guid customerId, CancellationToken cancellationToken)
{
var customer = await _customerRepository.GetByIdAsync(customerId, cancellationToken);
if (customer is null)
{
throw new BusinessPartnerNotFoundException(customerId);
}
var customerDto = ConvertToCustomerDto(customer);
return customerDto;
}
private static CustomerDto ConvertToCustomerDto(Customer customer)
{
var customerDto = new CustomerDto
{
Id = customer.CustomerId,
Salutaion = customer.Salutation,
Name1 = customer.Name1,
Name2 = customer.Name2,
Email = customer.Email,
PhoneNumber = customer.PhoneNumber,
Iban = customer.Iban,
};
return customerDto;
} }
} }