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 restore $orderingPathToJson
|
||||||
dotnet build $orderingPathToJson
|
dotnet build $orderingPathToJson
|
||||||
dotnet publish $orderingPathToJson -o $orderingPathToPub
|
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/web $webPathToPub
|
||||||
docker build -t eshop/catalog.api $catalogPathToPub
|
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/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/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/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/web "$(pwd)/pub/webMVC"
|
||||||
docker build -t eshop/catalog.api "$(pwd)/pub/catalog"
|
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:
|
ordering.data:
|
||||||
image: eshop/ordering.data.sqlserver.linux
|
image: eshop/ordering.data.sqlserver.linux
|
||||||
ports:
|
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": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"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.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
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
|
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||||
{
|
{
|
||||||
@ -29,6 +33,21 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
{
|
{
|
||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddMvc();
|
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.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "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": {
|
"dependencies": {
|
||||||
"Microsoft.NETCore.App": {
|
"Microsoft.NETCore.App": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "platform"
|
"type": "platform"
|
||||||
},
|
},
|
||||||
|
"System.Threading": "4.0.11",
|
||||||
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
||||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
||||||
@ -13,13 +14,13 @@
|
|||||||
"Microsoft.Extensions.Logging": "1.0.0",
|
"Microsoft.Extensions.Logging": "1.0.0",
|
||||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||||
"Microsoft.Extensions.Logging.Debug": "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": {
|
"tools": {
|
||||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
|
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"netcoreapp1.0": {
|
"netcoreapp1.0": {
|
||||||
"imports": [
|
"imports": [
|
||||||
@ -28,29 +29,31 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"buildOptions": {
|
"buildOptions": {
|
||||||
"emitEntryPoint": true,
|
"emitEntryPoint": true,
|
||||||
"preserveCompilationContext": true
|
"preserveCompilationContext": true,
|
||||||
|
"debugType": "portable"
|
||||||
},
|
},
|
||||||
|
|
||||||
"runtimeOptions": {
|
"runtimeOptions": {
|
||||||
"configProperties": {
|
"configProperties": {
|
||||||
"System.GC.Server": true
|
"System.GC.Server": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"publishOptions": {
|
"publishOptions": {
|
||||||
"include": [
|
"include": [
|
||||||
"wwwroot",
|
"wwwroot",
|
||||||
"Views",
|
"Views",
|
||||||
"Areas/**/Views",
|
"Areas/**/Views",
|
||||||
"appsettings.json",
|
"appsettings.json",
|
||||||
"web.config"
|
"web.config",
|
||||||
|
"Dockerfile",
|
||||||
|
"docker-compose.yml",
|
||||||
|
".dockerignore"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
"scripts": {
|
"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