Maison >développement back-end >Tutoriel C#.Net >Service de catalogue - Analyse de l'exemple de code de l'architecture de microservice Microsoft
Dans le dernier article, nous avons parlé d'Identity Service. Parce qu'il est développé sur la base d'IdentityServer4, il n'y a pas beaucoup de points de connaissances. Aujourd'hui, nous examinerons Catalog Service. Dans les explications futures, nous nous concentrerons sur différents et. points clés. J’espère que tout le monde comprend.
Jetons d'abord un coup d'œil à sa structure de répertoires, un répertoire webapi très standard :
Premier aperçu du programme , suivi de IdentityService est similaire, avec l'ajout de UseWebRoot ("Pics") Le répertoire pics est défini sur webroot, et tout le reste est identique.
Dans la méthode de construction de Startup, nous avons également vu l'utilisation de l'outil de gestion de secrets, mais il y a un paramètre supplémentaire ici, nous voyons le type Assembly. En fait, le secret n'a besoin que du userSecretsId.
Dans ConfigureServices, nous voyons le code suivant :
services.AddMvc(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices();
Un filtre a été ajouté. Ce HTtpGlobalExceptionFilter peut être trouvé dans le projet. Cela signifie probablement qu'une erreur de type CatalogDomainException est présente. rencontré. Lorsqu'un code d'erreur spécifique est renvoyé.
AddControllersAsServices est une méthode d'extension qui enregistre tous les contrôleurs du projet dans Services. Jetons un coup d'œil au code source :
public static IMvcCoreBuilder AddControllersAsServices(this IMvcCoreBuilder builder) { var feature = new ControllerFeature(); builder.PartManager.PopulateFeature(feature);foreach (var controller in feature.Controllers.Select(c => c.AsType())) { builder.Services.TryAddTransient(controller, controller); } builder.Services.Replace(ServiceDescriptor.Transient<icontrolleractivator>());return builder; }</icontrolleractivator>
Le foreach au milieu est le suivant, afin que nous puissions. utiliser l'injection de dépendances dans le projet Chaque contrôleur est facilement accessible de n'importe quelle manière.
Descendre :
services.AddDbContext<catalogcontext>(options => { options.UseSqlServer(Configuration["ConnectionString"], sqlServerOptionsAction: sqlOptions => { sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); //Configuring Connection Resiliency: sqlOptions.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); });// Changing default behavior when client evaluation occurs to throw. // Default in EF Core would be to log a warning when client evaluation is performed.options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));//Check Client vs. Server evaluation: });</catalogcontext>
Lors de la configuration de DBContext, la méthode Connection Resiliency (bounce connection) est utilisée ici, où vous pouvez voir l'utilisation de la migration Quand , il utilise MigrationsAssembly (AssemblyName). Cette méthode est quelque peu similaire à FluentNhibernate dont j'ai parlé précédemment. EnableRetryOnFailure définit le mécanisme de tentative échouée de cette action si un échec est rencontré lors de la migration, elle réessayera automatiquement de cette manière. d'échecs de connexion occasionnels causés par la séparation de l'application et de la base de données. Pourquoi existe-t-il ce mécanisme ? Parce que lorsque notre base de données est dans le cloud, comme Azure SQL, des problèmes de connexion réseau se produiront inévitablement. Même si nous plaçons l'application et la base de données dans un centre de données, je pense qu'il y aura parfois ce problème. Nous pouvons maintenant configurer cela. s'il rencontre une panne, il redémarrera le fonctionnement, ce qui évite dans une certaine mesure les problèmes occasionnels causés par le réseau. Vous pouvez également définir certaines stratégies pour activer les tentatives lors de l'exécution de commandes. Par défaut, EF enregistre uniquement les avertissements lors de l'évaluation du client. Nous pouvons lui faire émettre cet avertissement via ConfigureWarnings, et vous pouvez également le configurer pour l'ignorer.
Ensuite, nous voyons le code suivant :
services.Configure<catalogsettings>(Configuration);</catalogsettings>
Nous pouvons trouver des instructions similaires dans chaque projet eShop, qui enregistreront certains paramètres liés au projet dans les services, ce qui en fera une variable d'environnement, qui nous pouvons configurer via settings.json. En plus de la configuration via settings.json, nous pouvons également effectuer une configuration flexible via Docker run –e.
Ici, notre CatalogSetting contient un attribut ExternalCatalogBaseUrl Nous pouvons entrer la commande suivante lors de l'exécution de Docker :
docke run -e "ExternalCatalogBaseUrl=http://localhost:5011/" ....
De cette façon, nous pouvons le configurer de manière flexible via les commandes Docker, ce qui est très pratique. , nous pouvons également utiliser -e pour attribuer des valeurs aux variables de notre paramètre .json, telles que ConnectionString. Vous pouvez cliquer pour en savoir plus.
// Add framework services.services.AddSwaggerGen(); services.ConfigureSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info() { Title = "eShopOnContainers - Catalog HTTP API", Version = "v1", Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample", TermsOfService = "Terms Of Service" }); }); services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); });
Les deux morceaux de code ci-dessus configurent respectivement les stratégies SwaggerGen et Cors (inter-domaines). SwaggenGen est un framework très pratique qui peut automatiquement convertir notre API en mode web et la présenter devant nous. Il peut également être débogué, ce qui est très utile. La configuration de Cors n'est pas bien utilisée ici. Elle autorise toutes les requêtes. Il est recommandé de suivre les besoins réels, sinon cela n'a aucun sens dans les paramètres inter-domaines.
Ensuite, nous avons vu une série d'opérations d'ajout de service, toutes liées à EventBus. Après l'avoir examiné pendant un moment, nous avons constaté que seule l'action de journalisation avait été effectuée jusqu'à présent. Jetons un coup d'œil au code :
if (raiseProductPriceChangedEvent) // Save and publish integration event if price has changed{//Create Integration Event to be published through the Event Busvar priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transactionawait _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(priceChangedEvent);// Publish through the Event Bus and mark the saved event as publishedawait _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); }
Le code ci-dessus signifie que lorsque le prix change, nous appelons EventService pour sauvegarder et enregistrer l'opération. La méthode PublishThroughEventBusAsync modifie l'état de cet enregistrement en publié. À l'heure actuelle, je ne sais pas pourquoi cette méthode est utilisée, et je ne sais pas pourquoi elle s'appelle EventBus. Cependant, j'ai soulevé cette question dans le numéro du projet, et j'espère que les développeurs du projet pourront me donner une réponse. répondre. J'ai vérifié Basket.Api. Il y aura un comportement d'abonnement dans ce projet. Nous examinerons les détails de plus près dans le chapitre suivant.
ok, regardons à nouveau la méthode Configure. On peut étudier le morceau de code suivant :
var context = (CatalogContext)app .ApplicationServices.GetService(typeof(CatalogContext)); WaitForSqlAvailability(context, loggerFactory);
On voit qu'ici il appelle le CatalogContext précédemment enregistré, et il ne passe pas. new Au lieu d'instancier, obtenez l'enregistrement précédent via GetService, afin que d'autres instances dont dépend le contexte soient également introduites, ce qui est très pratique et facile à utiliser.
La méthode WaitForSqlAvailability consiste à essayer de s'assurer que la base de données est disponible, car elle nécessite une migration des données ultérieurement.
CatalogService contient 2 contrôleurs, l'un est PicController et l'autre est CatalogController. PicController n'obtient que des Service de catalogue - Analyse de lexemple de code de larchitecture de microservice Microsofts basées sur l'ID CatalogController montre comment utiliser webapi pour faire CURD.
如果你要运行Catalog.Api,你必须安装MSSQL和RabbitMQ,这次我把我的系统换成了Win10 Pro,并在电脑上使用Docker安装了MSSQL-Server-Linux和RabbitMQ。安装这2个非常简单,仅仅需要输入几条命令即可:
docker run --name mssql -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Pass@word' -p 5433:1433 -d microsoft/mssql-server-linux docker run -d --hostname my-rabbit --name rabbitmq -p 8080:15672 -p 5672:5672 rabbitmq:3-management
ok,我们使用docker创建了mssql和rabbitmq,这里注意一下,我把mssql的端口映射到了本机的5433上,还有rabbitmq的管理页面,我映射到了本机的8080端口,你可以通过http://localhost:8080 进行访问。
上一篇我们说过我们可以通过iisexpress/Kestrel或者docker的形式运行因为牵涉到配置,所以这两种方式的运行有些不同。
一、iisExpress或Kestrel方式下,因为刚刚我们把mssql和rabbitmq的端口都映射到了本机,所以我们只需要在setting.json中把数据库连接和rabbitmq的地址指向本机即可,如下:
{ "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word", "ExternalCatalogBaseUrl": "http://localhost:5101", "EventBusConnection": "localhost", "Logging": {"IncludeScopes": false,"LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information"} } }
ok,Ctrl+F5,运行一下看看:
当看到上面这个页面,说明你的运行正常了,你还得测试下api是否运行正常,比如Pic,比如Items。
二、docker中运行,参照上一篇的方式,先publish再build Service de catalogue - Analyse de lexemple de code de larchitecture de microservice Microsoft, 不过这里要注意一点,因为你之前的ConnectionString和EventBusConnection都是指向本机(127.0.0.1)的,所以这里必须改一下,改成主机的ip地址或者是对应容器的ip也可以,如果您不想更改的话,也可以通过docker -e进行设置,比如:
docker run -p 8899:80 --name catalog -e "EventBusConnection=172.17.0.2" -d catalog:01
我这里的172.17.0.2是我rabbitmq容器的ip地址,你可以通过docker inspect containerId 进行查看容器的ip。
如果一切配置都正确的话,你就可以通过浏览器http://localhost:8899 进行浏览了。
当然,除了正常浏览外,你还需测试下api是否正常。
在这个项目中有一些疑惑,希望大家能够给我答案。
Connection Resiliency,我看了很久,字面意思是弹性连接,但我觉得用弹性好像不太适合,一般来讲我们说的弹性都是指架构或者系统的伸缩性,我一开始也是从这个角度去了解,但看了很多文章,觉得它只是让我们在启动的时候,设置一些重试策略,在后面调用中可使用此策略,策略会根据你设置的重试次数、延迟时间等去自动重试,避免因为偶尔的错误造成的影响,所以觉得用弹回比较恰当。
EventBus,我感觉很奇怪,为什么一定要取这个名字呢?在Android中,很明确的,它是进行订阅发布,消息传递,可以解耦发布者和订阅者,但在Catalog.Api里,变成了记录操作,没有看到解耦,也没有看到订阅。在我的理解中,应该在Startup进行订阅操作,发布者CatalogController在进行update操作的时候,订阅者进行add log动作,但在这个实例中,我看到的是同步进行了这些操作,所以很不解。
Mssql-server-linux,当你用Docker安装了以后,你却不能使用visual studio 2017的sql server data tools进行查询(只能进行连接),为了查看效果,还需要安装Microsoft Sql Server Management Studio(必须17版本以后)进行查看数据。
这次的文章来的比较晚,一方面有点忙,另一方面就是上面提到的困惑,面对困惑我试着去解答,但有时候真的无法解答,所以提出来集思广益。
后面可能会比较慢,需要学习的东西真多,一边写一边学习成为这次系列的乐趣,现在每天坚持6公里快走,夜走能够是我保持头脑清晰,思考项目中的疑问,现在发觉生活越发有趣。
或许有很多人觉得只看了Startup就够了吗?其实真不够,我目前先把框架的源码过一遍,后面会分篇讲述,比如Connection Resiliency。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!