Updated codes from net21rc1 branch

This commit is contained in:
rafsanulhasan 2018-08-12 04:58:18 +06:00
parent 571b4e1a4c
commit 49200d77b2
59 changed files with 1044 additions and 1000 deletions

View File

@ -1,8 +1,8 @@
FROM microsoft/aspnetcore:2.0 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/
RUN dotnet restore src/ApiGateways/ApiGw-Base/

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/ApiGateways/Mobile.Bff.Shopping/aggregator
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure
{
public class HttpClientAuthorizationDelegatingHandler
: DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccesor;
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
{
_httpContextAccesor = httpContextAccesor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authorizationHeader = _httpContextAccesor.HttpContext
.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authorizationHeader))
{
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
}
var token = await GetToken();
if (token != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
return await base.SendAsync(request, cancellationToken);
}
async Task<string> GetToken()
{
const string ACCESS_TOKEN = "access_token";
return await _httpContextAccesor.HttpContext
.GetTokenAsync(ACCESS_TOKEN);
}
}
}

View File

@ -1,53 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{
public class BasketService : IBasketService
{
private readonly IHttpClient _apiClient;
private readonly HttpClient _httpClient;
private readonly ILogger<BasketService> _logger;
private readonly UrlsConfig _urls;
private readonly IHttpContextAccessor _httpContextAccessor;
public BasketService(IHttpClient httpClient, IHttpContextAccessor httpContextAccessor, ILogger<BasketService> logger, IOptionsSnapshot<UrlsConfig> config)
public BasketService(HttpClient httpClient, ILogger<BasketService> logger, IOptions<UrlsConfig> config)
{
_apiClient = httpClient;
_httpClient = httpClient;
_logger = logger;
_urls = config.Value;
_httpContextAccessor = httpContextAccessor;
}
public async Task<BasketData> GetById(string id)
{
var token = await GetUserTokenAsync();
var data = await _apiClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id), token);
var data = await _httpClient.GetStringAsync(_urls.Basket + UrlsConfig.BasketOperations.GetItemById(id));
var basket = !string.IsNullOrEmpty(data) ? JsonConvert.DeserializeObject<BasketData>(data) : null;
return basket;
}
public async Task Update(BasketData currentBasket)
{
var token = await GetUserTokenAsync();
var data = await _apiClient.PostAsync<BasketData>(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), currentBasket, token);
int i = 0;
}
var basketContent = new StringContent(JsonConvert.SerializeObject(currentBasket), System.Text.Encoding.UTF8, "application/json");
async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccessor.HttpContext;
return await context.GetTokenAsync("access_token");
var data = await _httpClient.PostAsync(_urls.Basket + UrlsConfig.BasketOperations.UpdateBasket(), basketContent);
}
}
}

View File

@ -1,43 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{
public class CatalogService : ICatalogService
{
private readonly IHttpClient _apiClient;
private readonly HttpClient _httpClient;
private readonly ILogger<CatalogService> _logger;
private readonly UrlsConfig _urls;
public CatalogService(IHttpClient httpClient, ILogger<CatalogService> logger, IOptionsSnapshot<UrlsConfig> config)
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<UrlsConfig> config)
{
_apiClient = httpClient;
_httpClient = httpClient;
_logger = logger;
_urls = config.Value;
}
public async Task<CatalogItem> GetCatalogItem(int id)
{
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var item = JsonConvert.DeserializeObject<CatalogItem>(data);
return item;
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemById(id));
var catalogItem = JsonConvert.DeserializeObject<CatalogItem>(stringContent);
return catalogItem;
}
public async Task<IEnumerable<CatalogItem>> GetCatalogItems(IEnumerable<int> ids)
{
var data = await _apiClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
var item = JsonConvert.DeserializeObject<CatalogItem[]>(data);
return item;
var stringContent = await _httpClient.GetStringAsync(_urls.Catalog + UrlsConfig.CatalogOperations.GetItemsById(ids));
var catalogItems = JsonConvert.DeserializeObject<CatalogItem[]>(stringContent);
return catalogItems;
}
}
}

View File

@ -1,24 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config;
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Models;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
{
public class OrderApiClient : IOrderApiClient
{
private readonly IHttpClient _apiClient;
private readonly HttpClient _apiClient;
private readonly ILogger<OrderApiClient> _logger;
private readonly UrlsConfig _urls;
public OrderApiClient(IHttpClient httpClient, ILogger<OrderApiClient> logger, IOptionsSnapshot<UrlsConfig> config)
public OrderApiClient(HttpClient httpClient, ILogger<OrderApiClient> logger, IOptions<UrlsConfig> config)
{
_apiClient = httpClient;
_logger = logger;
@ -27,11 +23,15 @@ namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Services
public async Task<OrderData> GetOrderDraftFromBasket(BasketData basket)
{
var url = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
var response = await _apiClient.PostAsync<BasketData>(url, basket);
var uri = _urls.Orders + UrlsConfig.OrdersOperations.GetOrderDraft();
var content = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PostAsync(uri, content);
response.EnsureSuccessStatusCode();
var jsonResponse = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<OrderData>(jsonResponse);
var ordersDraftResponse = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<OrderData>(ordersDraftResponse);
}
}
}

View File

@ -96,18 +96,6 @@
"UpstreamPathTemplate": "/catalog-api/{everything}",
"UpstreamHttpMethod": []
},
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "marketing.api",
"Port": 80
}
],
"UpstreamPathTemplate": "/marketing-api/{everything}",
"UpstreamHttpMethod": []
},
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
@ -119,18 +107,6 @@
],
"UpstreamPathTemplate": "/payment-api/{everything}",
"UpstreamHttpMethod": []
},
{
"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "locations.api",
"Port": 80
}
],
"UpstreamPathTemplate": "/location-api/{everything}",
"UpstreamHttpMethod": []
}
],

View File

@ -36,7 +36,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
var basket = await _repository.GetBasketAsync(id);
if (basket == null)
{
return NotFound();
return Ok(new CustomerBasket(id) { });
}
return Ok(basket);

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Basket/Basket.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -15,6 +15,7 @@ using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
{
[Route("api/v1/[controller]")]
[ApiController]
public class CatalogController : ControllerBase
{
private readonly CatalogContext _catalogContext;
@ -25,8 +26,8 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
{
_catalogContext = context ?? throw new ArgumentNullException(nameof(context));
_catalogIntegrationEventService = catalogIntegrationEventService ?? throw new ArgumentNullException(nameof(catalogIntegrationEventService));
_settings = settings.Value;
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
}

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Catalog/Catalog.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -1,6 +1,7 @@
using Catalog.API.Infrastructure.ActionResults;
using Catalog.API.Infrastructure.Exceptions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
@ -27,12 +28,16 @@ namespace Catalog.API.Infrastructure.Filters
if (context.Exception.GetType() == typeof(CatalogDomainException))
{
var json = new JsonErrorResponse
var problemDetails = new ValidationProblemDetails()
{
Messages = new[] { context.Exception.Message }
Instance = context.HttpContext.Request.Path,
Status = StatusCodes.Status400BadRequest,
Detail = "Please refer to the errors property for additional details."
};
context.Result = new BadRequestObjectResult(json);
problemDetails.Errors.Add("DomainValidations", new string[] { context.Exception.Message.ToString() });
context.Result = new BadRequestObjectResult(problemDetails);
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
}
else

View File

@ -17,7 +17,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
new ApiResource("locations", "Locations Service"),
new ApiResource("mobileshoppingagg", "Mobile Shopping Aggregator"),
new ApiResource("webshoppingagg", "Web Shopping Aggregator"),
new ApiResource("orders.signalrhub", "Ordering Signalr Hub")
new ApiResource("orders.signalrhub", "Ordering SignalR Hub")
};
}
@ -112,6 +112,10 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
{
$"{clientsUrl["Mvc"]}/signout-callback-oidc"
},
AllowedCorsOrigins = new List<string>
{
$"{clientsUrl["Mvc"]}"
},
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
@ -165,7 +169,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/o2c.html" },
RedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["LocationsApi"]}/swagger/" },
AllowedScopes =
@ -180,7 +184,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/o2c.html" },
RedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["MarketingApi"]}/swagger/" },
AllowedScopes =
@ -195,7 +199,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/o2c.html" },
RedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["BasketApi"]}/swagger/" },
AllowedScopes =
@ -210,7 +214,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/o2c.html" },
RedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["OrderingApi"]}/swagger/" },
AllowedScopes =
@ -225,7 +229,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/o2c.html" },
RedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["MobileShoppingAgg"]}/swagger/" },
AllowedScopes =
@ -240,7 +244,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Configuration
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/o2c.html" },
RedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/oauth2-redirect.html" },
PostLogoutRedirectUris = { $"{clientsUrl["WebShoppingAgg"]}/swagger/" },
AllowedScopes =

View File

@ -1,7 +1,10 @@
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Entities;
using IdentityServer4.EntityFramework.Mappers;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopOnContainers.Services.Identity.API.Configuration;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -30,16 +33,37 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
{
foreach (var client in Config.GetClients(clientUrls))
{
await context.Clients.AddAsync(client.ToEntity());
context.Clients.Add(client.ToEntity());
}
await context.SaveChangesAsync();
}
// Checking always for old redirects to fix existing deployments
// to use new swagger-ui redirect uri as of v3.0.0
// There should be no problem for new ones
// ref: https://github.com/dotnet-architecture/eShopOnContainers/issues/586
else
{
List<ClientRedirectUri> oldRedirects = (await context.Clients.Include(c => c.RedirectUris).ToListAsync())
.SelectMany(c => c.RedirectUris)
.Where(ru => ru.RedirectUri.EndsWith("/o2c.html"))
.ToList();
if (oldRedirects.Any())
{
foreach (var ru in oldRedirects)
{
ru.RedirectUri = ru.RedirectUri.Replace("/o2c.html", "/oauth2-redirect.html");
context.Update(ru.Client);
}
await context.SaveChangesAsync();
}
}
if (!context.IdentityResources.Any())
{
foreach (var resource in Config.GetResources())
{
await context.IdentityResources.AddAsync(resource.ToEntity());
context.IdentityResources.Add(resource.ToEntity());
}
await context.SaveChangesAsync();
}
@ -48,7 +72,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Data
{
foreach (var api in Config.GetApis())
{
await context.ApiResources.AddAsync(api.ToEntity());
context.ApiResources.Add(api.ToEntity());
}
await context.SaveChangesAsync();

View File

@ -1,12 +1,26 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS sdk-with-node
ENV NODE_VERSION 8.11.1
ENV NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60
RUN curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
&& echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
&& tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
&& rm nodejs.tar.gz \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
FROM sdk-with-node AS updated-npm
RUN npm i -g npm
FROM updated-npm as build
RUN npm install -g bower@1.8.4
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Identity/Identity.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -1,6 +1,7 @@
{
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.IdentityDb;User Id=sa;Password=Pass@word;",
"IsClusterEnv": "False",
"IdentityServer": "http://localhost:5105",
"MvcClient": "http://localhost:5100",
"SpaClient": "http://localhost:5104",
"XamarinCallback": "http://localhost:5105/xamarincallback",

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Location/Locations.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Marketing/Marketing.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -28,6 +28,7 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_orderingIntegrationEventService = orderingIntegrationEventService;
}
public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)

View File

@ -1,5 +1,6 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries
{
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -7,7 +8,7 @@
{
Task<Order> GetOrderAsync(int id);
Task<IEnumerable<OrderSummary>> GetOrdersAsync();
Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(Guid userId);
Task<IEnumerable<CardType>> GetCardTypesAsync();
}

View File

@ -42,7 +42,7 @@
}
}
public async Task<IEnumerable<OrderSummary>> GetOrdersAsync()
public async Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(Guid userId)
{
using (var connection = new SqlConnection(_connectionString))
{
@ -52,8 +52,10 @@
FROM [ordering].[Orders] o
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid
LEFT JOIN[ordering].[orderstatus] os on o.OrderStatusId = os.Id
LEFT JOIN[ordering].[buyers] ob on o.BuyerId = ob.Id
WHERE ob.IdentityGuid = @userId
GROUP BY o.[Id], o.[OrderDate], os.[Name]
ORDER BY o.[Id]");
ORDER BY o.[Id]", new { userId });
}
}

View File

@ -5,7 +5,6 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Ordering.API.Application.Commands;
using Ordering.API.Application.Models;
using System;
using System.Collections.Generic;
using System.Net;
@ -15,6 +14,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
{
[Route("api/v1/[controller]")]
[Authorize]
[ApiController]
public class OrdersController : Controller
{
private readonly IMediator _mediator;
@ -87,8 +87,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers
[ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetOrders()
{
var orders = await _orderQueries.GetOrdersAsync();
var userid = _identityService.GetUserIdentity();
var orders = await _orderQueries.GetOrdersFromUserAsync(Guid.Parse(userid));
return Ok(orders);
}

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Ordering/Ordering.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -3,6 +3,7 @@
using AspNetCore.Mvc;
using global::Ordering.Domain.Exceptions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults;
using Microsoft.Extensions.Logging;
@ -27,14 +28,16 @@
if (context.Exception.GetType() == typeof(OrderingDomainException))
{
var json = new JsonErrorResponse
var problemDetails = new ValidationProblemDetails()
{
Messages = new[] { context.Exception.Message }
Instance = context.HttpContext.Request.Path,
Status = StatusCodes.Status400BadRequest,
Detail = "Please refer to the errors property for additional details."
};
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
//It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
context.Result = new BadRequestObjectResult(json);
problemDetails.Errors.Add("DomainValidations", new string[] { context.Exception.Message.ToString() });
context.Result = new BadRequestObjectResult(problemDetails);
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
}
else

View File

@ -7,8 +7,6 @@
public string EventBusConnection { get; set; }
public int GracePeriodTime { get; set; }
public int CheckUpdateTime { get; set; }
}
}

View File

@ -12,7 +12,6 @@
},
"AzureServiceBusEnabled": false,
"SubscriptionClientName": "Ordering",
"GracePeriodTime": "1",
"CheckUpdateTime": "30000",
"ApplicationInsights": {
"InstrumentationKey": ""

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Ordering/Ordering.BackgroundTasks
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -1,18 +1,16 @@
FROM microsoft/aspnetcore:2.0 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY eShopOnContainers-ServicesAndWebApps.sln ./
COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/
RUN dotnet restore -nowarn:msb3202,nu1503
COPY . .
WORKDIR /src/src/Services/Ordering/Ordering.SignalrHub
RUN dotnet build Ordering.SignalrHub.csproj -c Release -o /app
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore Ordering.SignalrHub.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish Ordering.SignalrHub.csproj -c Release -o /app
RUN dotnet publish --no-restore Ordering.SignalrHub.csproj -c Release -o /app
FROM base AS final
WORKDIR /app

View File

@ -13,13 +13,13 @@ namespace Ordering.SignalrHub
public override async Task OnConnectedAsync()
{
await Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception ex)
{
await Groups.RemoveAsync(Context.ConnectionId, Context.User.Identity.Name);
await Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
await base.OnDisconnectedAsync(ex);
}
}

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Services/Payment/Payment.API
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -7,9 +7,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
{
public class AppSettings
{
public Connectionstrings ConnectionStrings { get; set; }
//public Connectionstrings ConnectionStrings { get; set; }
public string MarketingUrl { get; set; }
public string PurchaseUrl { get; set; }
public string SignalrHubUrl { get; set; }
public bool ActivateCampaignDetailFunction { get; set; }

View File

@ -71,7 +71,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
var user = _appUserParser.Parse(HttpContext.User);
await _basketSvc.AddItemToBasket(user, productDetails.Id);
//await _basketSvc.AddItemToBasket(user, product);
}
return RedirectToAction("Index", "Catalog");
}

View File

@ -1,14 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authorization;
using System.Net.Http;
using Polly.CircuitBreaker;
using WebMVC.Models;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
@ -56,6 +51,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
}
return View("Create", model);
}

View File

@ -1,12 +1,9 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks;
namespace WebMVC.Controllers
@ -14,6 +11,7 @@ namespace WebMVC.Controllers
class TestPayload
{
public int CatalogItemId { get; set; }
public string BasketId { get; set; }
public int Quantity { get; set; }
@ -22,9 +20,10 @@ namespace WebMVC.Controllers
[Authorize]
public class TestController : Controller
{
private readonly IHttpClient _client;
private readonly IHttpClientFactory _client;
private readonly IIdentityParser<ApplicationUser> _appUserParser;
public TestController(IHttpClient client, IIdentityParser<ApplicationUser> identityParser)
public TestController(IHttpClientFactory client, IIdentityParser<ApplicationUser> identityParser)
{
_client = client;
_appUserParser = identityParser;
@ -33,18 +32,24 @@ namespace WebMVC.Controllers
public async Task<IActionResult> Ocelot()
{
var url = "http://apigw/shopping/api/v1/basket/items";
var payload = new TestPayload()
{
CatalogItemId = 1,
Quantity = 1,
BasketId = _appUserParser.Parse(User).Id
};
var token = await HttpContext.GetTokenAsync("access_token");
var response = await _client.PostAsync<TestPayload>(url, payload, token);
var content = new StringContent(JsonConvert.SerializeObject(payload), System.Text.Encoding.UTF8, "application/json");
var response = await _client.CreateClient(nameof(IBasketService))
.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
var str = await response.Content.ReadAsStringAsync();
return Ok(str);
}
else

View File

@ -1,12 +1,25 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS sdk-with-node
ENV NODE_VERSION 8.11.1
ENV NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60
RUN curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
&& echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
&& tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
&& rm nodejs.tar.gz \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
FROM sdk-with-node AS updated-npm
RUN npm i -g npm
FROM updated-npm as build
RUN npm install -g bower@1.8.4
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Web/WebMVC
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -0,0 +1,49 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace WebMVC.Infrastructure
{
public class HttpClientAuthorizationDelegatingHandler
: DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccesor;
public HttpClientAuthorizationDelegatingHandler(IHttpContextAccessor httpContextAccesor)
{
_httpContextAccesor = httpContextAccesor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authorizationHeader = _httpContextAccesor.HttpContext
.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(authorizationHeader))
{
request.Headers.Add("Authorization", new List<string>() { authorizationHeader });
}
var token = await GetToken();
if (token != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
return await base.SendAsync(request, cancellationToken);
}
async Task<string> GetToken()
{
const string ACCESS_TOKEN = "access_token";
return await _httpContextAccesor.HttpContext
.GetTokenAsync(ACCESS_TOKEN);
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace WebMVC.Infrastructure
{
public class HttpClientRequestIdDelegatingHandler
: DelegatingHandler
{
public HttpClientRequestIdDelegatingHandler()
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post || request.Method == HttpMethod.Put)
{
request.Headers.Add("x-requestid", Guid.NewGuid().ToString());
}
return await base.SendAsync(request, cancellationToken);
}
}
}

View File

@ -1,10 +0,0 @@
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using System;
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
{
public interface IResilientHttpClientFactory
{
ResilientHttpClient CreateResilientHttpClient();
}
}

View File

@ -1,66 +0,0 @@
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.Extensions.Logging;
using Polly;
using System;
using System.Net.Http;
namespace Microsoft.eShopOnContainers.WebMVC.Infrastructure
{
public class ResilientHttpClientFactory : IResilientHttpClientFactory
{
private readonly ILogger<ResilientHttpClient> _logger;
private readonly int _retryCount;
private readonly int _exceptionsAllowedBeforeBreaking;
private readonly IHttpContextAccessor _httpContextAccessor;
public ResilientHttpClientFactory(ILogger<ResilientHttpClient> logger, IHttpContextAccessor httpContextAccessor, int exceptionsAllowedBeforeBreaking = 5, int retryCount = 6)
{
_logger = logger;
_exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
_retryCount = retryCount;
_httpContextAccessor = httpContextAccessor;
}
public ResilientHttpClient CreateResilientHttpClient()
=> new ResilientHttpClient((origin) => CreatePolicies(), _logger, _httpContextAccessor);
private Policy[] CreatePolicies()
=> new Policy[]
{
Policy.Handle<HttpRequestException>()
.WaitAndRetryAsync(
// number of retries
_retryCount,
// exponential backofff
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
// on retry
(exception, timeSpan, retryCount, context) =>
{
var msg = $"Retry {retryCount} implemented with Polly's RetryPolicy " +
$"of {context.PolicyKey} " +
$"at {context.ExecutionKey}, " +
$"due to: {exception}.";
_logger.LogWarning(msg);
_logger.LogDebug(msg);
}),
Policy.Handle<HttpRequestException>()
.CircuitBreakerAsync(
// number of exceptions before breaking circuit
_exceptionsAllowedBeforeBreaking,
// time circuit opened before retry
TimeSpan.FromMinutes(1),
(exception, duration) =>
{
// on circuit opened
_logger.LogTrace("Circuit breaker opened");
},
() =>
{
// on circuit closed
_logger.LogTrace("Circuit breaker reset");
})
};
}
}

View File

@ -17,7 +17,7 @@ namespace WebMVC.Infrastructure
{
var log = loggerFactory.CreateLogger("WebMVC seed");
var settings = (AppSettings)applicationBuilder
var settings = applicationBuilder
.ApplicationServices.GetRequiredService<IOptions<AppSettings>>().Value;
var useCustomizationData = settings.UseCustomizationData;
@ -66,9 +66,9 @@ namespace WebMVC.Infrastructure
string imagePath = Path.Combine(webroot, "images");
string[] imageFiles = Directory.GetFiles(imagePath).Select(file => Path.GetFileName(file)).ToArray();
using (ZipArchive zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
using (var zip = ZipFile.Open(imagesZipFile, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in zip.Entries)
foreach (var entry in zip.Entries)
{
if (imageFiles.Contains(entry.Name))
{

View File

@ -12,7 +12,8 @@
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"use64Bit": true
},
"Microsoft.eShopOnContainers.WebMVC": {
"commandName": "Project",

View File

@ -1,11 +1,9 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
using WebMVC.Models;
@ -14,42 +12,40 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{
public class BasketService : IBasketService
{
private readonly IOptionsSnapshot<AppSettings> _settings;
private readonly IHttpClient _apiClient;
private readonly IOptions<AppSettings> _settings;
private readonly HttpClient _apiClient;
private readonly string _basketByPassUrl;
private readonly string _purchaseUrl;
private readonly IHttpContextAccessor _httpContextAccesor;
private readonly string _bffUrl;
public BasketService(IOptionsSnapshot<AppSettings> settings,
IHttpContextAccessor httpContextAccesor, IHttpClient httpClient)
public BasketService(HttpClient httpClient, IOptions<AppSettings> settings)
{
_apiClient = httpClient;
_settings = settings;
_basketByPassUrl = $"{_settings.Value.PurchaseUrl}/api/v1/b/basket";
_purchaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1";
_httpContextAccesor = httpContextAccesor;
_apiClient = httpClient;
}
public async Task<Basket> GetBasket(ApplicationUser user)
{
var token = await GetUserTokenAsync();
var getBasketUri = API.Basket.GetBasket(_basketByPassUrl, user.Id);
var uri = API.Basket.GetBasket(_basketByPassUrl, user.Id);
var dataString = await _apiClient.GetStringAsync(getBasketUri, token);
var responseString = await _apiClient.GetStringAsync(uri);
return string.IsNullOrEmpty(dataString) ?
return string.IsNullOrEmpty(responseString) ?
new Basket() { BuyerId = user.Id } :
JsonConvert.DeserializeObject<Basket>(dataString);
JsonConvert.DeserializeObject<Basket>(responseString);
}
public async Task<Basket> UpdateBasket(Basket basket)
{
var token = await GetUserTokenAsync();
var updateBasketUri = API.Basket.UpdateBasket(_basketByPassUrl);
var uri = API.Basket.UpdateBasket(_basketByPassUrl);
var response = await _apiClient.PostAsync(updateBasketUri, basket, token);
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PostAsync(uri, basketContent);
response.EnsureSuccessStatusCode();
@ -58,65 +54,64 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task Checkout(BasketDTO basket)
{
var token = await GetUserTokenAsync();
var updateBasketUri = API.Basket.CheckoutBasket(_basketByPassUrl);
var uri = API.Basket.CheckoutBasket(_basketByPassUrl);
var basketContent = new StringContent(JsonConvert.SerializeObject(basket), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PostAsync(updateBasketUri, basket, token);
var response = await _apiClient.PostAsync(uri, basketContent);
response.EnsureSuccessStatusCode();
}
public async Task<Basket> SetQuantities(ApplicationUser user, Dictionary<string, int> quantities)
{
var uri = API.Purchase.UpdateBasketItem(_purchaseUrl);
var token = await GetUserTokenAsync();
var updateBasketUri = API.Purchase.UpdateBasketItem(_purchaseUrl);
var userId = user.Id;
var response = await _apiClient.PutAsync(updateBasketUri, new
var basketUpdate = new
{
BasketId = userId,
BasketId = user.Id,
Updates = quantities.Select(kvp => new
{
BasketItemId = kvp.Key,
NewQty = kvp.Value
}).ToArray()
}, token);
};
var basketContent = new StringContent(JsonConvert.SerializeObject(basketUpdate), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PutAsync(uri, basketContent);
response.EnsureSuccessStatusCode();
var jsonResponse = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Basket>(jsonResponse);
}
public async Task<Order> GetOrderDraft(string basketId)
{
var token = await GetUserTokenAsync();
var draftOrderUri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
var json = await _apiClient.GetStringAsync(draftOrderUri, token);
return JsonConvert.DeserializeObject<Order>(json);
var uri = API.Purchase.GetOrderDraft(_purchaseUrl, basketId);
var responseString = await _apiClient.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<Order>(responseString);
return response;
}
public async Task AddItemToBasket(ApplicationUser user, int productId)
{
var token = await GetUserTokenAsync();
var updateBasketUri = API.Purchase.AddItemToBasket(_purchaseUrl);
var userId = user.Id;
var uri = API.Purchase.AddItemToBasket(_purchaseUrl);
var response = await _apiClient.PostAsync(updateBasketUri, new
var newItem = new
{
CatalogItemId = productId,
BasketId = userId,
BasketId = user.Id,
Quantity = 1
}, token);
};
}
var basketContent = new StringContent(JsonConvert.SerializeObject(newItem), System.Text.Encoding.UTF8, "application/json");
async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccesor.HttpContext;
return await context.GetTokenAsync("access_token");
var response = await _apiClient.PostAsync(uri, basketContent);
}
}
}

View File

@ -1,69 +1,49 @@
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
using global::WebMVC.Infrastructure;
using AspNetCore.Authentication;
using AspNetCore.Http;
using BuildingBlocks.Resilience.Http;
using ViewModels;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using ViewModels;
public class CampaignService : ICampaignService
{
private readonly IOptionsSnapshot<AppSettings> _settings;
private readonly IHttpClient _apiClient;
private readonly IOptions<AppSettings> _settings;
private readonly HttpClient _httpClient;
private readonly ILogger<CampaignService> _logger;
private readonly string _remoteServiceBaseUrl;
private readonly IHttpContextAccessor _httpContextAccesor;
public CampaignService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
public CampaignService(IOptions<AppSettings> settings, HttpClient httpClient, ILogger<CampaignService> logger)
{
_settings = settings;
_apiClient = httpClient;
_httpClient = httpClient;
_logger = logger;
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/m/campaigns/";
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
}
public async Task<Campaign> GetCampaigns(int pageSize, int pageIndex)
{
var allCampaignItemsUri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl,
pageSize, pageIndex);
var uri = API.Marketing.GetAllCampaigns(_remoteServiceBaseUrl, pageSize, pageIndex);
var authorizationToken = await GetUserTokenAsync();
var dataString = await _apiClient.GetStringAsync(allCampaignItemsUri, authorizationToken);
var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<Campaign>(dataString);
var response = JsonConvert.DeserializeObject<Campaign>(responseString);
return response;
}
public async Task<CampaignItem> GetCampaignById(int id)
{
var campaignByIdItemUri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
var uri = API.Marketing.GetAllCampaignById(_remoteServiceBaseUrl, id);
var authorizationToken = await GetUserTokenAsync();
var dataString = await _apiClient.GetStringAsync(campaignByIdItemUri, authorizationToken);
var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<CampaignItem>(dataString);
var response = JsonConvert.DeserializeObject<CampaignItem>(responseString);
return response;
}
private string GetUserIdentity()
{
return _httpContextAccesor.HttpContext.User.FindFirst("sub").Value;
}
private async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccesor.HttpContext;
return await context.GetTokenAsync("access_token");
}
}
}

View File

@ -1,11 +1,11 @@
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
@ -13,16 +13,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{
public class CatalogService : ICatalogService
{
private readonly IOptionsSnapshot<AppSettings> _settings;
private readonly IHttpClient _apiClient;
private readonly IOptions<AppSettings> _settings;
private readonly HttpClient _httpClient;
private readonly ILogger<CatalogService> _logger;
private readonly string _remoteServiceBaseUrl;
public CatalogService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient, ILogger<CatalogService> logger)
public CatalogService(HttpClient httpClient, ILogger<CatalogService> logger, IOptions<AppSettings> settings)
{
_httpClient = httpClient;
_settings = settings;
_apiClient = httpClient;
_logger = logger;
_remoteServiceBaseUrl = $"{_settings.Value.PurchaseUrl}/api/v1/c/catalog/";
@ -30,25 +30,26 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
{
var allcatalogItemsUri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type);
var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type);
var dataString = await _apiClient.GetStringAsync(allcatalogItemsUri);
var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<Catalog>(dataString);
var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
return response;
return catalog;
}
public async Task<IEnumerable<SelectListItem>> GetBrands()
{
var getBrandsUri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl);
var uri = API.Catalog.GetAllBrands(_remoteServiceBaseUrl);
var dataString = await _apiClient.GetStringAsync(getBrandsUri);
var responseString = await _httpClient.GetStringAsync(uri);
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
var brands = JArray.Parse(dataString);
var brands = JArray.Parse(responseString);
foreach (var brand in brands.Children<JObject>())
{
@ -64,14 +65,14 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
public async Task<IEnumerable<SelectListItem>> GetTypes()
{
var getTypesUri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl);
var uri = API.Catalog.GetAllTypes(_remoteServiceBaseUrl);
var dataString = await _apiClient.GetStringAsync(getTypesUri);
var responseString = await _httpClient.GetStringAsync(uri);
var items = new List<SelectListItem>();
items.Add(new SelectListItem() { Value = null, Text = "All", Selected = true });
var brands = JArray.Parse(dataString);
var brands = JArray.Parse(responseString);
foreach (var brand in brands.Children<JObject>())
{
items.Add(new SelectListItem()
@ -80,6 +81,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
Text = brand.Value<string>("type")
});
}
return items;
}
}

View File

@ -18,7 +18,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{
return new ApplicationUser
{
CardHolderName = claims.Claims.FirstOrDefault(x => x.Type == "card_holder")?.Value ?? "",
CardNumber = claims.Claims.FirstOrDefault(x => x.Type == "card_number")?.Value ?? "",
Expiration = claims.Claims.FirstOrDefault(x => x.Type == "card_expiration")?.Value ?? "",

View File

@ -1,11 +1,9 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.WebMVC;
using Microsoft.eShopOnContainers.WebMVC;
using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using Newtonsoft.Json;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
using WebMVC.Models;
@ -14,36 +12,27 @@ namespace WebMVC.Services
{
public class LocationService : ILocationService
{
private readonly IOptionsSnapshot<AppSettings> _settings;
private readonly IHttpClient _apiClient;
private readonly IOptions<AppSettings> _settings;
private readonly HttpClient _httpClient;
private readonly ILogger<CampaignService> _logger;
private readonly string _remoteServiceBaseUrl;
private readonly IHttpContextAccessor _httpContextAccesor;
public LocationService(IOptionsSnapshot<AppSettings> settings, IHttpClient httpClient,
ILogger<CampaignService> logger, IHttpContextAccessor httpContextAccesor)
public LocationService(HttpClient httpClient, IOptions<AppSettings> settings, ILogger<CampaignService> logger)
{
_httpClient = httpClient;
_settings = settings;
_apiClient = httpClient;
_logger = logger;
_remoteServiceBaseUrl = $"{_settings.Value.MarketingUrl}/api/v1/l/locations/";
_httpContextAccesor = httpContextAccesor ?? throw new ArgumentNullException(nameof(httpContextAccesor));
}
public async Task CreateOrUpdateUserLocation(LocationDTO location)
{
var createOrUpdateUserLocationUri = API.Locations.CreateOrUpdateUserLocation(_remoteServiceBaseUrl);
var uri = API.Locations.CreateOrUpdateUserLocation(_remoteServiceBaseUrl);
var locationContent = new StringContent(JsonConvert.SerializeObject(location), System.Text.Encoding.UTF8, "application/json");
var authorizationToken = await GetUserTokenAsync();
var response = await _apiClient.PostAsync(createOrUpdateUserLocationUri, location, authorizationToken);
var response = await _httpClient.PostAsync(uri, locationContent);
response.EnsureSuccessStatusCode();
}
private async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccesor.HttpContext;
return await context.GetTokenAsync("access_token");
}
}
}

View File

@ -1,11 +1,9 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using WebMVC.Infrastructure;
using WebMVC.Models;
@ -14,69 +12,54 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{
public class OrderingService : IOrderingService
{
private IHttpClient _apiClient;
private HttpClient _httpClient;
private readonly string _remoteServiceBaseUrl;
private readonly IOptionsSnapshot<AppSettings> _settings;
private readonly IHttpContextAccessor _httpContextAccesor;
private readonly IOptions<AppSettings> _settings;
public OrderingService(IOptionsSnapshot<AppSettings> settings, IHttpContextAccessor httpContextAccesor, IHttpClient httpClient)
public OrderingService(HttpClient httpClient, IOptions<AppSettings> settings)
{
_remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders";
_httpClient = httpClient;
_settings = settings;
_httpContextAccesor = httpContextAccesor;
_apiClient = httpClient;
_remoteServiceBaseUrl = $"{settings.Value.PurchaseUrl}/api/v1/o/orders";
}
async public Task<Order> GetOrder(ApplicationUser user, string id)
{
var token = await GetUserTokenAsync();
var getOrderUri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
var uri = API.Order.GetOrder(_remoteServiceBaseUrl, id);
var dataString = await _apiClient.GetStringAsync(getOrderUri, token);
var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<Order>(dataString);
var response = JsonConvert.DeserializeObject<Order>(responseString);
return response;
}
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
{
var token = await GetUserTokenAsync();
var allMyOrdersUri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
var uri = API.Order.GetAllMyOrders(_remoteServiceBaseUrl);
var dataString = await _apiClient.GetStringAsync(allMyOrdersUri, token);
var response = JsonConvert.DeserializeObject<List<Order>>(dataString);
var responseString = await _httpClient.GetStringAsync(uri);
var response = JsonConvert.DeserializeObject<List<Order>>(responseString);
return response;
}
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
{
order.City = user.City;
order.Street = user.Street;
order.State = user.State;
order.Country = user.Country;
order.ZipCode = user.ZipCode;
order.CardNumber = user.CardNumber;
order.CardHolderName = user.CardHolderName;
order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1);
order.CardSecurityNumber = user.SecurityNumber;
return order;
}
async public Task CancelOrder(string orderId)
{
var token = await GetUserTokenAsync();
var order = new OrderDTO()
{
OrderNumber = orderId
};
var cancelOrderUri = API.Order.CancelOrder(_remoteServiceBaseUrl);
var uri = API.Order.CancelOrder(_remoteServiceBaseUrl);
var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PutAsync(cancelOrderUri, order, token, Guid.NewGuid().ToString());
var response = await _httpClient.PutAsync(uri, orderContent);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
@ -88,15 +71,15 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
async public Task ShipOrder(string orderId)
{
var token = await GetUserTokenAsync();
var order = new OrderDTO()
{
OrderNumber = orderId
};
var shipOrderUri = API.Order.ShipOrder(_remoteServiceBaseUrl);
var uri = API.Order.ShipOrder(_remoteServiceBaseUrl);
var orderContent = new StringContent(JsonConvert.SerializeObject(order), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PutAsync(shipOrderUri, order, token, Guid.NewGuid().ToString());
var response = await _httpClient.PutAsync(uri, orderContent);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
@ -120,6 +103,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
destination.CardSecurityNumber = original.CardSecurityNumber;
}
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
{
order.City = user.City;
order.Street = user.Street;
order.State = user.State;
order.Country = user.Country;
order.ZipCode = user.ZipCode;
order.CardNumber = user.CardNumber;
order.CardHolderName = user.CardHolderName;
order.CardExpiration = new DateTime(int.Parse("20" + user.Expiration.Split('/')[1]), int.Parse(user.Expiration.Split('/')[0]), 1);
order.CardSecurityNumber = user.SecurityNumber;
return order;
}
public BasketDTO MapOrderToBasket(Order order)
{
order.CardExpirationApiFormat();
@ -140,18 +139,5 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
RequestId = order.RequestId
};
}
void SetFakeIdToProducts(Order order)
{
var id = 1;
order.OrderItems.ForEach(x => { x.ProductId = id; id++; });
}
async Task<string> GetUserTokenAsync()
{
var context = _httpContextAccesor.HttpContext;
return await context.GetTokenAsync("access_token");
}
}
}

View File

@ -24,7 +24,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Annotations
DateTime d = new DateTime(year, month, 1);
return d > DateTime.UtcNow;
} else
}
else
{
return false;
}

View File

@ -1,12 +1,24 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS sdk-with-node
ENV NODE_VERSION 8.11.1
ENV NODE_DOWNLOAD_SHA 0e20787e2eda4cc31336d8327556ebc7417e8ee0a6ba0de96a09b0ec2b841f60
RUN curl -SL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" --output nodejs.tar.gz \
&& echo "$NODE_DOWNLOAD_SHA nodejs.tar.gz" | sha256sum -c - \
&& tar -xzf "nodejs.tar.gz" -C /usr/local --strip-components=1 \
&& rm nodejs.tar.gz \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
FROM sdk-with-node AS updated-npm
RUN npm i -g npm
FROM updated-npm as build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Web/WebSPA
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -2,8 +2,12 @@
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iis": {
"applicationUrl": "http://localhost/WebSPA",
"sslPort": 0
},
"iisExpress": {
"applicationUrl": "http://localhost:58018/",
"applicationUrl": "http://localhost:5104",
"sslPort": 0
}
},
@ -11,8 +15,9 @@
"IIS Express": {
"commandName": "IISExpress",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
"ASPNETCORE_ENVIRONMENT": "Development"
},
"use64Bit": true
}
}
}

View File

@ -90,7 +90,7 @@
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.1.1" />
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.2" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.4.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>

View File

@ -1,12 +1,12 @@
FROM microsoft/aspnetcore:2.0.5 AS base
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/aspnetcore-build:2.0.5-2.1.4 AS build
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore -nowarn:msb3202,nu1503
WORKDIR /src/src/Web/WebStatus
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app
FROM build AS publish

View File

@ -8,6 +8,7 @@
}
},
"OrderingUrl": "http://localhost:5102/hc",
"OrderingBackgroundTasksUrl": "http://localhost:5111/hc",
"BasketUrl": "http://localhost:5103/hc",
"CatalogUrl": "http://localhost:5101/hc",
"IdentityUrl": "http://localhost:5105/hc",