diff --git a/docker-compose-windows.override.yml b/docker-compose-windows.override.yml index 45b2db748..738549e7e 100644 --- a/docker-compose-windows.override.yml +++ b/docker-compose-windows.override.yml @@ -95,4 +95,16 @@ services: - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. - EventBusConnection=rabbitmq ports: - - "5109:80" \ No newline at end of file + - "5109:80" + + marketing.api: + environment: + - ASPNETCORE_ENVIRONMENT=Development + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word + - EventBusConnection=rabbitmq + - MongoConnectionString=mongodb://nosql.data + - MongoDatabase=MarketingDb + - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. + ports: + - "5110:80" \ No newline at end of file diff --git a/docker-compose-windows.prod.yml b/docker-compose-windows.prod.yml index 7b9c9ab22..4767bba70 100644 --- a/docker-compose-windows.prod.yml +++ b/docker-compose-windows.prod.yml @@ -75,7 +75,19 @@ services: - BasketUrl=http://basket.api ports: - "5100:80" - + + marketing.api: + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://0.0.0.0:80 + - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word + - EventBusConnection=rabbitmq + - MongoConnectionString=mongodb://nosql.data + - MongoDatabase=MarketingDb + - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. + ports: + - "5110:80" + sql.data: environment: - SA_PASSWORD=Pass@word diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml index 2caf209ab..f281d855a 100644 --- a/docker-compose-windows.yml +++ b/docker-compose-windows.yml @@ -61,7 +61,19 @@ services: dockerfile: Dockerfile depends_on: - nosql.data - + - rabbitmq + + marketing.api: + image: eshop/marketing.api + build: + context: ./src/Services/Marketing/Marketing.API + dockerfile: Dockerfile + depends_on: + - sql.data + - nosql.data + - identity.api + - rabbitmq + sql.data: image: microsoft/mssql-server-windows diff --git a/docker-compose.override.yml b/docker-compose.override.yml index c133de39a..021e5034f 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -58,6 +58,9 @@ services: - ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word + - MongoConnectionString=mongodb://nosql.data + - MongoDatabase=MarketingDb + - EventBusConnection=rabbitmq - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. ports: - "5110:80" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index b9c46b4c2..634253d8a 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -59,6 +59,9 @@ services: - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:80 - ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word + - MongoConnectionString=mongodb://nosql.data + - MongoDatabase=MarketingDb + - EventBusConnection=rabbitmq - identityUrl=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105. ports: - "5110:80" diff --git a/docker-compose.yml b/docker-compose.yml index 17284bce1..334e11537 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,7 +53,9 @@ services: dockerfile: Dockerfile depends_on: - sql.data + - nosql.data - identity.api + - rabbitmq webspa: image: eshop/webspa @@ -112,3 +114,4 @@ services: dockerfile: Dockerfile depends_on: - nosql.data + - rabbitmq diff --git a/src/Services/Location/Locations.API/Controllers/LocationsController.cs b/src/Services/Location/Locations.API/Controllers/LocationsController.cs index 71f21a721..1b4fd801b 100644 --- a/src/Services/Location/Locations.API/Controllers/LocationsController.cs +++ b/src/Services/Location/Locations.API/Controllers/LocationsController.cs @@ -54,6 +54,7 @@ namespace Locations.API.Controllers { var userId = _identityService.GetUserIdentity(); var result = await _locationsService.AddOrUpdateUserLocation(userId, newLocReq); + return result ? (IActionResult)Ok() : (IActionResult)BadRequest(); diff --git a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs index 4b1e3d55d..cd68313fe 100644 --- a/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs +++ b/src/Services/Location/Locations.API/Infrastructure/Services/LocationsService.cs @@ -8,14 +8,18 @@ using System.Linq; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Exceptions; using System.Collections.Generic; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; + using Microsoft.eShopOnContainers.Services.Locations.API.IntegrationEvents.Events; public class LocationsService : ILocationsService { - private ILocationsRepository _locationsRepository; + private readonly ILocationsRepository _locationsRepository; + private readonly IEventBus _eventBus; - public LocationsService(ILocationsRepository locationsRepository) + public LocationsService(ILocationsRepository locationsRepository, IEventBus eventBus) { _locationsRepository = locationsRepository ?? throw new ArgumentNullException(nameof(locationsRepository)); + _eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus)); } public async Task GetLocation(string locationId) @@ -23,14 +27,9 @@ return await _locationsRepository.GetAsync(locationId); } - public async Task GetUserLocation(string id) + public async Task GetUserLocation(string userId) { - if (!Guid.TryParse(id, out Guid userId)) - { - throw new ArgumentException("Not valid userId"); - } - - return await _locationsRepository.GetUserLocationAsync(userId.ToString()); + return await _locationsRepository.GetUserLocationAsync(id); } public async Task> GetAllLocation() @@ -38,13 +37,8 @@ return await _locationsRepository.GetLocationListAsync(); } - public async Task AddOrUpdateUserLocation(string id, LocationRequest currentPosition) - { - if (!Guid.TryParse(id, out Guid userId)) - { - throw new ArgumentException("Not valid userId"); - } - + public async Task AddOrUpdateUserLocation(string userId, LocationRequest currentPosition) + { // Get the list of ordered regions the user currently is within var currentUserAreaLocationList = await _locationsRepository.GetCurrentUserRegionsListAsync(currentPosition); @@ -55,14 +49,40 @@ // If current area found, then update user location var locationAncestors = new List(); - var userLocation = await _locationsRepository.GetUserLocationAsync(userId.ToString()); + var userLocation = await _locationsRepository.GetUserLocationAsync(userId); userLocation = userLocation ?? new UserLocation(); userLocation.UserId = userId; userLocation.LocationId = currentUserAreaLocationList[0].Id; userLocation.UpdateDate = DateTime.UtcNow; await _locationsRepository.UpdateUserLocationAsync(userLocation); + // Publish integration event to update marketing read data model + // with the new locations updated + PublishNewUserLocationPositionIntegrationEvent(userId, currentUserAreaLocationList); + return true; } + + private void PublishNewUserLocationPositionIntegrationEvent(string userId, List newLocations) + { + var newUserLocations = MapUserLocationDetails(newLocations); + var @event = new UserLocationUpdatedIntegrationEvent(userId, newUserLocations); + _eventBus.Publish(@event); + } + + private List MapUserLocationDetails(List newLocations) + { + var result = new List(); + newLocations.ForEach(location => { + result.Add(new UserLocationDetails() + { + LocationId = location.Id, + Code = location.Code, + Description = location.Description + }); + }); + + return result; + } } } diff --git a/src/Services/Location/Locations.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs b/src/Services/Location/Locations.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs new file mode 100644 index 000000000..d4112a54d --- /dev/null +++ b/src/Services/Location/Locations.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs @@ -0,0 +1,18 @@ +namespace Microsoft.eShopOnContainers.Services.Locations.API.IntegrationEvents.Events +{ + using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; + using Microsoft.eShopOnContainers.Services.Locations.API.Model; + using System.Collections.Generic; + + public class UserLocationUpdatedIntegrationEvent : IntegrationEvent + { + public string UserId { get; private set; } + public List LocationList { get; private set; } + + public UserLocationUpdatedIntegrationEvent(string userId, List locationList) + { + UserId = userId; + LocationList = locationList; + } + } +} diff --git a/src/Services/Location/Locations.API/Locations.API.csproj b/src/Services/Location/Locations.API/Locations.API.csproj index 57548fc03..b9ef671dc 100644 --- a/src/Services/Location/Locations.API/Locations.API.csproj +++ b/src/Services/Location/Locations.API/Locations.API.csproj @@ -10,6 +10,7 @@ + @@ -37,5 +38,9 @@ + + + + diff --git a/src/Services/Location/Locations.API/Model/UserLocation.cs b/src/Services/Location/Locations.API/Model/UserLocation.cs index 1b7572426..1d1b3d690 100644 --- a/src/Services/Location/Locations.API/Model/UserLocation.cs +++ b/src/Services/Location/Locations.API/Model/UserLocation.cs @@ -9,7 +9,7 @@ [BsonIgnoreIfDefault] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } - public Guid UserId { get; set; } + public string UserId { get; set; } [BsonRepresentation(BsonType.ObjectId)] public string LocationId { get; set; } public DateTime UpdateDate { get; set; } diff --git a/src/Services/Location/Locations.API/Model/UserLocationDetails.cs b/src/Services/Location/Locations.API/Model/UserLocationDetails.cs new file mode 100644 index 000000000..03d56b9ec --- /dev/null +++ b/src/Services/Location/Locations.API/Model/UserLocationDetails.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Services.Locations.API.Model +{ + public class UserLocationDetails + { + public string LocationId { get; set; } + public string Code { get; set; } + public string Description { get; set; } + } +} diff --git a/src/Services/Location/Locations.API/Startup.cs b/src/Services/Location/Locations.API/Startup.cs index d601f26be..f767f227b 100644 --- a/src/Services/Location/Locations.API/Startup.cs +++ b/src/Services/Location/Locations.API/Startup.cs @@ -1,17 +1,21 @@ -using Microsoft.AspNetCore.Builder; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Http; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; +using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure; +using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filters; +using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories; +using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using RabbitMQ.Client; using System.Reflection; using System; -using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Services; -using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Repositories; -using Microsoft.AspNetCore.Http; -using Microsoft.eShopOnContainers.Services.Locations.API.Infrastructure.Filters; namespace Microsoft.eShopOnContainers.Services.Locations.API { @@ -37,7 +41,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API } // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) + public IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(options => @@ -46,7 +50,21 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API }).AddControllersAsServices(); services.Configure(Configuration); - + + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = Configuration["EventBusConnection"] + }; + + return new DefaultRabbitMQPersistentConnection(factory, logger); + }); + + RegisterServiceBus(services); + // Add framework services. services.AddSwaggerGen(options => { @@ -72,7 +90,13 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API services.AddSingleton(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + + //configure autofac + var container = new ContainerBuilder(); + container.Populate(services); + + return new AutofacServiceProvider(container.Build()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -109,5 +133,11 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API RequireHttpsMetadata = false }); } + + private void RegisterServiceBus(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + } } } diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/MarketingReadDataContext.cs b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingReadDataContext.cs new file mode 100644 index 000000000..5790acf09 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Infrastructure/MarketingReadDataContext.cs @@ -0,0 +1,26 @@ +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure +{ + using Microsoft.eShopOnContainers.Services.Marketing.API.Model; + using Microsoft.Extensions.Options; + using MongoDB.Driver; + + public class MarketingReadDataContext + { + private readonly IMongoDatabase _database = null; + + public MarketingReadDataContext(IOptions settings) + { + var client = new MongoClient(settings.Value.MongoConnectionString); + if (client != null) + _database = client.GetDatabase(settings.Value.MongoDatabase); + } + + public IMongoCollection MarketingData + { + get + { + return _database.GetCollection("MarketingReadDataModel"); + } + } + } +} diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/Repositories/IMarketingDataRepository.cs b/src/Services/Marketing/Marketing.API/Infrastructure/Repositories/IMarketingDataRepository.cs new file mode 100644 index 000000000..12a4bf2f8 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Infrastructure/Repositories/IMarketingDataRepository.cs @@ -0,0 +1,11 @@ +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Repositories +{ + using Model; + using System.Threading.Tasks; + + public interface IMarketingDataRepository + { + Task GetAsync(string userId); + Task UpdateLocationAsync(MarketingData marketingData); + } +} diff --git a/src/Services/Marketing/Marketing.API/Infrastructure/Repositories/MarketingDataRepository.cs b/src/Services/Marketing/Marketing.API/Infrastructure/Repositories/MarketingDataRepository.cs new file mode 100644 index 000000000..19d264a4e --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Infrastructure/Repositories/MarketingDataRepository.cs @@ -0,0 +1,41 @@ +using Microsoft.eShopOnContainers.Services.Marketing.API.Model; +using Microsoft.Extensions.Options; +using MongoDB.Bson; +using MongoDB.Driver; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Repositories +{ + public class MarketingDataRepository + : IMarketingDataRepository + { + private readonly MarketingReadDataContext _context; + + public MarketingDataRepository(IOptions settings) + { + _context = new MarketingReadDataContext(settings); + } + + public async Task GetAsync(string userId) + { + var filter = Builders.Filter.Eq("UserId", userId); + return await _context.MarketingData + .Find(filter) + .FirstOrDefaultAsync(); + } + + public async Task UpdateLocationAsync(MarketingData marketingData) + { + var filter = Builders.Filter.Eq("UserId", marketingData.UserId); + var update = Builders.Update + .Set("Locations", marketingData.Locations) + .CurrentDate("UpdateDate"); + + await _context.MarketingData + .UpdateOneAsync(filter, update, new UpdateOptions { IsUpsert = true }); + } + } +} diff --git a/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs b/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs new file mode 100644 index 000000000..a7ab0cafd --- /dev/null +++ b/src/Services/Marketing/Marketing.API/IntegrationEvents/Events/UserLocationUpdatedIntegrationEvent.cs @@ -0,0 +1,18 @@ +namespace Microsoft.eShopOnContainers.Services.Marketing.API.IntegrationEvents.Events +{ + using Model; + using System.Collections.Generic; + using BuildingBlocks.EventBus.Events; + + public class UserLocationUpdatedIntegrationEvent : IntegrationEvent + { + public string UserId { get; private set; } + public List LocationList { get; private set; } + + public UserLocationUpdatedIntegrationEvent(string userId, List locationList) + { + UserId = userId; + LocationList = locationList; + } + } +} diff --git a/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs b/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs new file mode 100644 index 000000000..7879c3d96 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/IntegrationEvents/Handlers/UserLocationUpdatedIntegrationEventHandler.cs @@ -0,0 +1,46 @@ +namespace Microsoft.eShopOnContainers.Services.Marketing.API.IntegrationEvents.Handlers +{ + using BuildingBlocks.EventBus.Abstractions; + using System.Threading.Tasks; + using Events; + using System; + using Infrastructure.Repositories; + using Model; + using System.Collections.Generic; + + public class UserLocationUpdatedIntegrationEventHandler + : IIntegrationEventHandler + { + private readonly IMarketingDataRepository _marketingDataRepository; + + public UserLocationUpdatedIntegrationEventHandler(IMarketingDataRepository repository) + { + _marketingDataRepository = repository ?? throw new ArgumentNullException(nameof(repository)); + } + + public async Task Handle(UserLocationUpdatedIntegrationEvent @event) + { + var userMarketingData = await _marketingDataRepository.GetAsync(@event.UserId); + userMarketingData = userMarketingData ?? + new MarketingData() { UserId = @event.UserId }; + + userMarketingData.Locations = MapUpdatedUserLocations(@event.LocationList); + await _marketingDataRepository.UpdateLocationAsync(userMarketingData); + } + + private List MapUpdatedUserLocations(List newUserLocations) + { + var result = new List(); + newUserLocations.ForEach(location => { + result.Add(new Location() + { + LocationId = location.LocationId, + Code = location.Code, + Description = location.Description + }); + }); + + return result; + } + } +} diff --git a/src/Services/Marketing/Marketing.API/Marketing.API.csproj b/src/Services/Marketing/Marketing.API/Marketing.API.csproj index 34d594e51..556602f3b 100644 --- a/src/Services/Marketing/Marketing.API/Marketing.API.csproj +++ b/src/Services/Marketing/Marketing.API/Marketing.API.csproj @@ -12,10 +12,9 @@ - - + @@ -39,6 +38,10 @@ + + + + @@ -47,4 +50,7 @@ + + + diff --git a/src/Services/Marketing/Marketing.API/MarketingSettings.cs b/src/Services/Marketing/Marketing.API/MarketingSettings.cs index c6e1dfc40..d88726dcf 100644 --- a/src/Services/Marketing/Marketing.API/MarketingSettings.cs +++ b/src/Services/Marketing/Marketing.API/MarketingSettings.cs @@ -3,5 +3,7 @@ public class MarketingSettings { public string ConnectionString { get; set; } + public string MongoConnectionString { get; set; } + public string MongoDatabase { get; set; } } } diff --git a/src/Services/Marketing/Marketing.API/Model/Location.cs b/src/Services/Marketing/Marketing.API/Model/Location.cs new file mode 100644 index 000000000..388c0156b --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Model/Location.cs @@ -0,0 +1,17 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Model +{ + public class Location + { + [BsonRepresentation(BsonType.ObjectId)] + public string LocationId { get; set; } + public string Code { get; set; } + public string Description { get; set; } + } +} diff --git a/src/Services/Marketing/Marketing.API/Model/MarketingData.cs b/src/Services/Marketing/Marketing.API/Model/MarketingData.cs new file mode 100644 index 000000000..9f1f355b8 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Model/MarketingData.cs @@ -0,0 +1,19 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Model +{ + public class MarketingData + { + [BsonIgnoreIfDefault] + [BsonRepresentation(BsonType.ObjectId)] + public string Id { get; set; } + public string UserId { get; set; } + public List Locations { get; set; } + public DateTime UpdateDate { get; set; } + } +} diff --git a/src/Services/Marketing/Marketing.API/Model/UserLocationDetails.cs b/src/Services/Marketing/Marketing.API/Model/UserLocationDetails.cs new file mode 100644 index 000000000..0bbe89c44 --- /dev/null +++ b/src/Services/Marketing/Marketing.API/Model/UserLocationDetails.cs @@ -0,0 +1,9 @@ +namespace Microsoft.eShopOnContainers.Services.Marketing.API.Model +{ + public class UserLocationDetails + { + public string LocationId { get; set; } + public string Code { get; set; } + public string Description { get; set; } + } +} diff --git a/src/Services/Marketing/Marketing.API/Startup.cs b/src/Services/Marketing/Marketing.API/Startup.cs index 9609f903f..20eb97a12 100644 --- a/src/Services/Marketing/Marketing.API/Startup.cs +++ b/src/Services/Marketing/Marketing.API/Startup.cs @@ -11,6 +11,15 @@ using System.Reflection; using System; using Microsoft.eShopOnContainers.Services.Marketing.API.Infrastructure.Filters; + using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; + using RabbitMQ.Client; + using BuildingBlocks.EventBus.Abstractions; + using BuildingBlocks.EventBus; + using IntegrationEvents.Events; + using IntegrationEvents.Handlers; + using Infrastructure.Repositories; + using Autofac; + using Autofac.Extensions.DependencyInjection; public class Startup { @@ -35,7 +44,7 @@ public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) + public IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(options => @@ -43,6 +52,8 @@ options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); //Injecting Controllers themselves thru DIFor further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services + services.Configure(Configuration); + services.AddDbContext(options => { options.UseSqlServer(Configuration["ConnectionString"], @@ -59,6 +70,20 @@ //Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval }); + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = Configuration["EventBusConnection"] + }; + + return new DefaultRabbitMQPersistentConnection(factory, logger); + }); + + RegisterServiceBus(services); + // Add framework services. services.AddSwaggerGen(options => { @@ -80,6 +105,14 @@ .AllowAnyHeader() .AllowCredentials()); }); + + services.AddTransient(); + + //configure autofac + var container = new ContainerBuilder(); + container.Populate(services); + + return new AutofacServiceProvider(container.Build()); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -100,11 +133,12 @@ c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); + ConfigureEventBus(app); + MarketingContextSeed.SeedAsync(app, loggerFactory) .Wait(); } - protected virtual void ConfigureAuth(IApplicationBuilder app) { var identityUrl = Configuration.GetValue("IdentityUrl"); @@ -115,5 +149,22 @@ RequireHttpsMetadata = false }); } + + private void RegisterServiceBus(IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + + services.AddTransient, + UserLocationUpdatedIntegrationEventHandler>(); + } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + eventBus.Subscribe>(); + } } } diff --git a/src/Services/Marketing/Marketing.API/appsettings.json b/src/Services/Marketing/Marketing.API/appsettings.json index 36bdcad2c..aefa3526f 100644 --- a/src/Services/Marketing/Marketing.API/appsettings.json +++ b/src/Services/Marketing/Marketing.API/appsettings.json @@ -6,5 +6,7 @@ } }, "ConnectionString": "127.0.0.1", + "MongoConnectionString": "mongodb://nosql.data", + "MongoDatabase": "MarketingDb", "IdentityUrl": "http://localhost:5105" } diff --git a/test/Services/FunctionalTests/FunctionalTests.csproj b/test/Services/FunctionalTests/FunctionalTests.csproj index 54a74beda..2a4c1940d 100644 --- a/test/Services/FunctionalTests/FunctionalTests.csproj +++ b/test/Services/FunctionalTests/FunctionalTests.csproj @@ -25,6 +25,8 @@ + + @@ -33,6 +35,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/test/Services/FunctionalTests/Middleware/AutoAuthorizeMiddleware.cs b/test/Services/FunctionalTests/Middleware/AutoAuthorizeMiddleware.cs index 41f1dfc88..093ca4e97 100644 --- a/test/Services/FunctionalTests/Middleware/AutoAuthorizeMiddleware.cs +++ b/test/Services/FunctionalTests/Middleware/AutoAuthorizeMiddleware.cs @@ -18,7 +18,7 @@ namespace FunctionalTests.Middleware public async Task Invoke(HttpContext httpContext) { var identity = new ClaimsIdentity("cookies"); - identity.AddClaim(new Claim("sub", "1234")); + identity.AddClaim(new Claim("sub", "9e3163b9-1ae6-4652-9dc6-7898ab7b7a00")); httpContext.User.AddIdentity(identity); await _next.Invoke(httpContext); } diff --git a/test/Services/FunctionalTests/Services/Ordering/OrderingScenarios.cs b/test/Services/FunctionalTests/Services/Ordering/OrderingScenarios.cs index 57d107033..bce2c96c2 100644 --- a/test/Services/FunctionalTests/Services/Ordering/OrderingScenarios.cs +++ b/test/Services/FunctionalTests/Services/Ordering/OrderingScenarios.cs @@ -88,7 +88,7 @@ namespace FunctionalTests.Services.Ordering string BuildBasket() { - var order = new CustomerBasket("1234"); + var order = new CustomerBasket("9e3163b9-1ae6-4652-9dc6-7898ab7b7a00"); order.Items = new List() { new Microsoft.eShopOnContainers.Services.Basket.API.Model.BasketItem() diff --git a/test/Services/IntegrationTests/Services/Locations/LocationsScenarioBase.cs b/test/Services/IntegrationTests/Services/Locations/LocationsScenarioBase.cs index e74781e63..f50aa1441 100644 --- a/test/Services/IntegrationTests/Services/Locations/LocationsScenarioBase.cs +++ b/test/Services/IntegrationTests/Services/Locations/LocationsScenarioBase.cs @@ -1,9 +1,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; -using System; -using System.Collections.Generic; using System.IO; -using System.Text; namespace IntegrationTests.Services.Locations {