posgres image and pgAdmin
Add to docker-compose.yml:
```yml
services:
discountdb: image: postgres
pgadmin: image: dpage/pgadmin4
volumes: postgres_data: pgadmin_data:
- Add to `docker-compose.override.yml`:
```yml
services:
discountdb:
container_name: discountdb
environment:
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=admin1234
- POSTGRES_DB=DiscountDb
restart: always
ports:
- "5432:5432"
volumes:
# NOTE: in materials this is set to diff dir
# and wont work with newer psql versions
- postgres_data:/var/lib/postgresql/
pgadmin:
container_name: pgadmin
environment:
- PGADMIN_DEFAULT_EMAIL=razvoj.softvera.matf@gmail.com
- PGADMIN_DEFAULT_PASSWORD=admin1234
restart: always
ports:
- "5050:80"
volumes:
- pgadmin_data:/root/.pgadmin
$ docker-compose up discountdb pgadmin
localhost:5050DiscountDbCREATE TABLE Coupon (
ID SERIAL PRIMARY KEY NOT NULL,
ProductName VARCHAR(24) NOT NULL,
Description TEXT,
Amount INT
);
sql
INSERT INTO Coupon (ProductName, Description, Amount)
VALUES ('IPhone X', 'IPhone Discount', 150);
INSERT INTO Coupon (ProductName, Description, Amount)
VALUES ('Huawei Plus', 'Huawei Discount', 110);
INSERT INTO Coupon (ProductName, Description, Amount)
VALUES ('Xiaomi Mi 9', 'Xiaomi Discount', 75);
INSERT INTO Coupon (ProductName, Description, Amount)
VALUES ('Samsung 10', 'Samsung Discount', 100);
:coupon table
Services/DiscountClass Library instead of WebDiscount.CommonWebstore/Services/DiscountNpgsqlDapperAutoMapper
NOTE: deprecated AutoMapper.Extensions.Microsoft.DependencyInjectionMicrosoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.BinderMicrosoft.Extensions.DependencyInjection.AbstractionsWebAPI project
Discount.APIWebstore/Services/DiscountDiscount.Common
Discount.CommonSwashbuckle.AspNetCoreSwashbuckle.AspNetCore.SwaggerSwashbuckle.AspNetCore.SwaggerGenSwashbuckle.AspNetCore.SwaggerUIdiscountdb via docker-composeDiscount.API via RiderSamsung 10 product nameDiscount.APIdocker-compose.yml
services:
discount.api:
image: discount.api
build:
context: .
dockerfile: Services/Discount/Discount.API/Dockerfile
docker-compose.override.yml:
services:
discount.api:
container_name: discount.api
environment:
- ASPNETCORE_ENVIRONMENT=Development
- "DatabaseSettings:ConnectionString=Server=discountdb;Port=5432;Database=DiscountDb;User Id=admin;Password=admin1234;"
depends_on:
- discountdb
ports:
- "8002:8080"
gRPC Service project
Discount.GRPCWebstore/Services/DiscountDiscount.Common
Discount.CommonGoogle.ProtobufGrpc.CoreGrpc.Toolsgreet.protoGreeterService$ curl --http2-prior-knowledge http://localhost:<PORT>
Communication with gRPC endpoints must be made through a gRPC client...
greet.proto file on the left sideSayHello{
"name": "Ivan"
}
greet.protoGreeterServicecoupon.protoCouponService in Program.cs instead
of the default GreeterServiceCouponProtoService.CouponProtoServiceBase
launchSettings.json (copy it from Discount.API)| builder.Services.AddDiscountCommonServices(); |
| builder.Services.AddAutoMapper(configuration => |
| { |
| configuration.CreateMap<CouponDTO, GetDiscountResponse>().ReverseMap(); |
| configuration.CreateMap<CouponDTO, GetRandomDiscountsResponse.Types.Coupon>().ReverseMap(); |
Samsung 10, should workdocker-compose.yml
services:
discount.grpc:
image: discount.grpc
build:
context: .
dockerfile: Services/Discount/Discount.GRPC/Dockerfile
docker-compose.override.yml:
services:
discount.grpc:
container_name: discount.grpc
environment:
- ASPNETCORE_ENVIRONMENT=Development
- "DatabaseSettings:ConnectionString=Server=discountdb;Port=5432;Database=DiscountDb;User Id=admin;Password=admin1234;"
depends_on:
- discountdb
ports:
- "8003:8080"
Grpc.AspNetCoreGoogle.ProtobufGrpc.ToolsBasket.API.csproj:
<ItemGroup>
<Protobuf Include="..\..\Discount\Discount.GRPC\Protos\coupon.proto" GrpcServices="Client">
<Link>Protos\coupon.proto</Link>
</Protobuf>
</ItemGroup>
(should also work with Right click > Add existing file …)
| private readonly CouponGrpcService _couponGrpcService; |
+ | ... BasketController(..., CouponGrpcService couponGrpcService, ILogger<BasketController> logger)
| {
| _repository = repository ?? throw ...
+ | _couponGrpcService = couponGrpcService ?? throw ...
+ | _logger = logger ?? throw ...
| }
| ... UpdateBasket([FromBody] ShoppingCart basket)
| {
+ | foreach (var item in basket.Items)
+ | {
+ | try
+ | {
+ | var coupon = await _couponGrpcService.GetDiscount(item.ProductName);
+ | item.Price -= coupon.Amount;
+ | }
+ | catch (RpcException e)
+ | {
+ | _logger.LogInformation("Error while retrieving coupon for item {ProductName}: {message}", item.ProductName, e.Message);
+ | }
+ | }
+ | return Ok(await _repository.UpdateBasket(basket));
+ | }
builder.Services.AddGrpcClient<CouponProtoService.CouponProtoServiceClient>(
options => options.Address = new Uri(builder.Configuration["GrpcSettings:DiscountUrl"]));
builder.Services.AddScoped<CouponGrpcService>();
| “GrpcSettings”: { |
| “DiscountUrl”: “http://localhost:5003” |
| - “GrpcSettings:DiscountUrl=http://discount.grpc:8080” |
| depends_on: |
| … |
docker-compose downdocker-compose builddocker-compose up -d
IPhone X150rs2{
"username": "rs2",
"items": [
{
"quantity": 2,
"color": "white",
"price": 950,
"productId": "602d2149e773f2a3990b47f5",
"productName": "IPhone X"
},
{
"quantity": 1,
"color": "white",
"price": 380,
"productId": "602d2149e773f2a3990b47f9",
"productName": "HTC U11+ Plus"
}
]
}
Should return response where the price is 800 for IPhone X
Webstore/Tests/Basket/Webstore/Tests/Basket/Basket.API.TestsNUnitBasket.API:
Services/BasketService.cs
BasketController
BasketService.csICouponGrpcService.cs and make CouponGrpcService implement itExtensions/BasketExtensions.csBasket.API.Tests:
Mocks/
TestBasketRepository.csTestCouponGrpcService.csTestLogger.csBasketServiceTests.cs
Овај садржај је заштићен лиценцом Creative
Commons Attribution-NonCommercial 3.0 Unported License.