[Day27] 建立购物车系统 - 10

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

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

1.1 修改appSettings.json

在WebMvc专案的appSettings.json增加购物车服务的Api连结:

  "CartUrl": "http://localhost:1028",

1.2 修改Startup.cs类别

修改WebMvc专案的Startup.cs,主要是增加在OIDC的购物车Scope、注册购物车相关服务:

    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OpenIdConnect;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Newtonsoft.Json.Serialization;
    using System.IdentityModel.Tokens.Jwt;
    using System.Net.Http;
    using WebMvc.Infrastructure;
    using WebMvc.Models;
    using WebMvc.Services;
    
    namespace WebMvc
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<AppSettings>(Configuration);
                services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
                services.AddSingleton<IHttpClient, CustomHttpClient>();
                services.AddTransient<ICatalogService, CatalogService>();
    
                services.AddTransient<IAuthService<ApplicationUser>, AuthService>();
                services.AddTransient<ICartService, CartService>();
    
                services.AddControllersWithViews().AddNewtonsoftJson(options =>
                {
                    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
                });
    
                JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
    
                var identityUrl = Configuration.GetValue<string>("IdentityUrl");
                var callBackUrl = Configuration.GetValue<string>("CallBackUrl");
                services.AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
                {
                    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.Authority = identityUrl;
                    options.SignedOutRedirectUri = callBackUrl;
                    options.ClientId = "mvc";
                    options.ClientSecret = "secret";
                    options.ResponseType = "code id_token";
                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                    options.RequireHttpsMetadata = false;
                    options.Scope.Add("openid");
                    options.Scope.Add("profile");
                    options.Scope.Add("offline_access");
                    options.Scope.Add("basket");
    
                    options.NonceCookie.SameSite = SameSiteMode.Lax;
                    options.CorrelationCookie.SameSite = SameSiteMode.Lax;
    
                    options.BackchannelHttpHandler = new HttpClientHandler()
                    {
                        ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                    };
                });
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                }
                app.UseStaticFiles();
    
                app.UseRouting();
    
                app.UseAuthentication();
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                        name: "default",
                        pattern: "{controller=Catalog}/{action=Index}/{id?}");
                });
            }
        }
    }

===

1.3 新增Cart和CartList的ViewComponent

在WebMvc专案新增ViewComponents资料夹,并新增Cart.cs和CartList.cs 2个类别,都实作Microsoft.AspNetCore.Mvc.ViewComponent,之後Views的cshtml可以直接把它们当function呼叫并产生子View:

    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Threading.Tasks;
    using WebMvc.Models;
    using WebMvc.Services;
    using WebMvc.ViewModels;
    
    namespace WebMvc.ViewComponents
    {
        public class Cart : ViewComponent
        {
            private readonly ICartService _cartService;
            public Cart(ICartService cartService)
            {
                _cartService = cartService;
            }
    
            public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
            {
                var vm = new CartComponentViewModel();
                try
                {
                    var cart = await _cartService.GetCartAsync(user);
                    vm.ItemsInCart = cart.Items.Count;
                    vm.TotalCost = cart.Total();
                    return View(vm);
                }
                catch (Exception)
                {
                    ViewBag.IsCartInoperative = true;
                }
    
                return View(vm);
            }
        }
    }
    using Microsoft.AspNetCore.Mvc;
    using System;
    using System.Threading.Tasks;
    using WebMvc.Models;
    using WebMvc.Services;
    
    namespace WebMvc.ViewComponents
    {
        public class CartList : ViewComponent
        {
            private readonly ICartService _cartService;
            public CartList(ICartService cartService)
            {
                _cartService = cartService;
            }
    
            public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
            {
                var vm = new Models.CartModels.Cart();
                try
                {
                    vm = await _cartService.GetCartAsync(user);
                    return View(vm);
                }
                catch (Exception)
                {
                    ViewBag.IsCartInoperative = true;
                    TempData["CartInoperativeMsg"] = "Cart Service is inoperative, please retry later.";
                }
    
                return View(vm);
            }
        }
    }

1.4 新增CartComponentViewModel类别

在WebMvc专案的ViewModels新增CartComponentViewModel.cs,是Cart ViewComponent要回传的View:

    namespace WebMvc.ViewModels
    {
        public class CartComponentViewModel
        {
            public int ItemsInCart { get; set; }
            public decimal TotalCost { get; set; }
            public string Disabled => (ItemsInCart == 0) ? "is-disabled" : "";
        }
    }

<<:  第二十七天:UI切版 & 元件-按钮元件、常用的表单元件

>>:  完赛心得

Day15 - Ruby 字串处理入门

线上 Ruby 编辑器:https://runrb.io/ Ruby String 文件:http...

【C#】计算程序的执行时间

我们来看到C#要如何计算程序码的执行时间呢 ~ 有两种方法分别是 Stopwatch DateTim...

C# 入门之循环

在 C# 中,支持三类循环: do...while 循环 while 循环 for/foreach ...

【Day 22】卷积神经网路(Convolutional Neural Network, CNN)(下)

昨天讲完Convolution,接着今天要介绍的就是Max Pooling。 CNN - Max P...

Python 做自动化编译 相关指令汇整

有些公司因为历史原因 在Build react,vue,npm等相关专案 需经过 前置的处理作业 这...