From 31f8cabeb0d8eb9ee958ed1d4767fedfb71154e8 Mon Sep 17 00:00:00 2001 From: AleksDw Date: Fri, 9 May 2025 21:04:27 +0200 Subject: [PATCH] Using to MinimalAPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usunalem EventApiController(dobry byl ale mial problemy). Dodalem EventsEndpoints, zawiera async, używa Dtos (Data Transfer Objects). Jeżeli chcecie zrobić HTTP request ale nie wiecie co dać w body JSONa to można sprawdzić w tych Dtos. EventMapping służy do zmian obiektów Dto na Entity i odwrotnie. --- WebApp/Controllers/EventApiController.cs | 86 ----------------------- WebApp/DTOs/EventCreateDto.cs | 15 ++++ WebApp/DTOs/EventDetailsDto.cs | 17 +++++ WebApp/DTOs/EventSummaryDto.cs | 16 +++++ WebApp/DTOs/EventUpdateDto.cs | 15 ++++ WebApp/DTOs/EventsDto.cs | 15 ---- WebApp/Endpoints/EventsEndpoints.cs | 88 ++++++++++++++++++++++++ WebApp/Mapping/EventMapping.cs | 64 +++++++++++++++++ WebApp/Program.cs | 30 ++++---- WebApp/WebApp.csproj | 1 + 10 files changed, 232 insertions(+), 115 deletions(-) delete mode 100644 WebApp/Controllers/EventApiController.cs create mode 100644 WebApp/DTOs/EventCreateDto.cs create mode 100644 WebApp/DTOs/EventDetailsDto.cs create mode 100644 WebApp/DTOs/EventSummaryDto.cs create mode 100644 WebApp/DTOs/EventUpdateDto.cs delete mode 100644 WebApp/DTOs/EventsDto.cs create mode 100644 WebApp/Endpoints/EventsEndpoints.cs create mode 100644 WebApp/Mapping/EventMapping.cs diff --git a/WebApp/Controllers/EventApiController.cs b/WebApp/Controllers/EventApiController.cs deleted file mode 100644 index 64b890f..0000000 --- a/WebApp/Controllers/EventApiController.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using WebApp.Data; -using WebApp.Entities; - -namespace WebApp.Controllers.Api; - -[ApiController] -[Route("api/events")] -public class EventsApiController : ControllerBase -{ - private readonly ApplicationDbContext _context; - - public EventsApiController(ApplicationDbContext context) - { - _context = context; - } - - // GET: /api/events - [HttpGet] - public IActionResult GetAll() - { - var events = _context.Events.ToList(); - return Ok(events); - } - - // GET: /api/events/5 - [HttpGet("{id}")] - public IActionResult GetById(int id) - { - var ev = _context.Events.Find(id); - if (ev == null) - return NotFound(); - - return Ok(ev); - } - - // POST: /api/events - [HttpPost] - public IActionResult Create([FromBody] Event ev) - { - if (!ModelState.IsValid) - return BadRequest(ModelState); - - ev.EventDate = DateTime.SpecifyKind(ev.EventDate, DateTimeKind.Utc); - - _context.Events.Add(ev); - _context.SaveChanges(); - - return CreatedAtAction(nameof(GetById), new { id = ev.EventId }, ev); - } - - // PUT: /api/events/5 - [HttpPut("{id}")] - public IActionResult Update(int id, [FromBody] Event updated) - { - if (id != updated.EventId) - return BadRequest("ID w URL nie zgadza się z obiektem."); - - var ev = _context.Events.Find(id); - if (ev == null) - return NotFound(); - - ev.Title = updated.Title; - ev.Description = updated.Description; - ev.Location = updated.Location; - ev.EventDate = updated.EventDate; - ev.OrganisationId = updated.OrganisationId; - - _context.SaveChanges(); - return NoContent(); - } - - // DELETE: /api/events/5 - [HttpDelete("{id}")] - public IActionResult Delete(int id) - { - var ev = _context.Events.Find(id); - if (ev == null) - return NotFound(); - - _context.Events.Remove(ev); - _context.SaveChanges(); - - return NoContent(); - } -} diff --git a/WebApp/DTOs/EventCreateDto.cs b/WebApp/DTOs/EventCreateDto.cs new file mode 100644 index 0000000..a77bdd0 --- /dev/null +++ b/WebApp/DTOs/EventCreateDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using WebApp.Entities; + +namespace WebApp.DTOs; + +// Input values in JSON file to create event +public record class EventCreateDto +( + [Required] int? OrganisationId, + [Required][StringLength(50)] string Title, + [StringLength(500)] string Description, + [Required][StringLength(100)] string Location, + [Required] DateTime? EventDate, + ICollection EventSkills +); diff --git a/WebApp/DTOs/EventDetailsDto.cs b/WebApp/DTOs/EventDetailsDto.cs new file mode 100644 index 0000000..0dddd9d --- /dev/null +++ b/WebApp/DTOs/EventDetailsDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using WebApp.Entities; + +namespace WebApp.DTOs; + +// Output values in JSON file +public record class EventDetailsDto +( + int EventId, + [Required] int? OrganisationId, + [Required][StringLength(50)] string Title, + [StringLength(500)] string Description, + [Required][StringLength(100)] string Location, + [Required] DateTime? EventDate, + ICollection EventSkills, + ICollection EventRegistrations +); diff --git a/WebApp/DTOs/EventSummaryDto.cs b/WebApp/DTOs/EventSummaryDto.cs new file mode 100644 index 0000000..ae18f96 --- /dev/null +++ b/WebApp/DTOs/EventSummaryDto.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; +using WebApp.Entities; + +namespace WebApp.DTOs; + +// Output values in JSON file +public record class EventSummaryDto( + int EventId, + [Required] string Organisation, + [Required] [StringLength(50)] string Title, + [StringLength(500)] string Description, + [Required] [StringLength(100)] string Location, + [Required] DateTime? EventDate, + ICollection EventSkills, + ICollection EventRegistrations + ); diff --git a/WebApp/DTOs/EventUpdateDto.cs b/WebApp/DTOs/EventUpdateDto.cs new file mode 100644 index 0000000..59b9d72 --- /dev/null +++ b/WebApp/DTOs/EventUpdateDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using WebApp.Entities; + +namespace WebApp.DTOs; + +// Input values in JSON file to update event +public record class EventUpdateDto +( + [Required] int? OrganisationId, + [Required][StringLength(50)] string Title, + [StringLength(500)] string Description, + [Required][StringLength(100)] string Location, + [Required] DateTime? EventDate, + ICollection EventSkills +); diff --git a/WebApp/DTOs/EventsDto.cs b/WebApp/DTOs/EventsDto.cs deleted file mode 100644 index e2dcec3..0000000 --- a/WebApp/DTOs/EventsDto.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using WebApp.Entities; - -namespace WebApp.DTOs; -public record class EventsDto( - int EventId, - int OrganisationId, //foreign key - [StringLength(200)] string Title, - [StringLength(800)] string Description, - [StringLength(100)] string Location, - DateTime EventDate, - Organisation? Organisation, - ICollection EventSkills, - ICollection EventRegistrations - ); diff --git a/WebApp/Endpoints/EventsEndpoints.cs b/WebApp/Endpoints/EventsEndpoints.cs new file mode 100644 index 0000000..0cd0754 --- /dev/null +++ b/WebApp/Endpoints/EventsEndpoints.cs @@ -0,0 +1,88 @@ +using Microsoft.EntityFrameworkCore; +using WebApp.Data; +using WebApp.DTOs; +using WebApp.Entities; +using WebApp.Mapping; + +namespace WebApp.Endpoints +{ + public static class EventsEndpoints + { + const string GetEventEndpointName = "GetEvent"; + + public static RouteGroupBuilder MapEventsEndpoints(this WebApplication app) + { + var group = app.MapGroup("api/events") + .WithParameterValidation(); + + // GET /events + group.MapGet("/", async (ApplicationDbContext dbContext) => + await dbContext.Events + .Include(Eve => Eve.Organisation) + .Select(Eve => Eve.ToEventSummaryDto()) //EventSummaryDto + .AsNoTracking() + .ToListAsync()); + + // GET /events/1 + group.MapGet("/{id}", async (int id, ApplicationDbContext dbContext) => + { + Event? Eve = await dbContext.Events.FindAsync(id); + + + return Eve is null ? + Results.NotFound() : Results.Ok(Eve.ToEventDetailsDto()); //EventDetailsDto + }) + .WithName(GetEventEndpointName); + + // POST /events + group.MapPost("/", async (EventCreateDto newEvent, ApplicationDbContext dbContext) => + { + Event Eve = newEvent.ToEntity(); + + dbContext.Events.Add(Eve); + await dbContext.SaveChangesAsync(); + + return Results.CreatedAtRoute( + GetEventEndpointName, + new { id = Eve.EventId }, + Eve.ToEventDetailsDto()); //EventDetailsDto + }); + + // PUT /events/1 + group.MapPut("/{id}", async (int id, EventUpdateDto updatedEvent, ApplicationDbContext dbContext) => + { + var existingEvent = await dbContext.Events.FindAsync(id); + + if (existingEvent is null) + { + return Results.NotFound(); + } + + + dbContext.Entry(existingEvent) + .CurrentValues + .SetValues(updatedEvent.ToEntity(id)); + + dbContext.Entry(existingEvent) + .Collection(Eve => Eve.EventRegistrations) + .IsModified = false; + + await dbContext.SaveChangesAsync(); + + return Results.NoContent(); + }); + + // DELETE /events/1 + group.MapDelete("/{id}", async (int id, ApplicationDbContext dbContext) => + { + await dbContext.Events + .Where(Eve => Eve.EventId == id) + .ExecuteDeleteAsync(); + + return Results.NoContent(); + }); + + return group; + } + } +} diff --git a/WebApp/Mapping/EventMapping.cs b/WebApp/Mapping/EventMapping.cs new file mode 100644 index 0000000..8abf804 --- /dev/null +++ b/WebApp/Mapping/EventMapping.cs @@ -0,0 +1,64 @@ +using Microsoft.EntityFrameworkCore; +using WebApp.DTOs; +using WebApp.Entities; + +namespace WebApp.Mapping; + +public static class EventMapping +{ + public static Event ToEntity(this EventCreateDto ECDto) + { + return new Event() + { + OrganisationId = ECDto.OrganisationId!.Value, + Title = ECDto.Title, + Description = ECDto.Description, + Location = ECDto.Location, + EventDate = DateTime.SpecifyKind(ECDto.EventDate!.Value, DateTimeKind.Utc), + EventSkills = ECDto.EventSkills, + EventRegistrations = [] + }; + } + + public static Event ToEntity(this EventUpdateDto EUDto, int id) + { + return new Event() + { + EventId = id, + OrganisationId = EUDto.OrganisationId!.Value, + Title = EUDto.Title, + Description = EUDto.Description, + Location = EUDto.Location, + EventDate = DateTime.SpecifyKind(EUDto.EventDate!.Value, DateTimeKind.Utc), + EventSkills = EUDto.EventSkills + }; + } + + public static EventSummaryDto ToEventSummaryDto(this Event myEvent) + { + return new EventSummaryDto( + myEvent.EventId, + myEvent.Organisation!.Name, + myEvent.Title, + myEvent.Description, + myEvent.Location, + myEvent.EventDate, + myEvent.EventSkills, + myEvent.EventRegistrations + ); + } + + public static EventDetailsDto ToEventDetailsDto(this Event myEvent) + { + return new EventDetailsDto( + myEvent.EventId, + myEvent.OrganisationId, + myEvent.Title, + myEvent.Description, + myEvent.Location, + myEvent.EventDate, + myEvent.EventSkills, + myEvent.EventRegistrations + ); + } +} \ No newline at end of file diff --git a/WebApp/Program.cs b/WebApp/Program.cs index 83acd6e..df05866 100644 --- a/WebApp/Program.cs +++ b/WebApp/Program.cs @@ -1,25 +1,31 @@ using Microsoft.EntityFrameworkCore; using WebApp.Data; +using WebApp.Endpoints; using WebApp.Entities; +// Create WebAppliaction Builder var builder = WebApplication.CreateBuilder(args); -// Add services to the container. +// Configure Database Conecction var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); builder.Services.AddDbContext(options => options.UseNpgsql(connectionString)); + +// Add Developer Exception Filter builder.Services.AddDatabaseDeveloperPageExceptionFilter(); +// Configure Identity builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores(); -builder.Services.AddControllersWithViews(); +// API Services For Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "hermes", Version = "v1" }); }); +// Build Application var app = builder.Build(); // Configure the HTTP request pipeline. @@ -31,22 +37,18 @@ if (app.Environment.IsDevelopment()) } else { - app.UseExceptionHandler("/Home/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } -app.UseHttpsRedirection(); -app.UseDefaultFiles(); -app.UseStaticFiles(); +// Middleware Configuration +app.UseHttpsRedirection(); // Redirects all HTTP requests to HTTPS +app.UseDefaultFiles(); // Serves default files (index.html) if no specific file is requested +app.UseStaticFiles(); // Serves static files(CSS, JS, Img) from the wwwroot folder. +app.UseRouting(); // Enables routing to match incoming request to endpoints +app.UseAuthorization(); -app.UseRouting(); +// Map Minimal API Endpoints +app.MapEventsEndpoints(); -app.UseAuthorization(); - -app.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); -app.MapRazorPages(); app.Run(); diff --git a/WebApp/WebApp.csproj b/WebApp/WebApp.csproj index af037cd..599c9f3 100644 --- a/WebApp/WebApp.csproj +++ b/WebApp/WebApp.csproj @@ -22,6 +22,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive +