源码剖析
我们先看下它的目次组织,很规范的webapi目次:
起首看下Program,跟IdentityService相似,多了一个UseWebRoot(“Pics”),把pics这个目次设置成了webroot,其他都一样。
在Startup的组织要领中,我们也看到了运用了secret manager tool,然则多了一个参数,在这里我们看到的是Assembly范例,实在secret只须要个中的userSecretsId罢了。
在ConfigureServices中,我们看到以下代码:
services.AddMvc(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices();
添加了一个filter,这个HTtpGlobalExceptionFilter可以在项目中找到,也许的意义就是碰到抛出CatalogDomainException范例的毛病时,返回特定的毛病码。
AddControllersAsServices这个扩大要领是把项目中的Controller都注册到Services中,我们看下源码:
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, ServiceBasedControllerActivator>());return builder; }
中心那段foreach就是,如许我们在项目中经由过程依靠注入体式格局都能轻易的接见到各个controller了。
Going down:
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: });
对DBContext的设置的时刻,这里运用了Connection Resiliency(弹回衔接)的体式格局,个中可以看到运用migration的时刻,它运用了MigrationsAssembly(AssemblyName),这类体式格局跟我之前讲的FluentNhibernate有点相似,EnableRetryOnFailure设置了这个Action的失利尝试机制,假如Migration的时刻碰到Failure,就会自动重试,这类体式格局防止了app与database星散形成的衔接偶然失利形成的影响。为什么会有这个机制呢?由于当我们的database在云端的时刻,比方Azure SQL,不可防止的会涌现收集衔接题目,纵然我们把app和database放在一个数据中心中,我置信偶然也会有这个题目,我们如今可以经由过程设置,使其假如碰到失利就会从新操纵,肯定水平防止了收集偶然形成的题目。你也可以设置一些战略,使其可以在运转敕令的时刻可以举行重试EF默许情况下只是纪录client evaluation中的warns,我们可以经由过程ConfigureWarnings使其抛出这个正告,你也可以设置成疏忽。
接下来我们看到以下代码:
services.Configure<CatalogSettings>(Configuration);
我们可以在eShop的各个项目中都能找到相似的语句,它会把一些项目相干的Settings注册到services中,使其成为环境变量,我们可经由过程setting.json举行设置。除了经由过程setting.json举行设置,我们还能经由过程Docker run –e 举行天真化设置。
在这里我们的CatalogSetting含有一个ExternalCatalogBaseUrl属性,我们在docker run的时刻可以输入以下敕令:
docke run -e "ExternalCatalogBaseUrl=http://localhost:5011/" ....
如许就可以天真的经由过程docker敕令举行设置了,异常轻易,我们也可以经由过程-e对我们setting.json中的变量举行赋值,比方ConnectionString,你可以经由过程点击相识更多相干内容。
// 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()); });
上面两段代码,离别设置了SwaggerGen和Cors(跨域)战略,SwaggenGen是一个异常有用的框架,它能自动把我们的api转为web体式格局呈如今我们面前,还能举行调试,异常好用。Cors的设置这里用的不好,它许可了统统要求,发起照样依据现实需求来吧,不然没有跨域设置的意义了。
接下来我们看到了一系列的add service的操纵,都是关于EventBus的,轻微看了下,发明现在只做了log的行动,我们看下代码:
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); }
上面的代码意义是在价钱有变动的时刻,我们就挪用EventService举行保留,同时对操纵举行了纪录。PublishThroughEventBusAsync要领则对这条纪录的State变动成published。现在来讲我不太清楚为什么要用这类体式格局,也不知道为什么取名为EventBus,不过我在项目的issue中已提出了这个题目,愿望项目的开辟者们能给我一个答案。我有检察了Basket.Api,在这个项目中会有定阅行动,细致的比及下一章我们再细致看看。
ok,我们再看下Configure要领,下面一段代码我们可以进修下:
var context = (CatalogContext)app .ApplicationServices.GetService(typeof(CatalogContext)); WaitForSqlAvailability(context, loggerFactory);
我们看到在这里它挪用了之前注册的CatalogContext,它并没有经由过程new举行实例化,而是经由过程GetService的体式格局猎取之前的注册,如许context所依靠的其他实例也一并带进来了,异常轻易好用。
WaitForSqlAvailability要领是对数据库可用举行尝试,由于背面它须要举行数据迁徙。
CatalogService包含了2个Controller,一个是PicController,一个是CatalogController,PicController仅仅是依据ID猎取了图片,CatalogController展现了用webapi如何做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 image, 不过这里要注重一点,由于你之前的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。
以上就是Catalog Service - 剖析微软微效劳架构实例代码的细致内容,更多请关注ki4网别的相干文章!