[Day26] 建立购物车系统 - 9

本篇同步发文在个人Blog: 一袋.NET要扛几楼?打造容器化的ASP.NET Core网站!系列文章 - (26) 建立购物车系统 - 9

1. 在WebMvc专案新增购物车服务的功能

1.1 新增购物车的服务类别

在WebMvc专案的Services新增CartService,并实作ICartService,主要是实作与购物车服务Api的串接:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebMvc.Infrastructure;
using WebMvc.Models;
using WebMvc.Models.CartModels;

namespace WebMvc.Services
{
    public class CartService : ICartService
    {
        private readonly IOptionsSnapshot<AppSettings> _settings;
        private readonly IHttpClient _apiClient;
        private readonly string _remoteServiceBaseUrl;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ILogger<CartService> _logger;

        public CartService(
            IOptionsSnapshot<AppSettings> settings,
            IHttpClient httpClient,
            ILogger<CartService> logger,
            IHttpContextAccessor httpContextAccessor)
        {
            _settings = settings;
            _remoteServiceBaseUrl = $"{_settings.Value.CartUrl}/api/v1/cart";
            _httpContextAccessor = httpContextAccessor;
            _apiClient = httpClient;
            _logger = logger;
        }

        public async Task AddItemToCartAsync(ApplicationUser user, CartItem product)
        {
            var cart = await GetCartAsync(user);
            _logger.LogDebug("user name" + user.Id);
            if (cart == null)
            {
                cart = new Cart()
                {
                    BuyerId = user.Id,
                    Items = new List<CartItem>()
                };
            }

            var cartItem = cart.Items
                .Where(p => p.ProductId == product.ProductId)
                .FirstOrDefault();

            if (cartItem == null)
            {
                cart.Items.Add(product);
            }
            else
            {
                cartItem.Quantity += 1;
            }

            await UpdateCartAsync(cart);
        }

        public async Task ClearCartAsync(ApplicationUser user)
        {
            var token = await GetUserTokenAsync();
            var cleanCartUri = ApiPaths.Cart.CleanCart(_remoteServiceBaseUrl, user.Id);
            _logger.LogDebug("Clean cart uri : " + cleanCartUri);
            var response = await _apiClient.DeleteAsync(cleanCartUri);
            _logger.LogDebug("cart cleaned");
        }

        public async Task<Cart> GetCartAsync(ApplicationUser user)
        {
            var token = await GetUserTokenAsync();
            _logger.LogInformation("we are in get cart and user id " + user.Id);
            _logger.LogInformation(_remoteServiceBaseUrl);

            var getCartUri = ApiPaths.Cart.GetCart(_remoteServiceBaseUrl, user.Id);
            _logger.LogInformation(getCartUri);
            var dataString = await _apiClient.GetStringAsync(getCartUri, token);
            _logger.LogInformation(dataString);
            var response = JsonConvert.DeserializeObject<Cart>(dataString.ToString()) ??
                new Cart()
                {
                    BuyerId = user.Id
                };
            return response;
        }

        public async Task<Cart> SetQuantitiesAsync(ApplicationUser user, Dictionary<string, int> quantities)
        {
            var cart = await GetCartAsync(user);
            cart.Items.ForEach(x =>
            {
                if (quantities.TryGetValue(x.Id, out var quantity))
                {
                    x.Quantity = quantity;
                }
            });

            return cart;
        }

        public async Task<Cart> UpdateCartAsync(Cart cart)
        {
            var token = await GetUserTokenAsync();
            _logger.LogDebug("Service url: " + _remoteServiceBaseUrl);
            var updateCartUri = ApiPaths.Cart.UpdateCart(_remoteServiceBaseUrl);
            _logger.LogDebug("Update cart url: " + updateCartUri);
            var response = await _apiClient.PostAsync(updateCartUri, cart, token);
            response.EnsureSuccessStatusCode();

            return cart;
        }
        private async Task<string> GetUserTokenAsync()
        {
            var context = _httpContextAccessor.HttpContext;
            return await context.GetTokenAsync("access_token");
        }
    }
}

1.2 修改ApiPaths类别

在WebMvc专案的Infrastructure修改ApiPaths.cs,增加购物车Api的Pattern:

namespace WebMvc.Infrastructure
{
    public static class ApiPaths
    {
        public static class Cart
        {
            public static string GetCart(string baseUri, string cartId)
            {
                return $"{baseUri}/{cartId}";
            }

            public static string UpdateCart(string baseUri)
            {
                return baseUri;
            }

            public static string CleanCart(string baseUri, string cartId)
            {
                return $"{baseUri}/{cartId}";
            }
        }

        public static class Catalog
        {
            public static string GetAllCatalogItems(string baseUri, int pageIndex, int pageSize, int? type)
            {
                string typeQueryString = "";
                if (type.HasValue)
                {
                    typeQueryString = type.Value.ToString();
                }

                return $"{baseUri}items?catalogTypeId={typeQueryString}&pageIndex={pageIndex}&pageSize={pageSize}";
            }

            public static string GetAllTypes(string baseUri)
            {
                return $"{baseUri}catalogTypes";
            }
        }
    }
}

1.3 修改IHttpClient和CustomHttpClient

在WebMvc专案的Infrastructure修改IHttpClient介面和CustomHttpClient类别,增加了JWT的token参数:

using System.Net.Http;
using System.Threading.Tasks;

namespace WebMvc.Infrastructure
{
    public interface IHttpClient
    {
        Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
        Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer");
        Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer");
        Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer");
    }
}
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace WebMvc.Infrastructure
{
    public class CustomHttpClient : IHttpClient
    {
        private HttpClient _client;
        private ILogger<CustomHttpClient> _logger;

        public CustomHttpClient( ILogger<CustomHttpClient> logger)
        {
            _client = new HttpClient();
            _logger = logger;
        }

        public async Task<HttpResponseMessage> DeleteAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Delete, uri);
            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            return await _client.SendAsync(requestMessage);
        }

        public async Task<string> GetStringAsync(string uri, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }
            var response = await _client.SendAsync(requestMessage);
            return await response.Content.ReadAsStringAsync();
        }

        public async Task<HttpResponseMessage> PostAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            return await DoPostPutAsync(HttpMethod.Post, uri, item, authorizationToken, authorizationMethod);
        }

        public async Task<HttpResponseMessage> PutAsync<T>(string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            return await DoPostPutAsync(HttpMethod.Put, uri, item, authorizationToken, authorizationMethod);
        }

        private async Task<HttpResponseMessage> DoPostPutAsync<T>(HttpMethod method, string uri, T item, string authorizationToken = null, string authorizationMethod = "Bearer")
        {
            if (method != HttpMethod.Post && method != HttpMethod.Put)
            {
                throw new ArgumentException("Value must be either post or put.", nameof(method));
            }

            var requestMessage = new HttpRequestMessage(method, uri)
            {
                Content = new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json")
            };

            if (authorizationToken != null)
            {
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue(authorizationMethod, authorizationToken);
            }

            var response = await _client.SendAsync(requestMessage);

            if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
            {
                throw new HttpRequestException();
            }

            return response;
        }
    }
}

<<:  Day26 | 实现Extension内的MVVM架构

>>:  二十八日目:JavaScript XMLHttpRequest 壱ノ章

[Day10] CH07:站在巨人的肩膀上——方法

先来公布一下昨天的解答吧,应该画一下图就知道为什麽要这样了,这里就不再说明,因为今天要讲解一个新的概...

建立 Google App Script 专案(2)

今天目标是成功筛选出特定条件的信件内容,方便我们之後 push 到资料库供 Line Messagi...

[DAY-23] 有声 无声 在不同模式下 有效沟通

沟通的艺术在於顷听! 语言是人类天性的核心 光生长在某个文化里面 就能学会母语:) 想在职场上成功...

资安生活的日常

执行人员:工作超忙,资安什麽的就明天在处理吧... 客户:供应商内控功能疑似失效且烧到利害关系人.....

Day22 vue.js修改文章

延续昨日 今天来把修改文章的功能完成 修改文章跟修改帐户讯息基本上一样 所以我们就先从创一个Chan...