initial basket example.
This commit is contained in:
parent
fd3d5937f8
commit
2663ac7877
@ -39,8 +39,19 @@ Write-Host "Restore Dependencies just in case as it is needed to run dotnet publ
|
||||
dotnet restore $orderingPathToJson
|
||||
dotnet build $orderingPathToJson
|
||||
dotnet publish $orderingPathToJson -o $orderingPathToPub
|
||||
|
||||
|
||||
#*** Basket service image ***
|
||||
$basketPathToJson = $scriptPath + "\src\Services\Basket\Basket.API\project.json"
|
||||
Write-Host "basketPathToJson is $orderingPathToJson" -ForegroundColor Yellow
|
||||
$basketPathToPub = $scriptPath + "\pub\basket"
|
||||
Write-Host "basketPathToPub is $basketPathToPub" -ForegroundColor Yellow
|
||||
|
||||
Write-Host "Restore Dependencies just in case as it is needed to run dotnet publish" -ForegroundColor Blue
|
||||
dotnet restore $basketPathToJson
|
||||
dotnet build $basketPathToPub
|
||||
dotnet publish $basketPathToJson -o $basketPathToPub
|
||||
|
||||
docker build -t eshop/web $webPathToPub
|
||||
docker build -t eshop/catalog.api $catalogPathToPub
|
||||
docker build -t eshop/ordering.api $orderingPathToPub
|
||||
docker build -t eshop/ordering.api $orderingPathToPub
|
||||
docker build -t eshop/basket.api $basketPathToPub
|
@ -4,7 +4,9 @@ rm -rf ./pub
|
||||
dotnet publish "$(pwd)/src/Web/WebMVC/project.json" -o "$(pwd)/pub/webMVC"
|
||||
dotnet publish "$(pwd)/src/Services/Catalog/Catalog.API/project.json" -o "$(pwd)/pub/catalog"
|
||||
dotnet publish "$(pwd)/src/Services/Ordering/Ordering.API/project.json" -o "$(pwd)/pub/ordering"
|
||||
dotnet publish "$(pwd)/src/Services/Basket/Basket.API/project.json" -o "$(pwd)/pub/basket"
|
||||
|
||||
docker build -t eshop/web "$(pwd)/pub/webMVC"
|
||||
docker build -t eshop/catalog.api "$(pwd)/pub/catalog"
|
||||
docker build -t eshop/ordering.api "$(pwd)/pub/ordering"
|
||||
docker build -t eshop/ordering.api "$(pwd)/pub/ordering"
|
||||
docker build -t eshop/basket.api "$(pwd)/pub/basket"
|
@ -42,4 +42,14 @@ services:
|
||||
ordering.data:
|
||||
image: eshop/ordering.data.sqlserver.linux
|
||||
ports:
|
||||
- "1433:1433"
|
||||
- "1433:1433"
|
||||
|
||||
basket.api:
|
||||
image: eshop/basket.api:latest
|
||||
environment:
|
||||
- ConnectionString=basket.data
|
||||
depends_on:
|
||||
- basket.data
|
||||
|
||||
basket.data:
|
||||
image: redis
|
2
src/Services/Basket/Basket.API/.dockerignore
Normal file
2
src/Services/Basket/Basket.API/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
docker-compose.yml
|
||||
Dockerfile
|
12
src/Services/Basket/Basket.API/BasketSettings.cs
Normal file
12
src/Services/Basket/Basket.API/BasketSettings.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
public class BasketSettings
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
||||
{
|
||||
//NOTE: Right now this is a very chunky API, as the app evolves it is possible we would
|
||||
//want to make the actions more fine graned, add basket item as an action for example.
|
||||
//If this is the case we should also investigate changing the serialization format used for Redis,
|
||||
//using a HashSet instead of a simple string.
|
||||
[Route("/")]
|
||||
public class BasketController : Controller
|
||||
{
|
||||
private IBasketRepository _repository;
|
||||
|
||||
public BasketController(IBasketRepository repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
// GET api/values/5
|
||||
[HttpGet("{id}")]
|
||||
public async Task<CustomerBasket> Get(Guid id)
|
||||
{
|
||||
return await _repository.GetBasket(id);
|
||||
}
|
||||
|
||||
// POST api/values
|
||||
[HttpPost]
|
||||
public void Post([FromBody]CustomerBasket value)
|
||||
{
|
||||
_repository.UpdateBasket(value);
|
||||
}
|
||||
|
||||
// DELETE api/values/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(Guid id)
|
||||
{
|
||||
_repository.DeleteBasket(id);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
public class ValuesController : Controller
|
||||
{
|
||||
// GET api/values
|
||||
[HttpGet]
|
||||
public IEnumerable<string> Get()
|
||||
{
|
||||
return new string[] { "value1", "value2" };
|
||||
}
|
||||
|
||||
// GET api/values/5
|
||||
[HttpGet("{id}")]
|
||||
public string Get(int id)
|
||||
{
|
||||
return "value";
|
||||
}
|
||||
|
||||
// POST api/values
|
||||
[HttpPost]
|
||||
public void Post([FromBody]string value)
|
||||
{
|
||||
}
|
||||
|
||||
// PUT api/values/5
|
||||
[HttpPut("{id}")]
|
||||
public void Put(int id, [FromBody]string value)
|
||||
{
|
||||
}
|
||||
|
||||
// DELETE api/values/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(int id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
6
src/Services/Basket/Basket.API/Dockerfile
Normal file
6
src/Services/Basket/Basket.API/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
FROM microsoft/aspnetcore:1.0.1
|
||||
ENTRYPOINT ["dotnet", "Basket.API.dll"]
|
||||
ARG source=.
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
COPY $source .
|
18
src/Services/Basket/Basket.API/Model/Basket.cs
Normal file
18
src/Services/Basket/Basket.API/Model/Basket.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public class CustomerBasket
|
||||
{
|
||||
public Guid CustomerId { get; private set; }
|
||||
public IList<BasketItem> BasketItems => new List<BasketItem>();
|
||||
|
||||
public CustomerBasket(Guid customerId)
|
||||
{
|
||||
CustomerId = customerId;
|
||||
}
|
||||
}
|
||||
}
|
14
src/Services/Basket/Basket.API/Model/BasketItem.cs
Normal file
14
src/Services/Basket/Basket.API/Model/BasketItem.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public class BasketItem
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public int Count { get; set; }
|
||||
}
|
||||
}
|
14
src/Services/Basket/Basket.API/Model/IBasketRepository.cs
Normal file
14
src/Services/Basket/Basket.API/Model/IBasketRepository.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public interface IBasketRepository
|
||||
{
|
||||
Task<CustomerBasket> GetBasket(Guid customerId);
|
||||
Task<bool> UpdateBasket(CustomerBasket basket);
|
||||
Task<bool> DeleteBasket(Guid id);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using StackExchange.Redis;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API.Model
|
||||
{
|
||||
public class RedisBasketRepository : IBasketRepository
|
||||
{
|
||||
private ILogger<RedisBasketRepository> _logger;
|
||||
private BasketSettings _settings;
|
||||
|
||||
private ConnectionMultiplexer _redis;
|
||||
|
||||
|
||||
public RedisBasketRepository(IOptions<BasketSettings> options, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_settings = options.Value;
|
||||
_logger = loggerFactory.CreateLogger<RedisBasketRepository>();
|
||||
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteBasket(Guid id)
|
||||
{
|
||||
var database = await GetDatabase();
|
||||
return await database.KeyDeleteAsync(id.ToString());
|
||||
}
|
||||
|
||||
public async Task<CustomerBasket> GetBasket(Guid customerId)
|
||||
{
|
||||
var database = await GetDatabase();
|
||||
|
||||
var data = await database.StringGetAsync(customerId.ToString());
|
||||
if (data.IsNullOrEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<CustomerBasket>(data);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateBasket(CustomerBasket basket)
|
||||
{
|
||||
var database = await GetDatabase();
|
||||
return await database.StringSetAsync(basket.CustomerId.ToString(), JsonConvert.SerializeObject(basket));
|
||||
}
|
||||
|
||||
private async Task<IDatabase> GetDatabase()
|
||||
{
|
||||
if (_redis == null)
|
||||
{
|
||||
//TODO: Need to make this more robust. Also want to understand why the static connection method cannot accept dns names.
|
||||
var ips = await Dns.GetHostAddressesAsync(_settings.ConnectionString);
|
||||
_logger.LogInformation($"Connecting to database {_settings.ConnectionString} at IP {ips.First().ToString()}");
|
||||
_redis = await ConnectionMultiplexer.ConnectAsync(ips.First().ToString());
|
||||
}
|
||||
|
||||
return _redis.GetDatabase();
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,10 @@
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:{ServicePort}/api/values"
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,10 @@ using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||
using StackExchange.Redis;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Net;
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
@ -29,6 +33,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||
{
|
||||
// Add framework services.
|
||||
services.AddMvc();
|
||||
services.Configure<BasketSettings>(Configuration);
|
||||
|
||||
//By connection here we are making sure that our service
|
||||
//cannot start until redis is ready. This might slow down startup,
|
||||
//but given that it is there is a delay on resolving the ip address
|
||||
//and then creating the connection it seems reasonable to move
|
||||
//that cost to startup instead of having the first request pay the
|
||||
//penalty.
|
||||
services.AddSingleton<ConnectionMultiplexer>((sp) => {
|
||||
var config = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
|
||||
var ips = Dns.GetHostAddressesAsync(config.ConnectionString).Result;
|
||||
return ConnectionMultiplexer.Connect(ips.First().ToString());
|
||||
});
|
||||
|
||||
services.AddTransient<IBasketRepository, RedisBasketRepository>();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
@ -6,5 +6,6 @@
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ConnectionString": "127.0.0.1"
|
||||
}
|
||||
|
17
src/Services/Basket/Basket.API/docker-compose.dev.debug.yml
Normal file
17
src/Services/Basket/Basket.API/docker-compose.dev.debug.yml
Normal file
@ -0,0 +1,17 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
build:
|
||||
args:
|
||||
source: obj/Docker/empty/
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- DOTNET_USE_POLLING_FILE_WATCHER=1
|
||||
volumes:
|
||||
- .:/app
|
||||
- ~/.nuget/packages:/root/.nuget/packages:ro
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
@ -0,0 +1,9 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
labels:
|
||||
- "com.microsoft.visualstudio.targetoperatingsystem=linux"
|
||||
volumes:
|
||||
- ~/clrdbg:/clrdbg:ro
|
||||
entrypoint: tail -f /dev/null
|
16
src/Services/Basket/Basket.API/docker-compose.yml
Normal file
16
src/Services/Basket/Basket.API/docker-compose.yml
Normal file
@ -0,0 +1,16 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
basket.api:
|
||||
image: user/basket.api${TAG}
|
||||
environment:
|
||||
- ConnectionString=basket.data
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "32783:80"
|
||||
depends_on:
|
||||
- basket.data
|
||||
basket.data:
|
||||
image: redis
|
@ -1,9 +1,10 @@
|
||||
{
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"System.Threading": "4.0.11",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
||||
@ -13,13 +14,13 @@
|
||||
"Microsoft.Extensions.Logging": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
|
||||
"StackExchange.Redis": "1.1.608",
|
||||
"Newtonsoft.Json": "9.0.1"
|
||||
},
|
||||
|
||||
"tools": {
|
||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
@ -28,29 +29,31 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"preserveCompilationContext": true
|
||||
"preserveCompilationContext": true,
|
||||
"debugType": "portable"
|
||||
},
|
||||
|
||||
"runtimeOptions": {
|
||||
"configProperties": {
|
||||
"System.GC.Server": true
|
||||
}
|
||||
},
|
||||
|
||||
"publishOptions": {
|
||||
"include": [
|
||||
"wwwroot",
|
||||
"Views",
|
||||
"Areas/**/Views",
|
||||
"appsettings.json",
|
||||
"web.config"
|
||||
"web.config",
|
||||
"Dockerfile",
|
||||
"docker-compose.yml",
|
||||
".dockerignore"
|
||||
]
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
||||
"postpublish": [
|
||||
"dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user