Skip to content

Commit 122e4a0

Browse files
committed
End of section 12
1 parent 945b4c6 commit 122e4a0

File tree

9 files changed

+122
-2
lines changed

9 files changed

+122
-2
lines changed

API/Controllers/CartController.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Core.Entities;
2+
using Core.Interfaces;
3+
using Microsoft.AspNetCore.Mvc;
4+
5+
namespace API.Controllers;
6+
7+
public class CartController(ICartService cartService) : BaseApiController
8+
{
9+
[HttpGet]
10+
public async Task<ActionResult<ShoppingCart>> GetCartById(string id)
11+
{
12+
var cart = await cartService.GetCartAsync(id);
13+
14+
return Ok(cart ?? new ShoppingCart { Id = id });
15+
}
16+
17+
[HttpPost]
18+
public async Task<ActionResult<ShoppingCart>> UpdateCart(ShoppingCart cart)
19+
{
20+
var updatedCart = await cartService.SetCartAsync(cart);
21+
if (updatedCart == null) return BadRequest("Problem with cart");
22+
23+
return updatedCart;
24+
}
25+
26+
[HttpDelete]
27+
public async Task<ActionResult> DeleteCart(string id)
28+
{
29+
var result = await cartService.DeleteCartAsync(id);
30+
if (!result) return BadRequest("Problem deleting cart");
31+
32+
return Ok();
33+
}
34+
}

API/Program.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using API.Middleware;
22
using Core.Interfaces;
33
using Infrastructure.Data;
4+
using Infrastructure.Services;
45
using Microsoft.EntityFrameworkCore;
6+
using StackExchange.Redis;
57

68
var builder = WebApplication.CreateBuilder(args);
79

@@ -15,6 +17,15 @@
1517
builder.Services.AddScoped<IProductRepository, ProductRepository>();
1618
builder.Services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
1719
builder.Services.AddCors();
20+
builder.Services.AddSingleton<IConnectionMultiplexer>(config =>
21+
{
22+
var connString = builder.Configuration.GetConnectionString("Redis")
23+
?? throw new Exception("Cannot get redis connection string");
24+
25+
var configuration = ConfigurationOptions.Parse(connString, true);
26+
return ConnectionMultiplexer.Connect(configuration);
27+
});
28+
builder.Services.AddSingleton<ICartService, CartService>();
1829

1930
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
2031
builder.Services.AddOpenApi();

API/appsettings.Development.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
}
77
},
88
"ConnectionStrings": {
9-
"DefaultConnection": "Server=localhost,1433;Database=skinet;User Id=SA;Password=Password@1;TrustServerCertificate=True"
9+
"DefaultConnection": "Server=localhost,1433;Database=skinet;User Id=SA;Password=Password@1;TrustServerCertificate=True",
10+
"Redis": "localhost"
1011
}
1112
}

Core/Entities/CartItem.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Core.Entities;
2+
3+
public class CartItem
4+
{
5+
public int ProductId { get; set; }
6+
public required string ProductName { get; set; }
7+
public decimal Price { get; set; }
8+
public int Quantity { get; set; }
9+
public required string PictureUrl { get; set; }
10+
public required string Brand { get; set; }
11+
public required string Type { get; set; }
12+
}

Core/Entities/ShoppingCart.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Core.Entities;
2+
3+
public class ShoppingCart
4+
{
5+
public required string Id { get; set; }
6+
public List<CartItem> Items { get; set; } = [];
7+
8+
}

Core/Interfaces/ICartService.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using Core.Entities;
2+
3+
namespace Core.Interfaces;
4+
5+
public interface ICartService
6+
{
7+
Task<ShoppingCart?> GetCartAsync(string key);
8+
Task<ShoppingCart?> SetCartAsync(ShoppingCart cart);
9+
Task<bool> DeleteCartAsync(string key);
10+
}

Infrastructure/Infrastructure.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
<ItemGroup>
88
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.1" />
9+
<PackageReference Include="StackExchange.Redis" Version="2.8.24" />
910
</ItemGroup>
1011

1112
<ItemGroup>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Text.Json;
2+
using Core.Entities;
3+
using Core.Interfaces;
4+
using StackExchange.Redis;
5+
6+
namespace Infrastructure.Services;
7+
8+
public class CartService(IConnectionMultiplexer redis) : ICartService
9+
{
10+
private readonly IDatabase _database = redis.GetDatabase();
11+
12+
public async Task<bool> DeleteCartAsync(string key)
13+
{
14+
return await _database.KeyDeleteAsync(key);
15+
}
16+
17+
public async Task<ShoppingCart?> GetCartAsync(string key)
18+
{
19+
var data = await _database.StringGetAsync(key);
20+
21+
return data.IsNullOrEmpty ? null : JsonSerializer.Deserialize<ShoppingCart>(data!);
22+
}
23+
24+
public async Task<ShoppingCart?> SetCartAsync(ShoppingCart cart)
25+
{
26+
var created = await _database.StringSetAsync(cart.Id, JsonSerializer.Serialize(cart), TimeSpan.FromDays(30));
27+
if (!created) return null;
28+
29+
return await GetCartAsync(cart.Id);
30+
}
31+
}

docker-compose.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,16 @@ services:
55
ACCEPT_EULA: "1"
66
MSSQL_SA_PASSWORD: "Password@1"
77
ports:
8-
- "1433:1433"
8+
- "1433:1433"
9+
volumes:
10+
- sql-data:/var/opt/mssql
11+
redis:
12+
image: redis:latest
13+
ports:
14+
- "6379:6379"
15+
volumes:
16+
- redis-data:/data
17+
18+
volumes:
19+
redis-data:
20+
sql-data:

0 commit comments

Comments
 (0)