diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb.sln b/DotnetAzureCosmosDb/DotnetAzureCosmosDb.sln new file mode 100644 index 0000000..25a6876 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb.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}") = "DotnetAzureCosmosDb", "DotnetAzureCosmosDb\DotnetAzureCosmosDb.csproj", "{0B1346AB-9EEA-4A76-B885-6A25EB42C427}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0B1346AB-9EEA-4A76-B885-6A25EB42C427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B1346AB-9EEA-4A76-B885-6A25EB42C427}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B1346AB-9EEA-4A76-B885-6A25EB42C427}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B1346AB-9EEA-4A76-B885-6A25EB42C427}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/ApiResponse.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/ApiResponse.cs new file mode 100644 index 0000000..d378740 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/ApiResponse.cs @@ -0,0 +1,9 @@ +namespace DotnetAzureCosmosDb.Contracts +{ + public class ApiResponse + { + public string Message { get; set; } + public bool IsSuccess { get; set; } + public object Result { get; set; } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/IStudentService.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/IStudentService.cs new file mode 100644 index 0000000..a44dc29 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/IStudentService.cs @@ -0,0 +1,11 @@ +namespace DotnetAzureCosmosDb.Contracts +{ + public interface IStudentService + { + Task AddStudentAsync(CreateStudentDto student); + Task GetStudentByIdAsync(string id); + Task GetAllStudentsAsync(string qurey); + Task UpdateStudentAsync(string id, UpdateStudentDto student); + Task DeleteStudentAsync(string id); + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/StudentDTOs.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/StudentDTOs.cs new file mode 100644 index 0000000..eaf3dfe --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Contracts/StudentDTOs.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; + +namespace DotnetAzureCosmosDb.Contracts +{ + + public record CreateStudentDto + { + [JsonProperty(PropertyName = "name")] + public required string Name { get; init; } + + [JsonProperty(PropertyName = "email")] + public required string Email { get; init; } + + [JsonProperty(PropertyName = "age")] + public int Age { get; init; } + } + + + public record UpdateStudentDto + { + + public required string Name { get; init; } + [JsonProperty(PropertyName = "email")] + public required string Email { get; init; } + [JsonProperty(PropertyName = "age")] + public int Age { get; init; } + } + + +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Controllers/StudentController.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Controllers/StudentController.cs new file mode 100644 index 0000000..a96c950 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Controllers/StudentController.cs @@ -0,0 +1,96 @@ +using DotnetAzureCosmosDb.Contracts; +using Microsoft.AspNetCore.Mvc; + +namespace DotnetAzureCosmosDb.Controllers +{ + /// + /// Controller for managing student entities. + /// + [ApiController] + [Route("api/")] + public class StudentController : ControllerBase + { + private readonly IStudentService _studentService; + + /// + /// Initializes a new instance of the class. + /// + /// The student service. + public StudentController(IStudentService studentService) + { + _studentService = studentService; + } + + /// + /// Adds a new student asynchronously. + /// + /// The student to add. + /// An indicating the result of the operation. + [HttpPost("student")] + public async Task AddStudentAsync([FromBody] CreateStudentDto student) + { + var response = await _studentService.AddStudentAsync(student); + if (response.IsSuccess) + { + return Ok(response); + } + return BadRequest(response); + } + + /// + /// Gets all students asynchronously. + /// + /// An containing the list of students. + [HttpGet("students")] + public async Task GetAllStudents() + { + var students = await _studentService.GetAllStudentsAsync("SELECT * FROM c"); + return Ok(students); + } + + /// + /// Gets a student by ID asynchronously. + /// + /// The ID of the student. + /// An containing the student. + [HttpGet("student/{id}")] + public async Task GetStudentByIdAsync(string id) + { + var student = await _studentService.GetStudentByIdAsync(id); + return Ok(student); + } + + /// + /// Updates a student asynchronously. + /// + /// The ID of the student to update. + /// The updated student data. + /// An indicating the result of the operation. + [HttpPut("student")] + public async Task UpdateStudentAsync(string id, [FromBody] UpdateStudentDto student) + { + var response = await _studentService.UpdateStudentAsync(id, student); + if (response.IsSuccess) + { + return Ok(response); + } + return BadRequest(response); + } + + /// + /// Deletes a student asynchronously. + /// + /// The ID of the student to delete. + /// An indicating the result of the operation. + [HttpDelete("student/{id}")] + public async Task DeleteStudentAsync(string id) + { + var response = await _studentService.DeleteStudentAsync(id); + if (response.IsSuccess) + { + return Ok(response); + } + return BadRequest(response); + } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/DotnetAzureCosmosDb.csproj b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/DotnetAzureCosmosDb.csproj new file mode 100644 index 0000000..813429d --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/DotnetAzureCosmosDb.csproj @@ -0,0 +1,16 @@ + + + + net9.0 + enable + enable + + + + + + + + + + diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/DotnetAzureCosmosDb.http b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/DotnetAzureCosmosDb.http new file mode 100644 index 0000000..66a8427 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/DotnetAzureCosmosDb.http @@ -0,0 +1,6 @@ +@DotnetAzureCosmosDb_HostAddress = http://localhost:5176 + +GET {{DotnetAzureCosmosDb_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Extensions/CosmosDbServiceExtensions.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Extensions/CosmosDbServiceExtensions.cs new file mode 100644 index 0000000..bc74e0d --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Extensions/CosmosDbServiceExtensions.cs @@ -0,0 +1,21 @@ +using DotnetAzureCosmosDb.Services; + +namespace DotnetAzureCosmosDb.Extensions +{ + public static class CosmosDbServiceExtensions + { + public static async Task InitializeCosmosClientInstanceAsync(this IConfigurationSection configurationSection) + { + var databaseName = configurationSection["DatabaseName"]; + var containerName = configurationSection["ContainerName"]; + var account = configurationSection["Account"]; + var key = configurationSection["Key"]; + + var client = new Microsoft.Azure.Cosmos.CosmosClient(account, key); + var database = await client.CreateDatabaseIfNotExistsAsync(databaseName); + await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id"); + + return new StudentService(client, databaseName, containerName); + } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Models/Student.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Models/Student.cs new file mode 100644 index 0000000..c86a464 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Models/Student.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; + +namespace DotnetAzureCosmosDb.Models +{ + public class Student + { + [JsonProperty(PropertyName = "id")] + public string Id { get; set; } + + [JsonProperty(PropertyName = "name")] + + public string Name { get; set; } + + + [JsonProperty(PropertyName = "email")] + + public string Email { get; set; } + + + [JsonProperty(PropertyName = "age")] + public int Age { get; set; } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Program.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Program.cs new file mode 100644 index 0000000..2f94c5a --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Program.cs @@ -0,0 +1,35 @@ +using DotnetAzureCosmosDb.Contracts; +using DotnetAzureCosmosDb.Extensions; + +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.AddSwaggerGen(); + +// Adding services to the container +builder.Services.AddSingleton(builder.Configuration.GetSection("CosmosDb").InitializeCosmosClientInstanceAsync().GetAwaiter().GetResult()); + + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); + app.UseSwaggerUI(); + app.UseSwagger(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Properties/launchSettings.json b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Properties/launchSettings.json new file mode 100644 index 0000000..0dc39c7 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/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:5176", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7279;http://localhost:5176", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Services/StudentService.cs b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Services/StudentService.cs new file mode 100644 index 0000000..3732a4e --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/Services/StudentService.cs @@ -0,0 +1,176 @@ +using DotnetAzureCosmosDb.Contracts; +using DotnetAzureCosmosDb.Models; +using Microsoft.Azure.Cosmos; +using System.Net; + +namespace DotnetAzureCosmosDb.Services +{ + /// + /// Service for managing student entities in Azure Cosmos DB. + /// + public class StudentService : IStudentService + { + private readonly Container _container; + + /// + /// Initializes a new instance of the class. + /// + /// The Cosmos client. + /// The name of the database. + /// The name of the container. + public StudentService(CosmosClient cosmosClient, string databaseName, string containerName) + { + _container = cosmosClient.GetContainer(databaseName, containerName); + } + + /// + /// Adds a new student asynchronously. + /// + /// The student to add. + /// An indicating the result of the operation. + public async Task AddStudentAsync(CreateStudentDto student) + { + var studentEntity = new Student + { + Id = Guid.NewGuid().ToString(), + Name = student.Name, + Email = student.Email, + Age = student.Age, + }; + + var response = await _container.CreateItemAsync(studentEntity, new PartitionKey(studentEntity.Id)); + + return new ApiResponse + { + IsSuccess = response.Equals(HttpStatusCode.NoContent), + Message = response.StatusCode.ToString(), + Result = studentEntity + }; + } + + /// + /// Gets all students asynchronously. + /// + /// The query to execute. + /// An containing the list of students. + public async Task GetAllStudentsAsync(string query) + { + var queryIterator = _container.GetItemQueryIterator(new QueryDefinition(query)); + var students = new List(); + while (queryIterator.HasMoreResults) + { + var response = await queryIterator.ReadNextAsync(); + students.AddRange(response.Resource); + } + return new ApiResponse + { + IsSuccess = true, + Message = "Students fetched successfully", + Result = students + }; + } + + /// + /// Gets a student by ID asynchronously. + /// + /// The ID of the student. + /// An containing the student. + public async Task GetStudentByIdAsync(string id) + { + try + { + var response = await _container.ReadItemAsync(id, new PartitionKey(id)); + return new ApiResponse + { + IsSuccess = true, + Message = "Student fetched successfully", + Result = response.Resource + }; + } + catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return new ApiResponse + { + IsSuccess = false, + Message = ex.Message, + Result = null + }; + } + } + + /// + /// Updates a student asynchronously. + /// + /// The ID of the student to update. + /// The updated student data. + /// An indicating the result of the operation. + public async Task UpdateStudentAsync(string id, UpdateStudentDto student) + { + try + { + var patchOperations = new List(); + + if (!string.IsNullOrWhiteSpace(student.Name)) + { + patchOperations.Add(PatchOperation.Replace("/name", student.Name.Trim())); + } + + if (!string.IsNullOrWhiteSpace(student.Email)) + { + patchOperations.Add(PatchOperation.Replace("/email", student.Email.Trim())); + } + + if (student.Age != 0) + { + patchOperations.Add(PatchOperation.Replace("/age", student.Age)); + } + + var response = await _container.PatchItemAsync(id, new PartitionKey(id), patchOperations); + + return new ApiResponse + { + IsSuccess = response.Equals(HttpStatusCode.NoContent), + Message = response.StatusCode.ToString(), + Result = response.Resource + }; + } + catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return new ApiResponse + { + IsSuccess = false, + Message = ex.Message, + Result = null + }; + } + } + + /// + /// Deletes a student asynchronously. + /// + /// The ID of the student to delete. + /// An indicating the result of the operation. + public async Task DeleteStudentAsync(string id) + { + try + { + var response = await _container.DeleteItemAsync(id, new PartitionKey(id)); + return new ApiResponse + { + IsSuccess = response.Equals(HttpStatusCode.NoContent), + Message = response.StatusCode.ToString(), + Result = null + }; + } + catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return new ApiResponse + { + IsSuccess = false, + Message = ex.Message, + Result = null + }; + } + } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/appsettings.Development.json b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DotnetAzureCosmosDb/DotnetAzureCosmosDb/appsettings.json b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/appsettings.json new file mode 100644 index 0000000..34b6310 --- /dev/null +++ b/DotnetAzureCosmosDb/DotnetAzureCosmosDb/appsettings.json @@ -0,0 +1,16 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "CosmosDb": { + "Account": "your acccount here ", + "Key": "your key here ", + "DatabaseName": "Database name here", + "ContainerName": "Container Name here " + } +} \ No newline at end of file