You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
6.8 KiB

  1. using Basket.API.Infrastructure.Filters;
  2. using Basket.API.IntegrationEvents.EventHandling;
  3. using Basket.API.IntegrationEvents.Events;
  4. using Microsoft.AspNetCore.Builder;
  5. using Microsoft.AspNetCore.Hosting;
  6. using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
  7. using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
  8. using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
  9. using Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server;
  10. using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling;
  11. using Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events;
  12. using Microsoft.eShopOnContainers.Services.Basket.API.Model;
  13. using Microsoft.Extensions.Configuration;
  14. using Microsoft.Extensions.DependencyInjection;
  15. using Microsoft.Extensions.HealthChecks;
  16. using Microsoft.Extensions.Logging;
  17. using Microsoft.Extensions.Options;
  18. using RabbitMQ.Client;
  19. using StackExchange.Redis;
  20. using System.Linq;
  21. using System.Net;
  22. using System.Threading.Tasks;
  23. using System;
  24. namespace Microsoft.eShopOnContainers.Services.Basket.API
  25. {
  26. public class Startup
  27. {
  28. public Startup(IHostingEnvironment env)
  29. {
  30. var builder = new ConfigurationBuilder()
  31. .SetBasePath(env.ContentRootPath)
  32. .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
  33. .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  34. .AddEnvironmentVariables();
  35. Configuration = builder.Build();
  36. }
  37. public IConfigurationRoot Configuration { get; }
  38. // This method gets called by the runtime. Use this method to add services to the container.
  39. public void ConfigureServices(IServiceCollection services)
  40. {
  41. services.AddHealthChecks(checks =>
  42. {
  43. checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
  44. });
  45. // Add framework services.
  46. services.AddMvc(options =>
  47. {
  48. options.Filters.Add(typeof(HttpGlobalExceptionFilter));
  49. }).AddControllersAsServices();
  50. services.Configure<BasketSettings>(Configuration);
  51. //By connecting here we are making sure that our service
  52. //cannot start until redis is ready. This might slow down startup,
  53. //but given that there is a delay on resolving the ip address
  54. //and then creating the connection it seems reasonable to move
  55. //that cost to startup instead of having the first request pay the
  56. //penalty.
  57. services.AddSingleton<ConnectionMultiplexer>(sp =>
  58. {
  59. var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
  60. var ips = Dns.GetHostAddressesAsync(settings.ConnectionString).Result;
  61. return ConnectionMultiplexer.Connect(ips.First().ToString());
  62. });
  63. services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
  64. {
  65. var settings = sp.GetRequiredService<IOptions<BasketSettings>>().Value;
  66. var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
  67. var factory = new ConnectionFactory()
  68. {
  69. HostName = settings.EventBusConnection
  70. };
  71. return new DefaultRabbitMQPersistentConnection(factory, logger);
  72. });
  73. services.AddSwaggerGen();
  74. services.ConfigureSwaggerGen(options =>
  75. {
  76. options.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
  77. options.DescribeAllEnumsAsStrings();
  78. options.SingleApiVersion(new Swashbuckle.Swagger.Model.Info()
  79. {
  80. Title = "Basket HTTP API",
  81. Version = "v1",
  82. Description = "The Basket Service HTTP API",
  83. TermsOfService = "Terms Of Service"
  84. });
  85. });
  86. services.AddCors(options =>
  87. {
  88. options.AddPolicy("CorsPolicy",
  89. builder => builder.AllowAnyOrigin()
  90. .AllowAnyMethod()
  91. .AllowAnyHeader()
  92. .AllowCredentials());
  93. });
  94. services.AddTransient<IBasketRepository, RedisBasketRepository>();
  95. RegisterServiceBus(services);
  96. }
  97. private void RegisterServiceBus(IServiceCollection services)
  98. {
  99. services.AddSingleton<IEventBus, EventBusRabbitMQ>();
  100. services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
  101. services.AddTransient<ProductPriceChangedIntegrationEventHandler>();
  102. services.AddTransient<OrderStartedIntegrationEventHandler>();
  103. }
  104. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  105. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  106. {
  107. loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  108. loggerFactory.AddDebug();
  109. app.UseStaticFiles();
  110. // Use frameworks
  111. app.UseCors("CorsPolicy");
  112. ConfigureAuth(app);
  113. app.UseMvcWithDefaultRoute();
  114. app.UseSwagger()
  115. .UseSwaggerUi();
  116. ConfigureEventBus(app);
  117. }
  118. protected virtual void ConfigureAuth(IApplicationBuilder app)
  119. {
  120. var identityUrl = Configuration.GetValue<string>("IdentityUrl");
  121. app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
  122. {
  123. Authority = identityUrl.ToString(),
  124. ScopeName = "basket",
  125. RequireHttpsMetadata = false
  126. });
  127. }
  128. protected virtual void ConfigureEventBus(IApplicationBuilder app)
  129. {
  130. var catalogPriceHandler = app.ApplicationServices
  131. .GetService<IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>>();
  132. var orderStartedHandler = app.ApplicationServices
  133. .GetService<IIntegrationEventHandler<OrderStartedIntegrationEvent>>();
  134. var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();
  135. eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>
  136. (() => app.ApplicationServices.GetRequiredService<ProductPriceChangedIntegrationEventHandler>());
  137. eventBus.Subscribe<OrderStartedIntegrationEvent, OrderStartedIntegrationEventHandler>
  138. (() => app.ApplicationServices.GetRequiredService<OrderStartedIntegrationEventHandler>());
  139. }
  140. }
  141. }