From 22744ced427d2d6940cd5c470e25896a3f8f416b Mon Sep 17 00:00:00 2001 From: Isaiah Clifford Opoku Date: Thu, 5 Dec 2024 23:14:05 +0000 Subject: [PATCH] Add new ASP.NET Core project for student management Introduce a new ASP.NET Core project focused on managing student-related operations and handling global exceptions. Key components include: - Database context and initial migration for `Student` entity. - Configuration for services, OpenAPI/Swagger, and exception handling. - Models and DTOs for `Student` entity. - Service layer with `IStudentService` and `StudentService`. - `StudentController` for CRUD operations. - Global exception handling with `GlobalExceptionHandler`. - Added new solution and project files, including `GlobalExceptions.sln` and `GlobalExceptions.csproj`. - Updated various metadata and configuration files. --- GlobalExceptions/GlobalExceptions.sln | 22 ++++ .../GlobalExceptions/GlobalExceptions.csproj | 21 +++ .../20241205220123_InitialCreate.Designer.cs | 50 +++++++ .../20241205220123_InitialCreate.cs | 35 +++++ .../20241205222045_Update.Designer.cs | 50 +++++++ .../Migrations/20241205222045_Update.cs | 22 ++++ .../StudentDbContextModelSnapshot.cs | 47 +++++++ .../Properties/launchSettings.json | 23 ++++ .../appsettings.Development.json | 14 ++ .../GlobalExceptions/appsettings.json | 9 ++ .../src/Context/StudentDbContext.cs | 13 ++ .../src/Contracts/ErrorResponse.cs | 9 ++ .../src/Contracts/StudentDto.cs | 6 + .../src/Controllers/StudentController.cs | 96 ++++++++++++++ .../src/Exceptions/GlobalExceptionHandler.cs | 47 +++++++ .../src/Mapping/MappingProfile.cs | 16 +++ .../GlobalExceptions/src/Modles/Student.cs | 10 ++ .../GlobalExceptions/src/Program.cs | 51 ++++++++ .../src/Service/IStudentService.cs | 14 ++ .../src/Service/StudentService.cs | 122 ++++++++++++++++++ .../dotnet9-crash-course.metadata.v9.bin | Bin 1981 -> 1981 bytes .../dotnet9-crash-course.projects.v9.bin | Bin 37072 -> 74144 bytes .../dotnet9-crash-course.strings.v9.bin | Bin 181241 -> 181301 bytes .../17.12.31.40377/SemanticSymbols.db-shm | Bin 32768 -> 32768 bytes .../17.12.31.40377/SemanticSymbols.db-wal | Bin 2500872 -> 2504992 bytes .../DesignTimeBuild/.dtbcache.v2 | Bin 180320 -> 180320 bytes ...4465114a-863c-4e4a-b8df-46547689ca36.vsidx | Bin 11088 -> 0 bytes ...5c2d16ee-94d6-42d5-bbef-5bb62a144f9f.vsidx | Bin 18545 -> 0 bytes ...660ee5e5-105d-418e-a22a-ee726377b085.vsidx | Bin 10935 -> 0 bytes ...b2d01685-02c5-4d34-867c-5a3fbbed55cd.vsidx | Bin 11114 -> 0 bytes .../.vs/dotnet9-crash-course/v17/.suo | Bin 88576 -> 98816 bytes .../v17/DocumentLayout.backup.json | 10 +- .../v17/DocumentLayout.json | 65 ++++------ .../dotnet9-crash-course.AssemblyInfo.cs | 2 +- ...net9-crash-course.AssemblyInfoInputs.cache | 2 +- 35 files changed, 710 insertions(+), 46 deletions(-) create mode 100644 GlobalExceptions/GlobalExceptions.sln create mode 100644 GlobalExceptions/GlobalExceptions/GlobalExceptions.csproj create mode 100644 GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.Designer.cs create mode 100644 GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.cs create mode 100644 GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.Designer.cs create mode 100644 GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.cs create mode 100644 GlobalExceptions/GlobalExceptions/Migrations/StudentDbContextModelSnapshot.cs create mode 100644 GlobalExceptions/GlobalExceptions/Properties/launchSettings.json create mode 100644 GlobalExceptions/GlobalExceptions/appsettings.Development.json create mode 100644 GlobalExceptions/GlobalExceptions/appsettings.json create mode 100644 GlobalExceptions/GlobalExceptions/src/Context/StudentDbContext.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Contracts/ErrorResponse.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Contracts/StudentDto.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Controllers/StudentController.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Exceptions/GlobalExceptionHandler.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Mapping/MappingProfile.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Modles/Student.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Program.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Service/IStudentService.cs create mode 100644 GlobalExceptions/GlobalExceptions/src/Service/StudentService.cs delete mode 100644 dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/4465114a-863c-4e4a-b8df-46547689ca36.vsidx delete mode 100644 dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/5c2d16ee-94d6-42d5-bbef-5bb62a144f9f.vsidx delete mode 100644 dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/660ee5e5-105d-418e-a22a-ee726377b085.vsidx delete mode 100644 dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/b2d01685-02c5-4d34-867c-5a3fbbed55cd.vsidx diff --git a/GlobalExceptions/GlobalExceptions.sln b/GlobalExceptions/GlobalExceptions.sln new file mode 100644 index 0000000..7396d41 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35506.116 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GlobalExceptions", "GlobalExceptions\GlobalExceptions.csproj", "{DACC5DD3-A363-4A33-B169-DAF873F7ADC4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DACC5DD3-A363-4A33-B169-DAF873F7ADC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DACC5DD3-A363-4A33-B169-DAF873F7ADC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DACC5DD3-A363-4A33-B169-DAF873F7ADC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DACC5DD3-A363-4A33-B169-DAF873F7ADC4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GlobalExceptions/GlobalExceptions/GlobalExceptions.csproj b/GlobalExceptions/GlobalExceptions/GlobalExceptions.csproj new file mode 100644 index 0000000..4ee5476 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/GlobalExceptions.csproj @@ -0,0 +1,21 @@ + + + + net9.0 + enable + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.Designer.cs b/GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.Designer.cs new file mode 100644 index 0000000..72ed9f5 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.Designer.cs @@ -0,0 +1,50 @@ +// +using GlobalExceptions.src.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GlobalExceptions.Migrations +{ + [DbContext(typeof(StudentDbContext))] + [Migration("20241205220123_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GlobalExceptions.src.Modles.Student", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Biography") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Students"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.cs b/GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.cs new file mode 100644 index 0000000..db3c191 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/Migrations/20241205220123_InitialCreate.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GlobalExceptions.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Students", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(max)", nullable: false), + Biography = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Students", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Students"); + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.Designer.cs b/GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.Designer.cs new file mode 100644 index 0000000..73fbde1 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.Designer.cs @@ -0,0 +1,50 @@ +// +using GlobalExceptions.src.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GlobalExceptions.Migrations +{ + [DbContext(typeof(StudentDbContext))] + [Migration("20241205222045_Update")] + partial class Update + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GlobalExceptions.src.Modles.Student", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Biography") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Students"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.cs b/GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.cs new file mode 100644 index 0000000..179aab1 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/Migrations/20241205222045_Update.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GlobalExceptions.Migrations +{ + /// + public partial class Update : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/Migrations/StudentDbContextModelSnapshot.cs b/GlobalExceptions/GlobalExceptions/Migrations/StudentDbContextModelSnapshot.cs new file mode 100644 index 0000000..607d2be --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/Migrations/StudentDbContextModelSnapshot.cs @@ -0,0 +1,47 @@ +// +using GlobalExceptions.src.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GlobalExceptions.Migrations +{ + [DbContext(typeof(StudentDbContext))] + partial class StudentDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GlobalExceptions.src.Modles.Student", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Biography") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Students"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/Properties/launchSettings.json b/GlobalExceptions/GlobalExceptions/Properties/launchSettings.json new file mode 100644 index 0000000..2a4b46e --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5083", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7236;http://localhost:5083", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/appsettings.Development.json b/GlobalExceptions/GlobalExceptions/appsettings.Development.json new file mode 100644 index 0000000..2427c50 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/appsettings.Development.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + + "ConnectionStrings": { + "sqlConnection": "Server=localhost;Database=studentDb;Integrated Security=true;TrustServerCertificate=true;" + }, + + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/GlobalExceptions/GlobalExceptions/appsettings.json b/GlobalExceptions/GlobalExceptions/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/GlobalExceptions/GlobalExceptions/src/Context/StudentDbContext.cs b/GlobalExceptions/GlobalExceptions/src/Context/StudentDbContext.cs new file mode 100644 index 0000000..ea5a46f --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Context/StudentDbContext.cs @@ -0,0 +1,13 @@ +using GlobalExceptions.src.Modles; +using Microsoft.EntityFrameworkCore; + +namespace GlobalExceptions.src.Context +{ + public class StudentDbContext : DbContext + { + public StudentDbContext(DbContextOptions options) : base(options) + { + } + public DbSet Students { get; set; } + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Contracts/ErrorResponse.cs b/GlobalExceptions/GlobalExceptions/src/Contracts/ErrorResponse.cs new file mode 100644 index 0000000..fafa727 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Contracts/ErrorResponse.cs @@ -0,0 +1,9 @@ +namespace GlobalExceptions.src.Contracts +{ + public class ErrorResponse + { + public string Title { get; set; } + public int StatusCode { get; set; } + public string Message { get; set; } + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Contracts/StudentDto.cs b/GlobalExceptions/GlobalExceptions/src/Contracts/StudentDto.cs new file mode 100644 index 0000000..0032a61 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Contracts/StudentDto.cs @@ -0,0 +1,6 @@ +namespace GlobalExceptions.src.Contracts +{ + public record CreateStudent(string Name, string Biography); + public record UpdateStudent(int Id, string Name, string Biography); + public record StudentDto(int Id, string Name, string Biography); +} diff --git a/GlobalExceptions/GlobalExceptions/src/Controllers/StudentController.cs b/GlobalExceptions/GlobalExceptions/src/Controllers/StudentController.cs new file mode 100644 index 0000000..0996b6f --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Controllers/StudentController.cs @@ -0,0 +1,96 @@ +using GlobalExceptions.src.Contracts; +using GlobalExceptions.src.Service; +using Microsoft.AspNetCore.Mvc; + +namespace GlobalExceptions.src.Controllers +{ + /// + /// Controller for managing student-related operations. + /// + [ApiController] + public class StudentController : ControllerBase + { + private readonly IStudentService _studentService; + + /// + /// Initializes a new instance of the class. + /// + /// The student service. + public StudentController(IStudentService studentService) + { + _studentService = studentService; + } + + /// + /// Gets the list of all students. + /// + /// A list of students. + [HttpGet("api/students")] + public async Task GetStudents() + { + var students = await _studentService.GetStudents(); + return Ok(students); + } + + /// + /// Gets a student by the specified identifier. + /// + /// The student identifier. + /// The student with the specified identifier. + [HttpGet("api/students/{id}")] + public async Task GetStudent(int id) + { + + var student = await _studentService.GetStudent(id); + + if (student == null) + { + throw new Exception($"Student with id: {id} not found"); + + + } + return Ok(student); + } + + /// + /// Creates a new student. + /// + /// The student creation details. + /// The created student. + [HttpPost("api/students")] + public async Task CreateStudent([FromBody] CreateStudent createStudent) + { + var student = await _studentService.CreateStudent(createStudent); + return CreatedAtAction(nameof(GetStudent), new { id = student.Id }, student); + } + + /// + /// Updates an existing student. + /// + /// The student identifier. + /// The student update details. + /// The updated student. + [HttpPut("api/students/{id}")] + public async Task UpdateStudent(int id, [FromBody] UpdateStudent updateStudent) + { + if (id != updateStudent.Id) + { + throw new Exception("The student ID in the URL does not match the student ID in the request body."); + } + var student = await _studentService.UpdateStudent(updateStudent); + return Ok(student); + } + + /// + /// Deletes a student by the specified identifier. + /// + /// The student identifier. + /// The deleted student. + [HttpDelete("api/students/{id}")] + public async Task DeleteStudent(int id) + { + var student = await _studentService.DeleteStudent(id); + return Ok(student); + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Exceptions/GlobalExceptionHandler.cs b/GlobalExceptions/GlobalExceptions/src/Exceptions/GlobalExceptionHandler.cs new file mode 100644 index 0000000..3a12695 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Exceptions/GlobalExceptionHandler.cs @@ -0,0 +1,47 @@ +using GlobalExceptions.src.Contracts; +using Microsoft.AspNetCore.Diagnostics; +using System.Net; + +namespace GlobalExceptions.src.Exceptions +{ + public class GlobalExceptionHandler : IExceptionHandler + { + private readonly ILogger _logger; + + public GlobalExceptionHandler(ILogger logger) + { + _logger = logger; + } + + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) + { + _logger.LogError(exception, "An unhandled exception occurred."); + var errorResponse = new ErrorResponse + { + Message = exception.Message, + }; + + switch (exception) + { + case BadHttpRequestException: + errorResponse.StatusCode = (int)HttpStatusCode.BadRequest; + errorResponse.Title = exception.GetType().Name; + break; + + + default: + errorResponse.StatusCode = (int)HttpStatusCode.InternalServerError; + errorResponse.Title = "Internal Server Error"; + break; + + + } + + httpContext.Response.StatusCode = errorResponse.StatusCode; + + await httpContext.Response.WriteAsJsonAsync(errorResponse, cancellationToken); + + return true; + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Mapping/MappingProfile.cs b/GlobalExceptions/GlobalExceptions/src/Mapping/MappingProfile.cs new file mode 100644 index 0000000..e330818 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Mapping/MappingProfile.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using GlobalExceptions.src.Contracts; +using GlobalExceptions.src.Modles; + +namespace GlobalExceptions.src.Mapping +{ + public class MappingProfile : Profile + { + public MappingProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + } + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Modles/Student.cs b/GlobalExceptions/GlobalExceptions/src/Modles/Student.cs new file mode 100644 index 0000000..acbbb60 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Modles/Student.cs @@ -0,0 +1,10 @@ +namespace GlobalExceptions.src.Modles +{ + public class Student + { + public int Id { get; set; } + public string Name { get; set; } + public string Biography { get; set; } + + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Program.cs b/GlobalExceptions/GlobalExceptions/src/Program.cs new file mode 100644 index 0000000..b24f578 --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Program.cs @@ -0,0 +1,51 @@ +using GlobalExceptions.src.Context; +using GlobalExceptions.src.Exceptions; +using GlobalExceptions.src.Mapping; +using GlobalExceptions.src.Service; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +builder.Services.AddProblemDetails(); + +builder.Services.AddExceptionHandler(); + +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new() { Title = "GlobalExceptions.src", Version = "v1" }); +}); + + +builder.Services.AddDbContext(options => +{ + options.UseSqlServer(builder.Configuration.GetConnectionString("sqlConnection")); +}); + +builder.Services.AddScoped(); +builder.Services.AddAutoMapper(typeof(MappingProfile).Assembly); + + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); +app.UseExceptionHandler(); + +app.MapControllers(); + +app.Run(); diff --git a/GlobalExceptions/GlobalExceptions/src/Service/IStudentService.cs b/GlobalExceptions/GlobalExceptions/src/Service/IStudentService.cs new file mode 100644 index 0000000..9db818d --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Service/IStudentService.cs @@ -0,0 +1,14 @@ +using GlobalExceptions.src.Contracts; + +namespace GlobalExceptions.src.Service +{ + public interface IStudentService + { + public Task> GetStudents(); + public Task GetStudent(int id); + public Task CreateStudent(CreateStudent createStudent); + public Task UpdateStudent(UpdateStudent updateStudent); + public Task DeleteStudent(int id); + + } +} diff --git a/GlobalExceptions/GlobalExceptions/src/Service/StudentService.cs b/GlobalExceptions/GlobalExceptions/src/Service/StudentService.cs new file mode 100644 index 0000000..fc7d45c --- /dev/null +++ b/GlobalExceptions/GlobalExceptions/src/Service/StudentService.cs @@ -0,0 +1,122 @@ +using AutoMapper; +using GlobalExceptions.src.Context; +using GlobalExceptions.src.Contracts; +using GlobalExceptions.src.Modles; +using Microsoft.EntityFrameworkCore; + +namespace GlobalExceptions.src.Service +{ + /// + /// Service class for managing student operations. + /// + public class StudentService : IStudentService + { + private readonly IMapper _mapper; + private readonly StudentDbContext _context; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The mapper instance for object mapping. + /// The database context for student operations. + /// The logger instance for logging operations. + public StudentService(IMapper mapper, StudentDbContext context, ILogger logger) + { + _mapper = mapper; + _context = context; + _logger = logger; + } + + /// + /// Creates a new student. + /// + /// The student creation data. + /// The created student data transfer object. + public async Task CreateStudent(CreateStudent createStudent) + { + var student = _mapper.Map(createStudent); + await _context.Students.AddAsync(student); + await _context.SaveChangesAsync(); + + return _mapper.Map(student); + } + + /// + /// Gets a student by ID. + /// + /// The student ID. + /// The student data transfer object. + /// Thrown when the student is not found. + public async Task GetStudent(int id) + { + var student = await _context.Students.FindAsync(id); + if (student == null) + { + _logger.LogError($"Student with id: {id} not found"); + throw new Exception($"Student with id: {id} not found"); + } + + _logger.LogInformation($"Student with id: {id} found"); + return _mapper.Map(student); + } + + /// + /// Gets all students. + /// + /// A collection of student data transfer objects. + public async Task> GetStudents() + { + var students = await _context.Students.ToListAsync(); + + if (students == null || !students.Any()) + { + _logger.LogError("No students found"); + return Enumerable.Empty(); + } + + _logger.LogInformation("Students found"); + return _mapper.Map>(students); + } + + /// + /// Updates an existing student. + /// + /// The student update data. + /// The updated student data transfer object. + /// Thrown when the student is not found. + public async Task UpdateStudent(UpdateStudent updateStudent) + { + var student = await _context.Students.FindAsync(updateStudent.Id); + if (student == null) + { + _logger.LogError($"Student with id: {updateStudent.Id} not found"); + throw new Exception($"Student with id: {updateStudent.Id} not found"); + } + student.Name = updateStudent.Name; + student.Biography = updateStudent.Biography; + _context.Students.Update(student); + await _context.SaveChangesAsync(); + return _mapper.Map(student); + } + + /// + /// Deletes a student by ID. + /// + /// The student ID. + /// The deleted student data transfer object. + /// Thrown when the student is not found. + public async Task DeleteStudent(int id) + { + var student = await _context.Students.FindAsync(id); + if (student == null) + { + _logger.LogError($"Student with id: {id} not found"); + throw new Exception($"Student with id: {id} not found"); + } + _context.Students.Remove(student); + await _context.SaveChangesAsync(); + return _mapper.Map(student); + } + } +} diff --git a/dotnet9-crash-course/.vs/ProjectEvaluation/dotnet9-crash-course.metadata.v9.bin b/dotnet9-crash-course/.vs/ProjectEvaluation/dotnet9-crash-course.metadata.v9.bin index 28b1639ba0c0b8cb506ec1d54e72871f833bb2a4..9e560c4f0d00f3f1c17f6f80fcaa6abacd423b17 100644 GIT binary patch delta 42 scmdnXzn6c5IGgx|2@GJs3?xJ6%q{pOc$b6Oqkpm<+ae|)b&2gY0R1QpKmY&$ delta 42 qcmdnXzn6c5IGZ>F6g&aazkXIu>=(St!Msm$vL4$aCLnc*?KJ@Ostr{D diff --git a/dotnet9-crash-course/.vs/ProjectEvaluation/dotnet9-crash-course.projects.v9.bin b/dotnet9-crash-course/.vs/ProjectEvaluation/dotnet9-crash-course.projects.v9.bin index 965e5d7c911de3c026992a679e197b5c754f6d3a..f40e74daa06bf130a1bacaff7e4de52496490e71 100644 GIT binary patch delta 63 zcmV-F0Kosyp#q@81hCMMDfE5wAcd2WWiun!Pm9g}oX&7EB`^UwT1=b2`EeNn E0POlRcmMzZ delta 173 zcmZo@U}|V!s+V}A%K!q?fS8eiK_H%qfq@suR&%vje*C(-=+QWa?(OD=b2r?+P-1by zRf$yfAhSUr259boBmfa*V1v+;FS1E*T#&-KS%mAA#bgC8fzAJ%&TwuPU0L!H(!~g&Q delta 87 zcmV~$#}R@+006)_6Q~GAj36dv?9#_REP*FQSP7+2fxB(rgm2e`k6>VEWNac5o0^$R gETl3^D{C8DJGs4sqm#3XLg}hTY-`=?7CU~&ThwWJ=L diff --git a/dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/4465114a-863c-4e4a-b8df-46547689ca36.vsidx b/dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/4465114a-863c-4e4a-b8df-46547689ca36.vsidx deleted file mode 100644 index b84159a564eb3a175a64c8aba7e69e6b2bb6803d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11088 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 diff --git a/dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/b2d01685-02c5-4d34-867c-5a3fbbed55cd.vsidx b/dotnet9-crash-course/.vs/dotnet9-crash-course/FileContentIndex/b2d01685-02c5-4d34-867c-5a3fbbed55cd.vsidx deleted file mode 100644 index 9bcb004131104e91e5e52f7bba7265c1d3f72399..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11114 zcmcJTdz9T(b;r-#5qTvL9;G}a3JrhljNl`R7HFjuQM5=@qz0^LMQT?`&?O?e2nsE!q@V9T-+LLAKWlRD z{+xY&=eN(^`|NXmzqwuA3ywG_rJgfV{F`6M+y=VOTe@UyeRciH(czVA#x5J~8e26w zv9xQ=>Ps)Jj*eXJYfD#+O|BiCoO9;L_=<_k&m0+BKRz+~+MQivYbVFY)~p#FpIACL zKDKK8$mFYCts@h8>OYjHJ-z4ttGb?S_fcQKiQQSWV$JGRD<;Rt)6hB^qs~@&^j+&mCnoEcaq#iYZcJ%QN-I-pO6k!UtN~$mKVuqFLt|+?&!moNtgz433;^BKELwNX>KQJSR4mjC)ybHjk868U^%bY35h5yC04#QT{mvPZ~U zQfek+jq+!Ic=$7t6K1K9x-;^h%ujWI*c;QGg>+l^xrrGGD$KGp_^>NtJR+%mYGf5B zv-7Gb=EB3Mid-8k>mm4`(*0p%4>J2hqmUX>8jiwXISz}!KaoQ8A&>l@{?zg9d=^~H@4HcySNA<8Ta68JY`il)YNZAxc`@mE6P?H*=~ zjNt|oQ7X5jv?*f8{_C+5cYTrat8H7x>k?ag>Wpy?P~O;KB6}Wo@-jUTYxMP6c~j4M ziD|G>l3|T)k{7F~K?{UR(Nah+V43QQDy6VlYuq@C%tTsnrjyekykgjlSWQ+0XLi;0 z1@|6QFVt8I?z%Ux(bW2{c{o3Azc<|5ol-S+ld|;ter`;OowzA#Mti>@bzrlgRmKgL z^4H-NrNtsrFhoS!8Nj-1jGp=iCvasiI&-C+m=YDZH~QCw9a6EIC?Y84W&GZ}f>Vrt zE$WS9HfL;Vk>d{uVd{Hp<8!w09}g8>98lDlr>G61Kku(&3+XzXj1TvY#KvDvq>)=J zvzpAp8A$Qex6E;W)Xo_oMeNq?Q5%Fw&NoLP;rzC2b4sMR#{de_5rxmpGWG15U*8nD z7*fLFjd&X>Cp!7S>?tJg-&&$rmsesT zDC0pKi!|=8yGp_-5(ek|(5SU@*?Urq*Y*yJyAcm-&zHByx)UAoHr38aa)`lQQ*%qY z;!t8=YY)ab(DeHQ@}4?85}ThFgjrt>IhJ!i+9>7d}Tx=+un`I)+M)K)8_;uaK8Mo+CO~I6dN1UwU3?c0?2y+?=$#ujLdC zH^^i&x0CRQbRU67T{?S53BWlDqOaIo*BW^lWZK8gKU*{PMxD%b0rjN$6`+M`^r zPkAjuvN0LJIl}-lMouvMs{fH0FFI+doo{1NqRMcs*iQzWkYW$|7`LIAa{e6+GTN!F+?s(Hz%jnkSh}=E+d8QHe3` zG^qJn_^SU+eB}?%<6x^f+dRuW+dKytzTun8*1DJ>(`j?g&KdY z^-bpAn46*Q+rn4lZs4nRV{^s2-ei57^$(gKh8q77z8Zgv`BC#$^JC`6q2}3c{gdWx z=I!REpvLXsEBl}4EBkktUod&|i~hei?=ql8X8Y<2|H;;G!3FaHj z6U~|CNoEt&{LR)+vHnKurezBcRg%y#$B zx87lPnq4L@8j**h*<&t%vRg7QaDT7aXZD)|P;r#4SD@}6vcAY%Y`)!G0u>)GrQydV z=CHZkTmfZo#QG|8)V$Q!FE`&|uJQFN%(dp2xz2o-Ic`os`E{lBtE|7r`UdkFD8DwE zo6OC={yyv1Ti;^-t$BmF)x6Pszj>3n&HR9Qv-v^u@5~QDt;0vG-(r5$ycNpdk3+?` z-TH05e!KZ8^V8;M%+H!T%+EpDy93JJo$kNOyxaT-^B>JGnfE~5cc1kyoA;YvF~4d) z05$$W>)$XRa{srjKWu)-e8kruwf>m-J@enp@0*XCKQMm?mDeY%|JZ!e{15XdQ2spy zm6tv4f7<*hl%1bjf5!ZU`K=Kb)ffVE6NvTE>Zj^B!p)V;=A8CqVf()A~tf zlXt-l3o+*_^BG0!vSnr-Ghv)w%3 zoNsnOKB>!kH&h-LS}$4ev)*sLY`p^cq#^5z%*9ZCUS#q!Lgf7tbJ$#Nt}s`cBjze7 zJC|9%+*}R$q<30hV_xC@G3)#+6Y)%1U+?QzTEEJCxBK}+FZ_IuxxwUz*_dx5RDL$Q z|9$3l?!UqMR`W*l{g97-BnFmHyk_hG0wZ-IQ$tq9fo$Dpo%!uocoaksnwv+myk z`J~TVzr*~3`9;V_f3pVfhO&DP)I9&>{(rW9pY{8#f5rT&`GEN~^Xulnm=BuYFds5^ zLO$tR*1v5&Y<|al1oBDWwZ6-I)O^hR9#lRaxBdgDxSp{7WAjPKC;bGW>rc6Vx4FlB z+We{cGbsDdSpS9jtocjxIrCRgn`^gH*zV(vF(RM+|W zCC2kZRLpa*`wxX$$7$wt_wzea^v{5N(oyCyQ1*_6x{qIhgU6dE`1*;~XF~beZ2c6- zC!L0nofhk7SU(fWZmT)lJj*=WJjZ-9oQssrmb4%ZA!SWc_sUL7c-4|FPCao?f5^q$-G+Cq*sUPD(m=>E zQoc#5r-+SKEUTv!Bm1z|8s183jC^k8n#NS3EzetH-qy63`)2$9AhXSm@w3CX*^D2e z=W52xNyB&{p9VvgLspQ=TU+X6uC|D@jnN&nOU&5DHMQkKTi9$1Pb7!vktg%WSXanW z$lOzo_7H26|923L)@dR3I#X}R3bKn?B&$f}M6!%jP9)_^DaMx~E2S9O8~we}--q3f z)EDEm%9^PQIT&MPs{@NmkjkN?e5mjvt)$|s@Ly76sxhV-_g2H7Dp7WjXZbDfBr6d^ zF=Poj5d8zNlWSGxS9Nr;O5GtV;gR|kufEDzk>AlIRUbvFT2dpG9aW6(9f)WK!rB0y zs1|iqwI^8$Ie^q2kW{@^!)BG$R$G?y+=@$W`Bsg&s??G8$E=X;NbRp~=BOfz_#)XK zvJz7LvZB@M3#qFEF<`Jgw6#lW@hewq=iQ+7tX2IG zZB?jbttyLAU&W{{t*Y+Tx=3mb6;qKtIWOb@vX^fWj|Y+cF{U3+i|F$D!f5O4(4K4w znfGT$v^9Gfdy*Poj=9QYPwiz$t(>IntD+?3iFQhnmTXqphmwk26)&l~G){71NX1wU zJ6b8VWkE9)`NgpmQ8gn~2R)II9-~(wCdW8@>p^pq-s#vmYfyxO(8W>t0K7psjN$CyrNMYCI0u4 zA^D^eP?ePZlhoCIUsdI5FX-fzg+cr*(UN`TSyDFTy`=7~hR>?=64&I1 z@=3}A)nRYclJ;JOwrWjMnU&9y*`D^NVv^KIS=C9T3e#EN%edx{x!q1%>(>_^NcKm& zjMT}YN}m;SUP$$;YWlF;h14CY+A4ApJ^2Zve5tMHfKI&yA^VUzdnEI&RR-m`Z-hutb~*W-KUyv4%re?ca=FgC0j$vf}T&3@HS5r9jP}CN%gm|%N3iRxLRMurn6qpTb=%$A@h@MwI}uTZKqdH znMy=jp*5GbVpPp(uWhAOX$O;$9%_8iD>9Vx+R9bG$92o@{z1Nou^_4fTw_8mad?d8z)q zW3$J)N6(mC{VlX#eL||;7d^70HIr0S`8lL#g7&;@=q!@d&d#TR&SSM@Kc9~Iq)~0? z>D3)l(P@83s$cahnX6BCtD2Ne|RUN-bBlpU?NvM*~(xNC^|*Ey>< zEXn-L%ujf&icajj>$Fa-wB@s;M(V_s>_f_P&7pg>(wa#&Rarxf&Tss^F}Lbl9_U=2 zi&XYh@m=x0SPEG|DxZ2&ud=iCo+H^G&vI3X_P%PRE1pjk{+7^5q`xT2NIjGFJRS&H lMk|EwHq~UlhmJwp-FATgl0OOD$*f!Y%>{+ooN!4N(+s55(D&I1KPwC`H3~E71kDDn^-HJ@y}J;KuCxBpjsCLGpLOviC9 zs$a(%jwI|*jgcWH4!}raaZjfvQtJ^ZM%=)$m}&Pxpte4VQ^~Sv8wZ7O;;%wF# zaQnoi=up;-BMUSipo2<8^uVA=k^`cTi?o5Q2<27nCTt{7mcU0^xT|2JR^gvcnK(No zPCB(@V!`t`djSVt=mtrM2T$SIs85Jkrk6}~E5Sg((g43O6~nj%mrh>Ffw|tSLs5?a zzaH5KCodQD9@@eaK)QSzPHnO31RO|Z*HgU}H_LYD;L>F&V)lrbG_mASCgG1m&>Z5s zV8R?ycVnjryBF@!9z)BEU_JhCxBd`o8c*d%XumkqehKRzBTgVrB2FPrBVRo%V*OLZS;Wr}uOZGMl27^Lcyyx>%@^(}%mfNk9SajCtM3&lofKi2-Yu?r zcta?KahDG~u2m4OaZ_7Of}xTpi{e$0Y>!A;NjgJIn|>|ZC(=%*-LE*g2_~}ZRg^Gr zX`>B)nue!AFlPfzm`EFM5P=2G4;w(=)d8-2mpstr;!%eX(XZ8z#LiCUgrI&y5{pA0 ziPo&Y3?}rOX6IiCLBl2u$)7R+0_DYEEnhsn5fpit4!YbYl1h@g&JG_h$Ay>U!YkZK zoRXTfb+$KPvVd-B3%5dW=>~8Yc|lj?5J`MUewAT78-hg`EXg_Psp40YZX4yvs(2w% z=>d;hQqv~yg58z%n&kNdQI6P7m_#>8yz)K-st!e3Trgr^1m~I(pmS&~I9eUhK4jMI z+*9_A%eh}S%+Oiqqou!MKp4SqOot;zmHGy@EKq7RsOc9jQvBE_L4(n#sYGuT z0&W^_T50ns=tAcn1hw~Ky^jX{C2f67NLFBDE>2Ty7x7G(Kx;7D0lU)I!=Ob{6D1;C zuouoOAX%q4OFu*tR^Z^uPC!f>t82G(^N=orqHKfU2) z4mHONF!TdGtb4dXzR=OZyT8!kIJYrU zFn?0)qyXFo!ITZtX-Rh-WsFD-N;)cczuQA&GH;(!N0tU+$%(s8kRVWmpZlZ)trzdi zPcfFC(_d!M07@!qz@5?$0dqaLEhv#xn@Sj>9)dGUt{j4P9H5X4fviLD`mkQscaO&Xdx{>D?>QkC=LtDGEv*+qBcZWU7S63( zezvam=Pt(^EWCP~8SVI|fBzT@U%8Nu_VqLR7g)IIiv?&Oy_Fkf;YD@>+VB7B#8noy zzEX(xXLuBOd-uyZXiGV(>lpjOce2oaZ?eqD!VmQ=Lp%87Ti<8l-&UE>ZfvgnJf4ab zdGvDAZ}tZnd+8nO7);aQMONNtK|5Me`7C4Kye|W7zOro@3%8Y}p^e-yP}x!U?M6Ht zinXM>bf01Hq}|E!jIvip)(?Wp>xX;1>EQCF!BxQso4rMGoN?Iiy+=crEGkelv;_X> zO$ArkK@f&3lj(f8kKK>YXFuGPg*TWLoI|c)0Hd=w^}6uh{b_qGYx|BZI=%(2{89kF z^Tg?fcQ~(sv4-5!ja&oL@M^jG?Tlo85w?EtK7SW{0eGYhgk501L1O z;AfCrS-piK36V5#B z)v23?F!SImx2hm~u>hLe%u*MgP)3a0wxX?Vdxg{4TH1WOJnv0^3we_J)i6E&r9NgIIzAb%Flo6 zac%Fp3?A)&ErV~=Lg`R7F8BN+{W=?elhY729WM-SoG3i*<0{}^eVQiL!FT^$F5f&p}&Q1-e299I<79>f$PS;G&De i=*V_xsWbNP^zo$YL>#q$vd28otxwN@@zs@P{#zzbAdou zAP`N8hX+ePcznjg+jYli^991|d2Lw^mrS+4xFE~S=nCywLiA)&Zg>7Kp zmRu1|5ScpmJ6WqKp+Pv%k3xZgjdmqFD_%C4&@8CYRpw9uzmlv0J@%C?)dFv4?~{)~ ze_1@XZ?Ivu0T2J=b$!$H7fRz3Bfrvb`+$k_=PR1ztKIAmhgdg{s{@H z+NaZsA3uHf<~t`0?}( zonOxxLozCxvO$5+8i}nf8q~!YF~2Da4>hHMh}}(jz6?RlDS;cNb!2+>Hml#VURnRj zy_y7sm>HwkZJ$=Gq1lgHXJcbaB$n)Z+ml&{g;_c1&a{b~KDoFJd5%BRDRPCCs~FRU zt}OD{xjCL(o05G+b|DqN?ryBjbqr~^w)J9vu0zd*eCSkHUYjpl82N`&$d^;I(VbGL z0xm1^_t2l>6b+=9^p~%tICHy4y$At-A{W7ph)_ETRx|0lOSa4G}n0qOww0g68EoC}9bzrQw+zt_Fofod# zTDoc5Rpb6hdDiPJ1~X_87B+ao-BUT~a7j2y=pb;JkhAX_B%dU(dE9)bic7%L+=Js$%)3v4tukyFo^1UeFts;}u zvG6*`LWplmD1NmpSvpaA6?`tiS1!=-TX++7OO~UqNaJlVK?1I>I_|wNp9-74zFcEY zGuO{6-BP(Bt5@1zUkSc?rBr%#JxJ^C`C^~~Pc1CQ_Hu)eV!_duW`(4{c2=F!L3}tS zf4LUl>(EOFIw}CWx-0OqBucNI4TVm30<2JLIF}4IUFWTda5SNFZz0r#4>>}0o#nvr zrylMIE4*#RP=lcf6`j>iXa#S&9rC2S>)qQ&vOUB*!wzdZZ|s0)gwC#&kPlvcF;!Mw Me17N7mCy`-02=Do