Using to MinimalAPI

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.
This commit is contained in:
AleksDw
2025-05-09 21:04:27 +02:00
parent 99f2e17a12
commit 31f8cabeb0
10 changed files with 232 additions and 115 deletions

View File

@@ -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();
}
}

View File

@@ -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<EventSkill> EventSkills
);

View File

@@ -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<EventSkill> EventSkills,
ICollection<EventRegistration> EventRegistrations
);

View File

@@ -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<EventSkill> EventSkills,
ICollection<EventRegistration> EventRegistrations
);

View File

@@ -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<EventSkill> EventSkills
);

View File

@@ -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<EventSkill> EventSkills,
ICollection<EventRegistration> EventRegistrations
);

View File

@@ -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;
}
}
}

View File

@@ -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
);
}
}

View File

@@ -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<ApplicationDbContext>(options =>
options.UseNpgsql(connectionString));
// Add Developer Exception Filter
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
// Configure Identity
builder.Services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
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();

View File

@@ -22,6 +22,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.OpenApi" Version="1.6.24" />
<PackageReference Include="MinimalApis.Extensions" Version="0.11.0" />
<PackageReference Include="Npgsql" Version="9.0.3" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />