Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ParkingLotApi.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34221.43
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParkingLotApi", "ParkingLotApi\ParkingLotApi.csproj", "{245411D4-F8E0-4BE6-AF4C-B4EB3AC0ABBE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParkingLotApi", "ParkingLotApi\ParkingLotApi.csproj", "{245411D4-F8E0-4BE6-AF4C-B4EB3AC0ABBE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParkingLotApiTest", "ParkingLotApiTest\ParkingLotApiTest.csproj", "{3C240C7A-4F4C-42B9-91A1-DE41AAB75DAE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParkingLotApiTest", "ParkingLotApiTest\ParkingLotApiTest.csproj", "{3C240C7A-4F4C-42B9-91A1-DE41AAB75DAE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
70 changes: 70 additions & 0 deletions ParkingLotApi/Controllers/ParkingLotsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Microsoft.AspNetCore.Mvc;
using ParkingLotApi.Exceptions;
using ParkingLotApi.Models;
using ParkingLotApi.Services;

namespace ParkingLotApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ParkingLotsController : ControllerBase
{
private readonly ParkingLotsService _parkingLotsService;
public ParkingLotsController(ParkingLotsService parkingLotsService)
{
_parkingLotsService = parkingLotsService;
}

[HttpPost]
public async Task<ActionResult<ParkingLotEntity>> AddParkingLot([FromBody] ParkingLotDto parkingLotDto)
{
/* try
{*/
// return Created("", await _parkingLotsService.AddAsync(parkingLotDto));
return StatusCode(StatusCodes.Status201Created, await _parkingLotsService.AddAsync(parkingLotDto));
/* } catch (InvalidCapacityException ex)
{
return BadRequest(ex.Message);
}*/
}

[HttpDelete("{id}")]
public async Task<ActionResult> RemoveParkingLot(string id)
{
var isRemoved = await _parkingLotsService.RemoveAsync(id);
if (isRemoved)
{
return NoContent();
}
return NotFound();
}

[HttpGet]
public async Task<ActionResult<List<ParkingLotEntity>>> GetOnePageParkingLots([FromQuery] int pageIndex)
{
return await _parkingLotsService.GetOnePageParkingLots(pageIndex);
}

[HttpGet("{id}")]
public async Task<ActionResult<List<ParkingLotEntity>>> GetParkingLotById(string id)
{
var parkingLot = await _parkingLotsService.GetByIdAsync(id);
if (parkingLot == null)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: avoid return null from method, since null is hard to understand. here we can throw exception from service

{
return NotFound();
}
return Ok(parkingLot);
}

[HttpPut("{id}")]
public async Task<ActionResult<ParkingLotEntity>> UpdateCapacityAsync(string id, [FromBody] int capacity)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: use class for request body instead of int

{
var updatedParkingLot = await _parkingLotsService.UpdateCapacity(id, capacity);
if (updatedParkingLot == null)
{
return NotFound();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: this can also be handled in global exception handler

}
return Ok(updatedParkingLot);
}
}
}
33 changes: 0 additions & 33 deletions ParkingLotApi/Controllers/WeatherForecastController.cs

This file was deleted.

14 changes: 14 additions & 0 deletions ParkingLotApi/Dtos/ParkingLotDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace ParkingLotApi.Models
{
public class ParkingLotDto
{
public string Name { get; set; }
public int Capacity { get; set; }
public string Location { get; set; }

internal ParkingLotEntity ToEntity()
{
return new ParkingLotEntity { Name = Name, Capacity = Capacity, Location = Location };
}
}
}
10 changes: 10 additions & 0 deletions ParkingLotApi/Exceptions/InvalidCapacityException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace ParkingLotApi.Exceptions
{
public class InvalidCapacityException : Exception
{
public InvalidCapacityException(string message) : base(message)
{

}
}
}
25 changes: 25 additions & 0 deletions ParkingLotApi/Filters/InvalidCapacityExceptionFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using ParkingLotApi.Exceptions;

namespace ParkingLotApi.Filters
{
public class InvalidCapacityExceptionFilter : IActionFilter, IOrderedFilter
{
public int Order => int.MaxValue - 10;

public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is InvalidCapacityException invalidCapacityException)
{
context.Result = new BadRequestResult();
context.ExceptionHandled = true;
}
}

public void OnActionExecuting(ActionExecutingContext context)
{
}
}
}
16 changes: 16 additions & 0 deletions ParkingLotApi/Models/ParkingLotEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace ParkingLotApi.Models
{
public class ParkingLotEntity
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string? Id { get; set; }

public string Name { get; set; }
public int Capacity { get; set; }
public string Location { get; set; }
}
}
9 changes: 9 additions & 0 deletions ParkingLotApi/Models/ParkingLotsDatabaseSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ParkingLotApi.Models
{
public class ParkingLotsDatabaseSettings
{
public string ConnectionString { get; set; } = null!;
public string DatabaseName { get; set; } = null!;
public string CollectionName { get; set; } = null!;
}
}
2 changes: 2 additions & 0 deletions ParkingLotApi/ParkingLotApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.13" />
<PackageReference Include="MongoDB.Bson" Version="2.22.0" />
<PackageReference Include="MongoDB.Driver" Version="2.22.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

Expand Down
23 changes: 21 additions & 2 deletions ParkingLotApi/Program.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
using ParkingLotApi.Filters;
using ParkingLotApi.Models;
using ParkingLotApi.Repositories;
using ParkingLotApi.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
builder.Services.AddControllers(options =>
{
options.Filters.Add<InvalidCapacityExceptionFilter>();
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddScoped<ParkingLotsService>();
builder.Services.AddSingleton<IParkingLotsRepository, ParkingLotsRepository>();
builder.Services.Configure<ParkingLotsDatabaseSettings>(
builder.Configuration.GetSection("ParkingLotsDatabase")
);

var app = builder.Build();

// Configure the HTTP request pipeline.
Expand All @@ -22,4 +36,9 @@

app.MapControllers();

app.Run();
app.Run();

public partial class Program
{

}
13 changes: 13 additions & 0 deletions ParkingLotApi/Repositories/IParkingLotsRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using ParkingLotApi.Models;

namespace ParkingLotApi.Repositories
{
public interface IParkingLotsRepository
{
Task<ParkingLotEntity> CreateParkingLotAsync(ParkingLotEntity parkingLo);
Task<bool> DeleteParkingLotAsync(string id);
Task<List<ParkingLotEntity>> GetAllAsync();
Task<ParkingLotEntity> GetByIdAsync(string id);
Task<ParkingLotEntity> UpdateCapacity(string id, ParkingLotEntity updatedParkingLot);
}
}
49 changes: 49 additions & 0 deletions ParkingLotApi/Repositories/ParkingLotsRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using ParkingLotApi.Models;

namespace ParkingLotApi.Repositories
{

public class ParkingLotsRepository : IParkingLotsRepository
{
private readonly IMongoCollection<ParkingLotEntity> _parkingLotsCollection;
public ParkingLotsRepository(IOptions<ParkingLotsDatabaseSettings> parkingLotsDatabaseSettings)
{
var mongoClient = new MongoClient(parkingLotsDatabaseSettings.Value.ConnectionString);
var mongoDatabase = mongoClient.GetDatabase(parkingLotsDatabaseSettings.Value.DatabaseName);
_parkingLotsCollection = mongoDatabase.GetCollection<ParkingLotEntity>(parkingLotsDatabaseSettings.Value.CollectionName);

}

public async Task<ParkingLotEntity> CreateParkingLotAsync(ParkingLotEntity parkingLot)
{
await _parkingLotsCollection.InsertOneAsync(parkingLot);
return await _parkingLotsCollection.Find(a => a.Name == parkingLot.Name).FirstAsync();
}

public async Task<bool> DeleteParkingLotAsync(string id)
{
var result = await _parkingLotsCollection.DeleteOneAsync(p => p.Id == id);
return result.DeletedCount > 0;
}

public async Task<List<ParkingLotEntity>> GetAllAsync()
{
return await _parkingLotsCollection.Find(_ => true).ToListAsync();
}

public async Task<ParkingLotEntity> GetByIdAsync(string id)
{
return await _parkingLotsCollection.Find(p => p.Id == id).FirstOrDefaultAsync();
}

public async Task<ParkingLotEntity?> UpdateCapacity(string id, ParkingLotEntity updatedParkingLot)
{
await _parkingLotsCollection.ReplaceOneAsync(p => p.Id == id, updatedParkingLot);
return await GetByIdAsync(id);
}


}
}
63 changes: 63 additions & 0 deletions ParkingLotApi/Services/ParkingLotsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using ParkingLotApi.Exceptions;
using ParkingLotApi.Models;
using ParkingLotApi.Repositories;
using System;

namespace ParkingLotApi.Services
{
public class ParkingLotsService
{
private readonly IParkingLotsRepository _parkingLotsRepository;
public ParkingLotsService(IParkingLotsRepository parkingLotsRepository) {
_parkingLotsRepository = parkingLotsRepository;
}
public async Task<ParkingLotEntity> AddAsync(ParkingLotDto parkingLotDto)
{
if (parkingLotDto.Capacity < 10)
{
throw new InvalidCapacityException("The capacity should be no less than 10");
}
return await _parkingLotsRepository.CreateParkingLotAsync(parkingLotDto.ToEntity());
}

public async Task<bool> RemoveAsync(string id)
{
return await _parkingLotsRepository.DeleteParkingLotAsync(id);
}

public async Task<List<ParkingLotEntity>> GetOnePageParkingLots(int pageIndex)
{
var allParkingLots = await _parkingLotsRepository.GetAllAsync();
int pageSize = 15;
int startIdx = (int)((pageIndex - 1) * pageSize);
return allParkingLots.Skip(startIdx).Take((int)pageSize).ToList();
}

public async Task<ParkingLotEntity> GetByIdAsync(string id)
{
return await _parkingLotsRepository.GetByIdAsync(id);
}

public IParkingLotsRepository Get_parkingLotsRepository()
{
return _parkingLotsRepository;
}

public async Task<ParkingLotEntity?> UpdateCapacity(string id, int capacity)
{
var parkingLot = await _parkingLotsRepository.GetByIdAsync(id);
if (parkingLot != null)
{
var updatedParkingLot = new ParkingLotEntity()
{
Capacity = capacity,
Id = parkingLot.Id,
Name = parkingLot.Name,
Location = parkingLot.Location
};
return await _parkingLotsRepository.UpdateCapacity(id, updatedParkingLot);
}
return null;
}
}
}
7 changes: 6 additions & 1 deletion ParkingLotApi/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,10 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"ParkingLotsDataBase": {
"ConnectionString": "mongodb://localhost:27017/",
"DatabaseName": "ParkingLots",
"CollectionName": "ParkingLots"
}
}
Loading