commit
						2e8e335fdc
					
				| @ -1,7 +1,7 @@ | |||||||
|  |  | ||||||
| Microsoft Visual Studio Solution File, Format Version 12.00 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||||
| # Visual Studio 15 | # Visual Studio 15 | ||||||
| VisualStudioVersion = 15.0.27004.2002 | VisualStudioVersion = 15.0.27004.2009 | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
| Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" | Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}" | ||||||
| EndProject | EndProject | ||||||
| @ -83,10 +83,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Location", "Location", "{41 | |||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Locations.API", "src\Services\Location\Locations.API\Locations.API.csproj", "{E7581357-FC34-474C-B8F5-307EE3CE05EF}" | ||||||
| EndProject | EndProject | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataProtection", "DataProtection", "{88B22DBB-AA8F-4290-A454-2C109352C345}" |  | ||||||
| EndProject |  | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataProtection", "src\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj", "{23A33F9B-7672-426D-ACF9-FF8436ADC81A}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Marketing", "Marketing", "{A5260DE0-1FDD-467E-9CC1-A028AB081CEE}" | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Marketing", "Marketing", "{A5260DE0-1FDD-467E-9CC1-A028AB081CEE}" | ||||||
| EndProject | EndProject | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Services\Marketing\Marketing.API\Marketing.API.csproj", "{DF395F85-B010-465D-857A-7EBCC512C0C2}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing.API", "src\Services\Marketing\Marketing.API\Marketing.API.csproj", "{DF395F85-B010-465D-857A-7EBCC512C0C2}" | ||||||
| @ -1075,54 +1071,6 @@ Global | |||||||
| 		{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x64.Build.0 = Release|Any CPU | 		{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x64.Build.0 = Release|Any CPU | ||||||
| 		{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x86.ActiveCfg = Release|Any CPU | 		{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x86.ActiveCfg = Release|Any CPU | ||||||
| 		{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x86.Build.0 = Release|Any CPU | 		{E7581357-FC34-474C-B8F5-307EE3CE05EF}.Release|x86.Build.0 = Release|Any CPU | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|ARM.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|ARM.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhone.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.AppStore|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|Any CPU.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|ARM.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|ARM.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhone.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhone.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x64.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x64.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x86.ActiveCfg = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Debug|x86.Build.0 = Debug|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|Any CPU.ActiveCfg = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|Any CPU.Build.0 = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|ARM.ActiveCfg = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|ARM.Build.0 = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhone.ActiveCfg = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhone.Build.0 = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x64.ActiveCfg = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x64.Build.0 = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.ActiveCfg = Release|Any CPU |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A}.Release|x86.Build.0 = Release|Any CPU |  | ||||||
| 		{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU | 		{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
| 		{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU | 		{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU | 		{DF395F85-B010-465D-857A-7EBCC512C0C2}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU | ||||||
| @ -1402,8 +1350,6 @@ Global | |||||||
| 		{4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379} | 		{4BD76717-3102-4969-8C2C-BAAA3F0263B6} = {A81ECBC2-6B00-4DCD-8388-469174033379} | ||||||
| 		{41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} | 		{41139F64-4046-4F16-96B7-D941D96FA9C6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} | ||||||
| 		{E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6} | 		{E7581357-FC34-474C-B8F5-307EE3CE05EF} = {41139F64-4046-4F16-96B7-D941D96FA9C6} | ||||||
| 		{88B22DBB-AA8F-4290-A454-2C109352C345} = {DB0EFB20-B024-4E5E-A75C-52143C131D25} |  | ||||||
| 		{23A33F9B-7672-426D-ACF9-FF8436ADC81A} = {88B22DBB-AA8F-4290-A454-2C109352C345} |  | ||||||
| 		{A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} | 		{A5260DE0-1FDD-467E-9CC1-A028AB081CEE} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8} | ||||||
| 		{DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} | 		{DF395F85-B010-465D-857A-7EBCC512C0C2} = {A5260DE0-1FDD-467E-9CC1-A028AB081CEE} | ||||||
| 		{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} | 		{69AF10D3-AA76-4FF7-B187-EC7E8CC5F5B8} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F} | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								img/appinsights/appinsights-loggerfactory.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/appinsights/appinsights-loggerfactory.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 28 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/appinsights/appinsights-register.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/appinsights/appinsights-register.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 26 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/appinsights/appinsights-screenshot.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/appinsights/appinsights-screenshot.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 112 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/appinsights/useappinsights-program.PNG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								img/appinsights/useappinsights-program.PNG
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 28 KiB | 
| @ -1,13 +0,0 @@ | |||||||
| <Project Sdk="Microsoft.NET.Sdk"> |  | ||||||
| 
 |  | ||||||
|   <PropertyGroup> |  | ||||||
|     <TargetFramework>netstandard1.5</TargetFramework> |  | ||||||
|     <RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks</RootNamespace> |  | ||||||
|   </PropertyGroup> |  | ||||||
| 
 |  | ||||||
|   <ItemGroup> |  | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.DataProtection" Version="1.1.2" /> |  | ||||||
|     <PackageReference Include="StackExchange.Redis.StrongName" Version="1.2.4" /> |  | ||||||
|   </ItemGroup> |  | ||||||
| 
 |  | ||||||
| </Project> |  | ||||||
| @ -1,97 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.BuildingBlocks |  | ||||||
| { |  | ||||||
|     using Microsoft.AspNetCore.DataProtection; |  | ||||||
|     using Microsoft.AspNetCore.DataProtection.Repositories; |  | ||||||
|     using Microsoft.Extensions.DependencyInjection; |  | ||||||
|     using Microsoft.Extensions.Logging; |  | ||||||
|     using StackExchange.Redis; |  | ||||||
|     using System; |  | ||||||
|     using System.Linq; |  | ||||||
|     using System.Net; |  | ||||||
| 
 |  | ||||||
|     /// <summary> |  | ||||||
|     /// Extension methods for <see cref="IDataProtectionBuilder"/> for configuring |  | ||||||
|     /// data protection options. |  | ||||||
|     /// </summary> |  | ||||||
|     public static class DataProtectionBuilderExtensions |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// Sets up data protection to persist session keys in Redis. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="builder">The <see cref="IDataProtectionBuilder"/> used to set up data protection options.</param> |  | ||||||
|         /// <param name="redisConnectionString">The connection string specifying the Redis instance and database for key storage.</param> |  | ||||||
|         /// <returns> |  | ||||||
|         /// The <paramref name="builder" /> for continued configuration. |  | ||||||
|         /// </returns> |  | ||||||
|         /// <exception cref="System.ArgumentNullException"> |  | ||||||
|         /// Thrown if <paramref name="builder" /> or <paramref name="redisConnectionString" /> is <see langword="null" />. |  | ||||||
|         /// </exception> |  | ||||||
|         /// <exception cref="System.ArgumentException"> |  | ||||||
|         /// Thrown if <paramref name="redisConnectionString" /> is empty. |  | ||||||
|         /// </exception> |  | ||||||
|         public static IDataProtectionBuilder PersistKeysToRedis(this IDataProtectionBuilder builder, string redisConnectionString) |  | ||||||
|         { |  | ||||||
|             if (builder == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(builder)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (redisConnectionString == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(redisConnectionString)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (redisConnectionString.Length == 0) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentException("Redis connection string may not be empty.", nameof(redisConnectionString)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             var configuration = ConfigurationOptions.Parse(redisConnectionString, true); |  | ||||||
|             configuration.ResolveDns = true; |  | ||||||
| 
 |  | ||||||
|             return builder.Use(ServiceDescriptor.Singleton<IXmlRepository>(services => |  | ||||||
|                 new RedisXmlRepository(configuration, services.GetRequiredService<ILogger<RedisXmlRepository>>()))); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Updates an <see cref="IDataProtectionBuilder"/> to use the service of |  | ||||||
|         /// a specific type, removing all other services of that type. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="builder">The <see cref="IDataProtectionBuilder"/> that should use the specified service.</param> |  | ||||||
|         /// <param name="descriptor">The <see cref="ServiceDescriptor"/> with the service the <paramref name="builder" /> should use.</param> |  | ||||||
|         /// <returns> |  | ||||||
|         /// The <paramref name="builder" /> for continued configuration. |  | ||||||
|         /// </returns> |  | ||||||
|         /// <exception cref="System.ArgumentNullException"> |  | ||||||
|         /// Thrown if <paramref name="builder" /> or <paramref name="descriptor" /> is <see langword="null" />. |  | ||||||
|         /// </exception> |  | ||||||
|         public static IDataProtectionBuilder Use(this IDataProtectionBuilder builder, ServiceDescriptor descriptor) |  | ||||||
|         { |  | ||||||
|             // This algorithm of removing all other services of a specific type |  | ||||||
|             // before adding the new/replacement service is how the base ASP.NET |  | ||||||
|             // DataProtection bits work. Due to some of the differences in how |  | ||||||
|             // that base set of bits handles DI, it's better to follow suit |  | ||||||
|             // and work in the same way than to try and debug weird issues. |  | ||||||
|             if (builder == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(builder)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (descriptor == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(descriptor)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             for (int i = builder.Services.Count - 1; i >= 0; i--) |  | ||||||
|             { |  | ||||||
|                 if (builder.Services[i]?.ServiceType == descriptor.ServiceType) |  | ||||||
|                 { |  | ||||||
|                     builder.Services.RemoveAt(i); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             builder.Services.Add(descriptor); |  | ||||||
|             return builder; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,210 +0,0 @@ | |||||||
| namespace Microsoft.eShopOnContainers.BuildingBlocks |  | ||||||
| { |  | ||||||
|     using Microsoft.AspNetCore.DataProtection.Repositories; |  | ||||||
|     using Microsoft.Extensions.Logging; |  | ||||||
|     using StackExchange.Redis; |  | ||||||
|     using System; |  | ||||||
|     using System.Collections.Generic; |  | ||||||
|     using System.Text.RegularExpressions; |  | ||||||
|     using System.Xml.Linq; |  | ||||||
| 
 |  | ||||||
|     /// <summary> |  | ||||||
|     /// Key repository that stores XML encrypted keys in a Redis distributed cache. |  | ||||||
|     /// </summary> |  | ||||||
|     /// <remarks> |  | ||||||
|     /// <para> |  | ||||||
|     /// The values stored in Redis are XML documents that contain encrypted session |  | ||||||
|     /// keys used for the protection of things like session state. The document contents |  | ||||||
|     /// are double-encrypted - first with a changing session key; then by a master key. |  | ||||||
|     /// As such, there's no risk in storing the keys in Redis - even if someone can crack |  | ||||||
|     /// the master key, they still need to also crack the session key. (Other solutions |  | ||||||
|     /// for sharing keys across a farm environment include writing them to files |  | ||||||
|     /// on a file share.) |  | ||||||
|     /// </para> |  | ||||||
|     /// <para> |  | ||||||
|     /// While the repository uses a hash to keep the set of encrypted keys separate, you |  | ||||||
|     /// can further separate these items from other items in Redis by specifying a unique |  | ||||||
|     /// database in the connection string. |  | ||||||
|     /// </para> |  | ||||||
|     /// <para> |  | ||||||
|     /// Consumers of the repository are responsible for caching the XML items as needed. |  | ||||||
|     /// Typically repositories are consumed by things like <see cref="Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider"/> |  | ||||||
|     /// which generates <see cref="Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.CacheableKeyRing"/> |  | ||||||
|     /// values that get cached. The mechanism is already optimized for caching so there's |  | ||||||
|     /// no need to create a redundant cache. |  | ||||||
|     /// </para> |  | ||||||
|     /// </remarks> |  | ||||||
|     /// <seealso cref="Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository" /> |  | ||||||
|     /// <seealso cref="System.IDisposable" /> |  | ||||||
|     public class RedisXmlRepository : IXmlRepository, IDisposable |  | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// The root cache key for XML items stored in Redis |  | ||||||
|         /// </summary> |  | ||||||
|         public static readonly string RedisHashKey = "DataProtectionXmlRepository"; |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// The connection to the Redis backing store. |  | ||||||
|         /// </summary> |  | ||||||
|         private IConnectionMultiplexer _connection; |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Flag indicating whether the object has been disposed. |  | ||||||
|         /// </summary> |  | ||||||
|         private bool _disposed = false; |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="RedisXmlRepository"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="connectionString"> |  | ||||||
|         /// The Redis connection string. |  | ||||||
|         /// </param> |  | ||||||
|         /// <param name="logger"> |  | ||||||
|         /// The <see cref="ILogger{T}"/> used to log diagnostic messages. |  | ||||||
|         /// </param> |  | ||||||
|         /// <exception cref="System.ArgumentNullException"> |  | ||||||
|         /// Thrown if <paramref name="connectionString" /> or <paramref name="logger" /> is <see langword="null" />. |  | ||||||
|         /// </exception> |  | ||||||
|         public RedisXmlRepository(ConfigurationOptions connectionString, ILogger<RedisXmlRepository> logger) |  | ||||||
|             : this(ConnectionMultiplexer.Connect(connectionString), logger) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="RedisXmlRepository"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="connection"> |  | ||||||
|         /// The Redis database connection. |  | ||||||
|         /// </param> |  | ||||||
|         /// <param name="logger"> |  | ||||||
|         /// The <see cref="ILogger{T}"/> used to log diagnostic messages. |  | ||||||
|         /// </param> |  | ||||||
|         /// <exception cref="System.ArgumentNullException"> |  | ||||||
|         /// Thrown if <paramref name="connection" /> or <paramref name="logger" /> is <see langword="null" />. |  | ||||||
|         /// </exception> |  | ||||||
|         public RedisXmlRepository(IConnectionMultiplexer connection, ILogger<RedisXmlRepository> logger) |  | ||||||
|         { |  | ||||||
|             if (connection == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(connection)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (logger == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(logger)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             this._connection = connection; |  | ||||||
|             this.Logger = logger; |  | ||||||
| 
 |  | ||||||
|             // Mask the password so it doesn't get logged. |  | ||||||
|             var configuration = Regex.Replace(this._connection.Configuration, @"password\s*=\s*[^,]*", "password=****", RegexOptions.IgnoreCase); |  | ||||||
|             this.Logger.LogDebug("Storing data protection keys in Redis: {RedisConfiguration}", configuration); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the logger. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <value> |  | ||||||
|         /// The <see cref="ILogger{T}"/> used to log diagnostic messages. |  | ||||||
|         /// </value> |  | ||||||
|         public ILogger<RedisXmlRepository> Logger { get; private set; } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Performs application-defined tasks associated with freeing, releasing, |  | ||||||
|         /// or resetting unmanaged resources. |  | ||||||
|         /// </summary> |  | ||||||
|         public void Dispose() |  | ||||||
|         { |  | ||||||
|             this.Dispose(true); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets all top-level XML elements in the repository. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns> |  | ||||||
|         /// An <see cref="IReadOnlyCollection{T}"/> with the set of elements |  | ||||||
|         /// stored in the repository. |  | ||||||
|         /// </returns> |  | ||||||
|         public IReadOnlyCollection<XElement> GetAllElements() |  | ||||||
|         { |  | ||||||
|             var database = this._connection.GetDatabase(); |  | ||||||
|             var hash = database.HashGetAll(RedisHashKey); |  | ||||||
|             var elements = new List<XElement>(); |  | ||||||
| 
 |  | ||||||
|             if (hash == null || hash.Length == 0) |  | ||||||
|             { |  | ||||||
|                 return elements.AsReadOnly(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             foreach (var item in hash.ToStringDictionary()) |  | ||||||
|             { |  | ||||||
|                 elements.Add(XElement.Parse(item.Value)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             this.Logger.LogDebug("Read {XmlElementCount} XML elements from Redis.", elements.Count); |  | ||||||
|             return elements.AsReadOnly(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Adds a top-level XML element to the repository. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="element">The element to add.</param> |  | ||||||
|         /// <param name="friendlyName"> |  | ||||||
|         /// An optional name to be associated with the XML element. |  | ||||||
|         /// For instance, if this repository stores XML files on disk, the friendly name may |  | ||||||
|         /// be used as part of the file name. Repository implementations are not required to |  | ||||||
|         /// observe this parameter even if it has been provided by the caller. |  | ||||||
|         /// </param> |  | ||||||
|         /// <remarks> |  | ||||||
|         /// The <paramref name="friendlyName" /> parameter must be unique if specified. |  | ||||||
|         /// For instance, it could be the ID of the key being stored. |  | ||||||
|         /// </remarks> |  | ||||||
|         /// <exception cref="System.ArgumentNullException"> |  | ||||||
|         /// Thrown if <paramref name="element" /> is <see langword="null" />. |  | ||||||
|         /// </exception> |  | ||||||
|         public void StoreElement(XElement element, string friendlyName) |  | ||||||
|         { |  | ||||||
|             if (element == null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(element)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (string.IsNullOrEmpty(friendlyName)) |  | ||||||
|             { |  | ||||||
|                 // The framework always passes in a name, but |  | ||||||
|                 // the contract indicates this may be null or empty. |  | ||||||
|                 friendlyName = Guid.NewGuid().ToString(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             this.Logger.LogDebug("Storing XML element with friendly name {XmlElementFriendlyName}.", friendlyName); |  | ||||||
| 
 |  | ||||||
|             this._connection.GetDatabase().HashSet(RedisHashKey, friendlyName, element.ToString()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |  | ||||||
|         /// Releases unmanaged and - optionally - managed resources. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="disposing"> |  | ||||||
|         /// <see langword="true" /> to release both managed and unmanaged resources; |  | ||||||
|         /// <see langword="false" /> to release only unmanaged resources. |  | ||||||
|         /// </param> |  | ||||||
|         protected virtual void Dispose(bool disposing) |  | ||||||
|         { |  | ||||||
|             if (!this._disposed) |  | ||||||
|             { |  | ||||||
|                 if (disposing) |  | ||||||
|                 { |  | ||||||
|                     if (this._connection != null) |  | ||||||
|                     { |  | ||||||
|                         this._connection.Close(); |  | ||||||
|                         this._connection.Dispose(); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 this._connection = null; |  | ||||||
|                 this._disposed = true; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -59,6 +59,12 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers | |||||||
|                 guid : basketCheckout.RequestId; |                 guid : basketCheckout.RequestId; | ||||||
| 
 | 
 | ||||||
|             var basket = await _repository.GetBasketAsync(userId); |             var basket = await _repository.GetBasketAsync(userId); | ||||||
|  | 
 | ||||||
|  |             if (basket == null) | ||||||
|  |             { | ||||||
|  |                 return BadRequest(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, basketCheckout.City, basketCheckout.Street, |             var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, basketCheckout.City, basketCheckout.Street, | ||||||
|                 basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, |                 basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, | ||||||
|                 basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket); |                 basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket); | ||||||
| @ -66,12 +72,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers | |||||||
|             // Once basket is checkout, sends an integration event to |             // Once basket is checkout, sends an integration event to | ||||||
|             // ordering.api to convert basket to order and proceeds with |             // ordering.api to convert basket to order and proceeds with | ||||||
|             // order creation process |             // order creation process | ||||||
|             _eventBus.Publish(eventMessage); |             _eventBus.Publish(eventMessage);             | ||||||
| 
 |  | ||||||
|             if (basket == null) |  | ||||||
|             { |  | ||||||
|                 return BadRequest(); |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             return Accepted(); |             return Accepted(); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ | |||||||
|     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> | ||||||
|     <PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.0.0" /> |     <PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.0.0" /> | ||||||
|     <PackageReference Include="IdentityServer4.EntityFramework" Version="2.0.0" /> |     <PackageReference Include="IdentityServer4.EntityFramework" Version="2.0.0" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.1" /> | ||||||
|     <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> |     <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| @ -43,7 +44,6 @@ | |||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ProjectReference Include="..\..\..\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj" /> |  | ||||||
|     <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> |     <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> | ||||||
|     <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" /> |     <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.SqlServer\Microsoft.Extensions.HealthChecks.SqlServer.csproj" /> | ||||||
|     <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" /> |     <ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" /> | ||||||
|  | |||||||
| @ -4,10 +4,10 @@ using IdentityServer4.Services; | |||||||
| using Microsoft.ApplicationInsights.Extensibility; | using Microsoft.ApplicationInsights.Extensibility; | ||||||
| using Microsoft.ApplicationInsights.ServiceFabric; | using Microsoft.ApplicationInsights.ServiceFabric; | ||||||
| using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||||
|  | using Microsoft.AspNetCore.DataProtection; | ||||||
| using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||||
| using Microsoft.AspNetCore.Identity; | using Microsoft.AspNetCore.Identity; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.eShopOnContainers.BuildingBlocks; |  | ||||||
| using Microsoft.eShopOnContainers.Services.Identity.API.Certificates; | using Microsoft.eShopOnContainers.Services.Identity.API.Certificates; | ||||||
| using Microsoft.eShopOnContainers.Services.Identity.API.Data; | using Microsoft.eShopOnContainers.Services.Identity.API.Data; | ||||||
| using Microsoft.eShopOnContainers.Services.Identity.API.Models; | using Microsoft.eShopOnContainers.Services.Identity.API.Models; | ||||||
| @ -16,6 +16,7 @@ using Microsoft.Extensions.Configuration; | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Microsoft.Extensions.HealthChecks; | using Microsoft.Extensions.HealthChecks; | ||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
|  | using StackExchange.Redis; | ||||||
| using System; | using System; | ||||||
| using System.Reflection; | using System.Reflection; | ||||||
| 
 | 
 | ||||||
| @ -59,7 +60,7 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API | |||||||
|                 { |                 { | ||||||
|                     opts.ApplicationDiscriminator = "eshop.identity"; |                     opts.ApplicationDiscriminator = "eshop.identity"; | ||||||
|                 }) |                 }) | ||||||
|                 .PersistKeysToRedis(Configuration["DPConnectionString"]); |                 .PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             services.AddHealthChecks(checks => |             services.AddHealthChecks(checks => | ||||||
|  | |||||||
| @ -86,9 +86,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Controllers | |||||||
|         [ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)] |         [ProducesResponseType(typeof(IEnumerable<OrderSummary>), (int)HttpStatusCode.OK)] | ||||||
|         public async Task<IActionResult> GetOrders() |         public async Task<IActionResult> GetOrders() | ||||||
|         { |         { | ||||||
|             var orderTask = _orderQueries.GetOrdersAsync(); |             var orders = await _orderQueries.GetOrdersAsync(); | ||||||
| 
 |  | ||||||
|             var orders = await orderTask; |  | ||||||
| 
 | 
 | ||||||
|             return Ok(orders); |             return Ok(orders); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -92,42 +92,34 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void SetAwaitingValidationStatus() |         public void SetAwaitingValidationStatus() | ||||||
|         { |         {            | ||||||
|             if (_orderStatusId == OrderStatus.Cancelled.Id || |             if (_orderStatusId == OrderStatus.Submitted.Id) | ||||||
|                 _orderStatusId != OrderStatus.Submitted.Id) |  | ||||||
|             { |             { | ||||||
|                 StatusChangeException(OrderStatus.AwaitingValidation); |                 AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, _orderItems)); | ||||||
|             }   |                 _orderStatusId = OrderStatus.AwaitingValidation.Id; | ||||||
| 
 |             }             | ||||||
|             AddDomainEvent(new OrderStatusChangedToAwaitingValidationDomainEvent(Id, _orderItems)); |  | ||||||
| 
 |  | ||||||
|             _orderStatusId = OrderStatus.AwaitingValidation.Id; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void SetStockConfirmedStatus() |         public void SetStockConfirmedStatus() | ||||||
|         { |         { | ||||||
|             if (_orderStatusId != OrderStatus.AwaitingValidation.Id) |             if (_orderStatusId == OrderStatus.AwaitingValidation.Id) | ||||||
|             { |             { | ||||||
|                 StatusChangeException(OrderStatus.StockConfirmed); |                 AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id)); | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             AddDomainEvent(new OrderStatusChangedToStockConfirmedDomainEvent(Id)); |                 _orderStatusId = OrderStatus.StockConfirmed.Id; | ||||||
| 
 |                 _description = "All the items were confirmed with available stock."; | ||||||
|             _orderStatusId = OrderStatus.StockConfirmed.Id; |             }            | ||||||
|             _description = "All the items were confirmed with available stock."; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void SetPaidStatus() |         public void SetPaidStatus() | ||||||
|         { |         { | ||||||
|             if (_orderStatusId != OrderStatus.StockConfirmed.Id) |             if (_orderStatusId == OrderStatus.StockConfirmed.Id) | ||||||
|             { |             { | ||||||
|                 StatusChangeException(OrderStatus.Paid); |                 AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems)); | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             AddDomainEvent(new OrderStatusChangedToPaidDomainEvent(Id, OrderItems)); |                 _orderStatusId = OrderStatus.Paid.Id; | ||||||
| 
 |                 _description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\""; | ||||||
|             _orderStatusId = OrderStatus.Paid.Id; |             }             | ||||||
|             _description = "The payment was performed at a simulated \"American Bank checking bank account endinf on XX35071\""; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void SetShippedStatus() |         public void SetShippedStatus() | ||||||
| @ -155,19 +147,17 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O | |||||||
| 
 | 
 | ||||||
|         public void SetCancelledStatusWhenStockIsRejected(IEnumerable<int> orderStockRejectedItems) |         public void SetCancelledStatusWhenStockIsRejected(IEnumerable<int> orderStockRejectedItems) | ||||||
|         { |         { | ||||||
|             if (_orderStatusId != OrderStatus.AwaitingValidation.Id) |             if (_orderStatusId == OrderStatus.AwaitingValidation.Id) | ||||||
|             { |             { | ||||||
|                 StatusChangeException(OrderStatus.Cancelled); |                 _orderStatusId = OrderStatus.Cancelled.Id; | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             _orderStatusId = OrderStatus.Cancelled.Id; |                 var itemsStockRejectedProductNames = OrderItems | ||||||
|  |                     .Where(c => orderStockRejectedItems.Contains(c.ProductId)) | ||||||
|  |                     .Select(c => c.GetOrderItemProductName()); | ||||||
| 
 | 
 | ||||||
|             var itemsStockRejectedProductNames = OrderItems |                 var itemsStockRejectedDescription = string.Join(", ", itemsStockRejectedProductNames); | ||||||
|                 .Where(c => orderStockRejectedItems.Contains(c.ProductId)) |                 _description = $"The product items don't have stock: ({itemsStockRejectedDescription})."; | ||||||
|                 .Select(c => c.GetOrderItemProductName()); |             }            | ||||||
| 
 |  | ||||||
|             var itemsStockRejectedDescription = string.Join(", ", itemsStockRejectedProductNames); |  | ||||||
|             _description = $"The product items don't have stock: ({itemsStockRejectedDescription})."; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, |         private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber, | ||||||
|  | |||||||
| @ -1,13 +1,11 @@ | |||||||
| using System; | using Microsoft.AspNetCore.Authorization; | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Linq; |  | ||||||
| using System.Threading.Tasks; |  | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| using Microsoft.eShopOnContainers.WebMVC.Services; | using Microsoft.eShopOnContainers.WebMVC.Services; | ||||||
| using Microsoft.eShopOnContainers.WebMVC.ViewModels; | using Microsoft.eShopOnContainers.WebMVC.ViewModels; | ||||||
| using Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Authentication; |  | ||||||
| using Polly.CircuitBreaker; | using Polly.CircuitBreaker; | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Threading.Tasks; | ||||||
| 
 | 
 | ||||||
| namespace Microsoft.eShopOnContainers.WebMVC.Controllers | namespace Microsoft.eShopOnContainers.WebMVC.Controllers | ||||||
| { | { | ||||||
| @ -94,12 +92,12 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers | |||||||
|                 HandleBrokenCircuitException(); |                 HandleBrokenCircuitException(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return RedirectToAction("Index", "Catalog"); |             return RedirectToAction("Index", "Catalog", new { errorMsg = ViewBag.BasketInoperativeMsg }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void HandleBrokenCircuitException() |         private void HandleBrokenCircuitException() | ||||||
|         { |         { | ||||||
|             TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)"; |             ViewBag.BasketInoperativeMsg = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)"; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; | |||||||
| using Microsoft.eShopOnContainers.WebMVC.ViewModels.Pagination; | using Microsoft.eShopOnContainers.WebMVC.ViewModels.Pagination; | ||||||
| using Microsoft.eShopOnContainers.WebMVC.Services; | using Microsoft.eShopOnContainers.WebMVC.Services; | ||||||
| using Microsoft.eShopOnContainers.WebMVC.ViewModels.CatalogViewModels; | using Microsoft.eShopOnContainers.WebMVC.ViewModels.CatalogViewModels; | ||||||
|  | using Microsoft.AspNetCore.Http; | ||||||
| 
 | 
 | ||||||
| namespace Microsoft.eShopOnContainers.WebMVC.Controllers | namespace Microsoft.eShopOnContainers.WebMVC.Controllers | ||||||
| { | { | ||||||
| @ -14,7 +15,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers | |||||||
|         public CatalogController(ICatalogService catalogSvc) =>  |         public CatalogController(ICatalogService catalogSvc) =>  | ||||||
|             _catalogSvc = catalogSvc; |             _catalogSvc = catalogSvc; | ||||||
| 
 | 
 | ||||||
|         public async Task<IActionResult> Index(int? BrandFilterApplied, int? TypesFilterApplied, int? page) |         public async Task<IActionResult> Index(int? BrandFilterApplied, int? TypesFilterApplied, int? page, [FromQuery]string errorMsg) | ||||||
|         { |         { | ||||||
|             var itemsPage = 10; |             var itemsPage = 10; | ||||||
|             var catalog = await _catalogSvc.GetCatalogItems(page ?? 0, itemsPage, BrandFilterApplied, TypesFilterApplied); |             var catalog = await _catalogSvc.GetCatalogItems(page ?? 0, itemsPage, BrandFilterApplied, TypesFilterApplied); | ||||||
| @ -37,6 +38,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers | |||||||
|             vm.PaginationInfo.Next = (vm.PaginationInfo.ActualPage == vm.PaginationInfo.TotalPages - 1) ? "is-disabled" : ""; |             vm.PaginationInfo.Next = (vm.PaginationInfo.ActualPage == vm.PaginationInfo.TotalPages - 1) ? "is-disabled" : ""; | ||||||
|             vm.PaginationInfo.Previous = (vm.PaginationInfo.ActualPage == 0) ? "is-disabled" : ""; |             vm.PaginationInfo.Previous = (vm.PaginationInfo.ActualPage == 0) ? "is-disabled" : ""; | ||||||
| 
 | 
 | ||||||
|  |             ViewBag.BasketInoperativeMsg = errorMsg; | ||||||
|  | 
 | ||||||
|             return View(vm); |             return View(vm); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -3,9 +3,9 @@ using Microsoft.ApplicationInsights.ServiceFabric; | |||||||
| using Microsoft.AspNetCore.Authentication.Cookies; | using Microsoft.AspNetCore.Authentication.Cookies; | ||||||
| using Microsoft.AspNetCore.Authentication.OpenIdConnect; | using Microsoft.AspNetCore.Authentication.OpenIdConnect; | ||||||
| using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||||
|  | using Microsoft.AspNetCore.DataProtection; | ||||||
| using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||||
| using Microsoft.AspNetCore.Http; | using Microsoft.AspNetCore.Http; | ||||||
| using Microsoft.eShopOnContainers.BuildingBlocks; |  | ||||||
| using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; | using Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http; | ||||||
| using Microsoft.eShopOnContainers.WebMVC.Infrastructure; | using Microsoft.eShopOnContainers.WebMVC.Infrastructure; | ||||||
| using Microsoft.eShopOnContainers.WebMVC.Services; | using Microsoft.eShopOnContainers.WebMVC.Services; | ||||||
| @ -14,6 +14,7 @@ using Microsoft.Extensions.Configuration; | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Microsoft.Extensions.HealthChecks; | using Microsoft.Extensions.HealthChecks; | ||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
|  | using StackExchange.Redis; | ||||||
| using System; | using System; | ||||||
| using System.IdentityModel.Tokens.Jwt; | using System.IdentityModel.Tokens.Jwt; | ||||||
| using WebMVC.Infrastructure; | using WebMVC.Infrastructure; | ||||||
| @ -36,7 +37,8 @@ namespace Microsoft.eShopOnContainers.WebMVC | |||||||
|         { |         { | ||||||
|             RegisterAppInsights(services); |             RegisterAppInsights(services); | ||||||
| 
 | 
 | ||||||
|             services.AddMvc();             |             services.AddMvc(); | ||||||
|  | 
 | ||||||
|             services.AddSession(); |             services.AddSession(); | ||||||
| 
 | 
 | ||||||
|             if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString) |             if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString) | ||||||
| @ -45,7 +47,7 @@ namespace Microsoft.eShopOnContainers.WebMVC | |||||||
|                 { |                 { | ||||||
|                     opts.ApplicationDiscriminator = "eshop.webmvc"; |                     opts.ApplicationDiscriminator = "eshop.webmvc"; | ||||||
|                 }) |                 }) | ||||||
|                 .PersistKeysToRedis(Configuration["DPConnectionString"]); |                 .PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             services.Configure<AppSettings>(Configuration); |             services.Configure<AppSettings>(Configuration); | ||||||
|  | |||||||
| @ -24,9 +24,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents | |||||||
|                 return View(vm); |                 return View(vm); | ||||||
|             } |             } | ||||||
|             catch (BrokenCircuitException) |             catch (BrokenCircuitException) | ||||||
|             {                |             { | ||||||
|                 // Catch error when Basket.api is in circuit-opened mode                  |                 // Catch error when Basket.api is in circuit-opened mode                  | ||||||
|                 TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)"; |                 ViewBag.BasketInoperativeMsg = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)"; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return View(vm); |             return View(vm); | ||||||
|  | |||||||
| @ -25,10 +25,10 @@ | |||||||
| <div class="container"> | <div class="container"> | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|         <br /> |         <br /> | ||||||
|         @if(TempData.ContainsKey("BasketInoperativeMsg")) |         @if(ViewBag.BasketInoperativeMsg != null) | ||||||
|         { |         { | ||||||
|             <div class="alert alert-warning" role="alert"> |             <div class="alert alert-warning" role="alert"> | ||||||
|                  @TempData["BasketInoperativeMsg"] |                  @ViewBag.BasketInoperativeMsg | ||||||
|             </div> |             </div> | ||||||
|         } |         } | ||||||
|     </div> |     </div> | ||||||
|  | |||||||
| @ -5,21 +5,21 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| <div class="container"> | <div class="container"> | ||||||
|     @if (TempData.ContainsKey("BasketInoperativeMsg")) |     @if (ViewBag.BasketInoperativeMsg != null) | ||||||
|     { |     { | ||||||
|         <br /> |         <br /> | ||||||
|         <div class="alert alert-warning" role="alert"> |         <div class="alert alert-warning" role="alert"> | ||||||
|              @TempData["BasketInoperativeMsg"] |              @ViewBag.BasketInoperativeMsg | ||||||
|         </div> |         </div> | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         <article class="esh-basket-titles row"> |         <article class="esh-basket-titles row"> | ||||||
|             <br /> |             <br /> | ||||||
|             @if (TempData.ContainsKey("BasketInoperativeMsg")) |             @if (ViewBag.BasketInoperativeMsg != null) | ||||||
|             { |             { | ||||||
|                 <div class="alert alert-warning" role="alert"> |                 <div class="alert alert-warning" role="alert"> | ||||||
|                      @TempData["BasketInoperativeMsg"] |                      @ViewBag.BasketInoperativeMsg | ||||||
|                 </div> |                 </div> | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ | |||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta1" /> |     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.0-beta1" /> |     <PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.1" /> | ||||||
|     <PackageReference Include="Microsoft.VisualStudio.Azure.Fabric.MSBuild" Version="1.6.2" /> |     <PackageReference Include="Microsoft.VisualStudio.Azure.Fabric.MSBuild" Version="1.6.2" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| @ -39,7 +40,6 @@ | |||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj" /> |  | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> |     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" /> |     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" /> | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj" /> |     <ProjectReference Include="..\..\BuildingBlocks\Resilience\Resilience.Http\Resilience.Http.csproj" /> | ||||||
|  | |||||||
| @ -3,13 +3,14 @@ using Microsoft.ApplicationInsights.Extensibility; | |||||||
| using Microsoft.ApplicationInsights.ServiceFabric; | using Microsoft.ApplicationInsights.ServiceFabric; | ||||||
| using Microsoft.AspNetCore.Antiforgery; | using Microsoft.AspNetCore.Antiforgery; | ||||||
| using Microsoft.AspNetCore.Builder; | using Microsoft.AspNetCore.Builder; | ||||||
|  | using Microsoft.AspNetCore.DataProtection; | ||||||
| using Microsoft.AspNetCore.Hosting; | using Microsoft.AspNetCore.Hosting; | ||||||
| using Microsoft.eShopOnContainers.BuildingBlocks; |  | ||||||
| using Microsoft.Extensions.Configuration; | using Microsoft.Extensions.Configuration; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Microsoft.Extensions.HealthChecks; | using Microsoft.Extensions.HealthChecks; | ||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
| using Newtonsoft.Json.Serialization; | using Newtonsoft.Json.Serialization; | ||||||
|  | using StackExchange.Redis; | ||||||
| using System; | using System; | ||||||
| using System.IO; | using System.IO; | ||||||
| using WebSPA.Infrastructure; | using WebSPA.Infrastructure; | ||||||
| @ -64,7 +65,7 @@ namespace eShopConContainers.WebSPA | |||||||
|                 { |                 { | ||||||
|                     opts.ApplicationDiscriminator = "eshop.webspa"; |                     opts.ApplicationDiscriminator = "eshop.webspa"; | ||||||
|                 }) |                 }) | ||||||
|                 .PersistKeysToRedis(Configuration["DPConnectionString"]); |                 .PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys"); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); |             services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ | |||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta1" /> |     <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.0-beta1" /> |     <PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.0-beta1" /> | ||||||
|     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> |     <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.3.1" /> | ||||||
|     <PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> |     <PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| @ -61,7 +62,6 @@ | |||||||
|   --> |   --> | ||||||
|      |      | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\DataProtection\DataProtection\DataProtection.csproj" /> |  | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> |     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" /> | ||||||
|     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" /> |     <ProjectReference Include="..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| @ -76,4 +76,6 @@ | |||||||
|     <Folder Include="wwwroot\assets\" /> |     <Folder Include="wwwroot\assets\" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
|  |   <ProjectExtensions><VisualStudio><UserProperties package-lock_1json__JSONSchema="http://json.schemastore.org/bower" /></VisualStudio></ProjectExtensions> | ||||||
|  | 
 | ||||||
| </Project> | </Project> | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ namespace UnitTest.Catalog.Application | |||||||
| 
 | 
 | ||||||
|             //Act |             //Act | ||||||
|             var orderController = new CatalogController(_catalogServiceMock.Object); |             var orderController = new CatalogController(_catalogServiceMock.Object); | ||||||
|             var actionResult = await orderController.Index(fakeBrandFilterApplied, fakeTypesFilterApplied, fakePage); |             var actionResult = await orderController.Index(fakeBrandFilterApplied, fakeTypesFilterApplied, fakePage, null); | ||||||
| 
 | 
 | ||||||
|             //Assert |             //Assert | ||||||
|             var viewResult = Assert.IsType<ViewResult>(actionResult); |             var viewResult = Assert.IsType<ViewResult>(actionResult); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user