commit
						a7394be2bc
					
				
							
								
								
									
										2
									
								
								.env
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.env
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ | |||||||
| # The IP below should be swapped to your real IP or DNS name, like 192.168.88.248, etc. if testing from remote browsers or mobile devices | # The IP below should be swapped to your real IP or DNS name, like 192.168.88.248, etc. if testing from remote browsers or mobile devices | ||||||
| 
 | 
 | ||||||
| ESHOP_EXTERNAL_DNS_NAME_OR_IP=localhost | ESHOP_EXTERNAL_DNS_NAME_OR_IP=localhost | ||||||
| ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=10.121.122.92 | ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=10.121.122.162 | ||||||
| 
 | 
 | ||||||
| #ESHOP_AZURE_REDIS_BASKET_DB=<YourAzureRedisBasketInfo> | #ESHOP_AZURE_REDIS_BASKET_DB=<YourAzureRedisBasketInfo> | ||||||
| #ESHOP_AZURE_STORAGE_CATALOG_URL=<YourAzureStorage_Catalog_BLOB_URL> | #ESHOP_AZURE_STORAGE_CATALOG_URL=<YourAzureStorage_Catalog_BLOB_URL> | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ version: '3' | |||||||
| # | # | ||||||
| # IMPORTANT: Note that this compose file uses ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP instead of ESHOP_EXTERNAL_DNS_NAME_OR_IP | # IMPORTANT: Note that this compose file uses ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP instead of ESHOP_EXTERNAL_DNS_NAME_OR_IP | ||||||
| 
 | 
 | ||||||
| # Set ASPNETCORE_ENVIRONMENT=Development, instead Production, if you want to show up errors while testing.  | # Set ASPNETCORE_ENVIRONMENT= Development or Production, depending if you want to show up errors while testing.  | ||||||
| # | # | ||||||
| # You need to start it with the following CLI command: | # You need to start it with the following CLI command: | ||||||
| # docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d | # docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d | ||||||
| @ -17,7 +17,7 @@ services: | |||||||
|        |        | ||||||
|   basket.api: |   basket.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket.data} |       - ConnectionString=${ESHOP_AZURE_REDIS_BASKET_DB:-basket.data} | ||||||
|       - identityUrl=http://identity.api              #Local: You need to open your local dev-machine firewall at range 5100-5110. |       - identityUrl=http://identity.api              #Local: You need to open your local dev-machine firewall at range 5100-5110. | ||||||
| @ -35,7 +35,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   catalog.api: |   catalog.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} |       - ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word} | ||||||
|       - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5101/api/v1/catalog/items/[0]/pic/}   #Local: You need to open your local dev-machine firewall at range 5100-5110.   |       - PicBaseUrl=${ESHOP_AZURE_STORAGE_CATALOG_URL:-http://localhost:5101/api/v1/catalog/items/[0]/pic/}   #Local: You need to open your local dev-machine firewall at range 5100-5110.   | ||||||
| @ -54,7 +54,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   identity.api: |   identity.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104 |       - SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104 | ||||||
|       - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback      #localhost do not work for UWP login, so we have to use "external" IP always |       - XamarinCallback=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105/xamarincallback      #localhost do not work for UWP login, so we have to use "external" IP always | ||||||
| @ -72,7 +72,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   ordering.api: |   ordering.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} |       - ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word} | ||||||
|       - identityUrl=http://identity.api              #Local: You need to open your local dev-machine firewall at range 5100-5110. |       - identityUrl=http://identity.api              #Local: You need to open your local dev-machine firewall at range 5100-5110. | ||||||
| @ -92,7 +92,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   marketing.api: |   marketing.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} |       - ConnectionString=${ESHOP_AZURE_MARKETING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word} | ||||||
|       - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} |       - MongoConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} | ||||||
| @ -116,7 +116,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   webspa: |   webspa: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - CatalogUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 |       - CatalogUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 | ||||||
|       - OrderingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102 |       - OrderingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102 | ||||||
| @ -126,7 +126,7 @@ services: | |||||||
|       - LocationsUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5109 |       - LocationsUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5109 | ||||||
|       - CatalogUrlHC=http://catalog.api/hc |       - CatalogUrlHC=http://catalog.api/hc | ||||||
|       - OrderingUrlHC=http://ordering.api/hc |       - OrderingUrlHC=http://ordering.api/hc | ||||||
|       - IdentityUrlHC=http://identity.api/hc     #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.           |       - IdentityUrlHC=http://identity.api/hc            | ||||||
|       - BasketUrlHC=http://basket.api/hc |       - BasketUrlHC=http://basket.api/hc | ||||||
|       - MarketingUrlHC=http://marketing.api/hc |       - MarketingUrlHC=http://marketing.api/hc | ||||||
|       - PaymentUrlHC=http://payment.api/hc |       - PaymentUrlHC=http://payment.api/hc | ||||||
| @ -138,17 +138,17 @@ services: | |||||||
| 
 | 
 | ||||||
|   webmvc: |   webmvc: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - CatalogUrl=http://catalog.api |       - CatalogUrl=http://catalog.api | ||||||
|       - OrderingUrl=http://ordering.api |       - OrderingUrl=http://ordering.api | ||||||
|       - BasketUrl=http://basket.api |       - BasketUrl=http://basket.api | ||||||
|       - LocationsUrl=http://locations.api |       - LocationsUrl=http://locations.api | ||||||
|       - IdentityUrl=http://10.0.75.1:5105 |       - IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105   #Local:  Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. #Remote: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.   | ||||||
|       - MarketingUrl=http://marketing.api  #Local:  Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser. #Remote: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.                                                   |       - MarketingUrl=http://marketing.api                                                   | ||||||
|       - CatalogUrlHC=http://catalog.api/hc |       - CatalogUrlHC=http://catalog.api/hc | ||||||
|       - OrderingUrlHC=http://ordering.api/hc |       - OrderingUrlHC=http://ordering.api/hc | ||||||
|       - IdentityUrlHC=http://identity.api/hc     #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.           |       - IdentityUrlHC=http://identity.api/hc              | ||||||
|       - BasketUrlHC=http://basket.api/hc |       - BasketUrlHC=http://basket.api/hc | ||||||
|       - MarketingUrlHC=http://marketing.api/hc |       - MarketingUrlHC=http://marketing.api/hc | ||||||
|       - PaymentUrlHC=http://payment.api/hc |       - PaymentUrlHC=http://payment.api/hc | ||||||
| @ -161,7 +161,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   webstatus: |   webstatus: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - CatalogUrl=http://catalog.api/hc |       - CatalogUrl=http://catalog.api/hc | ||||||
|       - OrderingUrl=http://ordering.api/hc |       - OrderingUrl=http://ordering.api/hc | ||||||
| @ -179,7 +179,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   payment.api: |   payment.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} |       - EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq} | ||||||
|       - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} |       - EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME} | ||||||
| @ -192,7 +192,7 @@ services: | |||||||
| 
 | 
 | ||||||
|   locations.api: |   locations.api: | ||||||
|     environment: |     environment: | ||||||
|       - ASPNETCORE_ENVIRONMENT=Production |       - ASPNETCORE_ENVIRONMENT=Development | ||||||
|       - ASPNETCORE_URLS=http://0.0.0.0:80 |       - ASPNETCORE_URLS=http://0.0.0.0:80 | ||||||
|       - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} |       - ConnectionString=${ESHOP_AZURE_COSMOSDB:-mongodb://nosql.data} | ||||||
|       - Database=LocationsDb |       - Database=LocationsDb | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								img/loadtests/k8ssettings.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/loadtests/k8ssettings.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 66 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/loadtests/loadtestproj_dir.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/loadtests/loadtestproj_dir.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 9.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/loadtests/runloadtest.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/loadtests/runloadtest.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 10 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/loadtests/sfmanifestsettings.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/loadtests/sfmanifestsettings.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 66 KiB | 
| @ -5,9 +5,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions | |||||||
| { | { | ||||||
|     public interface IEventBus |     public interface IEventBus | ||||||
|     { |     { | ||||||
|  |         void Publish(IntegrationEvent @event); | ||||||
|  | 
 | ||||||
|         void Subscribe<T, TH>() |         void Subscribe<T, TH>() | ||||||
|             where T : IntegrationEvent |             where T : IntegrationEvent | ||||||
|             where TH : IIntegrationEventHandler<T>; |             where TH : IIntegrationEventHandler<T>; | ||||||
|  | 
 | ||||||
|         void SubscribeDynamic<TH>(string eventName) |         void SubscribeDynamic<TH>(string eventName) | ||||||
|             where TH : IDynamicIntegrationEventHandler; |             where TH : IDynamicIntegrationEventHandler; | ||||||
| 
 | 
 | ||||||
| @ -17,7 +20,5 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions | |||||||
|         void Unsubscribe<T, TH>() |         void Unsubscribe<T, TH>() | ||||||
|             where TH : IIntegrationEventHandler<T> |             where TH : IIntegrationEventHandler<T> | ||||||
|             where T : IntegrationEvent; |             where T : IntegrationEvent; | ||||||
| 
 |  | ||||||
|         void Publish(IntegrationEvent @event); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,145 +0,0 @@ | |||||||
| //using Microsoft.eShopOnContainers.BuildingBlocks.CommandBus; |  | ||||||
| using Microsoft.Extensions.Logging; |  | ||||||
| using Newtonsoft.Json; |  | ||||||
| using Polly; |  | ||||||
| using Polly.Retry; |  | ||||||
| using RabbitMQ.Client; |  | ||||||
| using RabbitMQ.Client.Events; |  | ||||||
| using RabbitMQ.Client.Exceptions; |  | ||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Net.Sockets; |  | ||||||
| using System.Text; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| 
 |  | ||||||
| /* |  | ||||||
| namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ |  | ||||||
| { |  | ||||||
|     public class CommandBusRabbitMQ : ICommandBus, IDisposable |  | ||||||
|     { |  | ||||||
|         const string BROKER_NAME = "eshop_command_bus"; |  | ||||||
| 
 |  | ||||||
|         private readonly IRabbitMQPersistentConnection _persistentConnection; |  | ||||||
|         private readonly ILogger<CommandBusRabbitMQ> _logger; |  | ||||||
| 
 |  | ||||||
|         private IModel _consumerChannel; |  | ||||||
|         private string _queueName; |  | ||||||
| 
 |  | ||||||
|         private readonly Dictionary<string, IIntegrationCommandHandler> _handlers; |  | ||||||
|         private readonly Dictionary<string, Type> _typeMappings; |  | ||||||
| 
 |  | ||||||
|         public CommandBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection,  |  | ||||||
|             ILogger<CommandBusRabbitMQ> logger) |  | ||||||
|         { |  | ||||||
|             _logger = logger; |  | ||||||
|             _persistentConnection = persistentConnection; |  | ||||||
|             _handlers = new Dictionary<string, IIntegrationCommandHandler>(); |  | ||||||
|             _typeMappings = new Dictionary<string, Type>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void Send<T>(string name, T data) |  | ||||||
|         { |  | ||||||
|             Send(new IntegrationCommand<T>(name, data)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void Handle<TC>(string name, IIntegrationCommandHandler<TC> handler) |  | ||||||
|         { |  | ||||||
|             _handlers.Add(name, handler); |  | ||||||
|             _typeMappings.Add(name, typeof(TC)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void Handle(string name, IIntegrationCommandHandler handler) |  | ||||||
|         { |  | ||||||
|             _handlers.Add(name, handler); |  | ||||||
|         } |  | ||||||
|         public void Handle<TI, TC>(TI handler) where TI : IIntegrationCommandHandler<TC> |  | ||||||
|         { |  | ||||||
|             var name = typeof(TI).Name; |  | ||||||
|             _handlers.Add(name, handler); |  | ||||||
|             _typeMappings.Add(name, typeof(TC)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private void Send<T>(IntegrationCommand<T> command) |  | ||||||
|         { |  | ||||||
|             if (!_persistentConnection.IsConnected) |  | ||||||
|             { |  | ||||||
|                 _persistentConnection.TryConnect(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var policy = RetryPolicy.Handle<BrokerUnreachableException>() |  | ||||||
|                 .Or<SocketException>() |  | ||||||
|                 .WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) => |  | ||||||
|                     { |  | ||||||
|                         _logger.LogWarning(ex.ToString()); |  | ||||||
|                     }); |  | ||||||
| 
 |  | ||||||
|             using (var channel = _persistentConnection.CreateModel()) |  | ||||||
|             { |  | ||||||
|                 var commandName = command.Name; |  | ||||||
|                 channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); |  | ||||||
|                 var message = JsonConvert.SerializeObject(command); |  | ||||||
|                 var body = Encoding.UTF8.GetBytes(message); |  | ||||||
|                 policy.Execute(() => |  | ||||||
|                 { |  | ||||||
|                     channel.BasicPublish(exchange: BROKER_NAME, |  | ||||||
|                                      routingKey: commandName, |  | ||||||
|                                      basicProperties: null, |  | ||||||
|                                      body: body); |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private IModel CreateConsumerChannel() |  | ||||||
|         { |  | ||||||
|             if (!_persistentConnection.IsConnected) |  | ||||||
|             { |  | ||||||
|                 _persistentConnection.TryConnect(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var channel = _persistentConnection.CreateModel(); |  | ||||||
| 
 |  | ||||||
|             channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct"); |  | ||||||
|             _queueName = channel.QueueDeclare().QueueName; |  | ||||||
|             var consumer = new EventingBasicConsumer(channel); |  | ||||||
|             consumer.Received += async (model, ea) => |  | ||||||
|             { |  | ||||||
|                 var commandName = ea.RoutingKey; |  | ||||||
|                 var message = Encoding.UTF8.GetString(ea.Body); |  | ||||||
|                 await InvokeHandler(commandName, message); |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             channel.BasicConsume(queue: _queueName, |  | ||||||
|                                  noAck: true, |  | ||||||
|                                  consumer: consumer); |  | ||||||
| 
 |  | ||||||
|             channel.CallbackException += (sender, ea) => |  | ||||||
|             { |  | ||||||
|                 _consumerChannel.Dispose(); |  | ||||||
|                 _consumerChannel = CreateConsumerChannel(); |  | ||||||
|             }; |  | ||||||
| 
 |  | ||||||
|             return channel; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private Task InvokeHandler(string commandName, string message) |  | ||||||
|         { |  | ||||||
|             if (_handlers.ContainsKey(commandName)) |  | ||||||
|             { |  | ||||||
| 
 |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public void Dispose() |  | ||||||
|         { |  | ||||||
|             if (_consumerChannel != null) |  | ||||||
|             { |  | ||||||
|                 _consumerChannel.Dispose(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| */ |  | ||||||
| @ -32,11 +32,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ | |||||||
|         private string _queueName; |         private string _queueName; | ||||||
| 
 | 
 | ||||||
|         public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger, |         public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger, | ||||||
|             ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, int retryCount = 5) |             ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null, int retryCount = 5) | ||||||
|         { |         { | ||||||
|             _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); |             _persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection)); | ||||||
|             _logger = logger ?? throw new ArgumentNullException(nameof(logger)); |             _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||||||
|             _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); |             _subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager(); | ||||||
|  |             _queueName = queueName; | ||||||
|             _consumerChannel = CreateConsumerChannel(); |             _consumerChannel = CreateConsumerChannel(); | ||||||
|             _autofac = autofac; |             _autofac = autofac; | ||||||
|             _retryCount = retryCount; |             _retryCount = retryCount; | ||||||
| @ -147,7 +148,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ | |||||||
|             _subsManager.RemoveDynamicSubscription<TH>(eventName); |             _subsManager.RemoveDynamicSubscription<TH>(eventName); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         public void Dispose() |         public void Dispose() | ||||||
|         { |         { | ||||||
|             if (_consumerChannel != null) |             if (_consumerChannel != null) | ||||||
| @ -170,7 +170,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ | |||||||
|             channel.ExchangeDeclare(exchange: BROKER_NAME, |             channel.ExchangeDeclare(exchange: BROKER_NAME, | ||||||
|                                  type: "direct"); |                                  type: "direct"); | ||||||
| 
 | 
 | ||||||
|             _queueName = channel.QueueDeclare().QueueName; |             channel.QueueDeclare(queue: _queueName, | ||||||
|  |                                  durable: true, | ||||||
|  |                                  exclusive: false, | ||||||
|  |                                  autoDelete: false, | ||||||
|  |                                  arguments: null); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|             var consumer = new EventingBasicConsumer(channel); |             var consumer = new EventingBasicConsumer(channel); | ||||||
|             consumer.Received += async (model, ea) => |             consumer.Received += async (model, ea) => | ||||||
| @ -196,8 +201,6 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ | |||||||
| 
 | 
 | ||||||
|         private async Task ProcessEvent(string eventName, string message) |         private async Task ProcessEvent(string eventName, string message) | ||||||
|         { |         { | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|             if (_subsManager.HasSubscriptionsForEvent(eventName)) |             if (_subsManager.HasSubscriptionsForEvent(eventName)) | ||||||
|             { |             { | ||||||
|                 using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) |                 using (var scope = _autofac.BeginLifetimeScope(AUTOFAC_SCOPE_NAME)) | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> | ||||||
|  |     <PackageReference Include="Polly" Version="5.3.1" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| </Project> | </Project> | ||||||
|  | |||||||
| @ -1,7 +1,10 @@ | |||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
|  | using Polly; | ||||||
|  | using Polly.Retry; | ||||||
| using System; | using System; | ||||||
|  | using System.Data.SqlClient; | ||||||
| 
 | 
 | ||||||
| namespace Microsoft.AspNetCore.Hosting | namespace Microsoft.AspNetCore.Hosting | ||||||
| { | { | ||||||
| @ -21,10 +24,26 @@ namespace Microsoft.AspNetCore.Hosting | |||||||
|                 { |                 { | ||||||
|                     logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}"); |                     logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}"); | ||||||
| 
 | 
 | ||||||
|                     context.Database |                     var retry = Policy.Handle<SqlException>() | ||||||
|  |                          .WaitAndRetry(new TimeSpan[] | ||||||
|  |                          { | ||||||
|  |                              TimeSpan.FromSeconds(5), | ||||||
|  |                              TimeSpan.FromSeconds(10), | ||||||
|  |                              TimeSpan.FromSeconds(15), | ||||||
|  |                          }); | ||||||
|  | 
 | ||||||
|  |                     retry.Execute(() => | ||||||
|  |                     { | ||||||
|  |                         //if the sql server container is not created on run docker compose this | ||||||
|  |                         //migration can't fail for network related exception. The retry options for DbContext only  | ||||||
|  |                         //apply to transient exceptions. | ||||||
|  | 
 | ||||||
|  |                         context.Database | ||||||
|                         .Migrate(); |                         .Migrate(); | ||||||
| 
 | 
 | ||||||
|                     seeder(context,services); |                         seeder(context, services); | ||||||
|  |                     }); | ||||||
|  |                    | ||||||
| 
 | 
 | ||||||
|                     logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}"); |                     logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}"); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -34,148 +34,139 @@ | |||||||
|             <Color x:Key="AndroidListViewBackgroundColor">Transparent</Color> |             <Color x:Key="AndroidListViewBackgroundColor">Transparent</Color> | ||||||
|             <Color x:Key="iOSListViewBackgroundColor">Transparent</Color> |             <Color x:Key="iOSListViewBackgroundColor">Transparent</Color> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:TypeArguments="Color" | ||||||
|                 x:TypeArguments="Color" |                         x:Key="ActivityIndicatorColor"> | ||||||
|                 x:Key="ActivityIndicatorColor" |                 <On Platform="iOS" Value="{ StaticResource iOSDefaultTintColor }" /> | ||||||
|                 iOS="{ StaticResource iOSDefaultTintColor }" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="Color" | ||||||
|                 x:TypeArguments="Color" |                         x:Key="DefaultButtonClassBackgroundColor"> | ||||||
|                 x:Key="DefaultButtonClassBackgroundColor" |                 <On Platform="iOS" Value="{ StaticResource iOSDefaultButtonClassBackgroundColor }" /> | ||||||
|                 Android="{ StaticResource AndroidDefaultButtonClassBackgroundColor }" |                 <On Platform="Android" Value="{ StaticResource AndroidDefaultButtonClassBackgroundColor }" /> | ||||||
|                 iOS="{ StaticResource iOSDefaultButtonClassBackgroundColor }" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="Color" | ||||||
|                 x:TypeArguments="Color" |                         x:Key="DefaultButtonClassBorderColor"> | ||||||
|                 x:Key="DefaultButtonClassBorderColor" |                 <On Platform="iOS" Value="{ StaticResource iOSDefaultButtonClassBorderColor }" /> | ||||||
|                 Android="{ StaticResource AndroidDefaultButtonClassBorderColor }" |                 <On Platform="Android" Value="{ StaticResource AndroidDefaultButtonClassBorderColor }" /> | ||||||
|                 iOS="{ StaticResource iOSDefaultButtonClassBorderColor }" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="Color" | ||||||
|                 x:TypeArguments="Color" |                         x:Key="DefaultButtonClassTextColor"> | ||||||
|                 x:Key="DefaultButtonClassTextColor" |                 <On Platform="iOS" Value="{ StaticResource iOSDefaultButtonClassTextColor }" /> | ||||||
|                 Android="{ StaticResource AndroidDefaultButtonClassTextColor }" |                 <On Platform="Android" Value="{ StaticResource AndroidDefaultButtonClassTextColor }" /> | ||||||
|                 iOS="{ StaticResource iOSDefaultButtonClassTextColor }" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="Color" | ||||||
|                 x:TypeArguments="Color" |                         x:Key="EntryBackgroundColor"> | ||||||
|                 x:Key="EntryBackgroundColor" |                 <On Platform="iOS" Value="{ StaticResource iOSEntryBackgroundColor }" /> | ||||||
|                 Android="{ StaticResource AndroidEntryBackgroundColor }" |                 <On Platform="Android" Value="{ StaticResource AndroidEntryBackgroundColor }" /> | ||||||
|                 iOS="{ StaticResource iOSEntryBackgroundColor }" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="Color" | ||||||
|                 x:TypeArguments="Color" |                         x:Key="ThemeListViewBackgroundColor"> | ||||||
|                 x:Key="ThemeListViewBackgroundColor" |                 <On Platform="iOS" Value="{ StaticResource iOSListViewBackgroundColor }" /> | ||||||
|                 Android="{ StaticResource AndroidListViewBackgroundColor }" |                 <On Platform="Android" Value="{ StaticResource AndroidListViewBackgroundColor }" /> | ||||||
|                 iOS="{ StaticResource iOSListViewBackgroundColor }" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <!-- SIZES --> |             <!-- SIZES --> | ||||||
|             <OnPlatform  |             <OnPlatform x:TypeArguments="x:Double" | ||||||
|                 x:TypeArguments="x:Double" |                         x:Key="BaseButtonBorderRadius"> | ||||||
|                 x:Key="BaseButtonBorderRadius" |                 <On Platform="iOS" Value="6" /> | ||||||
|                 iOS="6" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:TypeArguments="x:Double" | ||||||
|                 x:TypeArguments="x:Double" |                         x:Key="BaseButtonBorderWidth"> | ||||||
|                 x:Key="BaseButtonBorderWidth" |                 <On Platform="iOS, Android" Value="0" /> | ||||||
|                 Android="0" |             </OnPlatform> | ||||||
|                 iOS="0" /> |  | ||||||
|              |              | ||||||
|             <!-- FONTS --> |             <!-- FONTS --> | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="MontserratRegular" | ||||||
|                 x:Key="MontserratRegular" |                         x:TypeArguments="x:String"> | ||||||
|                 x:TypeArguments="x:String" |                 <On Platform="iOS" Value="Montserrat-Regular" /> | ||||||
|                 iOS="Montserrat-Regular" |                 <On Platform="Android" Value="Montserrat-Regular.ttf#Montserrat" /> | ||||||
|                 Android="Montserrat-Regular.ttf#Montserrat" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/Fonts/Montserrat-Regular.ttf#Montserrat" /> | ||||||
|                 WinPhone="Assets/Fonts/Montserrat-Regular.ttf#Montserrat"/> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="MontserratBold" | ||||||
|                 x:Key="MontserratBold" |                         x:TypeArguments="x:String"> | ||||||
|                 x:TypeArguments="x:String" |                 <On Platform="iOS" Value="Montserrat-Bold" /> | ||||||
|                 iOS="Montserrat-Bold" |                 <On Platform="Android" Value="Montserrat-Bold.ttf#Montserrat" /> | ||||||
|                 Android="Montserrat-Bold.ttf#Montserrat" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/Fonts/Montserrat-Bold.ttf#Montserrat" /> | ||||||
|                 WinPhone="Assets/Fonts/Montserrat-Bold.ttf#Montserrat"/> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="SourceSansProRegular" | ||||||
|                 x:Key="SourceSansProRegular" |                         x:TypeArguments="x:String"> | ||||||
|                 x:TypeArguments="x:String" |                 <On Platform="iOS" Value="SourceSansPro-Regular" /> | ||||||
|                 iOS="SourceSansPro-Regular" |                 <On Platform="Android" Value="SourceSansPro-Regular.ttf#Source Sans Pro" /> | ||||||
|                 Android="SourceSansPro-Regular.ttf#Source Sans Pro" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/Fonts/SourceSansPro-Regular.ttf#Source Sans Pro" /> | ||||||
|                 WinPhone="Assets/Fonts/SourceSansPro-Regular.ttf#Source Sans Pro"/> |             </OnPlatform> | ||||||
|              |              | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="x:Double" | ||||||
|                 x:TypeArguments="x:Double" |                         x:Key="BaseButtonFontSize"> | ||||||
|                 x:Key="BaseButtonFontSize" |                 <On Platform="iOS" Value="18" /> | ||||||
|                 Android="16" |                 <On Platform="Android" Value="16" /> | ||||||
|                 iOS="18" /> |             </OnPlatform> | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="x:Double" | ||||||
|                 x:TypeArguments="x:Double" |                         x:Key="BaseFontSize"> | ||||||
|                 x:Key="BaseFontSize" |                 <On Platform="iOS" Value="16" /> | ||||||
|                 Android="15" |                 <On Platform="Android" Value="15" /> | ||||||
|                 iOS="16" /> |             </OnPlatform> | ||||||
|              |              | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="LittleSize" | ||||||
|                 x:Key="LittleSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="11" /> | ||||||
|                 iOS="11" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="12" /> | ||||||
|                 Android="12" |             </OnPlatform> | ||||||
|                 WinPhone="12"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="MidMediumSize" | ||||||
|                 x:Key="MidMediumSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="12" /> | ||||||
|                 iOS="12" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="14" /> | ||||||
|                 Android="14" |             </OnPlatform> | ||||||
|                 WinPhone="14"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="MediumSize" | ||||||
|                 x:Key="MediumSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="14" /> | ||||||
|                 iOS="14" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="16" /> | ||||||
|                 Android="16" |             </OnPlatform> | ||||||
|                 WinPhone="16"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="LargeSize" | ||||||
|                 x:Key="LargeSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="16" /> | ||||||
|                 iOS="16" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="18" /> | ||||||
|                 Android="18" |             </OnPlatform> | ||||||
|                 WinPhone="18"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="LargerSize" | ||||||
|                 x:Key="LargerSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="18" /> | ||||||
|                 iOS="18" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="20" /> | ||||||
|                 Android="20" |             </OnPlatform> | ||||||
|                 WinPhone="20"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="BigSize" | ||||||
|                 x:Key="BigSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="20" /> | ||||||
|                 iOS="20" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="24" /> | ||||||
|                 Android="24" |             </OnPlatform> | ||||||
|                 WinPhone="24"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="ExtraBigSize" | ||||||
|                 x:Key="ExtraBigSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="24" /> | ||||||
|                 iOS="24" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="32" /> | ||||||
|                 Android="32" |             </OnPlatform> | ||||||
|                 WinPhone="32"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform  |             <OnPlatform x:Key="HugeSize" | ||||||
|                 x:Key="HugeSize" |                         x:TypeArguments="x:Double"> | ||||||
|                 x:TypeArguments="x:Double" |                 <On Platform="iOS" Value="32" /> | ||||||
|                 iOS="32" |                 <On Platform="Android, UWP, WinRT, WinPhone" Value="48" /> | ||||||
|                 Android="48" |             </OnPlatform> | ||||||
|                 WinPhone="48"/> |  | ||||||
| 
 | 
 | ||||||
|             <OnPlatform |             <OnPlatform x:TypeArguments="FontAttributes" | ||||||
|                 x:TypeArguments="FontAttributes" |                         x:Key="BaseButtonFontAttributes"> | ||||||
|                 x:Key="BaseButtonFontAttributes" |                 <On Platform="iOS" Value="Bold" /> | ||||||
|                 Android="None" |                 <On Platform="Android" Value="None" /> | ||||||
|                 iOS="Bold" /> |             </OnPlatform> | ||||||
|              |              | ||||||
|             <!-- CONVERTERS --> |             <!-- CONVERTERS --> | ||||||
|             <converters:CountToBoolConverter x:Key="CountToBoolConverter" /> |             <converters:CountToBoolConverter x:Key="CountToBoolConverter" /> | ||||||
|  | |||||||
| @ -44,11 +44,10 @@ | |||||||
|             <!-- ANDROID --> |             <!-- ANDROID --> | ||||||
|             <Grid> |             <Grid> | ||||||
|                 <Grid.IsVisible> |                 <Grid.IsVisible> | ||||||
|                     <OnPlatform          |                     <OnPlatform x:TypeArguments="x:Boolean"> | ||||||
|                         x:TypeArguments="x:Boolean" |                         <On Platform="iOS, Android" Value="True" /> | ||||||
|                         Android="True" |                         <On Platform="UWP, WinRT, WinPhone" Value="False" /> | ||||||
|                         iOS="True" |                     </OnPlatform> | ||||||
|                         WinPhone="False"/> |  | ||||||
|                 </Grid.IsVisible> |                 </Grid.IsVisible> | ||||||
|                 <BoxView   |                 <BoxView   | ||||||
|                     BackgroundColor="{StaticResource LightGreenColor}" |                     BackgroundColor="{StaticResource LightGreenColor}" | ||||||
| @ -64,11 +63,10 @@ | |||||||
|             <!-- IOS & UWP --> |             <!-- IOS & UWP --> | ||||||
|             <Grid> |             <Grid> | ||||||
|                 <Grid.IsVisible> |                 <Grid.IsVisible> | ||||||
|                     <OnPlatform          |                     <OnPlatform x:TypeArguments="x:Boolean"> | ||||||
|                         x:TypeArguments="x:Boolean" |                         <On Platform="iOS, Android" Value="False" /> | ||||||
|                         Android="False" |                         <On Platform="UWP, WinRT, WinPhone" Value="True" /> | ||||||
|                         iOS="False" |                     </OnPlatform> | ||||||
|                         WinPhone="True"/> |  | ||||||
|                 </Grid.IsVisible> |                 </Grid.IsVisible> | ||||||
|                 <Image |                 <Image | ||||||
|                     Source="Assets\circle_button_background.png" |                     Source="Assets\circle_button_background.png" | ||||||
|  | |||||||
| @ -68,6 +68,7 @@ namespace eShopOnContainers.Core.Services.Order | |||||||
|                 CardSecurityNumber = order.CardSecurityNumber, |                 CardSecurityNumber = order.CardSecurityNumber, | ||||||
|                 CardTypeId = order.CardTypeId, |                 CardTypeId = order.CardTypeId, | ||||||
|                 City = order.ShippingCity, |                 City = order.ShippingCity, | ||||||
|  |                 State = order.ShippingState, | ||||||
|                 Country = order.ShippingCountry, |                 Country = order.ShippingCountry, | ||||||
|                 ZipCode = order.ShippingZipCode, |                 ZipCode = order.ShippingZipCode, | ||||||
|                 Street = order.ShippingStreet |                 Street = order.ShippingStreet | ||||||
|  | |||||||
| @ -165,7 +165,7 @@ namespace eShopOnContainers.Core.ViewModels | |||||||
|                 await NavigationService.RemoveLastFromBackStackAsync(); |                 await NavigationService.RemoveLastFromBackStackAsync(); | ||||||
| 
 | 
 | ||||||
|                 // Show Dialog |                 // Show Dialog | ||||||
|                 await DialogService.ShowAlertAsync("Order sent successfully!", string.Format("Order {0}", Order.OrderNumber), "Ok"); |                 await DialogService.ShowAlertAsync("Order sent successfully!", "Checkout", "Ok"); | ||||||
|                 await NavigationService.RemoveLastFromBackStackAsync(); |                 await NavigationService.RemoveLastFromBackStackAsync(); | ||||||
|             } |             } | ||||||
|             catch |             catch | ||||||
|  | |||||||
| @ -171,11 +171,10 @@ | |||||||
|             VerticalOptions="Center" |             VerticalOptions="Center" | ||||||
|             HorizontalOptions="Center"> |             HorizontalOptions="Center"> | ||||||
|             <ActivityIndicator.WidthRequest> |             <ActivityIndicator.WidthRequest> | ||||||
|                 <OnPlatform  |                 <OnPlatform x:TypeArguments="x:Double"> | ||||||
|                     x:TypeArguments="x:Double"  |                     <On Platform="iOS, Android" Value="100" /> | ||||||
|                     iOS="100"  |                     <On Platform="UWP, WinRT, WinPhone" Value="400" /> | ||||||
|                     Android="100" |                 </OnPlatform> | ||||||
|                     WinPhone="400" /> |  | ||||||
|             </ActivityIndicator.WidthRequest> |             </ActivityIndicator.WidthRequest> | ||||||
|         </ActivityIndicator> |         </ActivityIndicator> | ||||||
|     </Grid> |     </Grid> | ||||||
|  | |||||||
| @ -90,11 +90,10 @@ | |||||||
|             VerticalOptions="Center" |             VerticalOptions="Center" | ||||||
|             HorizontalOptions="Center"> |             HorizontalOptions="Center"> | ||||||
|             <ActivityIndicator.WidthRequest> |             <ActivityIndicator.WidthRequest> | ||||||
|                 <OnPlatform  |                 <OnPlatform x:TypeArguments="x:Double"> | ||||||
|                     x:TypeArguments="x:Double"  |                     <On Platform="iOS, Android" Value="100" /> | ||||||
|                     iOS="100"  |                     <On Platform="UWP, WinRT, WinPhone" Value="400" /> | ||||||
|                     Android="100" |                 </OnPlatform> | ||||||
|                     WinPhone="400" /> |  | ||||||
|             </ActivityIndicator.WidthRequest> |             </ActivityIndicator.WidthRequest> | ||||||
|         </ActivityIndicator> |         </ActivityIndicator> | ||||||
|     </Grid> |     </Grid> | ||||||
|  | |||||||
| @ -114,11 +114,10 @@ | |||||||
|             VerticalOptions="Center" |             VerticalOptions="Center" | ||||||
|             HorizontalOptions="Center"> |             HorizontalOptions="Center"> | ||||||
|             <ActivityIndicator.WidthRequest> |             <ActivityIndicator.WidthRequest> | ||||||
|                 <OnPlatform  |                 <OnPlatform x:TypeArguments="x:Double"> | ||||||
|                     x:TypeArguments="x:Double"  |                     <On Platform="iOS, Android" Value="100" /> | ||||||
|                     iOS="100"  |                     <On Platform="UWP, WinRT, WinPhone" Value="400" /> | ||||||
|                     Android="100" |                 </OnPlatform> | ||||||
|                     WinPhone="400" /> |  | ||||||
|             </ActivityIndicator.WidthRequest> |             </ActivityIndicator.WidthRequest> | ||||||
|         </ActivityIndicator> |         </ActivityIndicator> | ||||||
|     </Grid> |     </Grid> | ||||||
|  | |||||||
| @ -231,11 +231,10 @@ | |||||||
|             VerticalOptions="Center" |             VerticalOptions="Center" | ||||||
|             HorizontalOptions="Center"> |             HorizontalOptions="Center"> | ||||||
|             <ActivityIndicator.WidthRequest> |             <ActivityIndicator.WidthRequest> | ||||||
|                 <OnPlatform  |                 <OnPlatform x:TypeArguments="x:Double"> | ||||||
|                     x:TypeArguments="x:Double"  |                     <On Platform="iOS, Android" Value="100" /> | ||||||
|                     iOS="100"  |                     <On Platform="UWP, WinRT, WinPhone" Value="400" /> | ||||||
|                     Android="100" |                 </OnPlatform> | ||||||
|                     WinPhone="400" /> |  | ||||||
|             </ActivityIndicator.WidthRequest> |             </ActivityIndicator.WidthRequest> | ||||||
|         </ActivityIndicator> |         </ActivityIndicator> | ||||||
|     </Grid> |     </Grid> | ||||||
|  | |||||||
| @ -76,11 +76,10 @@ | |||||||
|       SelectedItem="{Binding Brand, Mode=TwoWay}" |       SelectedItem="{Binding Brand, Mode=TwoWay}" | ||||||
|       Style="{StaticResource FilterPickerStyle}"> |       Style="{StaticResource FilterPickerStyle}"> | ||||||
|       <Picker.HeightRequest>    |       <Picker.HeightRequest>    | ||||||
|         <OnPlatform  |         <OnPlatform x:TypeArguments="x:Double"> | ||||||
|           x:TypeArguments="x:Double"        |             <On Platform="iOS, Android" Value="48" /> | ||||||
|           Android="48" |             <On Platform="UWP, WinRT, WinPhone" Value="36" /> | ||||||
|           iOS="48" |         </OnPlatform> | ||||||
|           WinPhone="36"/> |  | ||||||
|       </Picker.HeightRequest>  |       </Picker.HeightRequest>  | ||||||
|     </Picker> |     </Picker> | ||||||
|     <!-- TYPE --> |     <!-- TYPE --> | ||||||
| @ -91,11 +90,10 @@ | |||||||
|       SelectedItem="{Binding Type, Mode=TwoWay}" |       SelectedItem="{Binding Type, Mode=TwoWay}" | ||||||
|       Style="{StaticResource FilterPickerStyle}">     |       Style="{StaticResource FilterPickerStyle}">     | ||||||
|       <Picker.HeightRequest>    |       <Picker.HeightRequest>    | ||||||
|         <OnPlatform  |         <OnPlatform x:TypeArguments="x:Double"> | ||||||
|           x:TypeArguments="x:Double"        |             <On Platform="iOS, Android" Value="48" /> | ||||||
|           Android="48" |             <On Platform="UWP, WinRT, WinPhone" Value="36" /> | ||||||
|           iOS="48" |         </OnPlatform> | ||||||
|           WinPhone="36"/> |  | ||||||
|       </Picker.HeightRequest>  |       </Picker.HeightRequest>  | ||||||
|     </Picker> |     </Picker> | ||||||
|     <Button  |     <Button  | ||||||
|  | |||||||
| @ -9,10 +9,9 @@ | |||||||
|              xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core" |              xmlns:behaviors="clr-namespace:eShopOnContainers.Core.Behaviors;assembly=eShopOnContainers.Core" | ||||||
| 			 viewModelBase:ViewModelLocator.AutoWireViewModel="true"> | 			 viewModelBase:ViewModelLocator.AutoWireViewModel="true"> | ||||||
|     <ContentPage.Title> |     <ContentPage.Title> | ||||||
|         <OnPlatform |         <OnPlatform x:TypeArguments="x:String"> | ||||||
|             x:TypeArguments="x:String" |             <On Platform="iOS, UWP, WinRT, WinPhone" Value="eShop on Containers" /> | ||||||
|             iOS="eShop on Containers" |         </OnPlatform> | ||||||
|             WinPhone="eShop on Containers"/> |  | ||||||
|     </ContentPage.Title> |     </ContentPage.Title> | ||||||
|     <ContentPage.Resources> |     <ContentPage.Resources> | ||||||
|         <ResourceDictionary> |         <ResourceDictionary> | ||||||
| @ -179,10 +178,10 @@ | |||||||
|                   Style="{StaticResource HeaderLabelStyle}" /> |                   Style="{StaticResource HeaderLabelStyle}" /> | ||||||
|                 <Entry Text="{Binding UserName.Value, Mode=TwoWay}"> |                 <Entry Text="{Binding UserName.Value, Mode=TwoWay}"> | ||||||
| 					<Entry.Style> | 					<Entry.Style> | ||||||
|                         <OnPlatform x:TypeArguments="Style" |                         <OnPlatform x:TypeArguments="Style"> | ||||||
|                           iOS="{StaticResource EntryStyle}" |                             <On Platform="iOS, Android" Value="{StaticResource EntryStyle}" /> | ||||||
|                           Android="{StaticResource EntryStyle}" |                             <On Platform="UWP, WinRT, WinPhone" Value="{StaticResource UwpEntryStyle}" /> | ||||||
|                           WinPhone="{StaticResource UwpEntryStyle}"/> |                         </OnPlatform> | ||||||
|                     </Entry.Style> |                     </Entry.Style> | ||||||
|                     <Entry.Behaviors> |                     <Entry.Behaviors> | ||||||
| 						<behaviors:EventToCommandBehavior | 						<behaviors:EventToCommandBehavior | ||||||
| @ -208,10 +207,10 @@ | |||||||
|                   IsPassword="True" |                   IsPassword="True" | ||||||
|                   Text="{Binding Password.Value, Mode=TwoWay}"> |                   Text="{Binding Password.Value, Mode=TwoWay}"> | ||||||
|                     <Entry.Style> |                     <Entry.Style> | ||||||
|                         <OnPlatform x:TypeArguments="Style" |                         <OnPlatform x:TypeArguments="Style"> | ||||||
|                           iOS="{StaticResource EntryStyle}" |                             <On Platform="iOS, Android" Value="{StaticResource EntryStyle}" /> | ||||||
|                           Android="{StaticResource EntryStyle}" |                             <On Platform="UWP, WinRT, WinPhone" Value="{StaticResource UwpEntryStyle}" /> | ||||||
|                           WinPhone="{StaticResource UwpEntryStyle}"/> |                         </OnPlatform> | ||||||
|                     </Entry.Style> |                     </Entry.Style> | ||||||
| 					<Entry.Behaviors> | 					<Entry.Behaviors> | ||||||
| 						<behaviors:EventToCommandBehavior | 						<behaviors:EventToCommandBehavior | ||||||
| @ -270,11 +269,10 @@ | |||||||
|                 Grid.ColumnSpan="3" |                 Grid.ColumnSpan="3" | ||||||
|                 Aspect="AspectFill"> |                 Aspect="AspectFill"> | ||||||
|                 <Image.Source> |                 <Image.Source> | ||||||
|                     <OnPlatform |                     <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                         x:TypeArguments="ImageSource" |                         <On Platform="iOS, Android" Value="banner.png" /> | ||||||
|                         Android="banner.png" |                         <On Platform="UWP, WinRT, WinPhone" Value="Assets\banner.png" /> | ||||||
|                         iOS="banner.png" |                     </OnPlatform> | ||||||
|                         WinPhone="Assets\banner.png"/> |  | ||||||
|                 </Image.Source> |                 </Image.Source> | ||||||
|             </Image> |             </Image> | ||||||
|             <Grid |             <Grid | ||||||
| @ -319,11 +317,10 @@ | |||||||
|                 <Image |                 <Image | ||||||
|                     Style="{StaticResource SettingsImageStyle}"> |                     Style="{StaticResource SettingsImageStyle}"> | ||||||
|                     <Image.Source> |                     <Image.Source> | ||||||
|                         <OnPlatform  |                         <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                             x:TypeArguments="ImageSource" |                             <On Platform="iOS, Android" Value="app_settings" /> | ||||||
|                             WinPhone="Assets/app_settings.png" |                             <On Platform="UWP, WinRT, WinPhone" Value="Assets/app_settings.png" /> | ||||||
|                             Android="app_settings" |                         </OnPlatform> | ||||||
|                             iOS="app_settings"/> |  | ||||||
|                     </Image.Source> |                     </Image.Source> | ||||||
|                 </Image> |                 </Image> | ||||||
|                 <Grid.GestureRecognizers> |                 <Grid.GestureRecognizers> | ||||||
| @ -345,24 +342,22 @@ | |||||||
|                   AbsoluteLayout.LayoutFlags="All"> |                   AbsoluteLayout.LayoutFlags="All"> | ||||||
|                     <WebView.Behaviors> |                     <WebView.Behaviors> | ||||||
|                         <OnPlatform x:TypeArguments="Behavior"> |                         <OnPlatform x:TypeArguments="Behavior"> | ||||||
|                             <OnPlatform.Android> |                             <On Platform="iOS, Android"> | ||||||
|                                 <behaviors:EventToCommandBehavior |                                 <On.Value> | ||||||
| 							        EventName="Navigating" |                                     <behaviors:EventToCommandBehavior  | ||||||
| 							        EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}" |                                         EventName="Navigating" | ||||||
| 							        Command="{Binding NavigateCommand}" /> |                                         EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}" | ||||||
|                             </OnPlatform.Android> |                                         Command="{Binding NavigateCommand}" /> | ||||||
|                             <OnPlatform.iOS> |                                 </On.Value> | ||||||
|                                 <behaviors:EventToCommandBehavior |                             </On> | ||||||
| 							        EventName="Navigating" |                             <On Platform="UWP"> | ||||||
| 							        EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}" |                                 <On.Value> | ||||||
| 							        Command="{Binding NavigateCommand}" /> |                                     <behaviors:EventToCommandBehavior  | ||||||
|                             </OnPlatform.iOS> |                                         EventName="Navigated" | ||||||
|                             <OnPlatform.WinPhone> |                                         EventArgsConverter="{StaticResource WebNavigatedEventArgsConverter}" | ||||||
|                                 <behaviors:EventToCommandBehavior |                                         Command="{Binding NavigateCommand}" /> | ||||||
| 							        EventName="Navigated" |                                 </On.Value> | ||||||
| 							        EventArgsConverter="{StaticResource WebNavigatedEventArgsConverter}" |                             </On> | ||||||
| 							        Command="{Binding NavigateCommand}" /> |  | ||||||
|                             </OnPlatform.WinPhone> |  | ||||||
|                         </OnPlatform> |                         </OnPlatform> | ||||||
|                     </WebView.Behaviors> |                     </WebView.Behaviors> | ||||||
|                 </WebView> |                 </WebView> | ||||||
| @ -376,11 +371,10 @@ | |||||||
|           VerticalOptions="Center" |           VerticalOptions="Center" | ||||||
|           HorizontalOptions="Center"> |           HorizontalOptions="Center"> | ||||||
|             <ActivityIndicator.WidthRequest> |             <ActivityIndicator.WidthRequest> | ||||||
|                 <OnPlatform    |                 <OnPlatform x:TypeArguments="x:Double"> | ||||||
|                   x:TypeArguments="x:Double" |                     <On Platform="iOS, Android" Value="100" /> | ||||||
|                   iOS="100" |                     <On Platform="UWP, WinRT, WinPhone" Value="400" /> | ||||||
|                   Android="100" |                 </OnPlatform> | ||||||
|                   WinPhone="400" /> |  | ||||||
|             </ActivityIndicator.WidthRequest> |             </ActivityIndicator.WidthRequest> | ||||||
|         </ActivityIndicator> |         </ActivityIndicator> | ||||||
|     </Grid> |     </Grid> | ||||||
|  | |||||||
| @ -10,21 +10,19 @@ | |||||||
|             BarTextColor="{StaticResource WhiteColor}" |             BarTextColor="{StaticResource WhiteColor}" | ||||||
| 			viewModelBase:ViewModelLocator.AutoWireViewModel="true"> | 			viewModelBase:ViewModelLocator.AutoWireViewModel="true"> | ||||||
|     <TabbedPage.Title> |     <TabbedPage.Title> | ||||||
|         <OnPlatform       |         <OnPlatform x:TypeArguments="x:String"> | ||||||
|             x:TypeArguments="x:String" |             <On Platform="iOS, UWP, WinRT, WinPhone" Value="eShop on Containers" /> | ||||||
|             iOS="eShop on Containers" |         </OnPlatform> | ||||||
|             WinPhone="eShop on Containers"/> |  | ||||||
|     </TabbedPage.Title> |     </TabbedPage.Title> | ||||||
|     <ContentPage.ToolbarItems> |     <ContentPage.ToolbarItems> | ||||||
|         <ToolbarItem  |         <ToolbarItem  | ||||||
|             Command="{Binding SettingsCommand}" |             Command="{Binding SettingsCommand}" | ||||||
|             Text="Settings"> |             Text="Settings"> | ||||||
|             <ToolbarItem.Icon> |             <ToolbarItem.Icon> | ||||||
|                 <OnPlatform  |                 <OnPlatform x:TypeArguments="FileImageSource"> | ||||||
|                     x:TypeArguments="FileImageSource" |                     <On Platform="iOS, Android" Value="app_settings" /> | ||||||
|                     WinPhone="Assets/app_settings.png" |                     <On Platform="UWP, WinRT, WinPhone" Value="Assets/app_settings.png" /> | ||||||
|                     Android="app_settings" |                 </OnPlatform> | ||||||
|                     iOS="app_settings"/> |  | ||||||
|             </ToolbarItem.Icon> |             </ToolbarItem.Icon> | ||||||
|         </ToolbarItem> |         </ToolbarItem> | ||||||
|     </ContentPage.ToolbarItems> |     </ContentPage.ToolbarItems> | ||||||
| @ -32,22 +30,20 @@ | |||||||
|     <views:CatalogView   |     <views:CatalogView   | ||||||
|         x:Name="HomeView"> |         x:Name="HomeView"> | ||||||
|         <views:CatalogView.Icon> |         <views:CatalogView.Icon> | ||||||
|             <OnPlatform         |             <OnPlatform x:TypeArguments="FileImageSource"> | ||||||
|                 x:TypeArguments="FileImageSource" |                 <On Platform="iOS, Android" Value="menu_filter" /> | ||||||
|                 Android="menu_filter" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets\menu_filter.png" /> | ||||||
|                 iOS="menu_filter" |             </OnPlatform> | ||||||
|                 WinPhone="Assets\menu_filter.png"/> |  | ||||||
|         </views:CatalogView.Icon> |         </views:CatalogView.Icon> | ||||||
|     </views:CatalogView> |     </views:CatalogView> | ||||||
|     <!-- PROFILE --> |     <!-- PROFILE --> | ||||||
|     <views:ProfileView |     <views:ProfileView | ||||||
|         x:Name="ProfileView"> |         x:Name="ProfileView"> | ||||||
|         <views:ProfileView.Icon> |         <views:ProfileView.Icon> | ||||||
|             <OnPlatform         |             <OnPlatform x:TypeArguments="FileImageSource"> | ||||||
|                 x:TypeArguments="FileImageSource" |                 <On Platform="iOS, Android" Value="menu_profile" /> | ||||||
|                 Android="menu_profile" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets\menu_profile.png" /> | ||||||
|                 iOS="menu_profile" |             </OnPlatform> | ||||||
|                 WinPhone="Assets\menu_profile.png"/> |  | ||||||
|         </views:ProfileView.Icon> |         </views:ProfileView.Icon> | ||||||
|     </views:ProfileView> |     </views:ProfileView> | ||||||
|     <!-- BASKET --> |     <!-- BASKET --> | ||||||
| @ -56,22 +52,20 @@ | |||||||
|         controls:CustomTabbedPage.BadgeText="{Binding BadgeCount}" |         controls:CustomTabbedPage.BadgeText="{Binding BadgeCount}" | ||||||
|         controls:CustomTabbedPage.BadgeColor="{StaticResource LightGreenColor}"> |         controls:CustomTabbedPage.BadgeColor="{StaticResource LightGreenColor}"> | ||||||
|         <views:BasketView.Icon> |         <views:BasketView.Icon> | ||||||
|             <OnPlatform         |             <OnPlatform x:TypeArguments="FileImageSource"> | ||||||
|                 x:TypeArguments="FileImageSource" |                 <On Platform="iOS, Android" Value="menu_cart" /> | ||||||
|                 Android="menu_cart" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets\menu_cart.png" /> | ||||||
|                 iOS="menu_cart" |             </OnPlatform> | ||||||
|                 WinPhone="Assets\menu_cart.png"/> |  | ||||||
|         </views:BasketView.Icon> |         </views:BasketView.Icon> | ||||||
|     </views:BasketView> |     </views:BasketView> | ||||||
|     <!-- CAMPAIGNS --> |     <!-- CAMPAIGNS --> | ||||||
|     <views:CampaignView   |     <views:CampaignView   | ||||||
|         x:Name="CampaignView"> |         x:Name="CampaignView"> | ||||||
|         <views:CampaignView.Icon> |         <views:CampaignView.Icon> | ||||||
|             <OnPlatform         |             <OnPlatform x:TypeArguments="FileImageSource"> | ||||||
|                 x:TypeArguments="FileImageSource" |                 <On Platform="iOS, Android" Value="menu_campaigns" /> | ||||||
|                 Android="menu_campaigns" |                 <On Platform="UWP, WinRT, WinPhone" Value="Assets\menu_campaigns.png" /> | ||||||
|                 iOS="menu_campaigns" |             </OnPlatform> | ||||||
|                 WinPhone="Assets\menu_campaigns.png"/> |  | ||||||
|         </views:CampaignView.Icon> |         </views:CampaignView.Icon> | ||||||
|     </views:CampaignView> |     </views:CampaignView> | ||||||
| </TabbedPage> | </TabbedPage> | ||||||
| @ -264,11 +264,10 @@ | |||||||
|                 VerticalOptions="Center" |                 VerticalOptions="Center" | ||||||
|                 HorizontalOptions="Center"> |                 HorizontalOptions="Center"> | ||||||
|                 <ActivityIndicator.WidthRequest> |                 <ActivityIndicator.WidthRequest> | ||||||
|                     <OnPlatform  |                     <OnPlatform x:TypeArguments="x:Double"> | ||||||
|                         x:TypeArguments="x:Double"  |                         <On Platform="iOS, Android" Value="100" /> | ||||||
|                         iOS="100"  |                         <On Platform="UWP, WinRT, WinPhone" Value="400" /> | ||||||
|                         Android="100" |                     </OnPlatform> | ||||||
|                         WinPhone="400" /> |  | ||||||
|                 </ActivityIndicator.WidthRequest> |                 </ActivityIndicator.WidthRequest> | ||||||
|             </ActivityIndicator> |             </ActivityIndicator> | ||||||
|         </Grid> |         </Grid> | ||||||
|  | |||||||
| @ -99,11 +99,10 @@ | |||||||
|                 <animations:FadeInAnimation  |                 <animations:FadeInAnimation  | ||||||
|                     Direction="Up"> |                     Direction="Up"> | ||||||
|                     <animations:FadeInAnimation.Duration> |                     <animations:FadeInAnimation.Duration> | ||||||
|                         <OnPlatform  |                         <OnPlatform x:TypeArguments="x:String"> | ||||||
|                             x:TypeArguments="x:String"  |                             <On Platform="iOS" Value="0" /> | ||||||
|                             Android="500" |                             <On Platform="Android, UWP, WinRT, WinPhone" Value="500" /> | ||||||
|                             iOS="0" |                         </OnPlatform> | ||||||
|                             WinPhone="500"/> |  | ||||||
|                     </animations:FadeInAnimation.Duration> |                     </animations:FadeInAnimation.Duration> | ||||||
|                 </animations:FadeInAnimation> |                 </animations:FadeInAnimation> | ||||||
|             </animations:StoryBoard> |             </animations:StoryBoard> | ||||||
| @ -156,16 +155,18 @@ | |||||||
|                         Command="{Binding ToggleMockServicesCommand}" |                         Command="{Binding ToggleMockServicesCommand}" | ||||||
|                         Style="{StaticResource SettingsToggleButtonStyle}"> |                         Style="{StaticResource SettingsToggleButtonStyle}"> | ||||||
|                         <controls:ToggleButton.CheckedImage> |                         <controls:ToggleButton.CheckedImage> | ||||||
|                             <OnPlatform x:TypeArguments="ImageSource" |                             <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                               Android="switch_on.png" |                                 <On Platform="iOS" Value="switchOn.png" /> | ||||||
|                               iOS="switchOn.png" |                                 <On Platform="Android" Value="switch_on.png" /> | ||||||
|                               WinPhone="Assets/switchOn.png"/> |                                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/switchOn.png" /> | ||||||
|  |                             </OnPlatform> | ||||||
|                         </controls:ToggleButton.CheckedImage> |                         </controls:ToggleButton.CheckedImage> | ||||||
|                         <controls:ToggleButton.UnCheckedImage> |                         <controls:ToggleButton.UnCheckedImage> | ||||||
|                             <OnPlatform x:TypeArguments="ImageSource" |                             <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                               Android="switch_off.png" |                                 <On Platform="iOS" Value="switchOff.png" /> | ||||||
|                               iOS="switchOff.png" |                                 <On Platform="Android" Value="switch_off.png" /> | ||||||
|                               WinPhone="Assets/switchOff.png"/> |                                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/switchOff.png" /> | ||||||
|  |                             </OnPlatform> | ||||||
|                         </controls:ToggleButton.UnCheckedImage> |                         </controls:ToggleButton.UnCheckedImage> | ||||||
|                     </controls:ToggleButton> |                     </controls:ToggleButton> | ||||||
|                     <!-- ENDPOINT --> |                     <!-- ENDPOINT --> | ||||||
| @ -181,11 +182,10 @@ | |||||||
|                         <Entry |                         <Entry | ||||||
|                             Text="{Binding Endpoint, Mode=TwoWay}"> |                             Text="{Binding Endpoint, Mode=TwoWay}"> | ||||||
|                             <Entry.Style> |                             <Entry.Style> | ||||||
|                                 <OnPlatform  |                                 <OnPlatform x:TypeArguments="Style"> | ||||||
|                                     x:TypeArguments="Style" |                                     <On Platform="iOS, Android" Value="{StaticResource SettingsEntryStyle}" /> | ||||||
|                                     iOS="{StaticResource SettingsEntryStyle}" |                                     <On Platform="UWP, WinRT, WinPhone" Value="{StaticResource SettingsUwpEntryStyle}" /> | ||||||
|                                     Android="{StaticResource SettingsEntryStyle}" |                                 </OnPlatform> | ||||||
|                                     WinPhone="{StaticResource SettingsUwpEntryStyle}"/> |  | ||||||
|                             </Entry.Style> |                             </Entry.Style> | ||||||
|                         </Entry> |                         </Entry> | ||||||
|                     </StackLayout> |                     </StackLayout> | ||||||
| @ -212,16 +212,18 @@ | |||||||
|                         Style="{StaticResource SettingsToggleButtonStyle}" |                         Style="{StaticResource SettingsToggleButtonStyle}" | ||||||
|                         IsVisible="{Binding UserIsLogged}"> |                         IsVisible="{Binding UserIsLogged}"> | ||||||
|                         <controls:ToggleButton.CheckedImage> |                         <controls:ToggleButton.CheckedImage> | ||||||
|                             <OnPlatform x:TypeArguments="ImageSource" |                             <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                               Android="switch_on.png" |                                 <On Platform="iOS" Value="switchOn.png" /> | ||||||
|                               iOS="switchOn.png" |                                 <On Platform="Android" Value="switch_on.png" /> | ||||||
|                               WinPhone="Assets/switchOn.png"/> |                                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/switchOn.png" /> | ||||||
|  |                             </OnPlatform> | ||||||
|                         </controls:ToggleButton.CheckedImage> |                         </controls:ToggleButton.CheckedImage> | ||||||
|                         <controls:ToggleButton.UnCheckedImage> |                         <controls:ToggleButton.UnCheckedImage> | ||||||
|                             <OnPlatform x:TypeArguments="ImageSource" |                             <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                               Android="switch_off.png" |                                 <On Platform="iOS" Value="switchOff.png" /> | ||||||
|                               iOS="switchOff.png" |                                 <On Platform="Android" Value="switch_off.png" /> | ||||||
|                               WinPhone="Assets/switchOff.png"/> |                                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/switchOff.png" /> | ||||||
|  |                             </OnPlatform> | ||||||
|                         </controls:ToggleButton.UnCheckedImage> |                         </controls:ToggleButton.UnCheckedImage> | ||||||
|                     </controls:ToggleButton> |                     </controls:ToggleButton> | ||||||
|                     <!-- FAKE LOCATIONS --> |                     <!-- FAKE LOCATIONS --> | ||||||
| @ -238,11 +240,10 @@ | |||||||
|                             Text="{Binding Latitude, Mode=TwoWay, Converter={StaticResource DoubleConverter}}" |                             Text="{Binding Latitude, Mode=TwoWay, Converter={StaticResource DoubleConverter}}" | ||||||
|                             Keyboard="Text"> |                             Keyboard="Text"> | ||||||
|                             <Entry.Style> |                             <Entry.Style> | ||||||
|                                 <OnPlatform  |                                 <OnPlatform x:TypeArguments="Style"> | ||||||
|                                     x:TypeArguments="Style" |                                     <On Platform="iOS, Android" Value="{StaticResource SettingsEntryStyle}" /> | ||||||
|                                     iOS="{StaticResource SettingsEntryStyle}" |                                     <On Platform="UWP, WinRT, WinPhone" Value="{StaticResource SettingsUwpEntryStyle}" /> | ||||||
|                                     Android="{StaticResource SettingsEntryStyle}" |                                 </OnPlatform> | ||||||
|                                     WinPhone="{StaticResource SettingsUwpEntryStyle}"/> |  | ||||||
|                             </Entry.Style> |                             </Entry.Style> | ||||||
|                         </Entry> |                         </Entry> | ||||||
|                         <Label |                         <Label | ||||||
| @ -252,11 +253,10 @@ | |||||||
|                             Text="{Binding Longitude, Mode=TwoWay, Converter={StaticResource DoubleConverter}}" |                             Text="{Binding Longitude, Mode=TwoWay, Converter={StaticResource DoubleConverter}}" | ||||||
|                             Keyboard="Text"> |                             Keyboard="Text"> | ||||||
|                             <Entry.Style> |                             <Entry.Style> | ||||||
|                                 <OnPlatform  |                                 <OnPlatform x:TypeArguments="Style"> | ||||||
|                                     x:TypeArguments="Style" |                                     <On Platform="iOS, Android" Value="{StaticResource SettingsEntryStyle}" /> | ||||||
|                                     iOS="{StaticResource SettingsEntryStyle}" |                                     <On Platform="UWP, WinRT, WinPhone" Value="{StaticResource SettingsUwpEntryStyle}" /> | ||||||
|                                     Android="{StaticResource SettingsEntryStyle}" |                                 </OnPlatform> | ||||||
|                                     WinPhone="{StaticResource SettingsUwpEntryStyle}"/> |  | ||||||
|                             </Entry.Style> |                             </Entry.Style> | ||||||
|                         </Entry> |                         </Entry> | ||||||
|                         <Button  |                         <Button  | ||||||
| @ -289,16 +289,18 @@ | |||||||
|                         Style="{StaticResource SettingsToggleButtonStyle}" |                         Style="{StaticResource SettingsToggleButtonStyle}" | ||||||
|                         IsVisible="{Binding UseFakeLocation, Converter={StaticResource InverseBoolConverter}}"> |                         IsVisible="{Binding UseFakeLocation, Converter={StaticResource InverseBoolConverter}}"> | ||||||
|                         <controls:ToggleButton.CheckedImage> |                         <controls:ToggleButton.CheckedImage> | ||||||
|                             <OnPlatform x:TypeArguments="ImageSource" |                             <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                                         Android="switch_on.png" |                                 <On Platform="iOS" Value="switchOn.png" /> | ||||||
|                                         iOS="switchOn.png" |                                 <On Platform="Android" Value="switch_on.png" /> | ||||||
|                                         WinPhone="Assets/switchOn.png"/> |                                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/switchOn.png" /> | ||||||
|  |                             </OnPlatform> | ||||||
|                         </controls:ToggleButton.CheckedImage> |                         </controls:ToggleButton.CheckedImage> | ||||||
|                         <controls:ToggleButton.UnCheckedImage> |                         <controls:ToggleButton.UnCheckedImage> | ||||||
|                             <OnPlatform x:TypeArguments="ImageSource" |                             <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                                         Android="switch_off.png" |                                 <On Platform="iOS" Value="switchOff.png" /> | ||||||
|                                         iOS="switchOff.png" |                                 <On Platform="Android" Value="switch_off.png" /> | ||||||
|                                         WinPhone="Assets/switchOff.png"/> |                                 <On Platform="UWP, WinRT, WinPhone" Value="Assets/switchOff.png" /> | ||||||
|  |                             </OnPlatform> | ||||||
|                         </controls:ToggleButton.UnCheckedImage> |                         </controls:ToggleButton.UnCheckedImage> | ||||||
|                     </controls:ToggleButton> |                     </controls:ToggleButton> | ||||||
|                 </Grid> |                 </Grid> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <ContentView | <ContentView | ||||||
|     xmlns="http://xamarin.com/schemas/2014/forms"      |     xmlns="http://xamarin.com/schemas/2014/forms"      | ||||||
|     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"   |     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"   | ||||||
| @ -71,11 +71,10 @@ | |||||||
|         <Grid    |         <Grid    | ||||||
|             BackgroundColor="{StaticResource BackgroundColor}"> |             BackgroundColor="{StaticResource BackgroundColor}"> | ||||||
|             <Grid.Padding> |             <Grid.Padding> | ||||||
|                 <OnPlatform          |                 <OnPlatform x:TypeArguments="Thickness"> | ||||||
|                     x:TypeArguments="Thickness" |                     <On Platform="iOS, Android" Value="0" /> | ||||||
|                     Android="0" |                     <On Platform="UWP, WinRT, WinPhone" Value="12, 0" /> | ||||||
|                     iOS="0" |                 </OnPlatform> | ||||||
|                     WinPhone="12, 0"/> |  | ||||||
|             </Grid.Padding> |             </Grid.Padding> | ||||||
|             <Grid.ColumnDefinitions> |             <Grid.ColumnDefinitions> | ||||||
|                 <ColumnDefinition Width="Auto" /> |                 <ColumnDefinition Width="Auto" /> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <ContentView  | <ContentView  | ||||||
|     xmlns="http://xamarin.com/schemas/2014/forms"  |     xmlns="http://xamarin.com/schemas/2014/forms"  | ||||||
|     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"     |     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"     | ||||||
| @ -59,18 +59,16 @@ | |||||||
|                 Source="{Binding PictureUri}"      |                 Source="{Binding PictureUri}"      | ||||||
|                 Aspect="AspectFill"> |                 Aspect="AspectFill"> | ||||||
|                 <ffimageloading:CachedImage.LoadingPlaceholder> |                 <ffimageloading:CachedImage.LoadingPlaceholder> | ||||||
|                     <OnPlatform    |                     <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                         x:TypeArguments="ImageSource" |                         <On Platform="iOS, Android" Value="default_campaign" /> | ||||||
|                         iOS="default_campaign" |                         <On Platform="UWP, WinRT, WinPhone" Value="Assets/default_campaign.png" /> | ||||||
|                         Android="default_campaign" |                     </OnPlatform> | ||||||
|                         WinPhone="Assets/default_campaign.png"/> |  | ||||||
|                 </ffimageloading:CachedImage.LoadingPlaceholder> |                 </ffimageloading:CachedImage.LoadingPlaceholder> | ||||||
|                 <ffimageloading:CachedImage.ErrorPlaceholder> |                 <ffimageloading:CachedImage.ErrorPlaceholder> | ||||||
|                     <OnPlatform    |                     <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                         x:TypeArguments="ImageSource" |                         <On Platform="iOS, Android" Value="noimage" /> | ||||||
|                         iOS="noimage" |                         <On Platform="UWP, WinRT, WinPhone" Value="Assets/noimage.png" /> | ||||||
|                         Android="noimage" |                     </OnPlatform> | ||||||
|                         WinPhone="Assets/noimage.png"/> |  | ||||||
|                 </ffimageloading:CachedImage.ErrorPlaceholder> |                 </ffimageloading:CachedImage.ErrorPlaceholder> | ||||||
|             </ffimageloading:CachedImage> |             </ffimageloading:CachedImage> | ||||||
|             <!-- NAME --> |             <!-- NAME --> | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||||
| <ContentView  | <ContentView  | ||||||
|     xmlns="http://xamarin.com/schemas/2014/forms"  |     xmlns="http://xamarin.com/schemas/2014/forms"  | ||||||
|     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"     |     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"     | ||||||
| @ -76,18 +76,16 @@ | |||||||
|                 Source="{Binding PictureUri}"      |                 Source="{Binding PictureUri}"      | ||||||
|                 Aspect="AspectFill"> |                 Aspect="AspectFill"> | ||||||
|                 <ffimageloading:CachedImage.LoadingPlaceholder> |                 <ffimageloading:CachedImage.LoadingPlaceholder> | ||||||
|                     <OnPlatform    |                     <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                         x:TypeArguments="ImageSource" |                         <On Platform="iOS, Android" Value="default_product" /> | ||||||
|                         iOS="default_product" |                         <On Platform="UWP, WinRT, WinPhone" Value="Assets/default_product.png" /> | ||||||
|                         Android="default_product" |                     </OnPlatform> | ||||||
|                         WinPhone="Assets/default_product.png"/> |  | ||||||
|                 </ffimageloading:CachedImage.LoadingPlaceholder> |                 </ffimageloading:CachedImage.LoadingPlaceholder> | ||||||
|                 <ffimageloading:CachedImage.ErrorPlaceholder> |                 <ffimageloading:CachedImage.ErrorPlaceholder> | ||||||
|                     <OnPlatform    |                     <OnPlatform x:TypeArguments="ImageSource"> | ||||||
|                         x:TypeArguments="ImageSource" |                         <On Platform="iOS, Android" Value="noimage" /> | ||||||
|                         iOS="noimage" |                         <On Platform="UWP, WinRT, WinPhone" Value="Assets/noimage.png" /> | ||||||
|                         Android="noimage" |                     </OnPlatform> | ||||||
|                         WinPhone="Assets/noimage.png"/> |  | ||||||
|                 </ffimageloading:CachedImage.ErrorPlaceholder> |                 </ffimageloading:CachedImage.ErrorPlaceholder> | ||||||
|             </ffimageloading:CachedImage> |             </ffimageloading:CachedImage> | ||||||
|             <Grid |             <Grid | ||||||
|  | |||||||
| @ -257,6 +257,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API | |||||||
| 
 | 
 | ||||||
|         private void RegisterEventBus(IServiceCollection services) |         private void RegisterEventBus(IServiceCollection services) | ||||||
|         { |         { | ||||||
|  |             var subscriptionClientName = Configuration["SubscriptionClientName"]; | ||||||
|  | 
 | ||||||
|             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) |             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) | ||||||
|             { |             { | ||||||
|                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | ||||||
| @ -264,8 +266,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API | |||||||
|                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); |                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | ||||||
|                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); |                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | ||||||
|                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | ||||||
|                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();                     | ||||||
|                     var subscriptionClientName = Configuration["SubscriptionClientName"]; |  | ||||||
| 
 | 
 | ||||||
|                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, |                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, | ||||||
|                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); |                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | ||||||
| @ -286,7 +287,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API | |||||||
|                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); |                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount); |                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -180,7 +180,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers | |||||||
|             catalogItem = productToUpdate; |             catalogItem = productToUpdate; | ||||||
|             _catalogContext.CatalogItems.Update(catalogItem); |             _catalogContext.CatalogItems.Update(catalogItem); | ||||||
| 
 | 
 | ||||||
|             if (raiseProductPriceChangedEvent) // Save and publish integration event if price has changed |             if (raiseProductPriceChangedEvent) // Save product's data and publish integration event through the Event Bus if price has changed | ||||||
|             { |             { | ||||||
|                 //Create Integration Event to be published through the Event Bus |                 //Create Integration Event to be published through the Event Bus | ||||||
|                 var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice); |                 var priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice); | ||||||
| @ -191,7 +191,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers | |||||||
|                 // Publish through the Event Bus and mark the saved event as published |                 // Publish through the Event Bus and mark the saved event as published | ||||||
|                 await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); |                 await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); | ||||||
|             } |             } | ||||||
|             else // Save updated product |             else // Just save the updated product because the Product's Price hasn't changed. | ||||||
|             { |             { | ||||||
|                 await _catalogContext.SaveChangesAsync(); |                 await _catalogContext.SaveChangesAsync(); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -224,6 +224,8 @@ | |||||||
| 
 | 
 | ||||||
|         private void RegisterEventBus(IServiceCollection services) |         private void RegisterEventBus(IServiceCollection services) | ||||||
|         { |         { | ||||||
|  |             var subscriptionClientName = Configuration["SubscriptionClientName"]; | ||||||
|  | 
 | ||||||
|             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) |             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) | ||||||
|             { |             { | ||||||
|                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | ||||||
| @ -232,7 +234,6 @@ | |||||||
|                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); |                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | ||||||
|                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | ||||||
|                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | ||||||
|                     var subscriptionClientName = Configuration["SubscriptionClientName"]; |  | ||||||
| 
 | 
 | ||||||
|                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, |                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, | ||||||
|                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); |                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | ||||||
| @ -254,7 +255,7 @@ | |||||||
|                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); |                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount); |                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|   "Logging": { |   "Logging": { | ||||||
|     "IncludeScopes": false, |     "IncludeScopes": false, | ||||||
|     "LogLevel": { |     "LogLevel": { | ||||||
|       "Default": "Debug", |       "Default": "Trace", | ||||||
|       "System": "Information", |       "System": "Information", | ||||||
|       "Microsoft": "Information" |       "Microsoft": "Information" | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|   "Logging": { |   "Logging": { | ||||||
|     "IncludeScopes": false, |     "IncludeScopes": false, | ||||||
|     "LogLevel": { |     "LogLevel": { | ||||||
|       "Default": "Debug", |       "Default": "Trace", | ||||||
|       "System": "Information", |       "System": "Information", | ||||||
|       "Microsoft": "Information" |       "Microsoft": "Information" | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -227,6 +227,8 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API | |||||||
| 
 | 
 | ||||||
|         private void RegisterEventBus(IServiceCollection services) |         private void RegisterEventBus(IServiceCollection services) | ||||||
|         { |         { | ||||||
|  |             var subscriptionClientName = Configuration["SubscriptionClientName"]; | ||||||
|  | 
 | ||||||
|             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) |             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) | ||||||
|             { |             { | ||||||
|                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | ||||||
| @ -235,7 +237,6 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API | |||||||
|                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); |                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | ||||||
|                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | ||||||
|                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | ||||||
|                     var subscriptionClientName = Configuration["SubscriptionClientName"]; |  | ||||||
| 
 | 
 | ||||||
|                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, |                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, | ||||||
|                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); |                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | ||||||
| @ -256,7 +257,7 @@ namespace Microsoft.eShopOnContainers.Services.Locations.API | |||||||
|                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); |                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount); |                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|   "Logging": { |   "Logging": { | ||||||
|     "IncludeScopes": false, |     "IncludeScopes": false, | ||||||
|     "LogLevel": { |     "LogLevel": { | ||||||
|       "Default": "Debug", |       "Default": "Trace", | ||||||
|       "System": "Information", |       "System": "Information", | ||||||
|       "Microsoft": "Information" |       "Microsoft": "Information" | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -246,8 +246,10 @@ | |||||||
|                 }); |                 }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|             private void RegisterEventBus(IServiceCollection services) |         private void RegisterEventBus(IServiceCollection services) | ||||||
|         { |         { | ||||||
|  |             var subscriptionClientName = Configuration["SubscriptionClientName"]; | ||||||
|  | 
 | ||||||
|             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) |             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) | ||||||
|             { |             { | ||||||
|                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | ||||||
| @ -255,8 +257,7 @@ | |||||||
|                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); |                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | ||||||
|                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); |                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | ||||||
|                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | ||||||
|                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();                     | ||||||
|                     var subscriptionClientName = Configuration["SubscriptionClientName"]; |  | ||||||
| 
 | 
 | ||||||
|                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, |                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, | ||||||
|                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); |                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | ||||||
| @ -277,7 +278,7 @@ | |||||||
|                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); |                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount); |                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
|   "Logging": { |   "Logging": { | ||||||
|     "IncludeScopes": false, |     "IncludeScopes": false, | ||||||
|     "LogLevel": { |     "LogLevel": { | ||||||
|       "Default": "Warning" |       "Default": "Trace" | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word", |   "ConnectionString": "Server=tcp:127.0.0.1,5433;Initial Catalog=Microsoft.eShopOnContainers.Services.MarketingDb;User Id=sa;Password=Pass@word", | ||||||
|  | |||||||
| @ -9,18 +9,7 @@ using System.Threading.Tasks; | |||||||
| 
 | 
 | ||||||
| namespace Ordering.API.Application.Commands | namespace Ordering.API.Application.Commands | ||||||
| { | { | ||||||
|     public class CancelOrderCommandIdentifiedHandler : IdentifierCommandHandler<CancelOrderCommand, bool> |     // Regular CommandHandler | ||||||
|     { |  | ||||||
|         public CancelOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         protected override bool CreateResultForDuplicateRequest() |  | ||||||
|         { |  | ||||||
|             return true;                // Ignore duplicate requests for processing order. |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public class CancelOrderCommandHandler : IAsyncRequestHandler<CancelOrderCommand, bool> |     public class CancelOrderCommandHandler : IAsyncRequestHandler<CancelOrderCommand, bool> | ||||||
|     { |     { | ||||||
|         private readonly IOrderRepository _orderRepository; |         private readonly IOrderRepository _orderRepository; | ||||||
| @ -43,4 +32,18 @@ namespace Ordering.API.Application.Commands | |||||||
|             return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); |             return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // Use for Idempotency in Command process | ||||||
|  |     public class CancelOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CancelOrderCommand, bool> | ||||||
|  |     { | ||||||
|  |         public CancelOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override bool CreateResultForDuplicateRequest() | ||||||
|  |         { | ||||||
|  |             return true;                // Ignore duplicate requests for processing order. | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,19 +7,7 @@ | |||||||
|     using System; |     using System; | ||||||
|     using System.Threading.Tasks; |     using System.Threading.Tasks; | ||||||
| 
 | 
 | ||||||
| 
 |     // Regular CommandHandler | ||||||
|     public class CreateOrderCommandIdentifiedHandler : IdentifierCommandHandler<CreateOrderCommand, bool> |  | ||||||
|     { |  | ||||||
|         public CreateOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         protected override bool CreateResultForDuplicateRequest() |  | ||||||
|         { |  | ||||||
|             return true;                // Ignore duplicate requests for creating order. |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public class CreateOrderCommandHandler |     public class CreateOrderCommandHandler | ||||||
|         : IAsyncRequestHandler<CreateOrderCommand, bool> |         : IAsyncRequestHandler<CreateOrderCommand, bool> | ||||||
|     { |     { | ||||||
| @ -55,4 +43,18 @@ | |||||||
|                 .SaveEntitiesAsync(); |                 .SaveEntitiesAsync(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // Use for Idempotency in Command process | ||||||
|  |     public class CreateOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CreateOrderCommand, bool> | ||||||
|  |     { | ||||||
|  |         public CreateOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override bool CreateResultForDuplicateRequest() | ||||||
|  |         { | ||||||
|  |             return true;                // Ignore duplicate requests for creating order. | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,13 +10,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands | |||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <typeparam name="T">Type of the command handler that performs the operation if request is not duplicated</typeparam> |     /// <typeparam name="T">Type of the command handler that performs the operation if request is not duplicated</typeparam> | ||||||
|     /// <typeparam name="R">Return value of the inner command handler</typeparam> |     /// <typeparam name="R">Return value of the inner command handler</typeparam> | ||||||
|     public class IdentifierCommandHandler<T, R> : IAsyncRequestHandler<IdentifiedCommand<T, R>, R> |     public class IdentifiedCommandHandler<T, R> : IAsyncRequestHandler<IdentifiedCommand<T, R>, R> | ||||||
|         where T : IRequest<R> |         where T : IRequest<R> | ||||||
|     { |     { | ||||||
|         private readonly IMediator _mediator; |         private readonly IMediator _mediator; | ||||||
|         private readonly IRequestManager _requestManager; |         private readonly IRequestManager _requestManager; | ||||||
| 
 | 
 | ||||||
|         public IdentifierCommandHandler(IMediator mediator, IRequestManager requestManager) |         public IdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) | ||||||
|         { |         { | ||||||
|             _mediator = mediator; |             _mediator = mediator; | ||||||
|             _requestManager = requestManager; |             _requestManager = requestManager; | ||||||
| @ -48,6 +48,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands | |||||||
|             { |             { | ||||||
|                 await _requestManager.CreateRequestForCommandAsync<T>(message.Id); |                 await _requestManager.CreateRequestForCommandAsync<T>(message.Id); | ||||||
| 
 | 
 | ||||||
|  |                 // Send the embeded business command to mediator so it runs its related CommandHandler  | ||||||
|                 var result = await _mediator.Send(message.Command); |                 var result = await _mediator.Send(message.Command); | ||||||
|                  |                  | ||||||
|                 return result; |                 return result; | ||||||
| @ -6,18 +6,7 @@ using System.Threading.Tasks; | |||||||
| 
 | 
 | ||||||
| namespace Ordering.API.Application.Commands | namespace Ordering.API.Application.Commands | ||||||
| { | { | ||||||
|     public class ShipOrderCommandIdentifiedHandler : IdentifierCommandHandler<ShipOrderCommand, bool> |     // Regular CommandHandler | ||||||
|     { |  | ||||||
|         public ShipOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         protected override bool CreateResultForDuplicateRequest() |  | ||||||
|         { |  | ||||||
|             return true;                // Ignore duplicate requests for processing order. |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public class ShipOrderCommandHandler : IAsyncRequestHandler<ShipOrderCommand, bool> |     public class ShipOrderCommandHandler : IAsyncRequestHandler<ShipOrderCommand, bool> | ||||||
|     {         |     {         | ||||||
|         private readonly IOrderRepository _orderRepository; |         private readonly IOrderRepository _orderRepository; | ||||||
| @ -40,4 +29,18 @@ namespace Ordering.API.Application.Commands | |||||||
|             return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); |             return await _orderRepository.UnitOfWork.SaveEntitiesAsync(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     // Use for Idempotency in Command process | ||||||
|  |     public class ShipOrderIdentifiedCommandHandler : IdentifiedCommandHandler<ShipOrderCommand, bool> | ||||||
|  |     { | ||||||
|  |         public ShipOrderIdentifiedCommandHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override bool CreateResultForDuplicateRequest() | ||||||
|  |         { | ||||||
|  |             return true;                // Ignore duplicate requests for processing order. | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -25,7 +25,6 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent | |||||||
|         public async Task Handle(OrderStartedDomainEvent orderStartedEvent) |         public async Task Handle(OrderStartedDomainEvent orderStartedEvent) | ||||||
|         { |         { | ||||||
|             var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1; |             var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1; | ||||||
| 
 |  | ||||||
|             var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId); |             var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId); | ||||||
|             bool buyerOriginallyExisted = (buyer == null) ? false : true; |             bool buyerOriginallyExisted = (buyer == null) ? false : true; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,10 +5,10 @@ | |||||||
| 
 | 
 | ||||||
|     public interface IOrderQueries |     public interface IOrderQueries | ||||||
|     { |     { | ||||||
|         Task<dynamic> GetOrderAsync(int id); |         Task<Order> GetOrderAsync(int id); | ||||||
| 
 | 
 | ||||||
|         Task<IEnumerable<dynamic>> GetOrdersAsync(); |         Task<IEnumerable<OrderSummary>> GetOrdersAsync(); | ||||||
| 
 | 
 | ||||||
|         Task<IEnumerable<dynamic>> GetCardTypesAsync(); |         Task<IEnumerable<CardType>> GetCardTypesAsync(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries | namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries | ||||||
| { | { | ||||||
|     using Dapper; |     using Dapper; | ||||||
|     using Microsoft.Extensions.Configuration; |  | ||||||
|     using System.Data.SqlClient; |     using System.Data.SqlClient; | ||||||
|     using System.Threading.Tasks; |     using System.Threading.Tasks; | ||||||
|     using System; |     using System; | ||||||
|     using System.Dynamic; |  | ||||||
|     using System.Collections.Generic; |     using System.Collections.Generic; | ||||||
| 
 | 
 | ||||||
|     public class OrderQueries |     public class OrderQueries | ||||||
| @ -19,7 +17,7 @@ | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         public async Task<dynamic> GetOrderAsync(int id) |         public async Task<Order> GetOrderAsync(int id) | ||||||
|         { |         { | ||||||
|             using (var connection = new SqlConnection(_connectionString)) |             using (var connection = new SqlConnection(_connectionString)) | ||||||
|             { |             { | ||||||
| @ -44,13 +42,13 @@ | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public async Task<IEnumerable<dynamic>> GetOrdersAsync() |         public async Task<IEnumerable<OrderSummary>> GetOrdersAsync() | ||||||
|         { |         { | ||||||
|             using (var connection = new SqlConnection(_connectionString)) |             using (var connection = new SqlConnection(_connectionString)) | ||||||
|             { |             { | ||||||
|                 connection.Open(); |                 connection.Open(); | ||||||
| 
 | 
 | ||||||
|                 return await connection.QueryAsync<dynamic>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total
 |                 return await connection.QueryAsync<OrderSummary>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total
 | ||||||
|                      FROM [ordering].[Orders] o |                      FROM [ordering].[Orders] o | ||||||
|                      LEFT JOIN[ordering].[orderitems] oi ON  o.Id = oi.orderid  |                      LEFT JOIN[ordering].[orderitems] oi ON  o.Id = oi.orderid  | ||||||
|                      LEFT JOIN[ordering].[orderstatus] os on o.OrderStatusId = os.Id                      |                      LEFT JOIN[ordering].[orderstatus] os on o.OrderStatusId = os.Id                      | ||||||
| @ -59,39 +57,41 @@ | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public async Task<IEnumerable<dynamic>> GetCardTypesAsync() |         public async Task<IEnumerable<CardType>> GetCardTypesAsync() | ||||||
|         { |         { | ||||||
|             using (var connection = new SqlConnection(_connectionString)) |             using (var connection = new SqlConnection(_connectionString)) | ||||||
|             { |             { | ||||||
|                 connection.Open(); |                 connection.Open(); | ||||||
| 
 | 
 | ||||||
|                 return await connection.QueryAsync<dynamic>("SELECT * FROM ordering.cardtypes"); |                 return await connection.QueryAsync<CardType>("SELECT * FROM ordering.cardtypes"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private dynamic MapOrderItems(dynamic result) |         private Order MapOrderItems(dynamic result) | ||||||
|         { |         { | ||||||
|             dynamic order = new ExpandoObject(); |             var order = new Order | ||||||
| 
 |             { | ||||||
|             order.ordernumber = result[0].ordernumber; |                 ordernumber = result[0].ordernumber, | ||||||
|             order.date = result[0].date; |                 date = result[0].date, | ||||||
|             order.status = result[0].status; |                 status = result[0].status, | ||||||
|             order.description = result[0].description; |                 description = result[0].description, | ||||||
|             order.street = result[0].street; |                 street = result[0].street, | ||||||
|             order.city = result[0].city; |                 city = result[0].city, | ||||||
|             order.zipcode = result[0].zipcode; |                 zipcode = result[0].zipcode, | ||||||
|             order.country = result[0].country; |                 country = result[0].country, | ||||||
| 
 |                 orderitems = new List<Orderitem>(), | ||||||
|             order.orderitems = new List<dynamic>(); |                 total = 0 | ||||||
|             order.total = 0; |             }; | ||||||
| 
 | 
 | ||||||
|             foreach (dynamic item in result) |             foreach (dynamic item in result) | ||||||
|             { |             { | ||||||
|                 dynamic orderitem = new ExpandoObject(); |                 var orderitem = new Orderitem | ||||||
|                 orderitem.productname = item.productname; |                 { | ||||||
|                 orderitem.units = item.units; |                     productname = item.productname, | ||||||
|                 orderitem.unitprice = item.unitprice; |                     units = item.units, | ||||||
|                 orderitem.pictureurl = item.pictureurl; |                     unitprice = (double)item.unitprice, | ||||||
|  |                     pictureurl = item.pictureurl | ||||||
|  |                 }; | ||||||
| 
 | 
 | ||||||
|                 order.total += item.units * item.unitprice; |                 order.total += item.units * item.unitprice; | ||||||
|                 order.orderitems.Add(orderitem); |                 order.orderitems.Add(orderitem); | ||||||
|  | |||||||
| @ -0,0 +1,41 @@ | |||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | 
 | ||||||
|  | namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries | ||||||
|  | { | ||||||
|  |     public class Orderitem | ||||||
|  |     { | ||||||
|  |         public string productname { get; set; } | ||||||
|  |         public int units { get; set; } | ||||||
|  |         public double unitprice { get; set; } | ||||||
|  |         public string pictureurl { get; set; } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class Order | ||||||
|  |     { | ||||||
|  |         public int ordernumber { get; set; } | ||||||
|  |         public DateTime date { get; set; } | ||||||
|  |         public string status { get; set; } | ||||||
|  |         public string description { get; set; } | ||||||
|  |         public string street { get; set; } | ||||||
|  |         public string city { get; set; } | ||||||
|  |         public string zipcode { get; set; } | ||||||
|  |         public string country { get; set; } | ||||||
|  |         public List<Orderitem> orderitems { get; set; } | ||||||
|  |         public decimal total { get; set; } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class OrderSummary | ||||||
|  |     { | ||||||
|  |         public int ordernumber { get; set; } | ||||||
|  |         public DateTime date { get; set; } | ||||||
|  |         public string status { get; set; } | ||||||
|  |         public double total { get; set; } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class CardType | ||||||
|  |     { | ||||||
|  |         public int Id { get; set; } | ||||||
|  |         public string Name { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -3,9 +3,9 @@ using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; | |||||||
| 
 | 
 | ||||||
| namespace Ordering.API.Application.Validations | namespace Ordering.API.Application.Validations | ||||||
| { | { | ||||||
|     public class IdentifierCommandValidator : AbstractValidator<IdentifiedCommand<CreateOrderCommand,bool>> |     public class IdentifiedCommandValidator : AbstractValidator<IdentifiedCommand<CreateOrderCommand,bool>> | ||||||
|     { |     { | ||||||
|         public IdentifierCommandValidator() |         public IdentifiedCommandValidator() | ||||||
|         { |         { | ||||||
|             RuleFor(command => command.Id).NotEmpty();     |             RuleFor(command => command.Id).NotEmpty();     | ||||||
|         } |         } | ||||||
| @ -64,7 +64,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers | |||||||
| 
 | 
 | ||||||
|         [Route("{orderId:int}")] |         [Route("{orderId:int}")] | ||||||
|         [HttpGet] |         [HttpGet] | ||||||
|         [ProducesResponseType((int)HttpStatusCode.OK)] |         [ProducesResponseType(typeof(Order),(int)HttpStatusCode.OK)] | ||||||
|         [ProducesResponseType((int)HttpStatusCode.NotFound)] |         [ProducesResponseType((int)HttpStatusCode.NotFound)] | ||||||
|         public async Task<IActionResult> GetOrder(int orderId) |         public async Task<IActionResult> GetOrder(int orderId) | ||||||
|         { |         { | ||||||
| @ -83,6 +83,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers | |||||||
| 
 | 
 | ||||||
|         [Route("")] |         [Route("")] | ||||||
|         [HttpGet] |         [HttpGet] | ||||||
|  |         [ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)] | ||||||
|         public async Task<IActionResult> GetOrders() |         public async Task<IActionResult> GetOrders() | ||||||
|         { |         { | ||||||
|             var orderTask = _orderQueries.GetOrdersAsync(); |             var orderTask = _orderQueries.GetOrdersAsync(); | ||||||
| @ -94,6 +95,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers | |||||||
| 
 | 
 | ||||||
|         [Route("cardtypes")] |         [Route("cardtypes")] | ||||||
|         [HttpGet] |         [HttpGet] | ||||||
|  |         [ProducesResponseType(typeof(IEnumerable<CardType>), (int)HttpStatusCode.OK)] | ||||||
|         public async Task<IActionResult> GetCardTypes() |         public async Task<IActionResult> GetCardTypes() | ||||||
|         { |         { | ||||||
|             var cardTypes = await _orderQueries |             var cardTypes = await _orderQueries | ||||||
|  | |||||||
| @ -23,11 +23,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof | |||||||
|             builder.RegisterAssemblyTypes(typeof(CreateOrderCommand).GetTypeInfo().Assembly) |             builder.RegisterAssemblyTypes(typeof(CreateOrderCommand).GetTypeInfo().Assembly) | ||||||
|                 .AsClosedTypesOf(typeof(IAsyncRequestHandler<,>)); |                 .AsClosedTypesOf(typeof(IAsyncRequestHandler<,>)); | ||||||
| 
 | 
 | ||||||
|             // Register all the event classes (they implement IAsyncNotificationHandler) in assembly holding the Commands |             // Register the DomainEventHandler classes (they implement IAsyncNotificationHandler<>) in assembly holding the Domain Events | ||||||
|             builder.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly) |             builder.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly) | ||||||
|                 .AsClosedTypesOf(typeof(IAsyncNotificationHandler<>)); |                 .AsClosedTypesOf(typeof(IAsyncNotificationHandler<>)); | ||||||
| 
 | 
 | ||||||
| 
 |             // Register the Command's Validators (Validators based on FluentValidation library) | ||||||
|             builder |             builder | ||||||
|                 .RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly) |                 .RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly) | ||||||
|                 .Where(t => t.IsClosedTypeOf(typeof(IValidator<>))) |                 .Where(t => t.IsClosedTypeOf(typeof(IValidator<>))) | ||||||
|  | |||||||
| @ -294,6 +294,8 @@ | |||||||
| 
 | 
 | ||||||
|         private void RegisterEventBus(IServiceCollection services) |         private void RegisterEventBus(IServiceCollection services) | ||||||
|         { |         { | ||||||
|  |             var subscriptionClientName = Configuration["SubscriptionClientName"]; | ||||||
|  | 
 | ||||||
|             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) |             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) | ||||||
|             { |             { | ||||||
|                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | ||||||
| @ -301,8 +303,7 @@ | |||||||
|                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); |                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | ||||||
|                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); |                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | ||||||
|                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | ||||||
|                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();                     | ||||||
|                     var subscriptionClientName = Configuration["SubscriptionClientName"]; |  | ||||||
| 
 | 
 | ||||||
|                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, |                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, | ||||||
|                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); |                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | ||||||
| @ -323,7 +324,7 @@ | |||||||
|                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); |                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount); |                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ | |||||||
|   "Logging": { |   "Logging": { | ||||||
|     "IncludeScopes": false, |     "IncludeScopes": false, | ||||||
|     "LogLevel": { |     "LogLevel": { | ||||||
|       "Default": "Debug", |       "Default": "Trace", | ||||||
|       "System": "Information", |       "System": "Information", | ||||||
|       "Microsoft": "Information" |       "Microsoft": "Information" | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -4,17 +4,12 @@ using System.Collections.Generic; | |||||||
| 
 | 
 | ||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate | namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate | ||||||
| { | { | ||||||
|     public class Address |     public class Address : ValueObject | ||||||
|         :ValueObject |  | ||||||
|     { |     { | ||||||
|         public String Street { get; private set; } |         public String Street { get; private set; } | ||||||
| 
 |  | ||||||
|         public String City { get; private set; } |         public String City { get; private set; } | ||||||
| 
 |  | ||||||
|         public String State { get; private set; } |         public String State { get; private set; } | ||||||
| 
 |  | ||||||
|         public String Country { get; private set; } |         public String Country { get; private set; } | ||||||
| 
 |  | ||||||
|         public String ZipCode { get; private set; } |         public String ZipCode { get; private set; } | ||||||
| 
 | 
 | ||||||
|         private Address() { } |         private Address() { } | ||||||
| @ -30,6 +25,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | |||||||
| 
 | 
 | ||||||
|         protected override IEnumerable<object> GetAtomicValues() |         protected override IEnumerable<object> GetAtomicValues() | ||||||
|         { |         { | ||||||
|  |             // Using a yield return statement to return each element one at a time | ||||||
|             yield return Street; |             yield return Street; | ||||||
|             yield return City; |             yield return City; | ||||||
|             yield return State; |             yield return State; | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | |||||||
|         // aligned with DDD Aggregates and Domain Entities (Instead of properties and property collections) |         // aligned with DDD Aggregates and Domain Entities (Instead of properties and property collections) | ||||||
|         private DateTime _orderDate; |         private DateTime _orderDate; | ||||||
| 
 | 
 | ||||||
|  |         // Address is a Value Object pattern example persisted as EF Core 2.0 owned entity | ||||||
|         public Address Address { get; private set; } |         public Address Address { get; private set; } | ||||||
| 
 | 
 | ||||||
|         private int? _buyerId; |         private int? _buyerId; | ||||||
| @ -29,12 +30,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | |||||||
|         // so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection, |         // so OrderItems cannot be added from "outside the AggregateRoot" directly to the collection, | ||||||
|         // but only through the method OrderAggrergateRoot.AddOrderItem() which includes behaviour. |         // but only through the method OrderAggrergateRoot.AddOrderItem() which includes behaviour. | ||||||
|         private readonly List<OrderItem> _orderItems; |         private readonly List<OrderItem> _orderItems; | ||||||
| 
 |  | ||||||
|         public IReadOnlyCollection<OrderItem> OrderItems => _orderItems; |         public IReadOnlyCollection<OrderItem> OrderItems => _orderItems; | ||||||
|         // Using List<>.AsReadOnly()  |  | ||||||
|         // This will create a read only wrapper around the private list so is protected against "external updates". |  | ||||||
|         // It's much cheaper than .ToList() because it will not have to copy all items in a new collection. (Just one heap alloc for the wrapper instance) |  | ||||||
|         //https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx  |  | ||||||
| 
 | 
 | ||||||
|         private int? _paymentMethodId; |         private int? _paymentMethodId; | ||||||
| 
 | 
 | ||||||
| @ -177,16 +173,16 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | |||||||
|         private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, |         private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, | ||||||
|                 string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) |                 string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) | ||||||
|         { |         { | ||||||
|             var orderStartedDomainEvent = new OrderStartedDomainEvent( |             var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, cardTypeId,  | ||||||
|                 this, userId, cardTypeId, cardNumber, cardSecurityNumber, |                                                                       cardNumber, cardSecurityNumber, | ||||||
|                 cardHolderName, cardExpiration); |                                                                       cardHolderName, cardExpiration); | ||||||
| 
 | 
 | ||||||
|             this.AddDomainEvent(orderStartedDomainEvent); |             this.AddDomainEvent(orderStartedDomainEvent); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void StatusChangeException(OrderStatus orderStatusToChange) |         private void StatusChangeException(OrderStatus orderStatusToChange) | ||||||
|         { |         { | ||||||
|             throw new OrderingDomainException($"Not possible to change order status from {OrderStatus.Name} to {orderStatusToChange.Name}."); |             throw new OrderingDomainException($"Is not possible to change the order status from {OrderStatus.Name} to {orderStatusToChange.Name}."); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public decimal GetTotal() |         public decimal GetTotal() | ||||||
|  | |||||||
| @ -9,8 +9,7 @@ namespace Ordering.Domain.Events | |||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Event used when an order is created |     /// Event used when an order is created | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public class OrderStartedDomainEvent |     public class OrderStartedDomainEvent : INotification | ||||||
|         : INotification |  | ||||||
|     { |     { | ||||||
|         public string UserId { get; private set; } |         public string UserId { get; private set; } | ||||||
|         public int CardTypeId { get; private set; } |         public int CardTypeId { get; private set; } | ||||||
| @ -21,9 +20,9 @@ namespace Ordering.Domain.Events | |||||||
|         public Order Order { get; private set; } |         public Order Order { get; private set; } | ||||||
| 
 | 
 | ||||||
|         public OrderStartedDomainEvent(Order order, string userId, |         public OrderStartedDomainEvent(Order order, string userId, | ||||||
|             int cardTypeId, string cardNumber,  |                                        int cardTypeId, string cardNumber,  | ||||||
|             string cardSecurityNumber, string cardHolderName,  |                                        string cardSecurityNumber, string cardHolderName,  | ||||||
|             DateTime cardExpiration) |                                        DateTime cardExpiration) | ||||||
|         { |         { | ||||||
|             Order = order; |             Order = order; | ||||||
|             UserId = userId; |             UserId = userId; | ||||||
|  | |||||||
| @ -6,12 +6,8 @@ | |||||||
| 
 | 
 | ||||||
|     public abstract class Entity |     public abstract class Entity | ||||||
|     { |     { | ||||||
| 
 |  | ||||||
|         int? _requestedHashCode; |         int? _requestedHashCode; | ||||||
|         int _Id; |         int _Id;         | ||||||
|          |  | ||||||
|         private List<INotification> _domainEvents; |  | ||||||
| 
 |  | ||||||
|         public virtual  int Id  |         public virtual  int Id  | ||||||
|         { |         { | ||||||
|             get |             get | ||||||
| @ -24,13 +20,14 @@ | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public List<INotification> DomainEvents => _domainEvents;         |         private List<INotification> _domainEvents; | ||||||
|  |         public List<INotification> DomainEvents => _domainEvents;        | ||||||
|  |          | ||||||
|         public void AddDomainEvent(INotification eventItem) |         public void AddDomainEvent(INotification eventItem) | ||||||
|         { |         { | ||||||
|             _domainEvents = _domainEvents ?? new List<INotification>(); |             _domainEvents = _domainEvents ?? new List<INotification>(); | ||||||
|             _domainEvents.Add(eventItem); |             _domainEvents.Add(eventItem); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         public void RemoveDomainEvent(INotification eventItem) |         public void RemoveDomainEvent(INotification eventItem) | ||||||
|         { |         { | ||||||
|             if (_domainEvents is null) return; |             if (_domainEvents is null) return; | ||||||
| @ -74,7 +71,6 @@ | |||||||
|                 return base.GetHashCode(); |                 return base.GetHashCode(); | ||||||
| 
 | 
 | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         public static bool operator ==(Entity left, Entity right) |         public static bool operator ==(Entity left, Entity right) | ||||||
|         { |         { | ||||||
|             if (Object.Equals(left, null)) |             if (Object.Equals(left, null)) | ||||||
|  | |||||||
| @ -14,16 +14,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork | |||||||
|             return ReferenceEquals(left, null) || left.Equals(right); |             return ReferenceEquals(left, null) || left.Equals(right); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         protected static bool NotEqualOperator(ValueObject left, ValueObject right) |         protected static bool NotEqualOperator(ValueObject left, ValueObject right) | ||||||
|         { |         { | ||||||
|             return !(EqualOperator(left, right)); |             return !(EqualOperator(left, right)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         protected abstract IEnumerable<object> GetAtomicValues(); |         protected abstract IEnumerable<object> GetAtomicValues(); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         public override bool Equals(object obj) |         public override bool Equals(object obj) | ||||||
|         { |         { | ||||||
|             if (obj == null || obj.GetType() != GetType()) |             if (obj == null || obj.GetType() != GetType()) | ||||||
| @ -47,7 +44,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork | |||||||
|             return !thisValues.MoveNext() && !otherValues.MoveNext(); |             return !thisValues.MoveNext() && !otherValues.MoveNext(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         public override int GetHashCode() |         public override int GetHashCode() | ||||||
|         { |         { | ||||||
|             return GetAtomicValues() |             return GetAtomicValues() | ||||||
|  | |||||||
| @ -7,8 +7,7 @@ using System; | |||||||
| 
 | 
 | ||||||
| namespace Ordering.Infrastructure.EntityConfigurations | namespace Ordering.Infrastructure.EntityConfigurations | ||||||
| { | { | ||||||
|     class OrderEntityTypeConfiguration |     class OrderEntityTypeConfiguration : IEntityTypeConfiguration<Order> | ||||||
|         : IEntityTypeConfiguration<Order> |  | ||||||
|     { |     { | ||||||
|         public void Configure(EntityTypeBuilder<Order> orderConfiguration) |         public void Configure(EntityTypeBuilder<Order> orderConfiguration) | ||||||
|         { |         { | ||||||
| @ -21,6 +20,7 @@ namespace Ordering.Infrastructure.EntityConfigurations | |||||||
|             orderConfiguration.Property(o => o.Id) |             orderConfiguration.Property(o => o.Id) | ||||||
|                 .ForSqlServerUseSequenceHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA); |                 .ForSqlServerUseSequenceHiLo("orderseq", OrderingContext.DEFAULT_SCHEMA); | ||||||
| 
 | 
 | ||||||
|  |             //Address value object persisted as owned entity type supported since EF Core 2.0 | ||||||
|             orderConfiguration.OwnsOne(o => o.Address); |             orderConfiguration.OwnsOne(o => o.Address); | ||||||
| 
 | 
 | ||||||
|             orderConfiguration.Property<DateTime>("OrderDate").IsRequired(); |             orderConfiguration.Property<DateTime>("OrderDate").IsRequired(); | ||||||
| @ -32,7 +32,7 @@ namespace Ordering.Infrastructure.EntityConfigurations | |||||||
|             var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems)); |             var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems)); | ||||||
|              |              | ||||||
|             // DDD Patterns comment: |             // DDD Patterns comment: | ||||||
|             //Set as Field (New since EF 1.1) to access the OrderItem collection property through its field |             //Set as field (New since EF 1.1) to access the OrderItem collection property through its field | ||||||
|             navigation.SetPropertyAccessMode(PropertyAccessMode.Field); |             navigation.SetPropertyAccessMode(PropertyAccessMode.Field); | ||||||
| 
 | 
 | ||||||
|             orderConfiguration.HasOne<PaymentMethod>() |             orderConfiguration.HasOne<PaymentMethod>() | ||||||
|  | |||||||
| @ -12,22 +12,14 @@ using System.Threading.Tasks; | |||||||
| 
 | 
 | ||||||
| namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure | namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure | ||||||
| { | { | ||||||
|     public class OrderingContext |     public class OrderingContext : DbContext, IUnitOfWork | ||||||
|       : DbContext,IUnitOfWork |  | ||||||
| 
 |  | ||||||
|     { |     { | ||||||
|         public const string DEFAULT_SCHEMA = "ordering"; |         public const string DEFAULT_SCHEMA = "ordering"; | ||||||
| 
 |  | ||||||
|         public DbSet<Order> Orders { get; set; } |         public DbSet<Order> Orders { get; set; } | ||||||
| 
 |  | ||||||
|         public DbSet<OrderItem> OrderItems { get; set; } |         public DbSet<OrderItem> OrderItems { get; set; } | ||||||
| 
 |  | ||||||
|         public DbSet<PaymentMethod> Payments { get; set; } |         public DbSet<PaymentMethod> Payments { get; set; } | ||||||
| 
 |  | ||||||
|         public DbSet<Buyer> Buyers { get; set; } |         public DbSet<Buyer> Buyers { get; set; } | ||||||
| 
 |  | ||||||
|         public DbSet<CardType> CardTypes { get; set; } |         public DbSet<CardType> CardTypes { get; set; } | ||||||
| 
 |  | ||||||
|         public DbSet<OrderStatus> OrderStatus { get; set; } |         public DbSet<OrderStatus> OrderStatus { get; set; } | ||||||
| 
 | 
 | ||||||
|         private readonly IMediator _mediator; |         private readonly IMediator _mediator; | ||||||
| @ -63,7 +55,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure | |||||||
|             // You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers.  |             // You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers.  | ||||||
|             await _mediator.DispatchDomainEventsAsync(this); |             await _mediator.DispatchDomainEventsAsync(this); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|             // After executing this line all the changes (from the Command Handler and Domain Event Handlers)  |             // After executing this line all the changes (from the Command Handler and Domain Event Handlers)  | ||||||
|             // performed throught the DbContext will be commited |             // performed throught the DbContext will be commited | ||||||
|             var result = await base.SaveChangesAsync(); |             var result = await base.SaveChangesAsync(); | ||||||
|  | |||||||
| @ -11,7 +11,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor | |||||||
|         : IBuyerRepository |         : IBuyerRepository | ||||||
|     { |     { | ||||||
|         private readonly OrderingContext _context; |         private readonly OrderingContext _context; | ||||||
| 
 |  | ||||||
|         public IUnitOfWork UnitOfWork |         public IUnitOfWork UnitOfWork | ||||||
|         { |         { | ||||||
|             get |             get | ||||||
| @ -29,7 +28,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor | |||||||
|         { |         { | ||||||
|             if (buyer.IsTransient()) |             if (buyer.IsTransient()) | ||||||
|             { |             { | ||||||
|                 //TODO: when migrating to ef core 1.1.1 change Add by AddAsync-. A bug in ef core 1.1.0 does not allow to do it https://github.com/aspnet/EntityFramework/issues/7298  |  | ||||||
|                 return _context.Buyers |                 return _context.Buyers | ||||||
|                     .Add(buyer) |                     .Add(buyer) | ||||||
|                     .Entity; |                     .Entity; | ||||||
| @ -37,8 +35,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor | |||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 return buyer; |                 return buyer; | ||||||
|             } |             }            | ||||||
|              |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public Buyer Update(Buyer buyer) |         public Buyer Update(Buyer buyer) | ||||||
|  | |||||||
| @ -127,6 +127,8 @@ namespace Payment.API | |||||||
| 
 | 
 | ||||||
|         private void RegisterEventBus(IServiceCollection services) |         private void RegisterEventBus(IServiceCollection services) | ||||||
|         { |         { | ||||||
|  |             var subscriptionClientName = Configuration["SubscriptionClientName"]; | ||||||
|  | 
 | ||||||
|             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) |             if (Configuration.GetValue<bool>("AzureServiceBusEnabled")) | ||||||
|             { |             { | ||||||
|                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => |                 services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | ||||||
| @ -134,8 +136,7 @@ namespace Payment.API | |||||||
|                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); |                     var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | ||||||
|                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); |                     var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>(); | ||||||
|                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); |                     var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | ||||||
|                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); |                     var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();                     | ||||||
|                     var subscriptionClientName = Configuration["SubscriptionClientName"]; |  | ||||||
| 
 | 
 | ||||||
|                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, |                     return new EventBusServiceBus(serviceBusPersisterConnection, logger, | ||||||
|                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); |                         eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); | ||||||
| @ -156,7 +157,7 @@ namespace Payment.API | |||||||
|                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); |                         retryCount = int.Parse(Configuration["EventBusRetryCount"]); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, retryCount); |                     return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | ||||||
|                 }); |                 }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -22,7 +22,7 @@ | |||||||
|         </article> |         </article> | ||||||
|     @if (Model != null && Model.Any()) |     @if (Model != null && Model.Any()) | ||||||
|     { |     { | ||||||
|         @foreach (var item in Model) |         foreach (var item in Model) | ||||||
|         { |         { | ||||||
|             <article class="esh-orders-items row"> |             <article class="esh-orders-items row"> | ||||||
|                 <section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section> |                 <section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section> | ||||||
|  | |||||||
| @ -39,6 +39,7 @@ | |||||||
|                         <a asp-area="" asp-controller="Catalog" asp-action="Index"> |                         <a asp-area="" asp-controller="Catalog" asp-action="Index"> | ||||||
|                             <img src="~/images/brand.png" /> |                             <img src="~/images/brand.png" /> | ||||||
|                         </a> |                         </a> | ||||||
|  |                     </a> | ||||||
|                 </section> |                 </section> | ||||||
| 
 | 
 | ||||||
|                 @await Html.PartialAsync("_LoginPartial") |                 @await Html.PartialAsync("_LoginPartial") | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ | |||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|             Assert.NotNull(basket); |             Assert.NotNull(basket); | ||||||
|             Assert.Equal(1, basket.Items.Count); |             Assert.Single(basket.Items); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Fact] |         [Fact] | ||||||
|  | |||||||
| @ -41,7 +41,7 @@ namespace IntegrationTests.Services.Catalog | |||||||
|                 var response = await server.CreateClient() |                 var response = await server.CreateClient() | ||||||
|                     .GetAsync(Get.ItemById(int.MinValue)); |                     .GetAsync(Get.ItemById(int.MinValue)); | ||||||
| 
 | 
 | ||||||
|                 Assert.Equal(response.StatusCode, HttpStatusCode.BadRequest); |                 Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -53,7 +53,7 @@ namespace IntegrationTests.Services.Catalog | |||||||
|                 var response = await server.CreateClient() |                 var response = await server.CreateClient() | ||||||
|                     .GetAsync(Get.ItemById(int.MaxValue)); |                     .GetAsync(Get.ItemById(int.MaxValue)); | ||||||
| 
 | 
 | ||||||
|                 Assert.Equal(response.StatusCode, HttpStatusCode.NotFound); |                 Assert.Equal( HttpStatusCode.NotFound, response.StatusCode); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -147,15 +147,15 @@ | |||||||
|     <None Include="WebMVC\AddProducts.webtest"> |     <None Include="WebMVC\AddProducts.webtest"> | ||||||
|       <CopyToOutputDirectory>Always</CopyToOutputDirectory> |       <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||||
|     </None> |     </None> | ||||||
|     <None Include="WebMVC\CatalogFilter.webtest"> |  | ||||||
|       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |  | ||||||
|     </None> |  | ||||||
|     <None Include="Identity.API\Logout.webtest"> |     <None Include="Identity.API\Logout.webtest"> | ||||||
|       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||||
|     </None> |     </None> | ||||||
|     <None Include="WebMVC\CreateNewOrder.webtest"> |     <None Include="WebMVC\CreateNewOrder.webtest"> | ||||||
|       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> |       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||||
|     </None> |     </None> | ||||||
|  |     <None Include="WebMVC\CatalogFilter.webtest"> | ||||||
|  |       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||||
|  |     </None> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup /> |   <ItemGroup /> | ||||||
|   <Choose> |   <Choose> | ||||||
|  | |||||||
| @ -3,7 +3,10 @@ | |||||||
|   <Scenarios> |   <Scenarios> | ||||||
|     <Scenario Name="OrderProductsLoadTest" DelayBetweenIterations="0" PercentNewUsers="0" IPSwitching="false" TestMixType="PercentageOfTestsStarted" ApplyDistributionToPacingDelay="true" MaxTestIterations="0" DisableDuringWarmup="false" DelayStartTime="0" AllowedAgents=""> |     <Scenario Name="OrderProductsLoadTest" DelayBetweenIterations="0" PercentNewUsers="0" IPSwitching="false" TestMixType="PercentageOfTestsStarted" ApplyDistributionToPacingDelay="true" MaxTestIterations="0" DisableDuringWarmup="false" DelayStartTime="0" AllowedAgents=""> | ||||||
|       <ThinkProfile Value="0.2" Pattern="NormalDistribution" /> |       <ThinkProfile Value="0.2" Pattern="NormalDistribution" /> | ||||||
|       <LoadProfile Pattern="Step" InitialUsers="1" MaxUsers="50" StepUsers="2" StepDuration="10" StepRampTime="10" /> |       <LoadProfile Pattern="Step" InitialUsers="1" MaxUsers="1000" StepUsers="50" StepDuration="10" StepRampTime="10" /> | ||||||
|  |       <InitializeTest> | ||||||
|  |         <TestProfile Name="AddProducts" Path="webmvc\addproducts.webtest" Id="2c9d53ae-0237-47bd-a5d2-6500ef5d8fcb" Percentage="0.0" Type="Microsoft.VisualStudio.TestTools.WebStress.DeclarativeWebTestElement, Microsoft.VisualStudio.QualityTools.LoadTest, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> | ||||||
|  |       </InitializeTest> | ||||||
|       <TestMix> |       <TestMix> | ||||||
|         <TestProfile Name="GetItems" Path="catalog.api\getitems.webtest" Id="e527de7e-beff-4824-af52-dda763fd5e6c" Percentage="19" Type="Microsoft.VisualStudio.TestTools.WebStress.DeclarativeWebTestElement, Microsoft.VisualStudio.QualityTools.LoadTest, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> |         <TestProfile Name="GetItems" Path="catalog.api\getitems.webtest" Id="e527de7e-beff-4824-af52-dda763fd5e6c" Percentage="19" Type="Microsoft.VisualStudio.TestTools.WebStress.DeclarativeWebTestElement, Microsoft.VisualStudio.QualityTools.LoadTest, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> | ||||||
|         <TestProfile Name="GetCatalogTypes" Path="catalog.api\getcatalogtypes.webtest" Id="7df20b29-d5c3-447b-b73d-95c63e9c4061" Percentage="15" Type="Microsoft.VisualStudio.TestTools.WebStress.DeclarativeWebTestElement, Microsoft.VisualStudio.QualityTools.LoadTest, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> |         <TestProfile Name="GetCatalogTypes" Path="catalog.api\getcatalogtypes.webtest" Id="7df20b29-d5c3-447b-b73d-95c63e9c4061" Percentage="15" Type="Microsoft.VisualStudio.TestTools.WebStress.DeclarativeWebTestElement, Microsoft.VisualStudio.QualityTools.LoadTest, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> | ||||||
|  | |||||||
| @ -164,7 +164,7 @@ | |||||||
|         <FormPostParameter Name="Total" Value="8.5" RecordedValue="8.5" CorrelationBinding="" UrlEncode="True" /> |         <FormPostParameter Name="Total" Value="8.5" RecordedValue="8.5" CorrelationBinding="" UrlEncode="True" /> | ||||||
|         <FormPostParameter Name="action" Value="[ Place Order ]" RecordedValue="[ Place Order ]" CorrelationBinding="{{FormPostParam9.action}}" UrlEncode="True" /> |         <FormPostParameter Name="action" Value="[ Place Order ]" RecordedValue="[ Place Order ]" CorrelationBinding="{{FormPostParam9.action}}" UrlEncode="True" /> | ||||||
|         <FormPostParameter Name="ZipCode" Value="98052" RecordedValue="98052" CorrelationBinding="" UrlEncode="True" /> |         <FormPostParameter Name="ZipCode" Value="98052" RecordedValue="98052" CorrelationBinding="" UrlEncode="True" /> | ||||||
|         <FormPostParameter Name="RequestId" Value="{{GenGuid}} " RecordedValue="f58b9345-ea25-4125-a8bf-b0992233af6c" CorrelationBinding="" UrlEncode="True" /> |         <FormPostParameter Name="RequestId" Value="{{GenGuid}}" RecordedValue="{{GenGuid}}" CorrelationBinding="" UrlEncode="True" /> | ||||||
|         <FormPostParameter Name="CardTypeId" Value="1" RecordedValue="" CorrelationBinding="" UrlEncode="True" /> |         <FormPostParameter Name="CardTypeId" Value="1" RecordedValue="" CorrelationBinding="" UrlEncode="True" /> | ||||||
|       </FormPostHttpBody> |       </FormPostHttpBody> | ||||||
|     </Request> |     </Request> | ||||||
|  | |||||||
							
								
								
									
										84
									
								
								test/Services/LoadTest/readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								test/Services/LoadTest/readme.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | |||||||
|  | # Load Testing settings | ||||||
|  | 
 | ||||||
|  | This folder contains files needed to run load tests locally or on a Kubernetes / Service Fabric cluster. | ||||||
|  | 
 | ||||||
|  | <p> | ||||||
|  | <img src="../../../img/loadtests/loadtestproj_dir.png"> | ||||||
|  | <p> | ||||||
|  | 
 | ||||||
|  | ## Set a local environment | ||||||
|  | 
 | ||||||
|  | Modify the **app.config** file in the LoadTest project directory and set the following service urls. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | <Servers> | ||||||
|  |     <MvcWebServer url="http://localhost:5100" /> | ||||||
|  |     <CatalogApiServer url="http://localhost:5101" /> | ||||||
|  |     <OrderingApiServer url="http://localhost:5102" /> | ||||||
|  |     <BasketApiServer url="http://localhost:5103" /> | ||||||
|  |     <IdentityApiServer url="http://localhost:5105" /> | ||||||
|  |     <LocationsApiServer url="http://localhost:5109" /> | ||||||
|  |     <MarketingApiServer url="http://localhost:5110" /> | ||||||
|  |   </Servers> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Modify the **.env** file and set the following config property as shown bellow. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | USE_LOADTEST=True | ||||||
|  | ``` | ||||||
|  | ## Set a Service Fabric environment | ||||||
|  | 
 | ||||||
|  | Modify the **app.config** file in the LoadTest project directory and set the following service urls. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | <Servers> | ||||||
|  |     <MvcWebServer url="http://<target_sf_dns>:5100" /> | ||||||
|  |     <CatalogApiServer url="http://<target_sf_dns>:5101" /> | ||||||
|  |     <OrderingApiServer url="http://<target_sf_dns>:5102" /> | ||||||
|  |     <BasketApiServer url="http://<target_sf_dns>:5103" /> | ||||||
|  |     <IdentityApiServer url="http://<target_sf_dns>:5105" /> | ||||||
|  |     <LocationsApiServer url="http://<target_sf_dns>:5109" /> | ||||||
|  |     <MarketingApiServer url="http://<target_sf_dns>:5110" /> | ||||||
|  |   </Servers> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Modify the **ServiceManifest.xml** files of the eShop SF Services and set the **UseLoadTest** environment variable to True. This setting enables the load tests to bypass authorization in api services. | ||||||
|  | 
 | ||||||
|  | <p> | ||||||
|  | <img src="../../../img/loadtests/sfmanifestsettings.png"> | ||||||
|  | <p> | ||||||
|  | 
 | ||||||
|  | Deploy the SF services. **PLEASE** Read our [SF deployment guide for Linux](./../../../deploy/az/servicefabric/LinuxContainers/readme.md) And [SF deployment guide for Windows](./../../../deploy/az/servicefabric/WindowsContainers/readme.md) to know about how to deploy eshop on SF. | ||||||
|  | 
 | ||||||
|  | ## Set a Kubernetes environment | ||||||
|  | 
 | ||||||
|  | Modify the **app.config** file in the LoadTest project directory and set the following service urls. | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | <Servers> | ||||||
|  |     <MvcWebServer url="http://<public_ip_k8s>/webmvc" /> | ||||||
|  |     <CatalogApiServer url="http://<public_ip_k8s>/catalog-api" /> | ||||||
|  |     <OrderingApiServer url="http://<public_ip_k8s>/ordering-api" /> | ||||||
|  |     <BasketApiServer url="http://<public_ip_k8s>/basket-api" /> | ||||||
|  |     <IdentityApiServer url="http://<public_ip_k8s>/identity" /> | ||||||
|  |     <LocationsApiServer url="http://<public_ip_k8s>/locations-api" /> | ||||||
|  |     <MarketingApiServer url="http://<public_ip_k8s>/marketing-api" /> | ||||||
|  |   </Servers> | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Modify the **conf_local.yml** file in the K8s directory and set the **EnableLoadTest** environment variable to True. This setting enables the load tests to bypass authorization in api services. | ||||||
|  | 
 | ||||||
|  | <p> | ||||||
|  | <img src="../../../img/loadtests/k8ssettings.png"> | ||||||
|  | <p> | ||||||
|  | 
 | ||||||
|  | Deploy the kubernetes services. **PLEASE** Read our [k8s deployment guide](./../../../k8s/README.k8s.md) to know about how to deploy eshop on Kubernetes. | ||||||
|  | 
 | ||||||
|  | ## Run Load Tests | ||||||
|  | 
 | ||||||
|  | Open the load test you want to perform ***.loadtest** files and click the Run Load test button. | ||||||
|  | 
 | ||||||
|  | <p> | ||||||
|  | <img src="./../../../img/loadtests/runloadtest.png"> | ||||||
|  | <p> | ||||||
| @ -13,12 +13,12 @@ namespace UnitTest.Ordering.Application | |||||||
|     using System.Collections.Generic; |     using System.Collections.Generic; | ||||||
|     using System.Threading.Tasks; |     using System.Threading.Tasks; | ||||||
|     using Xunit; |     using Xunit; | ||||||
|     public class IdentifierCommandHandlerTest |     public class IdentifiedCommandHandlerTest | ||||||
|     { |     { | ||||||
|         private readonly Mock<IRequestManager> _requestManager; |         private readonly Mock<IRequestManager> _requestManager; | ||||||
|         private readonly Mock<IMediator> _mediator; |         private readonly Mock<IMediator> _mediator; | ||||||
| 
 | 
 | ||||||
|         public IdentifierCommandHandlerTest() |         public IdentifiedCommandHandlerTest() | ||||||
|         { |         { | ||||||
|             _requestManager = new Mock<IRequestManager>(); |             _requestManager = new Mock<IRequestManager>(); | ||||||
|             _mediator = new Mock<IMediator>(); |             _mediator = new Mock<IMediator>(); | ||||||
| @ -38,7 +38,7 @@ namespace UnitTest.Ordering.Application | |||||||
|                .Returns(Task.FromResult(true)); |                .Returns(Task.FromResult(true)); | ||||||
| 
 | 
 | ||||||
|             //Act |             //Act | ||||||
|             var handler = new IdentifierCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object); |             var handler = new IdentifiedCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object); | ||||||
|             var result = await handler.Handle(fakeOrderCmd); |             var result = await handler.Handle(fakeOrderCmd); | ||||||
| 
 | 
 | ||||||
|             //Assert |             //Assert | ||||||
| @ -60,7 +60,7 @@ namespace UnitTest.Ordering.Application | |||||||
|                .Returns(Task.FromResult(true)); |                .Returns(Task.FromResult(true)); | ||||||
| 
 | 
 | ||||||
|             //Act |             //Act | ||||||
|             var handler = new IdentifierCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object); |             var handler = new IdentifiedCommandHandler<CreateOrderCommand, bool>(_mediator.Object, _requestManager.Object); | ||||||
|             var result = await handler.Handle(fakeOrderCmd); |             var result = await handler.Handle(fakeOrderCmd); | ||||||
| 
 | 
 | ||||||
|             //Assert |             //Assert | ||||||
| @ -93,7 +93,7 @@ namespace UnitTest.Ordering.Application | |||||||
|         public async Task Get_orders_success() |         public async Task Get_orders_success() | ||||||
|         { |         { | ||||||
|             //Arrange |             //Arrange | ||||||
|             var fakeDynamicResult = Enumerable.Empty<object>(); |             var fakeDynamicResult = Enumerable.Empty<OrderSummary>(); | ||||||
|             _orderQueriesMock.Setup(x => x.GetOrdersAsync()) |             _orderQueriesMock.Setup(x => x.GetOrdersAsync()) | ||||||
|                 .Returns(Task.FromResult(fakeDynamicResult)); |                 .Returns(Task.FromResult(fakeDynamicResult)); | ||||||
| 
 | 
 | ||||||
| @ -110,7 +110,7 @@ namespace UnitTest.Ordering.Application | |||||||
|         { |         { | ||||||
|             //Arrange |             //Arrange | ||||||
|             var fakeOrderId = 123; |             var fakeOrderId = 123; | ||||||
|             var fakeDynamicResult = new Object(); |             var fakeDynamicResult = new Order(); | ||||||
|             _orderQueriesMock.Setup(x => x.GetOrderAsync(It.IsAny<int>())) |             _orderQueriesMock.Setup(x => x.GetOrderAsync(It.IsAny<int>())) | ||||||
|                 .Returns(Task.FromResult(fakeDynamicResult)); |                 .Returns(Task.FromResult(fakeDynamicResult)); | ||||||
| 
 | 
 | ||||||
| @ -126,7 +126,7 @@ namespace UnitTest.Ordering.Application | |||||||
|         public async Task Get_cardTypes_success() |         public async Task Get_cardTypes_success() | ||||||
|         { |         { | ||||||
|             //Arrange |             //Arrange | ||||||
|             var fakeDynamicResult = Enumerable.Empty<object>(); |             var fakeDynamicResult = Enumerable.Empty<CardType>(); | ||||||
|             _orderQueriesMock.Setup(x => x.GetCardTypesAsync()) |             _orderQueriesMock.Setup(x => x.GetCardTypesAsync()) | ||||||
|                 .Returns(Task.FromResult(fakeDynamicResult)); |                 .Returns(Task.FromResult(fakeDynamicResult)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -111,7 +111,6 @@ public class OrderAggregateTest | |||||||
|     public void Add_new_Order_raises_new_event() |     public void Add_new_Order_raises_new_event() | ||||||
|     { |     { | ||||||
|         //Arrange |         //Arrange | ||||||
|         var userId = new Guid(); |  | ||||||
|         var street = "fakeStreet"; |         var street = "fakeStreet"; | ||||||
|         var city = "FakeCity"; |         var city = "FakeCity"; | ||||||
|         var state = "fakeState"; |         var state = "fakeState"; | ||||||
| @ -135,7 +134,6 @@ public class OrderAggregateTest | |||||||
|     public void Add_event_Order_explicitly_raises_new_event() |     public void Add_event_Order_explicitly_raises_new_event() | ||||||
|     { |     { | ||||||
|         //Arrange    |         //Arrange    | ||||||
|         var userId = new Guid(); |  | ||||||
|         var street = "fakeStreet"; |         var street = "fakeStreet"; | ||||||
|         var city = "FakeCity"; |         var city = "FakeCity"; | ||||||
|         var state = "fakeState"; |         var state = "fakeState"; | ||||||
| @ -159,7 +157,6 @@ public class OrderAggregateTest | |||||||
|     public void Remove_event_Order_explicitly() |     public void Remove_event_Order_explicitly() | ||||||
|     { |     { | ||||||
|         //Arrange     |         //Arrange     | ||||||
|         var userId = new Guid(); |  | ||||||
|         var street = "fakeStreet"; |         var street = "fakeStreet"; | ||||||
|         var city = "FakeCity"; |         var city = "FakeCity"; | ||||||
|         var state = "fakeState"; |         var state = "fakeState"; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user