Catalog Service-Parsing Microsoft MicroServices Architecture Instance Code

Source: Internet
Author: User
Tags management studio microsoft sql server management studio sql server management sql server management studio rabbitmq docker run eventbus
The previous article we said the identity Service, because it is based on IdentityServer4 development, so the knowledge point is not many, today we look at the catalog Service, the future of the explanation will be different, the focus of the show, I hope you understand.





SOURCE Analysis



Let's look at its directory structure, the standard WEBAPI directory:






First look at program, similar to Identityservice, more than a usewebroot ("Pics"), Pics this directory is set to Webroot, the others are the same.



In the startup construction method, we also saw the use of the secret Manager tool, but one more parameter, here we see is the assembly type, in fact secret only need the USERSECRETSID.



In Configureservices, we see the following code:


services.AddMvc (options =>
{
options.Filters.Add (typeof (HttpGlobalExceptionFilter));
}). AddControllersAsServices ();
A filter has been added. This HTtpGlobalExceptionFilter can be found in the project. The general meaning is that when it encounters an error of type CatalogDomainException, it returns a specific error code.

AddControllersAsServices This extension method is to register the Controller in the project to Services. Let's look at the source code:

        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;
        }
The foreach in the middle is so that we can easily access each controller through dependency injection in the project.

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:});
When configuring the DBContext, the Connection Resiliency method is used here. It can be seen that when using migration, it uses MigrationsAssembly (AssemblyName). This method is similar to the FluentNhibernate I mentioned earlier. The failure attempt mechanism of this Action is set. If a Failure is encountered during Migration, it will automatically retry. This method avoids the impact of the occasional failure of the connection caused by the separation of the app from the database. Why is there such a mechanism? Because when our database is in the cloud, such as Azure SQL, network connection problems will inevitably occur. Even if we put the app and database in a data center, I believe that this problem will occasionally occur. We can now configure it , So that if it encounters failure, it will re-operation, to a certain extent to avoid the problems caused by the network. You can also set some policies so that they can retry when running the command. EF only records the warns in the client evaluation by default. We can use ConfigureWarnings to throw this warning. You can also configure to ignore it.

Next we see the following code:

services.Configure <CatalogSettings> (Configuration);
We can find similar statements in each project of eShop, it will register some project-related Settings to services, making it an environment variable, we can configure it through setting.json. In addition to configuration via setting.json, we can also perform flexible configuration via Docker run -e.

Here our CatalogSetting contains an ExternalCatalogBaseUrl property, we can enter the following command when docker run:

docke run -e "ExternalCatalogBaseUrl = http: // localhost: 5011 /" ....
This can be flexibly configured through the docker command, which is very convenient. We can also use -e to assign values to variables in our setting.json, such as ConnectionString. You can click for more information.

            // 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 ());
            });
The above two pieces of code are configured with SwaggerGen and Cors (cross-domain) policies, respectively. SwaggenGen is a very practical framework that can automatically turn our api into web mode and present it to our eyes. It can also be debugged, which is very easy to use. Cors configuration is not well used here, it allows all requests, it is recommended to follow the actual needs, otherwise it does not make sense to set up across domains.

Next we saw a series of add service operations, all related to EventBus. After a little look, we found that only the log action has been done. Let's look at the 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);
}
The above code means that when the price changes, we call EventService to save and record the operation at the same time. The PublishThroughEventBusAsync method changes the state of this record to published. At present, I don't know why I use this method, and I don't know why it is called EventBus, but I have already raised this issue in the project issue. I hope the developers of the project can give me an answer. I have checked Basket.Api, there will be subscription behavior in this project, we will wait until the next chapter to take a closer look.

OK, let's take a look at the Configure method again. We can learn the following code:

var context = (CatalogContext) app
            .ApplicationServices.GetService (typeof (CatalogContext));

WaitForSqlAvailability (context, loggerFactory);
We see here that it called the CatalogContext that was previously registered, and it did not instantiate it through new, but instead obtained the previous registration through GetService, so that the context depends on Other examples of Lai are also brought in, which is very convenient and easy to use.

The WaitForSqlAvailability method is an attempt to make the database available, because it requires data migration later.

CatalogService contains 2 Controllers, one is PicController and the other is CatalogController. PicController just gets the picture based on the ID. CatalogController shows how to do CURD using webapi.

Run deployment
If you want to run Catalog.Api, you must install MSSQL and RabbitMQ. This time I replaced my system with Win10 Pro and installed MSSQL-Server-Linux and RabbitMQ on my computer using Docker. Installing these two is very simple, just need to enter a few commands:

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, we used docker to create mssql and rabbitmq. Note here that I mapped the port of mssql to the local 5433, and the management page of rabbitmq. I mapped to the local port 8080. You can do this via http: / / localhost: 8080.

In the previous article, we said that we can run in the form of iisexpress / Kestrel or docker. Because of the configuration involved, the two modes of operation are somewhat different.

First, in the iisExpress or Kestrel mode, because we just mapped the ports of mssql and rabbitmq to this machine, we only need to point the database connection and rabbitmq address to this machine in setting.json, as follows:

{"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, run and see:

When you see the above page, it means that your operation is normal. You also need to test whether the api is running normally, such as Pic, such as Items.

Second, run in docker, refer to the method in the previous article, first publish and then build the image, but pay attention here, because your previous ConnectionString and EventBusConnection are pointing to the local (127.0.0.1), so you must change it here, It can also be changed to the IP address of the host or the IP of the corresponding container. If you do not want to change it, you can also set it by docker -e, such as:

docker run -p 8899: 80 --name catalog -e "EventBusConnection = 172.17.0.2" -d catalog: 01
My 172.17.0.2 here is the IP address of my rabbitmq container. You can check the container IP by docker inspect containerId.

If everything is configured correctly, you can browse through the browser http: // localhost: 8899.

Of course, in addition to normal browsing, you also need to test whether the api is normal.

confused
There are some doubts in this project, I hope everyone can give me answers.

Connection Resiliency, I have read it for a long time, literally meaning elastic connection, but I do n’t think it is suitable for elasticity. Generally speaking, elasticity refers to the scalability of architecture or system. , But read a lot of articles, I think it just let us set some retry strategies when starting, this strategy can be used in subsequent calls, the strategy will automatically retry according to the number of retry times, delay time you set, etc. To avoid the impact caused by occasional errors, it is more appropriate to use bounce.

EventBus, I feel weird, why do we have to take this name? In Android, it is very clear that it is used for subscription publishing and messaging, which can decouple publishers and subscribers, but in Catalog.Api, it becomes a record operation, without seeing decoupling and subscriptions. . In my understanding, the subscription operation should be performed in Startup. When the publisher CatalogController performs the update operation, the subscriber performs the add log action, but in this example, I see that these operations are performed synchronously, so it is not solution.

Mssql-server-linux, after you install it with Docker, you can't use visual studio 2017's sql server data tools to query (only connect), in order to see the effect, you also need to install Microsoft Sql Server Management Studio (must be 17 After version) to view the data.

Write at the end
This article came late. On the one hand, it is a bit busy, on the other hand, it is the confusion mentioned above. I tried to answer it in the face of confusion, but sometimes I could n’t answer it, so I proposed to brainstorm.

It may be slow in the back. There is so much to learn. Writing and learning become the fun of this series. Now walking 6 kilometers a day. Walking at night can keep my mind clear and think about the questions in the project. Now I find that life is getting more and more interesting.

Maybe many people think that just watching Startup is enough? In fact, it's not enough. I'm going to go through the source code of the framework first, and I will talk about it later, such as Connection Resiliency.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.