eShopOnContainers 知多少[7]:Basket microservice

640?wx_fmt=png

引言

Basket microservice(购物车微服务)主要用于处理购物车的业务逻辑,包括:

  1. 购物车商品的CRUD

  2. 订阅商品价格更新事件,进行购物车商品同步处理

  3. 购物车结算事件发布

  4. 订阅订单成功创建事件,进行购物车的清空操作

架构模式

640?wx_fmt=png

如上图所示,本微服务采用数据驱动的CRUD微服务架构,并使用Redis数据库进行持久化。 这种类型的服务在单个 ASP.NET Core Web API 项目中即可实现所有功能,该项目包括数据模型类、业务逻辑类及其数据访问类。其项目结构如下:640?wx_fmt=png

核心技术选型:

  1. ASP.NET Core Web API

  2. Entity Framework Core

  3. Redis

  4. Swashbuckle(可选)

  5. Autofac

  6. Eventbus

  7. Newtonsoft.Json

实体建模和持久化

该微服务的核心领域实体是购物车,其类图如下:640?wx_fmt=png

其中 CustomerBasketBasketItem为一对多关系,使用仓储模式进行持久化。

  1. 通过对 CustomerBasket对象进行json格式的序列化和反序列化来完成在redis中的持久化和读取。

  2. 以单例模式注入redis连接 ConnectionMultiplexer,该对象最终通过构造函数注入到 RedisBasketRepository中。

  1. services.AddSingleton<ConnectionMultiplexer>(sp =>

  2. {

  3.    var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;

  4.    var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true);


  5.    configuration.ResolveDns = true;


  6.    return ConnectionMultiplexer.Connect(configuration);

  7. });

事件的注册和消费

在本服务中主要需要处理以下事件的发布和消费:

  1. 事件发布:当用户点击购物车结算时,发布用户结算事件。

  2. 事件消费:订单创建成功后,进行购物车的清空

  3. 事件消费:商品价格更新后,进行购物车相关商品的价格同步


  1. private void ConfigureEventBus(IApplicationBuilder app)

  2. {

  3.    var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();


  4.    eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>();

  5.    eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>();

  6. }

以上都是基于事件总线来达成。

认证和授权

购物车管理界面是需要认证和授权。那自然需要与上游的 IdentityMicroservice进行衔接。在启动类进行认证中间件的配置。

  1. private void ConfigureAuthService(IServiceCollection services)

  2. {

  3.    // prevent from mapping "sub" claim to nameidentifier.

  4.    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

  5.    var identityUrl = Configuration.GetValue<string>("IdentityUrl");


  6.    services.AddAuthentication(options =>

  7.    {

  8.        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

  9.        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

  10.    }).AddJwtBearer(options =>

  11.    {

  12.        options.Authority = identityUrl;

  13.        options.RequireHttpsMetadata = false;

  14.        options.Audience = "basket";

  15.    });

  16. }

  17. protected virtual void ConfigureAuth(IApplicationBuilder app)

  18. {

  19.    if (Configuration.GetValue<bool>("UseLoadTest"))

  20.    {

  21.        app.UseMiddleware<ByPassAuthMiddleware>();

  22.    }

  23.    app.UseAuthentication();

  24. }

手动启用断路器

在该微服务中,定义了一个中断中间件FailingMiddleware,通过访问 http://localhost:5103/failing获取该中间件的启用状态,通过请求参数指定:即通过 http://localhost:5103/failing?enablehttp://localhost:5103/failing?disable来手动中断和恢复服务,来模拟断路,以便用于测试断路器模式。 开启断路后,当访问购物车页面时,Polly在重试指定次数依然无法访问服务时,就会抛出 BrokenCircuitException异常,通过捕捉该异常告知用户稍后再试。

  1. public class CartController : Controller

  2. {

  3.    //…

  4.    public async Task<IActionResult> Index()

  5.    {

  6.        try

  7.        {          

  8.            var user = _appUserParser.Parse(HttpContext.User);

  9.            //Http requests using the Typed Client (Service Agent)

  10.            var vm = await _basketSvc.GetBasket(user);

  11.            return View(vm);

  12.        }

  13.        catch (BrokenCircuitException)

  14.        {

  15.            // Catches error when Basket.api is in circuit-opened mode                

  16.            HandleBrokenCircuitException();

  17.        }

  18.        return View();

  19.    }      

  20.    private void HandleBrokenCircuitException()

  21.    {

  22.        TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business message due to Circuit-Breaker)";

  23.    }

  24. }

640?wx_fmt=png

注入过滤器

在配置MVC服务时指定了两个过滤器:全局异常过滤器和模型验证过滤器。

  1. // Add framework services.

  2. services.AddMvc(options =>

  3. {

  4.    options.Filters.Add(typeof(HttpGlobalExceptionFilter));

  5.    options.Filters.Add(typeof(ValidateModelStateFilter));


  6. }).AddControllersAsServices();


1. 全局异常过滤器是通过定义 BasketDomainException异常和 HttpGlobalExceptionFilter过滤器来实现的。

2. 模型验证过滤器是通过继承 ActionFilterAttribute特性实现的 ValidateModelStateFilter来获取模型状态中的错误。


  1. public class ValidateModelStateFilter : ActionFilterAttribute

  2. {

  3.    public override void OnActionExecuting(ActionExecutingContext context)

  4.    {

  5.        if (context.ModelState.IsValid)

  6.        {

  7.            return;

  8.        }


  9.        var validationErrors = context.ModelState

  10.            .Keys

  11.            .SelectMany(k => context.ModelState[k].Errors)

  12.            .Select(e => e.ErrorMessage)

  13.            .ToArray();


  14.        var json = new JsonErrorResponse

  15.        {

  16.            Messages = validationErrors

  17.        };


  18.        context.Result = new BadRequestObjectResult(json);

  19.    }

  20. }

SwaggerUI认证授权集成

因为默认启用了安全认证,所以为了方便在SwaggerUI界面进行测试,那么我们就必须为其集成认证授权。代码如下:

  1. services.AddSwaggerGen(options =>

  2. {

  3.    options.DescribeAllEnumsAsStrings();

  4.    options.SwaggerDoc("v1", new Info

  5.    {

  6.        Title = "Basket HTTP API",

  7.        Version = "v1",

  8.        Description = "The Basket Service HTTP API",

  9.        TermsOfService = "Terms Of Service"

  10.    });

  11.    options.AddSecurityDefinition("oauth2", new OAuth2Scheme

  12.    {

  13.        Type = "oauth2",

  14.        Flow = "implicit",

  15.        AuthorizationUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",

  16.        TokenUrl = $"{Configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",

  17.        Scopes = new Dictionary<string, string>()

  18.        {

  19.            { "basket", "Basket API" }

  20.        }

  21.    });

  22.    options.OperationFilter<AuthorizeCheckOperationFilter>();

  23. });

其中有主要做了三件事:

1. 配置授权Url

2. 配置TokenUrl

3. 指定授权范围

4. 注入授权检查过滤器 AuthorizeCheckOperationFilter用于拦截需要授权的请求

  1. public class AuthorizeCheckOperationFilter : IOperationFilter

  2. {

  3.    public void Apply(Operation operation, OperationFilterContext context)

  4.    {

  5.        // Check for authorize attribute

  6.        var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||

  7.                           context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();

  8.        if (hasAuthorize)

  9.        {

  10.            operation.Responses.Add("401", new Response { Description = "Unauthorized" });

  11.            operation.Responses.Add("403", new Response { Description = "Forbidden" });

  12.            operation.Security = new List<IDictionary<string, IEnumerable<string>>>();

  13.            operation.Security.Add(new Dictionary<string, IEnumerable<string>>

  14.            {

  15.                { "oauth2", new [] { "basketapi" } }

  16.            });

  17.        }

  18.    }

  19. }

最后

本服务较之前讲的Catalog microservice 而言,主要是多了一个认证和redis存储。

640?wx_fmt=png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318014.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

后缀数组 SA

后缀数组 SA 后缀树组(SA&#xff0c;suffix array)&#xff0c;用于处理字符串子串形成的结构。 处理子串的结构主要方式有&#xff1a;后缀数组 SA&#xff0c;后缀自动机 SAM&#xff0c;后缀树 ST。 后缀树和后缀自动机暂时决定咕咕咕&#xff0c;以后学习可以参考ix35 的字…

微软热门开源项目及代码库地址

点击蓝字关注我这几年来&#xff0c;微软在开源与社区方向的努力与成就是全世界有目共睹的。微软的开源项目超过2000多个&#xff0c;挑了一些比较火热的给大家整理了一下。欢迎补充~Visual Studio Code非常流行的跨平台代码编辑器&#xff0c;提供全面的编辑和调试支持、可扩展…

[树链剖分][SDOI 2011]染色,Housewife Wind

文章目录T1&#xff1a;Housewife Wind题目题解codeT2&#xff1a;染色题目题解code今天选择写这篇博客主要是为了告诉大家一个道理&#xff0c;数组比vectorvectorvector快太多了&#xff0c;我这两道题第一次都因为vectorvectorvector&#xff0c;TTT到飞起 T1&#xff1a;…

ASP.NET Core 网站运行时修改设置如何自动生效

点击蓝字关注我在ASP.NET Core中&#xff0c;如果修改了appsettings.json中的设置&#xff0c;那么默认情况下就得重启网站才能生效。有没有办法在修改设置后自动刷新并应用呢&#xff1f;背景首先&#xff0c;我们看看默认模板建出来的 ASP.NET Core 网站&#xff0c;配置文件…

1022. 宠物小精灵之收服

1022. 宠物小精灵之收服 题意&#xff1a; 现在有n个胶囊&#xff0c;m个生命值&#xff0c;k个怪物&#xff0c;每个怪物需要a[i]个胶囊&#xff0c;且会造成b[i]个伤害后才能捕获&#xff0c;问在活着的前提下&#xff0c;最多捕获多少怪物&#xff0c;在怪物最多的情况下剩…

【周末狂欢赛6】[AT1219]历史研究(回滚莫队),大魔法师(矩阵+线段树),单峰排列

文章目录T1&#xff1a;单峰排列题目题解codeT2&#xff1a;历史研究题目题解codeT3&#xff1a;大魔法师题目题解code我可能这辈子都更不出来狂欢赛5了&#xff0c;先咕咕 T1&#xff1a;单峰排列 题目 一个n的全排列A[i]是单峰的&#xff0c;当且仅当存在某个x使得A[1]<…

YBTOJ:圈套问题(分治法、鸽笼原理)

文章目录题目描述数据范围解析代码图片转载自&#xff1a; https://blog.csdn.net/weixin_43346722/article/details/118435430题目描述 平面上有 n个点&#xff0c;用n个大小相同的圆分别将一个点作为圆心&#xff0c;同时满足圆圈不相交&#xff0c;求圆的最大半径。 数据范…

ASP.NET Core 实战:使用 NLog 将日志信息记录到 MongoDB

一、前言在项目开发中&#xff0c;日志系统是系统的一个重要组成模块&#xff0c;通过在程序中记录运行日志、错误日志&#xff0c;可以让我们对于系统的运行情况做到很好的掌控。同时&#xff0c;收集日志不仅仅可以用于诊断排查错误&#xff0c;由于日志同样也是大量的数据&a…

[学习笔记] 伸展树splay详解+全套模板+例题[Luogu P3369 【模板】普通平衡树]

文章目录引入概念全套模板变量声明updaterotate旋转splay操作insert插入delete删除查找x的位置查找第k大前驱/后继极小值-inf和极大值inf的作用例题&#xff1a;P3369 【模板】普通平衡树题目code声明一下&#xff0c;许多代码的注解都在模板代码里面写了的&#xff0c;所以正文…

手写AspNetCore 认证授权代码

在普通的MVC项目中 我们普遍的使用Cookie来作为认证授权方式&#xff0c;使用简单。登录成功后将用户信息写入Cookie&#xff1b;但当我们做WebApi的时候显然Cookie这种方式就有点不适用了。在dotnet core 中 WebApi中目前比较流行的认证授权方式是Jwt (Json Web Token) 技术。…

YBTOJ:采矿战略(线段树维护dp、树链剖分)

文章目录题目描述解析代码题目描述 所谓线段树维护dp&#xff0c;就是在线段树上维护dp &#xff08;逃&#xff09; 解析 把树剖一下后就变成了区间问题 考虑建一棵线段树&#xff0c;每一个结点都是一个背包 这样就能区间查询&#xff0c;也能带修了 这种做法复杂度其实并不…

【用皇宫三十六计生存法则带你走进LCT(动态树)】LCT概念+模板+例题【洛谷P3690 Link Cut Tree(动态树)】

文章目录LCT概念模板rotatoisrootsplayaccessmakerootsplitfindrootlinkcut封装版例题题目code普通版code封装版这篇博客主要是帮助大家理解各个模板及LCTLCTLCT的意思&#xff0c;方便理解&#xff0c;模板写法的理解在代码里有注释详解&#xff0c;如果要看原理的话&#xff…

迈向现代化的 .Net 配置指北

1. 欢呼 .NET Standard 时代我现在已不大提 .Net Core&#xff0c;对于我来说&#xff0c;未来的开发将是基于 .NET Standard&#xff0c;不仅仅是 面向未来 &#xff0c;也是 面向过去&#xff1b;不只是 .Net Core 可以享受便利&#xff0c; .NET Framework 不升级一样能享受…

YBTOJ洛谷P2042:维护数列(平衡树)

文章目录题目描述解析删除区间插入数列修改&翻转区间和&最大子段和代码传送门题目描述 解析 阴间题… 这不是裸的板子吗&#xff1f; 国赛真的有人能把这题写出来吗… 应该算一道练习作用很强的题了 写完这题&#xff0c;各种平衡树维护区间操作的方法可以说是毕业了吧…

CAP 2.4版本发布,支持版本隔离特性

前言自从上次 CAP 2.3 版本发布 以来&#xff0c;已经过去了几个月的时间&#xff0c;这几个月比较忙&#xff0c;所以也没有怎么写博客&#xff0c;趁着2019年到来之际&#xff08;现在应该是2019年开始的时候&#xff09;&#xff0c;CAP也发布了2018年的最后一个大版本 2.4&…

【周末狂欢赛7】【NOIP模拟赛】七夕祭,齿轮(dfs),天才黑客

文章目录T1题目题解codeT2题目题解codeT3题目题解codeT1 题目 七夕节因牛郎织女的传说而被扣上了「情人节」的帽子。于是TYVJ今年举办了一次线下七夕祭。Vani同学今年成功邀请到了cl同学陪他来共度七夕&#xff0c;于是他们决定去TYVJ七夕祭游玩。 TYVJ七夕祭和11区的夏祭的…

.NET Core 如何为项目提供高性能解决方案?

本系列&#xff0c;我们将探讨.NET Core 的一些好处&#xff0c;以及它如何为市场提供高性能解决方案&#xff0c;为传统.NET 开发人员和技术人员提供帮助。正文前言随着.NET Core 2.0 在 2016 年首次发布&#xff0c;微软拥有了这个通用、模块化、跨平台开源项目的下一个主要版…

[2.9训练]【CF909C】Python Indentation,【CF909D】Colorful Points,【CF909E】Coprocessor

文章目录T1&#xff1a;Python Indentation题目题解codeT2&#xff1a;Colorful Points题目题解codeT3&#xff1a;Coprocessor题目题解codeT1&#xff1a;Python Indentation 题目 题目描述 In Python, code blocks don’t have explicit begin/end or curly braces to mark…

Docker最全教程之使用Tencent Hub来完成CI(十)

本周更新两篇&#xff0c;保证不太监&#xff01;在本系列教程中&#xff0c;笔者希望将必要的知识点围绕理论、流程&#xff08;工作流程&#xff09;、方法、实践来进行讲解&#xff0c;而不是单纯的为讲解知识点而进行讲解。也就是说&#xff0c;笔者希望能够让大家将理论、…

[2.7]【CF933A】A Twisty Movement【CF926B】Add Points【CF917A】The Monster【CF919E】Congruence Equation

文章目录T1&#xff1a;A Twisty Movement题目题解codeT2&#xff1a;Add Points题目题解codeT3&#xff1a;The Monster题目题解codeT4&#xff1a;Congruence Equation题目题解codeT1&#xff1a;A Twisty Movement 题目 题目 题解 因为aia_iai​1/21/21/2&#xff0c;于…