diff --git a/.doc_gen/metadata/redshift_metadata.yaml b/.doc_gen/metadata/redshift_metadata.yaml index d9627603d72..fad23ba02fa 100644 --- a/.doc_gen/metadata/redshift_metadata.yaml +++ b/.doc_gen/metadata/redshift_metadata.yaml @@ -5,6 +5,14 @@ redshift_Hello: synopsis: get started using &RS;. category: Hello languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.Hello Go: versions: - sdk_version: 2 @@ -35,6 +43,14 @@ redshift_Hello: redshift: {DescribeClusters} redshift_ListDatabases: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.ListDatabases Java: versions: - sdk_version: 2 @@ -48,6 +64,14 @@ redshift_ListDatabases: redshift: {ListDatabases} redshift_CreateCluster: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.CreateCluster Go: versions: - sdk_version: 2 @@ -105,6 +129,14 @@ redshift_CreateCluster: redshift: {CreateCluster} redshift_DeleteCluster: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.DeleteCluster Go: versions: - sdk_version: 2 @@ -162,6 +194,14 @@ redshift_DeleteCluster: redshift: {DeleteCluster} redshift_DescribeClusters: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.DescribeClusters Go: versions: - sdk_version: 2 @@ -219,6 +259,14 @@ redshift_DescribeClusters: redshift: {DescribeClusters} redshift_ModifyCluster: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.ModifyCluster Go: versions: - sdk_version: 2 @@ -276,6 +324,14 @@ redshift_ModifyCluster: redshift: {ModifyCluster} redshift_DescribeStatement: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.DescribeStatement Java: versions: - sdk_version: 2 @@ -302,6 +358,14 @@ redshift_DescribeStatement: redshift: {DescribeStatement} redshift_GetStatementResult: languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: + snippet_tags: + - Redshift.dotnetv4.GetStatementResult Java: versions: - sdk_version: 2 @@ -356,6 +420,17 @@ redshift_Scenario: - Delete the Amazon Redshift cluster. category: Basics languages: + .NET: + versions: + - sdk_version: 4 + github: dotnetv4/Redshift + excerpts: + - description: Create a Redshift wrapper class to manage operations. + snippet_tags: + - Redshift.dotnetv4.RedshiftWrapper + - description: Run an interactive scenario demonstrating Redshift basics. + snippet_tags: + - Redshift.dotnetv4.RedshiftScenario Go: versions: - sdk_version: 2 diff --git a/dotnetv4/DotNetV4Examples.sln b/dotnetv4/DotNetV4Examples.sln index e4e1cf6f809..820afe0cfbe 100644 --- a/dotnetv4/DotNetV4Examples.sln +++ b/dotnetv4/DotNetV4Examples.sln @@ -63,7 +63,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Command_R_InvokeModelWithRe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Command_R_InvokeModel", "Bedrock-runtime\Models\CohereCommand\Command_R_InvokeModel\Command_R_InvokeModel.csproj", "{6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}" EndProject - Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AnthropicClaude", "AnthropicClaude", "{6FF2EDB6-D1B8-4EE0-B1F0-2BCE66972E39}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InvokeModelWithResponseStream", "Bedrock-runtime\Models\AnthropicClaude\InvokeModelWithResponseStream\InvokeModelWithResponseStream.csproj", "{345DA0D1-C762-49EF-9953-6F4D57CB7FC7}" @@ -76,7 +75,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Converse", "Bedrock-runtime EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AmazonTitanText", "AmazonTitanText", "{74979310-8A92-47DC-B5CA-EFA7970E1202}" EndProject - Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BedrockRuntimeActions", "Bedrock-runtime\Actions\BedrockRuntimeActions.csproj", "{05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CloudFormation", "CloudFormation", "{5FBEAD92-9234-4824-9320-2052D236C9CD}" @@ -147,206 +145,636 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scenarios", "Scenarios", "{ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Basics", "S3\Scenarios\S3_CreatePresignedPost\Basics.csproj", "{2B6F24A0-4569-E8A2-81B4-3925FA4F0320}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Redshift", "Redshift", "{BC1690DE-FD9E-72EA-CAED-A2B9A3D6B335}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedshiftActions", "Redshift\Actions\RedshiftActions.csproj", "{4E74F2DB-3BA5-4390-8FBF-C58F57601671}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedshiftBasics", "Redshift\Scenarios\RedshiftBasics.csproj", "{A30F8E57-AF18-40EC-B130-140585246CC7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedshiftTests", "Redshift\Tests\RedshiftTests.csproj", "{1DB37AC5-18FE-4535-816C-827B4D3DCB96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {44801438-44F3-4B57-8A5E-3C788A9B2686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {44801438-44F3-4B57-8A5E-3C788A9B2686}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Debug|x64.ActiveCfg = Debug|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Debug|x64.Build.0 = Debug|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Debug|x86.ActiveCfg = Debug|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Debug|x86.Build.0 = Debug|Any CPU {44801438-44F3-4B57-8A5E-3C788A9B2686}.Release|Any CPU.ActiveCfg = Release|Any CPU {44801438-44F3-4B57-8A5E-3C788A9B2686}.Release|Any CPU.Build.0 = Release|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Release|x64.ActiveCfg = Release|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Release|x64.Build.0 = Release|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Release|x86.ActiveCfg = Release|Any CPU + {44801438-44F3-4B57-8A5E-3C788A9B2686}.Release|x86.Build.0 = Release|Any CPU {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Debug|x64.ActiveCfg = Debug|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Debug|x64.Build.0 = Debug|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Debug|x86.ActiveCfg = Debug|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Debug|x86.Build.0 = Debug|Any CPU {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Release|Any CPU.ActiveCfg = Release|Any CPU {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Release|Any CPU.Build.0 = Release|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Release|x64.ActiveCfg = Release|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Release|x64.Build.0 = Release|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Release|x86.ActiveCfg = Release|Any CPU + {67C93719-C71C-44C3-8677-BF9C7CD093B6}.Release|x86.Build.0 = Release|Any CPU {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Debug|x64.ActiveCfg = Debug|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Debug|x64.Build.0 = Debug|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Debug|x86.ActiveCfg = Debug|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Debug|x86.Build.0 = Debug|Any CPU {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Release|Any CPU.ActiveCfg = Release|Any CPU {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Release|Any CPU.Build.0 = Release|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Release|x64.ActiveCfg = Release|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Release|x64.Build.0 = Release|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Release|x86.ActiveCfg = Release|Any CPU + {33E362E5-40F3-4C90-A229-44EF3E2389EF}.Release|x86.Build.0 = Release|Any CPU {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Debug|x64.ActiveCfg = Debug|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Debug|x64.Build.0 = Debug|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Debug|x86.ActiveCfg = Debug|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Debug|x86.Build.0 = Debug|Any CPU {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Release|Any CPU.ActiveCfg = Release|Any CPU {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Release|Any CPU.Build.0 = Release|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Release|x64.ActiveCfg = Release|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Release|x64.Build.0 = Release|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Release|x86.ActiveCfg = Release|Any CPU + {28C9796E-9E28-4715-BD44-82CCF4BF8797}.Release|x86.Build.0 = Release|Any CPU {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Debug|x64.ActiveCfg = Debug|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Debug|x64.Build.0 = Debug|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Debug|x86.ActiveCfg = Debug|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Debug|x86.Build.0 = Debug|Any CPU {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Release|Any CPU.ActiveCfg = Release|Any CPU {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Release|Any CPU.Build.0 = Release|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Release|x64.ActiveCfg = Release|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Release|x64.Build.0 = Release|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Release|x86.ActiveCfg = Release|Any CPU + {96B016E8-CDB3-490B-A1BB-6A9008E9E30B}.Release|x86.Build.0 = Release|Any CPU {18B07F62-06CC-4562-BB86-2C072758B90F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {18B07F62-06CC-4562-BB86-2C072758B90F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Debug|x64.ActiveCfg = Debug|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Debug|x64.Build.0 = Debug|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Debug|x86.ActiveCfg = Debug|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Debug|x86.Build.0 = Debug|Any CPU {18B07F62-06CC-4562-BB86-2C072758B90F}.Release|Any CPU.ActiveCfg = Release|Any CPU {18B07F62-06CC-4562-BB86-2C072758B90F}.Release|Any CPU.Build.0 = Release|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Release|x64.ActiveCfg = Release|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Release|x64.Build.0 = Release|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Release|x86.ActiveCfg = Release|Any CPU + {18B07F62-06CC-4562-BB86-2C072758B90F}.Release|x86.Build.0 = Release|Any CPU {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Debug|x64.ActiveCfg = Debug|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Debug|x64.Build.0 = Debug|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Debug|x86.ActiveCfg = Debug|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Debug|x86.Build.0 = Debug|Any CPU {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Release|Any CPU.ActiveCfg = Release|Any CPU {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Release|Any CPU.Build.0 = Release|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Release|x64.ActiveCfg = Release|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Release|x64.Build.0 = Release|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Release|x86.ActiveCfg = Release|Any CPU + {F98B4D67-5A92-4D66-9DAA-8334D65E23B1}.Release|x86.Build.0 = Release|Any CPU {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Debug|x64.ActiveCfg = Debug|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Debug|x64.Build.0 = Debug|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Debug|x86.Build.0 = Debug|Any CPU {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Release|Any CPU.ActiveCfg = Release|Any CPU {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Release|Any CPU.Build.0 = Release|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Release|x64.ActiveCfg = Release|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Release|x64.Build.0 = Release|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Release|x86.ActiveCfg = Release|Any CPU + {C1A6A3FD-5ADD-4489-92E3-D888F256B74A}.Release|x86.Build.0 = Release|Any CPU {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Debug|x64.ActiveCfg = Debug|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Debug|x64.Build.0 = Debug|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Debug|x86.ActiveCfg = Debug|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Debug|x86.Build.0 = Debug|Any CPU {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Release|Any CPU.Build.0 = Release|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Release|x64.ActiveCfg = Release|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Release|x64.Build.0 = Release|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Release|x86.ActiveCfg = Release|Any CPU + {F8B5BC77-F8BF-45E8-8E12-7E197F925772}.Release|x86.Build.0 = Release|Any CPU {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Debug|x64.ActiveCfg = Debug|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Debug|x64.Build.0 = Debug|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Debug|x86.ActiveCfg = Debug|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Debug|x86.Build.0 = Debug|Any CPU {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Release|Any CPU.ActiveCfg = Release|Any CPU {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Release|Any CPU.Build.0 = Release|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Release|x64.ActiveCfg = Release|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Release|x64.Build.0 = Release|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Release|x86.ActiveCfg = Release|Any CPU + {37CACA7D-D3BE-42AF-A8C2-639E16C03BC4}.Release|x86.Build.0 = Release|Any CPU {7B624438-4340-4333-B2F6-2ADA7A93006C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B624438-4340-4333-B2F6-2ADA7A93006C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Debug|x64.ActiveCfg = Debug|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Debug|x64.Build.0 = Debug|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Debug|x86.ActiveCfg = Debug|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Debug|x86.Build.0 = Debug|Any CPU {7B624438-4340-4333-B2F6-2ADA7A93006C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B624438-4340-4333-B2F6-2ADA7A93006C}.Release|Any CPU.Build.0 = Release|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Release|x64.ActiveCfg = Release|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Release|x64.Build.0 = Release|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Release|x86.ActiveCfg = Release|Any CPU + {7B624438-4340-4333-B2F6-2ADA7A93006C}.Release|x86.Build.0 = Release|Any CPU {F60B3806-CC22-470E-80EE-2E480912CE4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F60B3806-CC22-470E-80EE-2E480912CE4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Debug|x64.ActiveCfg = Debug|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Debug|x64.Build.0 = Debug|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Debug|x86.ActiveCfg = Debug|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Debug|x86.Build.0 = Debug|Any CPU {F60B3806-CC22-470E-80EE-2E480912CE4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F60B3806-CC22-470E-80EE-2E480912CE4D}.Release|Any CPU.Build.0 = Release|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Release|x64.ActiveCfg = Release|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Release|x64.Build.0 = Release|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Release|x86.ActiveCfg = Release|Any CPU + {F60B3806-CC22-470E-80EE-2E480912CE4D}.Release|x86.Build.0 = Release|Any CPU {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Debug|x64.ActiveCfg = Debug|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Debug|x64.Build.0 = Debug|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Debug|x86.ActiveCfg = Debug|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Debug|x86.Build.0 = Debug|Any CPU {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Release|Any CPU.ActiveCfg = Release|Any CPU {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Release|Any CPU.Build.0 = Release|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Release|x64.ActiveCfg = Release|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Release|x64.Build.0 = Release|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Release|x86.ActiveCfg = Release|Any CPU + {E264ABD1-EDC9-4E8E-B828-9CA239792051}.Release|x86.Build.0 = Release|Any CPU {44E0145A-684C-466D-8258-171AF9751D95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {44E0145A-684C-466D-8258-171AF9751D95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Debug|x64.ActiveCfg = Debug|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Debug|x64.Build.0 = Debug|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Debug|x86.ActiveCfg = Debug|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Debug|x86.Build.0 = Debug|Any CPU {44E0145A-684C-466D-8258-171AF9751D95}.Release|Any CPU.ActiveCfg = Release|Any CPU {44E0145A-684C-466D-8258-171AF9751D95}.Release|Any CPU.Build.0 = Release|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Release|x64.ActiveCfg = Release|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Release|x64.Build.0 = Release|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Release|x86.ActiveCfg = Release|Any CPU + {44E0145A-684C-466D-8258-171AF9751D95}.Release|x86.Build.0 = Release|Any CPU {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Debug|x64.ActiveCfg = Debug|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Debug|x64.Build.0 = Debug|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Debug|x86.ActiveCfg = Debug|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Debug|x86.Build.0 = Debug|Any CPU {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Release|Any CPU.ActiveCfg = Release|Any CPU {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Release|Any CPU.Build.0 = Release|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Release|x64.ActiveCfg = Release|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Release|x64.Build.0 = Release|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Release|x86.ActiveCfg = Release|Any CPU + {112C5C1D-F0A6-4068-A9EB-6047CA1F5CDF}.Release|x86.Build.0 = Release|Any CPU {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Debug|x64.ActiveCfg = Debug|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Debug|x64.Build.0 = Debug|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Debug|x86.ActiveCfg = Debug|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Debug|x86.Build.0 = Debug|Any CPU {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Release|Any CPU.ActiveCfg = Release|Any CPU {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Release|Any CPU.Build.0 = Release|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Release|x64.ActiveCfg = Release|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Release|x64.Build.0 = Release|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Release|x86.ActiveCfg = Release|Any CPU + {51F052FC-2DCB-48AF-A4D3-5C42C8C5F713}.Release|x86.Build.0 = Release|Any CPU {A350D217-DC32-4537-8A9C-167B560CAF75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A350D217-DC32-4537-8A9C-167B560CAF75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Debug|x64.ActiveCfg = Debug|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Debug|x64.Build.0 = Debug|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Debug|x86.ActiveCfg = Debug|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Debug|x86.Build.0 = Debug|Any CPU {A350D217-DC32-4537-8A9C-167B560CAF75}.Release|Any CPU.ActiveCfg = Release|Any CPU {A350D217-DC32-4537-8A9C-167B560CAF75}.Release|Any CPU.Build.0 = Release|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Release|x64.ActiveCfg = Release|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Release|x64.Build.0 = Release|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Release|x86.ActiveCfg = Release|Any CPU + {A350D217-DC32-4537-8A9C-167B560CAF75}.Release|x86.Build.0 = Release|Any CPU {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Debug|x64.ActiveCfg = Debug|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Debug|x64.Build.0 = Debug|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Debug|x86.ActiveCfg = Debug|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Debug|x86.Build.0 = Debug|Any CPU {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Release|Any CPU.ActiveCfg = Release|Any CPU {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Release|Any CPU.Build.0 = Release|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Release|x64.ActiveCfg = Release|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Release|x64.Build.0 = Release|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Release|x86.ActiveCfg = Release|Any CPU + {9A433C22-4811-4AD9-99C1-3DF85D9FB54B}.Release|x86.Build.0 = Release|Any CPU {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Debug|x64.ActiveCfg = Debug|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Debug|x64.Build.0 = Debug|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Debug|x86.ActiveCfg = Debug|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Debug|x86.Build.0 = Debug|Any CPU {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Release|Any CPU.ActiveCfg = Release|Any CPU {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Release|Any CPU.Build.0 = Release|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Release|x64.ActiveCfg = Release|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Release|x64.Build.0 = Release|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Release|x86.ActiveCfg = Release|Any CPU + {81EA8494-176C-4178-A1C3-6FA3B1222B74}.Release|x86.Build.0 = Release|Any CPU {085F3A30-A788-48D6-8067-74D71C29A941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {085F3A30-A788-48D6-8067-74D71C29A941}.Debug|Any CPU.Build.0 = Debug|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Debug|x64.ActiveCfg = Debug|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Debug|x64.Build.0 = Debug|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Debug|x86.ActiveCfg = Debug|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Debug|x86.Build.0 = Debug|Any CPU {085F3A30-A788-48D6-8067-74D71C29A941}.Release|Any CPU.ActiveCfg = Release|Any CPU {085F3A30-A788-48D6-8067-74D71C29A941}.Release|Any CPU.Build.0 = Release|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Release|x64.ActiveCfg = Release|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Release|x64.Build.0 = Release|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Release|x86.ActiveCfg = Release|Any CPU + {085F3A30-A788-48D6-8067-74D71C29A941}.Release|x86.Build.0 = Release|Any CPU {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Debug|x64.ActiveCfg = Debug|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Debug|x64.Build.0 = Debug|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Debug|x86.ActiveCfg = Debug|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Debug|x86.Build.0 = Debug|Any CPU {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Release|Any CPU.ActiveCfg = Release|Any CPU {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Release|Any CPU.Build.0 = Release|Any CPU - + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Release|x64.ActiveCfg = Release|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Release|x64.Build.0 = Release|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Release|x86.ActiveCfg = Release|Any CPU + {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716}.Release|x86.Build.0 = Release|Any CPU {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Debug|x64.ActiveCfg = Debug|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Debug|x64.Build.0 = Debug|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Debug|x86.ActiveCfg = Debug|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Debug|x86.Build.0 = Debug|Any CPU {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Release|Any CPU.ActiveCfg = Release|Any CPU {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Release|Any CPU.Build.0 = Release|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Release|x64.ActiveCfg = Release|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Release|x64.Build.0 = Release|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Release|x86.ActiveCfg = Release|Any CPU + {345DA0D1-C762-49EF-9953-6F4D57CB7FC7}.Release|x86.Build.0 = Release|Any CPU {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Debug|x64.ActiveCfg = Debug|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Debug|x64.Build.0 = Debug|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Debug|x86.ActiveCfg = Debug|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Debug|x86.Build.0 = Debug|Any CPU {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Release|Any CPU.ActiveCfg = Release|Any CPU {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Release|Any CPU.Build.0 = Release|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Release|x64.ActiveCfg = Release|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Release|x64.Build.0 = Release|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Release|x86.ActiveCfg = Release|Any CPU + {C95689B5-C0A1-4C1F-9E97-369D3D397930}.Release|x86.Build.0 = Release|Any CPU {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Debug|x64.ActiveCfg = Debug|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Debug|x64.Build.0 = Debug|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Debug|x86.ActiveCfg = Debug|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Debug|x86.Build.0 = Debug|Any CPU {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Release|Any CPU.ActiveCfg = Release|Any CPU {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Release|Any CPU.Build.0 = Release|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Release|x64.ActiveCfg = Release|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Release|x64.Build.0 = Release|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Release|x86.ActiveCfg = Release|Any CPU + {8551C158-60B4-4594-8B1D-5BE851F90EE4}.Release|x86.Build.0 = Release|Any CPU {874C7405-ED8D-477D-9362-0C69CF56F213}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {874C7405-ED8D-477D-9362-0C69CF56F213}.Debug|Any CPU.Build.0 = Debug|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Debug|x64.ActiveCfg = Debug|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Debug|x64.Build.0 = Debug|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Debug|x86.ActiveCfg = Debug|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Debug|x86.Build.0 = Debug|Any CPU {874C7405-ED8D-477D-9362-0C69CF56F213}.Release|Any CPU.ActiveCfg = Release|Any CPU {874C7405-ED8D-477D-9362-0C69CF56F213}.Release|Any CPU.Build.0 = Release|Any CPU - + {874C7405-ED8D-477D-9362-0C69CF56F213}.Release|x64.ActiveCfg = Release|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Release|x64.Build.0 = Release|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Release|x86.ActiveCfg = Release|Any CPU + {874C7405-ED8D-477D-9362-0C69CF56F213}.Release|x86.Build.0 = Release|Any CPU {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Debug|x64.ActiveCfg = Debug|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Debug|x64.Build.0 = Debug|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Debug|x86.ActiveCfg = Debug|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Debug|x86.Build.0 = Debug|Any CPU {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Release|Any CPU.ActiveCfg = Release|Any CPU {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Release|Any CPU.Build.0 = Release|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Release|x64.ActiveCfg = Release|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Release|x64.Build.0 = Release|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Release|x86.ActiveCfg = Release|Any CPU + {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D}.Release|x86.Build.0 = Release|Any CPU {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Debug|x64.ActiveCfg = Debug|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Debug|x64.Build.0 = Debug|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Debug|x86.ActiveCfg = Debug|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Debug|x86.Build.0 = Debug|Any CPU {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Release|Any CPU.ActiveCfg = Release|Any CPU {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Release|Any CPU.Build.0 = Release|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Release|x64.ActiveCfg = Release|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Release|x64.Build.0 = Release|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Release|x86.ActiveCfg = Release|Any CPU + {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A}.Release|x86.Build.0 = Release|Any CPU {98A11016-DD41-4848-A848-51D703951A91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {98A11016-DD41-4848-A848-51D703951A91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Debug|x64.ActiveCfg = Debug|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Debug|x64.Build.0 = Debug|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Debug|x86.ActiveCfg = Debug|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Debug|x86.Build.0 = Debug|Any CPU {98A11016-DD41-4848-A848-51D703951A91}.Release|Any CPU.ActiveCfg = Release|Any CPU {98A11016-DD41-4848-A848-51D703951A91}.Release|Any CPU.Build.0 = Release|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Release|x64.ActiveCfg = Release|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Release|x64.Build.0 = Release|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Release|x86.ActiveCfg = Release|Any CPU + {98A11016-DD41-4848-A848-51D703951A91}.Release|x86.Build.0 = Release|Any CPU {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Debug|x64.ActiveCfg = Debug|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Debug|x64.Build.0 = Debug|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Debug|x86.ActiveCfg = Debug|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Debug|x86.Build.0 = Debug|Any CPU {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Release|Any CPU.ActiveCfg = Release|Any CPU {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Release|Any CPU.Build.0 = Release|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Release|x64.ActiveCfg = Release|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Release|x64.Build.0 = Release|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Release|x86.ActiveCfg = Release|Any CPU + {106FBE12-6FF7-40DC-9B3C-E5F67F335B32}.Release|x86.Build.0 = Release|Any CPU {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Debug|Any CPU.Build.0 = Debug|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Debug|x64.ActiveCfg = Debug|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Debug|x64.Build.0 = Debug|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Debug|x86.ActiveCfg = Debug|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Debug|x86.Build.0 = Debug|Any CPU {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Release|Any CPU.ActiveCfg = Release|Any CPU {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Release|Any CPU.Build.0 = Release|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Release|x64.ActiveCfg = Release|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Release|x64.Build.0 = Release|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Release|x86.ActiveCfg = Release|Any CPU + {565A9701-3D9C-49F8-86B7-D256A1D9E074}.Release|x86.Build.0 = Release|Any CPU {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Debug|x64.Build.0 = Debug|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Debug|x86.ActiveCfg = Debug|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Debug|x86.Build.0 = Debug|Any CPU {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Release|Any CPU.ActiveCfg = Release|Any CPU {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Release|Any CPU.Build.0 = Release|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Release|x64.ActiveCfg = Release|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Release|x64.Build.0 = Release|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Release|x86.ActiveCfg = Release|Any CPU + {EAF4A3B8-5CD0-48ED-B848-0EA6D451B8D3}.Release|x86.Build.0 = Release|Any CPU {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Debug|x64.ActiveCfg = Debug|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Debug|x64.Build.0 = Debug|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Debug|x86.ActiveCfg = Debug|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Debug|x86.Build.0 = Debug|Any CPU {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Release|Any CPU.ActiveCfg = Release|Any CPU {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Release|Any CPU.Build.0 = Release|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Release|x64.ActiveCfg = Release|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Release|x64.Build.0 = Release|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Release|x86.ActiveCfg = Release|Any CPU + {C99A0F7C-9477-4985-90F6-8EED38ECAC10}.Release|x86.Build.0 = Release|Any CPU {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Debug|x64.ActiveCfg = Debug|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Debug|x64.Build.0 = Debug|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Debug|x86.ActiveCfg = Debug|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Debug|x86.Build.0 = Debug|Any CPU {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Release|Any CPU.ActiveCfg = Release|Any CPU {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Release|Any CPU.Build.0 = Release|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Release|x64.ActiveCfg = Release|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Release|x64.Build.0 = Release|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Release|x86.ActiveCfg = Release|Any CPU + {D95519CA-BD27-45AE-B83B-3FB02E7AE445}.Release|x86.Build.0 = Release|Any CPU {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Debug|x64.ActiveCfg = Debug|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Debug|x64.Build.0 = Debug|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Debug|x86.ActiveCfg = Debug|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Debug|x86.Build.0 = Debug|Any CPU {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Release|Any CPU.Build.0 = Release|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Release|x64.ActiveCfg = Release|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Release|x64.Build.0 = Release|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Release|x86.ActiveCfg = Release|Any CPU + {0633CB2B-3508-48E5-A8C2-427A83A5CA6E}.Release|x86.Build.0 = Release|Any CPU {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Debug|x64.ActiveCfg = Debug|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Debug|x64.Build.0 = Debug|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Debug|x86.ActiveCfg = Debug|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Debug|x86.Build.0 = Debug|Any CPU {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Release|Any CPU.ActiveCfg = Release|Any CPU {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Release|Any CPU.Build.0 = Release|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Release|x64.ActiveCfg = Release|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Release|x64.Build.0 = Release|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Release|x86.ActiveCfg = Release|Any CPU + {63DC05A0-5B16-45A4-BDE5-90DD2E200507}.Release|x86.Build.0 = Release|Any CPU {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Debug|x64.ActiveCfg = Debug|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Debug|x64.Build.0 = Debug|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Debug|x86.ActiveCfg = Debug|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Debug|x86.Build.0 = Debug|Any CPU {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Release|Any CPU.ActiveCfg = Release|Any CPU {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Release|Any CPU.Build.0 = Release|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Release|x64.ActiveCfg = Release|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Release|x64.Build.0 = Release|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Release|x86.ActiveCfg = Release|Any CPU + {38C8C3B0-163D-4B7B-86A2-3EFFBC165E99}.Release|x86.Build.0 = Release|Any CPU {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Debug|x64.ActiveCfg = Debug|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Debug|x64.Build.0 = Debug|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Debug|x86.ActiveCfg = Debug|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Debug|x86.Build.0 = Debug|Any CPU {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Release|Any CPU.ActiveCfg = Release|Any CPU {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Release|Any CPU.Build.0 = Release|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Release|x64.ActiveCfg = Release|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Release|x64.Build.0 = Release|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Release|x86.ActiveCfg = Release|Any CPU + {1AF980DF-DEEA-4E5D-9001-6EC67EB96AD1}.Release|x86.Build.0 = Release|Any CPU {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Debug|x64.Build.0 = Debug|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Debug|x86.Build.0 = Debug|Any CPU {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Release|Any CPU.Build.0 = Release|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Release|x64.ActiveCfg = Release|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Release|x64.Build.0 = Release|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Release|x86.ActiveCfg = Release|Any CPU + {3F159C49-3DE7-42F5-AF14-E64C03AF19E8}.Release|x86.Build.0 = Release|Any CPU {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Debug|x64.ActiveCfg = Debug|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Debug|x64.Build.0 = Debug|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Debug|x86.ActiveCfg = Debug|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Debug|x86.Build.0 = Debug|Any CPU {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Release|Any CPU.ActiveCfg = Release|Any CPU {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Release|Any CPU.Build.0 = Release|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Release|x64.ActiveCfg = Release|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Release|x64.Build.0 = Release|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Release|x86.ActiveCfg = Release|Any CPU + {D44D50E1-EC65-4A1C-AAA1-C360E4FC563F}.Release|x86.Build.0 = Release|Any CPU {7485EAED-F81C-4119-BABC-E009A21ACE46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7485EAED-F81C-4119-BABC-E009A21ACE46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Debug|x64.ActiveCfg = Debug|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Debug|x64.Build.0 = Debug|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Debug|x86.ActiveCfg = Debug|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Debug|x86.Build.0 = Debug|Any CPU {7485EAED-F81C-4119-BABC-E009A21ACE46}.Release|Any CPU.ActiveCfg = Release|Any CPU {7485EAED-F81C-4119-BABC-E009A21ACE46}.Release|Any CPU.Build.0 = Release|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Release|x64.ActiveCfg = Release|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Release|x64.Build.0 = Release|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Release|x86.ActiveCfg = Release|Any CPU + {7485EAED-F81C-4119-BABC-E009A21ACE46}.Release|x86.Build.0 = Release|Any CPU {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Debug|x64.ActiveCfg = Debug|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Debug|x64.Build.0 = Debug|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Debug|x86.ActiveCfg = Debug|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Debug|x86.Build.0 = Debug|Any CPU {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Release|Any CPU.ActiveCfg = Release|Any CPU {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Release|Any CPU.Build.0 = Release|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Release|x64.ActiveCfg = Release|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Release|x64.Build.0 = Release|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Release|x86.ActiveCfg = Release|Any CPU + {43C5E98B-5EC4-9F2B-2676-8F1E34969855}.Release|x86.Build.0 = Release|Any CPU {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Debug|x64.ActiveCfg = Debug|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Debug|x64.Build.0 = Debug|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Debug|x86.ActiveCfg = Debug|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Debug|x86.Build.0 = Debug|Any CPU {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Release|Any CPU.Build.0 = Release|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Release|x64.ActiveCfg = Release|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Release|x64.Build.0 = Release|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Release|x86.ActiveCfg = Release|Any CPU + {6B1F00FF-7F1D-C5D8-A8D3-E0EF2886B8C6}.Release|x86.Build.0 = Release|Any CPU {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Debug|x64.Build.0 = Debug|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Debug|x86.ActiveCfg = Debug|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Debug|x86.Build.0 = Debug|Any CPU {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Release|Any CPU.Build.0 = Release|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Release|x64.ActiveCfg = Release|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Release|x64.Build.0 = Release|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Release|x86.ActiveCfg = Release|Any CPU + {9D601495-FDBA-C852-4ACB-EC54EDC9B3E5}.Release|x86.Build.0 = Release|Any CPU {F578CA07-E74F-4F47-9203-C67777D9BB78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F578CA07-E74F-4F47-9203-C67777D9BB78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Debug|x64.ActiveCfg = Debug|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Debug|x64.Build.0 = Debug|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Debug|x86.ActiveCfg = Debug|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Debug|x86.Build.0 = Debug|Any CPU {F578CA07-E74F-4F47-9203-C67777D9BB78}.Release|Any CPU.ActiveCfg = Release|Any CPU {F578CA07-E74F-4F47-9203-C67777D9BB78}.Release|Any CPU.Build.0 = Release|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Release|x64.ActiveCfg = Release|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Release|x64.Build.0 = Release|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Release|x86.ActiveCfg = Release|Any CPU + {F578CA07-E74F-4F47-9203-C67777D9BB78}.Release|x86.Build.0 = Release|Any CPU {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Debug|x64.ActiveCfg = Debug|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Debug|x64.Build.0 = Debug|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Debug|x86.ActiveCfg = Debug|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Debug|x86.Build.0 = Debug|Any CPU {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Release|Any CPU.Build.0 = Release|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Release|x64.ActiveCfg = Release|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Release|x64.Build.0 = Release|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Release|x86.ActiveCfg = Release|Any CPU + {E10920BB-6409-41BB-9A9D-813BC37CC3C0}.Release|x86.Build.0 = Release|Any CPU {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Debug|x64.ActiveCfg = Debug|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Debug|x64.Build.0 = Debug|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Debug|x86.ActiveCfg = Debug|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Debug|x86.Build.0 = Debug|Any CPU {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Release|Any CPU.Build.0 = Release|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Release|x64.ActiveCfg = Release|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Release|x64.Build.0 = Release|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Release|x86.ActiveCfg = Release|Any CPU + {B0F91FE2-6AC5-4FA8-B321-54623A516D4D}.Release|x86.Build.0 = Release|Any CPU {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Debug|x64.ActiveCfg = Debug|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Debug|x64.Build.0 = Debug|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Debug|x86.ActiveCfg = Debug|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Debug|x86.Build.0 = Debug|Any CPU {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Release|Any CPU.ActiveCfg = Release|Any CPU {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Release|Any CPU.Build.0 = Release|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Release|x64.ActiveCfg = Release|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Release|x64.Build.0 = Release|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Release|x86.ActiveCfg = Release|Any CPU + {11497EB7-B702-B537-3CBE-BA2F4F85F313}.Release|x86.Build.0 = Release|Any CPU {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Debug|x64.ActiveCfg = Debug|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Debug|x64.Build.0 = Debug|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Debug|x86.ActiveCfg = Debug|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Debug|x86.Build.0 = Debug|Any CPU {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Release|Any CPU.Build.0 = Release|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Release|x64.ActiveCfg = Release|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Release|x64.Build.0 = Release|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Release|x86.ActiveCfg = Release|Any CPU + {2B6F24A0-4569-E8A2-81B4-3925FA4F0320}.Release|x86.Build.0 = Release|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Debug|x64.ActiveCfg = Debug|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Debug|x64.Build.0 = Debug|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Debug|x86.ActiveCfg = Debug|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Debug|x86.Build.0 = Debug|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Release|Any CPU.Build.0 = Release|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Release|x64.ActiveCfg = Release|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Release|x64.Build.0 = Release|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Release|x86.ActiveCfg = Release|Any CPU + {4E74F2DB-3BA5-4390-8FBF-C58F57601671}.Release|x86.Build.0 = Release|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Debug|x64.ActiveCfg = Debug|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Debug|x64.Build.0 = Debug|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Debug|x86.ActiveCfg = Debug|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Debug|x86.Build.0 = Debug|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Release|Any CPU.Build.0 = Release|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Release|x64.ActiveCfg = Release|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Release|x64.Build.0 = Release|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Release|x86.ActiveCfg = Release|Any CPU + {A30F8E57-AF18-40EC-B130-140585246CC7}.Release|x86.Build.0 = Release|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Debug|x64.ActiveCfg = Debug|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Debug|x64.Build.0 = Debug|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Debug|x86.ActiveCfg = Debug|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Debug|x86.Build.0 = Debug|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Release|Any CPU.Build.0 = Release|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Release|x64.ActiveCfg = Release|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Release|x64.Build.0 = Release|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Release|x86.ActiveCfg = Release|Any CPU + {1DB37AC5-18FE-4535-816C-827B4D3DCB96}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -378,14 +806,12 @@ Global {81EA8494-176C-4178-A1C3-6FA3B1222B74} = {39EAAA32-53A8-4641-873C-976FD5963360} {085F3A30-A788-48D6-8067-74D71C29A941} = {39EAAA32-53A8-4641-873C-976FD5963360} {6FCC8A6C-A172-4AAF-A0FC-66C3BD9E8716} = {39EAAA32-53A8-4641-873C-976FD5963360} - {6FF2EDB6-D1B8-4EE0-B1F0-2BCE66972E39} = {4429C078-35C8-4E2B-9C7B-F0C619741B67} {345DA0D1-C762-49EF-9953-6F4D57CB7FC7} = {6FF2EDB6-D1B8-4EE0-B1F0-2BCE66972E39} {C95689B5-C0A1-4C1F-9E97-369D3D397930} = {6FF2EDB6-D1B8-4EE0-B1F0-2BCE66972E39} {8551C158-60B4-4594-8B1D-5BE851F90EE4} = {6FF2EDB6-D1B8-4EE0-B1F0-2BCE66972E39} {874C7405-ED8D-477D-9362-0C69CF56F213} = {6FF2EDB6-D1B8-4EE0-B1F0-2BCE66972E39} {74979310-8A92-47DC-B5CA-EFA7970E1202} = {4429C078-35C8-4E2B-9C7B-F0C619741B67} - {05E93A3E-CFA0-4980-8EE5-CD25C7ED766D} = {D859B39C-9106-4D3D-8C57-11B15FA8106B} {AAFC86EB-49D7-4FD8-8C79-C42C129EB75A} = {5FBEAD92-9234-4824-9320-2052D236C9CD} {98A11016-DD41-4848-A848-51D703951A91} = {5FBEAD92-9234-4824-9320-2052D236C9CD} @@ -414,6 +840,9 @@ Global {11497EB7-B702-B537-3CBE-BA2F4F85F313} = {F929DB74-DD0E-B0EF-AA66-D8703D547BBD} {A65C33EA-4F2E-DE85-7501-4389A2100813} = {F929DB74-DD0E-B0EF-AA66-D8703D547BBD} {2B6F24A0-4569-E8A2-81B4-3925FA4F0320} = {A65C33EA-4F2E-DE85-7501-4389A2100813} + {4E74F2DB-3BA5-4390-8FBF-C58F57601671} = {BC1690DE-FD9E-72EA-CAED-A2B9A3D6B335} + {A30F8E57-AF18-40EC-B130-140585246CC7} = {BC1690DE-FD9E-72EA-CAED-A2B9A3D6B335} + {1DB37AC5-18FE-4535-816C-827B4D3DCB96} = {BC1690DE-FD9E-72EA-CAED-A2B9A3D6B335} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {08502818-E8E1-4A91-A51C-4C8C8D4FF9CA} diff --git a/dotnetv4/Redshift/Actions/HelloRedshift.cs b/dotnetv4/Redshift/Actions/HelloRedshift.cs new file mode 100644 index 00000000000..2527f82d68b --- /dev/null +++ b/dotnetv4/Redshift/Actions/HelloRedshift.cs @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Amazon.Redshift; +using Amazon.Redshift.Model; +using Microsoft.Extensions.Logging; + +namespace RedshiftActions; + +/// +/// Hello Amazon Redshift example. +/// +public class HelloRedshift +{ + private static ILogger logger = null!; + + // snippet-start:[Redshift.dotnetv4.Hello] + /// + /// Main method to run the Hello Amazon Redshift example. + /// + /// Command line arguments (not used). + public static async Task Main(string[] args) + { + var redshiftClient = new AmazonRedshiftClient(); + + Console.WriteLine("Hello, Amazon Redshift! Let's list available clusters:"); + + var clusters = new List(); + + try + { + // Use pagination to retrieve all clusters. + var clustersPaginator = redshiftClient.Paginators.DescribeClusters(new DescribeClustersRequest()); + + await foreach (var response in clustersPaginator.Responses) + { + if (response.Clusters != null) + clusters.AddRange(response.Clusters); + } + + Console.WriteLine($"{clusters.Count} cluster(s) retrieved."); + + foreach (var cluster in clusters) + { + Console.WriteLine($"\t{cluster.ClusterIdentifier} (Status: {cluster.ClusterStatus})"); + } + } + catch (AmazonRedshiftException ex) + { + Console.WriteLine($"Couldn't list clusters. Here's why: {ex.Message}"); + } + catch (Exception ex) + { + Console.WriteLine($"An error occurred: {ex.Message}"); + } + } + // snippet-end:[Redshift.dotnetv4.Hello] +} \ No newline at end of file diff --git a/dotnetv4/Redshift/Actions/RedshiftActions.csproj b/dotnetv4/Redshift/Actions/RedshiftActions.csproj new file mode 100644 index 00000000000..899ba4b8047 --- /dev/null +++ b/dotnetv4/Redshift/Actions/RedshiftActions.csproj @@ -0,0 +1,28 @@ + + + + Exe + net8.0 + enable + latest + RedshiftActions + + + + + + + + + + + + + + + + PreserveNewest + settings.json + + + diff --git a/dotnetv4/Redshift/Actions/RedshiftWrapper.cs b/dotnetv4/Redshift/Actions/RedshiftWrapper.cs new file mode 100644 index 00000000000..acab6f29170 --- /dev/null +++ b/dotnetv4/Redshift/Actions/RedshiftWrapper.cs @@ -0,0 +1,505 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Amazon.Redshift; +using Amazon.Redshift.Model; +using Amazon.RedshiftDataAPIService; +using Amazon.RedshiftDataAPIService.Model; + +namespace RedshiftActions; + +// snippet-start:[Redshift.dotnetv4.RedshiftWrapper] +/// +/// Wrapper class for Amazon Redshift operations. +/// +public class RedshiftWrapper +{ + private readonly IAmazonRedshift _redshiftClient; + private readonly IAmazonRedshiftDataAPIService _redshiftDataClient; + + /// + /// Constructor for RedshiftWrapper. + /// + /// Amazon Redshift client. + /// Amazon Redshift Data API client. + public RedshiftWrapper(IAmazonRedshift redshiftClient, IAmazonRedshiftDataAPIService redshiftDataClient) + { + _redshiftClient = redshiftClient; + _redshiftDataClient = redshiftDataClient; + } + + // snippet-start:[Redshift.dotnetv4.CreateCluster] + /// + /// Create a new Amazon Redshift cluster. + /// + /// The identifier for the cluster. + /// The name of the database. + /// The master username. + /// The master user password. + /// The node type for the cluster. + /// The cluster that was created. + public async Task CreateClusterAsync(string clusterIdentifier, string databaseName, + string masterUsername, string masterUserPassword, string nodeType = "ra3.large") + { + try + { + var request = new CreateClusterRequest + { + ClusterIdentifier = clusterIdentifier, + DBName = databaseName, + MasterUsername = masterUsername, + MasterUserPassword = masterUserPassword, + NodeType = nodeType, + NumberOfNodes = 1, + ClusterType = "single-node" + }; + + var response = await _redshiftClient.CreateClusterAsync(request); + Console.WriteLine($"Created cluster {clusterIdentifier}"); + return response.Cluster; + } + catch (ClusterAlreadyExistsException ex) + { + Console.WriteLine($"Cluster already exists: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't create cluster. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.CreateCluster] + + // snippet-start:[Redshift.dotnetv4.DescribeClusters] + /// + /// Describe Amazon Redshift clusters. + /// + /// Optional cluster identifier to describe a specific cluster. + /// A list of clusters. + public async Task> DescribeClustersAsync(string? clusterIdentifier = null) + { + try + { + var clusters = new List(); + var request = new DescribeClustersRequest(); + if (!string.IsNullOrEmpty(clusterIdentifier)) + { + request.ClusterIdentifier = clusterIdentifier; + } + + var clustersPaginator = _redshiftClient.Paginators.DescribeClusters(request); + await foreach (var response in clustersPaginator.Responses) + { + if (response.Clusters != null) + clusters.AddRange(response.Clusters); + } + + Console.WriteLine($"{clusters.Count} cluster(s) retrieved."); + foreach (var cluster in clusters) + { + Console.WriteLine($"\t{cluster.ClusterIdentifier} (Status: {cluster.ClusterStatus})"); + } + + return clusters; + } + catch (ClusterNotFoundException ex) + { + Console.WriteLine($"Cluster {clusterIdentifier} not found: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't describe clusters. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.DescribeClusters] + + // snippet-start:[Redshift.dotnetv4.ModifyCluster] + /// + /// Modify an Amazon Redshift cluster. + /// + /// The identifier for the cluster. + /// The preferred maintenance window. + /// True if successful. + public async Task ModifyClusterAsync(string clusterIdentifier, string preferredMaintenanceWindow) + { + try + { + var request = new ModifyClusterRequest + { + ClusterIdentifier = clusterIdentifier, + PreferredMaintenanceWindow = preferredMaintenanceWindow + }; + + var response = await _redshiftClient.ModifyClusterAsync(request); + Console.WriteLine($"The modified cluster was successfully modified and has {response.Cluster.PreferredMaintenanceWindow} as the maintenance window"); + return true; + } + catch (ClusterNotFoundException ex) + { + Console.WriteLine($"Cluster {clusterIdentifier} not found: {ex.Message}"); + return false; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't modify cluster. Here's why: {ex.Message}"); + return false; + } + } + // snippet-end:[Redshift.dotnetv4.ModifyCluster] + + // snippet-start:[Redshift.dotnetv4.DeleteCluster] + /// + /// Delete an Amazon Redshift cluster without a final snapshot. + /// + /// The identifier for the cluster. + /// True if successful. + public async Task DeleteClusterWithoutSnapshotAsync(string clusterIdentifier) + { + try + { + var request = new DeleteClusterRequest + { + ClusterIdentifier = clusterIdentifier, + SkipFinalClusterSnapshot = true + }; + + var response = await _redshiftClient.DeleteClusterAsync(request); + Console.WriteLine($"The {clusterIdentifier} was deleted"); + return true; + } + catch (ClusterNotFoundException ex) + { + Console.WriteLine($"Cluster not found: {ex.Message}"); + return false; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't delete cluster. Here's why: {ex.Message}"); + return false; + } + } + // snippet-end:[Redshift.dotnetv4.DeleteCluster] + + // snippet-start:[Redshift.dotnetv4.ListDatabases] + /// + /// List databases in a Redshift cluster. + /// + /// The cluster identifier. + /// The database user. + /// The database name for authentication. + /// A list of database names. + public async Task> ListDatabasesAsync(string clusterIdentifier, string dbUser, string databaseName) + { + try + { + var request = new ListDatabasesRequest + { + ClusterIdentifier = clusterIdentifier, + DbUser = dbUser, + Database = databaseName + }; + + var response = await _redshiftDataClient.ListDatabasesAsync(request); + var databases = new List(); + + foreach (var database in response.Databases) + { + Console.WriteLine($"The database name is : {database}"); + databases.Add(database); + } + + return databases; + } + catch (Amazon.RedshiftDataAPIService.Model.ValidationException ex) + { + Console.WriteLine($"Validation error: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't list databases. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.ListDatabases] + + // snippet-start:[Redshift.dotnetv4.CreateTable] + /// + /// Create a table in the Redshift database. + /// + /// The cluster identifier. + /// The database name. + /// The database user. + /// The statement ID. + public async Task CreateTableAsync(string clusterIdentifier, string database, string dbUser) + { + try + { + var sqlStatement = @" + CREATE TABLE Movies ( + id INTEGER PRIMARY KEY, + title VARCHAR(250) NOT NULL, + year INTEGER NOT NULL + )"; + + var request = new ExecuteStatementRequest + { + ClusterIdentifier = clusterIdentifier, + Database = database, + DbUser = dbUser, + Sql = sqlStatement + }; + + var response = await _redshiftDataClient.ExecuteStatementAsync(request); + await WaitForStatementToCompleteAsync(response.Id); + Console.WriteLine("Table created: Movies"); + return response.Id; + } + catch (Amazon.RedshiftDataAPIService.Model.ValidationException ex) + { + Console.WriteLine($"Validation error: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't create table. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.CreateTable] + + // snippet-start:[Redshift.dotnetv4.Insert] + /// + /// Insert a record into the Movies table using parameterized query. + /// + /// The cluster identifier. + /// The database name. + /// The database user. + /// The movie ID. + /// The movie title. + /// The movie year. + /// The statement ID. + public async Task InsertMovieAsync(string clusterIdentifier, string database, string dbUser, + int id, string title, int year) + { + try + { + var sqlStatement = "INSERT INTO Movies (id, title, year) VALUES (:id, :title, :year)"; + + var request = new ExecuteStatementRequest + { + ClusterIdentifier = clusterIdentifier, + Database = database, + DbUser = dbUser, + Sql = sqlStatement, + Parameters = new List + { + new SqlParameter { Name = "id", Value = id.ToString() }, + new SqlParameter { Name = "title", Value = title }, + new SqlParameter { Name = "year", Value = year.ToString() } + } + }; + + var response = await _redshiftDataClient.ExecuteStatementAsync(request); + await WaitForStatementToCompleteAsync(response.Id); + Console.WriteLine($"Inserted: {title} ({year})"); + return response.Id; + } + catch (Amazon.RedshiftDataAPIService.Model.ValidationException ex) + { + Console.WriteLine($"Validation error: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't insert movie. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.Insert] + + // snippet-start:[Redshift.dotnetv4.Query] + /// + /// Query movies by year using parameterized query. + /// + /// The cluster identifier. + /// The database name. + /// The database user. + /// The year to query. + /// A list of movie titles. + public async Task> QueryMoviesByYearAsync(string clusterIdentifier, string database, + string dbUser, int year) + { + try + { + var sqlStatement = "SELECT title FROM Movies WHERE year = :year"; + + var request = new ExecuteStatementRequest + { + ClusterIdentifier = clusterIdentifier, + Database = database, + DbUser = dbUser, + Sql = sqlStatement, + Parameters = new List + { + new SqlParameter { Name = "year", Value = year.ToString() } + } + }; + + var response = await _redshiftDataClient.ExecuteStatementAsync(request); + Console.WriteLine($"The identifier of the statement is {response.Id}"); + + await WaitForStatementToCompleteAsync(response.Id); + + var results = await GetStatementResultAsync(response.Id); + var movieTitles = new List(); + + foreach (var row in results) + { + if (row.Count > 0) + { + var title = row[0].StringValue; + Console.WriteLine($"The Movie title field is {title}"); + movieTitles.Add(title); + } + } + + return movieTitles; + } + catch (Amazon.RedshiftDataAPIService.Model.ValidationException ex) + { + Console.WriteLine($"Validation error: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't query movies. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.Query] + + // snippet-start:[Redshift.dotnetv4.DescribeStatement] + /// + /// Describe a statement execution. + /// + /// The statement ID. + /// The statement description. + public async Task DescribeStatementAsync(string statementId) + { + try + { + var request = new DescribeStatementRequest + { + Id = statementId + }; + + var response = await _redshiftDataClient.DescribeStatementAsync(request); + return response; + } + catch (Amazon.RedshiftDataAPIService.Model.ResourceNotFoundException ex) + { + Console.WriteLine($"Statement not found: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't describe statement. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.DescribeStatement] + + // snippet-start:[Redshift.dotnetv4.GetStatementResult] + /// + /// Get the results of a statement execution. + /// + /// The statement ID. + /// A list of result rows. + public async Task>> GetStatementResultAsync(string statementId) + { + try + { + var request = new GetStatementResultRequest + { + Id = statementId + }; + + var response = await _redshiftDataClient.GetStatementResultAsync(request); + return response.Records; + } + catch (Amazon.RedshiftDataAPIService.Model.ResourceNotFoundException ex) + { + Console.WriteLine($"Statement not found: {ex.Message}"); + throw; + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't get statement result. Here's why: {ex.Message}"); + throw; + } + } + // snippet-end:[Redshift.dotnetv4.GetStatementResult] + + /// + /// Wait for a statement to complete execution. + /// + /// The statement ID. + /// A task representing the asynchronous operation. + private async Task WaitForStatementToCompleteAsync(string statementId) + { + var status = StatusString.SUBMITTED; + DescribeStatementResponse? response = null; + + while (status == StatusString.SUBMITTED || status == StatusString.PICKED || status == StatusString.STARTED) + { + await Task.Delay(1000); // Wait 1 second + response = await DescribeStatementAsync(statementId); + status = response.Status; + Console.WriteLine($"...{status}"); + } + + if (status == StatusString.FINISHED) + { + Console.WriteLine("The statement is finished!"); + } + else + { + var errorMessage = response?.Error ?? "Unknown error"; + Console.WriteLine($"The statement failed with status: {status}"); + Console.WriteLine($"Error message: {errorMessage}"); + } + } + + /// + /// Wait for a cluster to become available. + /// + /// The cluster identifier. + /// A task representing the asynchronous operation. + public async Task WaitForClusterAvailableAsync(string clusterIdentifier) + { + Console.WriteLine($"Wait until {clusterIdentifier} is available. This may take a few minutes."); + + var startTime = DateTime.Now; + var clusters = await DescribeClustersAsync(clusterIdentifier); + + while (clusters[0].ClusterStatus != "available") + { + var elapsed = DateTime.Now - startTime; + Console.WriteLine($"Elapsed Time: {elapsed:mm\\:ss} - Waiting for cluster..."); + + await Task.Delay(5000); // Wait 5 seconds + clusters = await DescribeClustersAsync(clusterIdentifier); + } + + var totalElapsed = DateTime.Now - startTime; + Console.WriteLine($"Cluster is available! Total Elapsed Time: {totalElapsed:mm\\:ss}"); + } +} +// snippet-end:[Redshift.dotnetv4.RedshiftWrapper] \ No newline at end of file diff --git a/dotnetv4/Redshift/README.md b/dotnetv4/Redshift/README.md new file mode 100644 index 00000000000..6965d9bd97f --- /dev/null +++ b/dotnetv4/Redshift/README.md @@ -0,0 +1,119 @@ +# Amazon Redshift code examples for the SDK for .NET (v4) + +## Overview + +Shows how to use the AWS SDK for .NET (v4) to work with Amazon Redshift. + + + + +_Amazon Redshift is a fast, fully managed, petabyte-scale data warehouse service that makes it simple and cost-effective to efficiently analyze all your data using your existing business intelligence tools._ + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../README.md#Prerequisites) in the `dotnetv4` folder. + + + + + +### Get started + +- [Hello Amazon Redshift](Actions/HelloRedshift.cs#L20) (`DescribeClusters`) + + +### Basics + +Code examples that show you how to perform the essential operations within a service. + +- [Learn the basics](Actions/RedshiftWrapper.cs) + + +### Single actions + +Code excerpts that show you how to call individual service functions. + +- [CreateCluster](Actions/RedshiftWrapper.cs#L34) +- [DeleteCluster](Actions/RedshiftWrapper.cs#L156) +- [DescribeClusters](Actions/RedshiftWrapper.cs#L77) +- [DescribeStatement](Actions/RedshiftWrapper.cs#L388) +- [GetStatementResult](Actions/RedshiftWrapper.cs#L419) +- [ListDatabases](Actions/RedshiftWrapper.cs#L189) +- [ModifyCluster](Actions/RedshiftWrapper.cs#L122) + + + + + +## Run the examples + +### Instructions + + + + + +#### Hello Amazon Redshift + +This example shows you how to get started using Amazon Redshift. + + +#### Learn the basics + +This example shows you how to do the following: + +- Create a Redshift cluster. +- List databases in the cluster. +- Create a table named Movies. +- Populate the Movies table. +- Query the Movies table by year. +- Modify the Redshift cluster. +- Delete the Amazon Redshift cluster. + + + + + + + + + +### Tests + +⚠ Running tests might result in charges to your AWS account. + + +To find instructions for running these tests, see the [README](../README.md#Tests) +in the `dotnetv4` folder. + + + + + + +## Additional resources + +- [Amazon Redshift Management Guide](https://docs.aws.amazon.com/redshift/latest/mgmt/welcome.html) +- [Amazon Redshift API Reference](https://docs.aws.amazon.com/redshift/latest/APIReference/Welcome.html) +- [SDK for .NET (v4) Amazon Redshift reference](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/Redshift/NRedshift.html) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 diff --git a/dotnetv4/Redshift/RedshiftExamples.sln b/dotnetv4/Redshift/RedshiftExamples.sln new file mode 100644 index 00000000000..ca60478e539 --- /dev/null +++ b/dotnetv4/Redshift/RedshiftExamples.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33414.496 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RedshiftActions", "Actions\RedshiftActions.csproj", "{A1B2C3D4-E5F6-4A5B-8C9D-1E2F3A4B5C6D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RedshiftBasics", "Scenarios\RedshiftBasics.csproj", "{C3D4E5F6-A7B8-4C5D-9E1F-3A4B5C6D7E8F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RedshiftTests", "Tests\RedshiftTests.csproj", "{D4E5F6A7-B8C9-4D5E-9F1A-4B5C6D7E8F9A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A1B2C3D4-E5F6-4A5B-8C9D-1E2F3A4B5C6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-1E2F3A4B5C6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-1E2F3A4B5C6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-4A5B-8C9D-1E2F3A4B5C6D}.Release|Any CPU.Build.0 = Release|Any CPU + {C3D4E5F6-A7B8-4C5D-9E1F-3A4B5C6D7E8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3D4E5F6-A7B8-4C5D-9E1F-3A4B5C6D7E8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3D4E5F6-A7B8-4C5D-9E1F-3A4B5C6D7E8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3D4E5F6-A7B8-4C5D-9E1F-3A4B5C6D7E8F}.Release|Any CPU.Build.0 = Release|Any CPU + {D4E5F6A7-B8C9-4D5E-9F1A-4B5C6D7E8F9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4E5F6A7-B8C9-4D5E-9F1A-4B5C6D7E8F9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4E5F6A7-B8C9-4D5E-9F1A-4B5C6D7E8F9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4E5F6A7-B8C9-4D5E-9F1A-4B5C6D7E8F9A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F1A2B3C4-D5E6-4F7A-8B9C-0D1E2F3A4B5C} + EndGlobalSection +EndGlobal diff --git a/dotnetv4/Redshift/Scenarios/RedshiftBasics.cs b/dotnetv4/Redshift/Scenarios/RedshiftBasics.cs new file mode 100644 index 00000000000..6adab87011f --- /dev/null +++ b/dotnetv4/Redshift/Scenarios/RedshiftBasics.cs @@ -0,0 +1,283 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using Amazon.Redshift; +using Amazon.RedshiftDataAPIService; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using RedshiftActions; + +namespace RedshiftBasics; + +// snippet-start:[Redshift.dotnetv4.RedshiftScenario] +/// +/// Amazon Redshift Getting Started Scenario. +/// +public class RedshiftBasics +{ + public static bool IsInteractive = true; + public static RedshiftWrapper? Wrapper = null; + public static ILogger logger = null!; + private static readonly string _moviesFilePath = "../../../../../../resources/sample_files/movies.json"; + + /// + /// Main method for the Amazon Redshift Getting Started scenario. + /// + /// Command line arguments. + public static async Task Main(string[] args) + { + using var host = Host.CreateDefaultBuilder(args) + .ConfigureServices((_, services) => + services.AddAWSService() + .AddAWSService() + .AddTransient() + ) + .Build(); + + logger = LoggerFactory.Create(builder => { builder.AddConsole(); }) + .CreateLogger(); + + Wrapper = host.Services.GetRequiredService(); + + await RunScenarioAsync(); + } + + /// + /// Run the complete Amazon Redshift scenario. + /// + public static async Task RunScenarioAsync() + { + // Set all variables to default values + string userName = "awsuser"; + string userPassword = "AwsUser1000"; + string clusterIdentifier = "redshift-cluster-movies"; + var databaseName = "dev"; + int recordCount = 50; + int year = 2013; + try + { + Console.WriteLine( + "================================================================================"); + Console.WriteLine("Welcome to the Amazon Redshift SDK Getting Started scenario."); + Console.WriteLine( + "This .NET program demonstrates how to interact with Amazon Redshift by using the AWS SDK for .NET."); + Console.WriteLine("Let's get started..."); + Console.WriteLine( + "================================================================================"); + + // Step 1: Get user credentials (if interactive) + if (IsInteractive) + { + Console.WriteLine("Please enter a user name for the cluster (default is awsuser):"); + var userInput = Console.ReadLine(); + if (!string.IsNullOrEmpty(userInput)) + userName = userInput; + + Console.WriteLine("================================================================================"); + Console.WriteLine("Please enter a user password for the cluster (default is AwsUser1000):"); + var passwordInput = Console.ReadLine(); + if (!string.IsNullOrEmpty(passwordInput)) + userPassword = passwordInput; + + Console.WriteLine("================================================================================"); + + // Step 2: Get cluster identifier + Console.WriteLine("Enter a cluster id value (default is redshift-cluster-movies):"); + var clusterInput = Console.ReadLine(); + if (!string.IsNullOrEmpty(clusterInput)) + clusterIdentifier = clusterInput; + } + else + { + Console.WriteLine($"Using default values: userName={userName}, clusterIdentifier={clusterIdentifier}"); + } + + // Step 3: Create Redshift cluster + await Wrapper!.CreateClusterAsync(clusterIdentifier, databaseName, userName, userPassword); + Console.WriteLine("================================================================================"); + + // Step 4: Wait for cluster to become available + Console.WriteLine("================================================================================"); + await Wrapper.WaitForClusterAvailableAsync(clusterIdentifier); + Console.WriteLine("================================================================================"); + + // Step 5: List databases + Console.WriteLine("================================================================================"); + Console.WriteLine($" When you created {clusterIdentifier}, the dev database is created by default and used in this scenario."); + Console.WriteLine(" To create a custom database, you need to have a CREATEDB privilege."); + Console.WriteLine(" For more information, see the documentation here: https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_DATABASE.html."); + if (IsInteractive) + { + Console.WriteLine("Press Enter to continue..."); + Console.ReadLine(); + } + Console.WriteLine("================================================================================"); + + Console.WriteLine("================================================================================"); + Console.WriteLine($"List databases in {clusterIdentifier}"); + if (IsInteractive) + { + Console.WriteLine("Press Enter to continue..."); + Console.ReadLine(); + } + await Wrapper.ListDatabasesAsync(clusterIdentifier, userName, databaseName); + Console.WriteLine("================================================================================"); + + // Step 6: Create Movies table + Console.WriteLine("================================================================================"); + Console.WriteLine("Now you will create a table named Movies."); + if (IsInteractive) + { + Console.WriteLine("Press Enter to continue..."); + Console.ReadLine(); + } + await Wrapper.CreateTableAsync(clusterIdentifier, databaseName, userName); + Console.WriteLine("================================================================================"); + + // Step 7: Populate the Movies table + Console.WriteLine("================================================================================"); + Console.WriteLine("Populate the Movies table using the Movies.json file."); + + if (IsInteractive) + { + Console.WriteLine("Specify the number of records you would like to add to the Movies Table."); + Console.WriteLine("Please enter a value between 50 and 200."); + Console.Write("Enter a value: "); + + var recordCountInput = Console.ReadLine(); + if (int.TryParse(recordCountInput, out var inputCount) && inputCount is >= 50 and <= 200) + { + recordCount = inputCount; + } + else + { + Console.WriteLine($"Invalid input. Using default value of {recordCount}."); + } + } + else + { + Console.WriteLine($"Using default record count: {recordCount}"); + } + + await PopulateMoviesTableAsync(clusterIdentifier, databaseName, userName, recordCount); + Console.WriteLine($"{recordCount} records were added to the Movies table."); + Console.WriteLine("================================================================================"); + + // Step 8 & 9: Query movies by year + Console.WriteLine("================================================================================"); + Console.WriteLine("Query the Movies table by year. Enter a value between 2012-2014."); + + if (IsInteractive) + { + Console.Write("Enter a year: "); + var yearInput = Console.ReadLine(); + if (int.TryParse(yearInput, out var inputYear) && inputYear is >= 2012 and <= 2014) + { + year = inputYear; + } + else + { + Console.WriteLine($"Invalid input. Using default value of {year}."); + } + } + else + { + Console.WriteLine($"Using default year: {year}"); + } + + await Wrapper.QueryMoviesByYearAsync(clusterIdentifier, databaseName, userName, year); + Console.WriteLine("================================================================================"); + + // Step 10: Modify the cluster + Console.WriteLine("================================================================================"); + Console.WriteLine("Now you will modify the Redshift cluster."); + if (IsInteractive) + { + Console.WriteLine("Press Enter to continue..."); + Console.ReadLine(); + } + await Wrapper.ModifyClusterAsync(clusterIdentifier, "wed:07:30-wed:08:00"); + Console.WriteLine("================================================================================"); + + // Step 11 & 12: Delete cluster confirmation + Console.WriteLine("================================================================================"); + if (IsInteractive) + { + Console.WriteLine("Would you like to delete the Amazon Redshift cluster? (y/n)"); + var deleteResponse = Console.ReadLine(); + if (deleteResponse?.ToLower() == "y") + { + await Wrapper.DeleteClusterWithoutSnapshotAsync(clusterIdentifier); + } + } + else + { + Console.WriteLine("Deleting the Amazon Redshift cluster..."); + await Wrapper.DeleteClusterWithoutSnapshotAsync(clusterIdentifier); + } + Console.WriteLine("================================================================================"); + + Console.WriteLine("================================================================================"); + Console.WriteLine("This concludes the Amazon Redshift SDK Getting Started scenario."); + Console.WriteLine("================================================================================"); + } + catch (Exception ex) + { + Console.WriteLine($"An error occurred during the scenario: {ex.Message}"); + Console.WriteLine("Deleting the Amazon Redshift cluster..."); + await Wrapper!.DeleteClusterWithoutSnapshotAsync(clusterIdentifier); + throw; + } + } + + /// + /// Populate the Movies table with data from the JSON file. + /// + /// The cluster identifier. + /// The database name. + /// The database user. + /// Number of records to insert. + private static async Task PopulateMoviesTableAsync(string clusterIdentifier, string database, string dbUser, int recordCount) + { + if (!File.Exists(_moviesFilePath)) + { + throw new FileNotFoundException($"Required movies data file not found at: {_moviesFilePath}"); + } + + var jsonContent = await File.ReadAllTextAsync(_moviesFilePath); + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; + var movies = JsonSerializer.Deserialize>(jsonContent, options); + + if (movies == null || movies.Count == 0) + { + throw new InvalidOperationException("Failed to parse movies JSON file or file is empty."); + } + + var insertCount = Math.Min(recordCount, movies.Count); + + for (int i = 0; i < insertCount; i++) + { + var movie = movies[i]; + await Wrapper!.InsertMovieAsync(clusterIdentifier, database, dbUser, i, movie.Title, movie.Year); + } + } + + /// + /// Movie data model. + /// + private class Movie + { + public string Title { get; set; } = string.Empty; + public int Year { get; set; } + } +} +// snippet-end:[Redshift.dotnetv4.RedshiftScenario] \ No newline at end of file diff --git a/dotnetv4/Redshift/Scenarios/RedshiftBasics.csproj b/dotnetv4/Redshift/Scenarios/RedshiftBasics.csproj new file mode 100644 index 00000000000..df3ebce01f5 --- /dev/null +++ b/dotnetv4/Redshift/Scenarios/RedshiftBasics.csproj @@ -0,0 +1,29 @@ + + + + Exe + net8.0 + enable + latest + RedshiftBasics + + + + + + + + + + + + + + + + + PreserveNewest + settings.json + + + diff --git a/dotnetv4/Redshift/Tests/RedshiftIntegrationTests.cs b/dotnetv4/Redshift/Tests/RedshiftIntegrationTests.cs new file mode 100644 index 00000000000..89eb84f403c --- /dev/null +++ b/dotnetv4/Redshift/Tests/RedshiftIntegrationTests.cs @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Threading.Tasks; +using Amazon.Redshift; +using Amazon.RedshiftDataAPIService; +using Microsoft.Extensions.Logging; +using Moq; +using RedshiftActions; +using Xunit; + +namespace RedshiftTests; + +/// +/// Integration tests for the AWS Redshift Basics scenario. +/// +public class RedshiftBasicsTests +{ + /// + /// Verifies the scenario with an integration test. No errors should be logged. + /// + /// Async task. + [Fact] + [Trait("Category", "Integration")] + public async Task TestScenarioIntegration() + { + // Arrange + RedshiftBasics.RedshiftBasics.IsInteractive = false; + + var loggerScenarioMock = new Mock>(); + + loggerScenarioMock.Setup(logger => logger.Log( + It.Is(logLevel => logLevel == LogLevel.Error), + It.IsAny(), + It.Is((@object, @type) => true), + It.IsAny(), + It.IsAny>() + )); + + // Act + RedshiftBasics.RedshiftBasics.logger = loggerScenarioMock.Object; + + // Act + RedshiftBasics.RedshiftBasics.Wrapper = new RedshiftWrapper( + new AmazonRedshiftClient(), + new AmazonRedshiftDataAPIServiceClient()); + + await RedshiftBasics.RedshiftBasics.RunScenarioAsync(); + + // Assert no errors logged + loggerScenarioMock.Verify( + logger => logger.Log( + It.Is(logLevel => logLevel == LogLevel.Error), + It.IsAny(), + It.Is((@object, @type) => true), + It.IsAny(), + It.IsAny>()), + Times.Never); + } +} \ No newline at end of file diff --git a/dotnetv4/Redshift/Tests/RedshiftTests.csproj b/dotnetv4/Redshift/Tests/RedshiftTests.csproj new file mode 100644 index 00000000000..edcc870eb3b --- /dev/null +++ b/dotnetv4/Redshift/Tests/RedshiftTests.csproj @@ -0,0 +1,38 @@ + + + + net8.0 + false + enable + latest + RedshiftTests + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + PreserveNewest + settings.json + + + diff --git a/scenarios/basics/redshift/SPECIFICATION.md b/scenarios/basics/redshift/SPECIFICATION.md index b518011e2e8..086326c8efe 100644 --- a/scenarios/basics/redshift/SPECIFICATION.md +++ b/scenarios/basics/redshift/SPECIFICATION.md @@ -13,6 +13,20 @@ The following user input is required for this SDK getting started scenario: - The year to use to query records from the database. - Whether or not to delete the Amazon Redshift cluster. +## SQL Statement Requirements + +All SQL statements that include user input or variable data MUST use parameterized queries to prevent SQL injection vulnerabilities. This applies to: + +- INSERT statements when adding movie records (use parameters for id, title, and year values) +- SELECT statements when querying by year (use parameters for the year value) +- Any other SQL operations that incorporate dynamic values + +Example of parameterized query usage: +- Instead of: `SELECT * FROM Movies WHERE year = 2013` +- Use: `SELECT * FROM Movies WHERE year = :year` with a parameter binding for `:year` + +This security best practice ensures that user input is properly escaped and prevents malicious SQL code injection. + ## Hello Redshift This program is intended for users not familiar with the Redshift SDK to easily get up an running. The logic is to show use of `redshiftClient.describeClustersPaginator()`. @@ -148,6 +162,21 @@ This concludes the Amazon Redshift SDK Getting Started scenario. ``` +## Exception Handling + +The following table lists the exceptions that should be caught and handled for each action in the scenario: + +| Action | Exception | Handling | +|---------------------------|--------------------------------|---------------------------------------------------------------------------------------------| +| `createCluster` | ClusterAlreadyExistsFault | Notify the user that a cluster with this identifier already exists and exit. | +| `describeClusters` | ClusterNotFoundFault | Notify the user that the specified cluster was not found. | +| `listDatabases` | ValidationException | Notify the user that the cluster is not available or parameters are invalid. | +| `executeStatement` | ValidationException | Notify the user of SQL syntax errors or invalid query parameters. | +| `describeStatement` | ResourceNotFoundException | Notify the user that the statement ID was not found. | +| `getStatementResult` | ResourceNotFoundException | Notify the user that results are not available for the statement ID. | +| `modifyCluster` | ClusterNotFoundFault | Notify the user that the cluster to modify was not found. | +| `deleteCluster` | ClusterNotFoundFault | Notify the user that the cluster to delete was not found. | + ## SOS Tags The following table describes the metadata used in this SDK Getting Started Scenario. diff --git a/steering_docs/dotnet-tech.md b/steering_docs/dotnet-tech.md index 290814eaf05..4b6b8aca1f7 100644 --- a/steering_docs/dotnet-tech.md +++ b/steering_docs/dotnet-tech.md @@ -45,12 +45,16 @@ dotnet format # Format code - **Documentation**: Include XML documentation explaining the hello example purpose #### Code Structure Standards -- **Namespace naming**: Use reverse domain notation (e.g., `Amazon.DocSamples.S3`) +- **Namespace naming**: Use file-scoped namespaces (e.g., `namespace RedshiftActions;`) - **Class structure**: One public class per file matching filename - **Method naming**: Use PascalCase for method names - **Properties**: Use PascalCase for property names - **Constants**: Use PascalCase for constants - **Async methods**: Suffix with `Async` (e.g., `ListBucketsAsync`) +- **Indentation**: Use 4 spaces (no tabs), proper indentation after file-scoped namespace +- **Target Framework**: .NET 8.0 (`net8.0`) +- **Language Version**: Latest (`latest`) +- **Snippet tags**: Use format `[{Service}.dotnetv4.{ActionName}]` (e.g., `[Redshift.dotnetv4.CreateCluster]`) #### Dependency Injection Patterns ```csharp @@ -130,17 +134,28 @@ public class ExampleClass #### Project Structure ``` -src/ -├── {Service}Examples/ -│ ├── Hello{Service}.cs -│ ├── {Service}Actions.cs -│ ├── {Service}Scenarios.cs -│ └── {Service}Examples.csproj -└── {Service}Examples.Tests/ - ├── {Service}Tests.cs - └── {Service}Examples.Tests.csproj +dotnetv4/{Service}/ +├── Actions/ +│ ├── Hello{Service}.cs # Hello example (with Main method) +│ ├── {Service}Wrapper.cs # Service wrapper class +│ └── {Service}Actions.csproj # Actions project file +├── Scenarios/ +│ ├── {Service}Basics.cs # Basics scenario +│ └── {Service}Basics.csproj # Scenarios project file +├── Tests/ +│ ├── {Service}IntegrationTests.cs # Integration tests only +│ └── {Service}Tests.csproj # Test project file +└── {Service}Examples.sln # Service-specific solution file ``` +**CRITICAL Project Organization Rules:** +- ✅ **Hello examples MUST be in the Actions project** with a Main method +- ✅ **Integration tests ONLY** - no separate unit tests for wrapper methods +- ✅ **No separate Hello project** - Hello is part of Actions +- ✅ **No separate IntegrationTests project** - all tests in Tests project +- ✅ **Create a service-specific solution file** named {Service}Examples.sln +- ✅ **Solution must include**: Actions, Scenarios, and Tests projects only + #### Documentation Requirements - **XML documentation**: Use `///` for class and method documentation - **Parameter documentation**: Document all parameters with `` @@ -176,21 +191,49 @@ src/ - ✅ **ALWAYS create examples in the dotnetv4 directory unless instructed otherwise** - ✅ **ALWAYS follow the established .NET project structure** - ✅ **ALWAYS use PascalCase for .NET identifiers** +- ✅ **ALWAYS use file-scoped namespaces** (namespace Name; instead of namespace Name { }) - ✅ **ALWAYS use using statements for AWS client management** - ✅ **ALWAYS include proper exception handling for AWS service calls** - ✅ **ALWAYS test AWS credentials before assuming credential issues** - ✅ **ALWAYS include comprehensive XML documentation** - ✅ **ALWAYS use async/await patterns for AWS operations** - ✅ **ALWAYS use dependency injection for AWS services** -- ✅ **ALWAYS create a separate class in the Actions project for the Hello example** -- ✅ **ALWAYS add project files to the main solution file DotNetV4Examples.sln** +- ✅ **ALWAYS create Hello example in the Actions project** with a Main method +- ✅ **ALWAYS create a service-specific solution file** (e.g., Redshift.sln) +- ✅ **ALWAYS target .NET 8.0** with latest language version +- ✅ **ALWAYS put integration tests in the Tests project** (no separate IntegrationTests project) - ✅ **ALWAYS put print statements in the action methods if possible** +- ✅ **ALWAYS update package versions** to avoid NU1603 warnings ### Project Configuration Requirements -- **Target Framework**: Specify appropriate .NET version in .csproj -- **AWS SDK packages**: Include specific AWS service NuGet packages -- **Test packages**: Include xUnit and test runner packages +- **Target Framework**: .NET 8.0 (`net8.0`) +- **Language Version**: Latest (`latest`) +- **AWS SDK packages**: Include specific AWS service NuGet packages (use latest versions) +- **Test packages**: Include MSTest and test runner packages - **Configuration**: Support for appsettings.json and environment variables +- **Nullable**: Enable nullable reference types (`enable`) + +### Solution File Management +Each service should have its own solution file in the service directory: + +```bash +# Create solution file +dotnet new sln -n {Service}Examples -o dotnetv4/{Service} + +# Add projects to solution +dotnet sln dotnetv4/{Service}/{Service}Examples.sln add dotnetv4/{Service}/Actions/{Service}Actions.csproj +dotnet sln dotnetv4/{Service}/{Service}Examples.sln add dotnetv4/{Service}/Scenarios/{Service}Basics.csproj +dotnet sln dotnetv4/{Service}/{Service}Examples.sln add dotnetv4/{Service}/Tests/{Service}Tests.csproj + +# Build solution +dotnet build dotnetv4/{Service}/{Service}Examples.sln +``` + +**Solution Structure:** +- ✅ **3 projects only**: Actions, Scenarios, Tests +- ✅ **No solution folders** - flat structure +- ✅ **Service-specific naming**: {Service}Examples.sln (e.g., RedshiftExamples.sln) +- ✅ **Located in service directory**: dotnetv4/{Service}/{Service}Examples.sln ### Integration with Knowledge Base Before creating .NET code examples: diff --git a/steering_docs/dotnet-tech/basics.md b/steering_docs/dotnet-tech/basics.md index 98a94e968bc..b1d0ed452da 100644 --- a/steering_docs/dotnet-tech/basics.md +++ b/steering_docs/dotnet-tech/basics.md @@ -392,4 +392,396 @@ catch (Amazon{Service}Exception ex) - Show before/after states as outlined in specification - Provide context about service capabilities from specification - Include tips and best practices mentioned in specification -- Follow the educational flow described in specification structure \ No newline at end of file +- Follow the educational flow described in specification structure + +--- + +# +.NET v4 Project Organization Standards + +## Overview +This section outlines the standardized project structure and organization for .NET v4 AWS SDK examples, based on the Redshift implementation. + +## Project Structure + +### Directory Layout +``` +dotnetv4/{Service}/ +├── Actions/ +│ ├── Hello{Service}.cs # Hello example (with Main method) +│ ├── {Service}Wrapper.cs # Service wrapper class +│ └── {Service}Actions.csproj # Actions project file +├── Scenarios/ +│ ├── {Service}Basics.cs # Basics scenario +│ └── {Service}Basics.csproj # Scenarios project file +├── Tests/ +│ ├── {Service}IntegrationTests.cs # Integration tests +│ └── {Service}Tests.csproj # Test project file +└── {Service}Examples.sln # Service-specific solution file +``` + +## Critical Organization Rules + +### ✅ DO +- **Create service-specific solution files** in the service directory (e.g., `RedshiftExamples.sln`) +- **Name solution files** as `{Service}Examples.sln` for consistency +- **Include Hello example in Actions project** with a Main method +- **Put integration tests in Tests project** (no separate IntegrationTests project) +- **Use 3 projects only**: Actions, Scenarios, Tests +- **Use flat solution structure** (no solution folders) +- **Target .NET 8.0** with latest language version +- **Use file-scoped namespaces** (namespace Name; instead of namespace Name { }) +- **Update package versions** to latest to avoid NU1603 warnings + +### ❌ DON'T +- **Don't create separate Hello project** - it belongs in Actions +- **Don't create separate IntegrationTests project** - use Tests project +- **Don't use solution folders** - keep flat structure +- **Don't target .NET Framework 4.8** - use .NET 8.0 +- **Don't use traditional namespaces** - use file-scoped +- **Don't create unit tests with mocks** - use integration tests only + +## Project Configuration + +### Actions Project (.csproj) +```xml + + + + Exe + net8.0 + enable + latest + {Service}Actions + + + + + + + + + + + + + + + + PreserveNewest + settings.json + + + +``` + +**Key Points:** +- `Exe` - Required for Hello example Main method +- `net8.0` - Use .NET 8.0 +- `latest` - Enable latest C# features +- Include Microsoft.Extensions packages for dependency injection in Hello example +- Use latest stable AWS SDK package versions (3.7.500 for AWS services) + +### Scenarios Project (.csproj) +```xml + + + + Exe + net8.0 + enable + latest + {Service}Basics + + + + + + + + + + + + + + PreserveNewest + settings.json + + + +``` + +### Tests Project (.csproj) +```xml + + + + net8.0 + false + enable + latest + {Service}Tests + + + + + + + + + + + + + + + + + + PreserveNewest + settings.json + + + +``` + +**Key Points:** +- Use MSTest framework (not xUnit) +- No `` - tests are libraries +- Reference Actions project only +- Use latest stable test framework versions + +## Solution File Management + +### Creating Solution File +```bash +# Navigate to service directory +cd dotnetv4/{Service} + +# Create solution file +dotnet new sln -n {Service}Examples + +# Add projects +dotnet sln {Service}Examples.sln add Actions/{Service}Actions.csproj +dotnet sln {Service}Examples.sln add Scenarios/{Service}Basics.csproj +dotnet sln {Service}Examples.sln add Tests/{Service}Tests.csproj + +# Build solution +dotnet build {Service}Examples.sln +``` + +### Solution File Structure +``` +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33414.496 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "{Service}Actions", "Actions\{Service}Actions.csproj", "{GUID1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "{Service}Basics", "Scenarios\{Service}Basics.csproj", "{GUID2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "{Service}Tests", "Tests\{Service}Tests.csproj", "{GUID3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {GUID1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {GUID1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {GUID1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {GUID1}.Release|Any CPU.Build.0 = Release|Any CPU + {GUID2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {GUID2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {GUID2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {GUID2}.Release|Any CPU.Build.0 = Release|Any CPU + {GUID3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {GUID3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {GUID3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {GUID3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {SOLUTION-GUID} + EndGlobalSection +EndGlobal +``` + +## Code Style Standards + +### File-Scoped Namespaces +```csharp +// ✅ CORRECT - File-scoped namespace +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Threading.Tasks; +using Amazon.Redshift; + +namespace RedshiftActions; + +public class HelloRedshift +{ + public static async Task Main(string[] args) + { + // Implementation + } +} +``` + +```csharp +// ❌ WRONG - Traditional namespace +namespace RedshiftActions +{ + public class HelloRedshift + { + public static async Task Main(string[] args) + { + // Implementation + } + } +} +``` + +### Indentation +- Use 4 spaces (no tabs) +- No extra indentation after file-scoped namespace +- Consistent indentation throughout + +### Snippet Tags +**CRITICAL**: Use the correct snippet tag format for all code examples: + +```csharp +// ✅ CORRECT - Service name first, then dotnetv4 +// snippet-start:[{Service}.dotnetv4.CreateClusterSteering] +public async Task CreateClusterAsync(...) +{ + // Implementation +} +// snippet-end:[{Service}.dotnetv4.CreateClusterSteering] + +// ❌ WRONG - Old format +// snippet-start:[dotnetv4.example_code.redshift.CreateClusterSteering] +// snippet-end:[dotnetv4.example_code.redshift.CreateClusterSteering] +``` + +**Format**: `[{Service}.dotnetv4.{ActionName}]` +- Service name in PascalCase (e.g., Redshift, S3, DynamoDB) +- Followed by `.dotnetv4.` +- Action name in PascalCase (e.g., CreateCluster, ListBuckets, Hello) +- For wrapper class: `[{Service}.dotnetv4.{Service}Wrapper]` +- For scenarios: `[{Service}.dotnetv4.{Service}Scenario]` + +## Testing Standards + +### Integration Tests Only +- **No unit tests with mocks** - test against real AWS services +- **Use MSTest framework** - not xUnit +- **Test complete workflows** - not individual methods +- **Proper resource cleanup** - use ClassCleanup method +- **Use TestCategory attributes** - for test organization + +### Test Class Structure +```csharp +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Threading.Tasks; +using Amazon.Redshift; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using RedshiftActions; + +namespace RedshiftTests; + +[TestClass] +public class RedshiftIntegrationTests +{ + private static RedshiftWrapper? _redshiftWrapper; + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + // Initialize clients + } + + [ClassCleanup] + public static async Task ClassCleanup() + { + // Clean up resources + } + + [TestMethod] + [TestCategory("Integration")] + public async Task TestOperation() + { + // Test implementation + } +} +``` + +## Migration Checklist + +When updating existing projects to new standards: + +- [ ] Create service-specific solution file +- [ ] Move Hello example to Actions project +- [ ] Add `Exe` to Actions project +- [ ] Consolidate integration tests into Tests project +- [ ] Remove separate IntegrationTests project +- [ ] Update all projects to target .NET 8.0 +- [ ] Add `latest` to all projects +- [ ] Convert all namespaces to file-scoped +- [ ] Fix indentation (remove extra level after namespace) +- [ ] Update AWS SDK package versions to latest +- [ ] Remove solution folders (use flat structure) +- [ ] Update test framework to MSTest if using xUnit +- [ ] Remove unit tests with mocks +- [ ] Verify solution builds without warnings + +## Build and Test Commands + +```bash +# Build solution +dotnet build dotnetv4/{Service}/{Service}Examples.sln + +# Run all tests +dotnet test dotnetv4/{Service}/{Service}Examples.sln + +# Run integration tests only +dotnet test dotnetv4/{Service}/Tests/{Service}Tests.csproj --filter TestCategory=Integration + +# Run Hello example +dotnet run --project dotnetv4/{Service}/Actions/{Service}Actions.csproj + +# Run Basics scenario +dotnet run --project dotnetv4/{Service}/Scenarios/{Service}Basics.csproj +``` + +## Common Issues and Solutions + +### Issue: Package version warnings (NU1603) +**Solution:** Update all AWS SDK packages to latest version (e.g., 3.7.401) + +### Issue: C# language version errors +**Solution:** Add `latest` to all project files + +### Issue: Hello example won't run +**Solution:** Ensure Actions project has `Exe` + +### Issue: Build errors after namespace conversion +**Solution:** Check indentation - no extra level after file-scoped namespace + +### Issue: Tests not discovered +**Solution:** Ensure using MSTest attributes ([TestClass], [TestMethod]) + +## References +- Main steering doc: `steering_docs/dotnet-tech.md` +- Hello examples: `steering_docs/dotnet-tech/hello.md` +- Tests: `steering_docs/dotnet-tech/tests.md` +- Wrapper: `steering_docs/dotnet-tech/wrapper.md` diff --git a/steering_docs/dotnet-tech/hello.md b/steering_docs/dotnet-tech/hello.md index 2d50ef4a0c8..4e4b9278042 100644 --- a/steering_docs/dotnet-tech/hello.md +++ b/steering_docs/dotnet-tech/hello.md @@ -32,7 +32,28 @@ Generate simple "Hello" examples that demonstrate basic service connectivity and ## File Structure ``` dotnetv4/{Service}/Actions/ -├── Hello{Service}.cs # Hello example file +├── Hello{Service}.cs # Hello example file (with Main method) +├── {Service}Wrapper.cs # Service wrapper class +└── {Service}Actions.csproj # Actions project file (OutputType=Exe) +``` + +**CRITICAL:** +- ✅ Hello example MUST be in the Actions project +- ✅ Actions project MUST have `Exe` to support Main method +- ✅ NO separate Hello project should be created +- ✅ Actions project MUST include Microsoft.Extensions packages for dependency injection + +**Required NuGet Packages for Actions Project:** +```xml + + + + + + + + + ``` ## Hello Example Pattern @@ -40,59 +61,83 @@ dotnetv4/{Service}/Actions/ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -/// -/// Purpose -/// -/// Shows how to get started with {AWS Service} by {basic operation description}. -/// - using System; +using System.Collections.Generic; using System.Threading.Tasks; using Amazon.{Service}; using Amazon.{Service}.Model; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Console; +using Microsoft.Extensions.Logging.Debug; + +namespace {Service}Actions; -namespace Amazon.DocSamples.{Service} +/// +/// Hello Amazon {Service} example. +/// +public class Hello{Service} { - public class Hello{Service} + private static ILogger logger = null!; + + // snippet-start:[{Service}.dotnetv4.Hello] + /// + /// Main method to run the Hello Amazon {Service} example. + /// + /// Command line arguments (not used). + public static async Task Main(string[] args) { - /// - /// Use the AWS SDK for .NET to create an {AWS Service} client and - /// {basic operation description}. - /// This example uses the default settings specified in your shared credentials - /// and config files. - /// - /// Command line arguments. - public static async Task Main(string[] args) + // Set up dependency injection for Amazon {Service}. + using var host = Host.CreateDefaultBuilder(args) + .ConfigureLogging(logging => + logging.AddFilter("System", LogLevel.Debug) + .AddFilter("Microsoft", LogLevel.Information) + .AddFilter("Microsoft", LogLevel.Trace)) + .ConfigureServices((_, services) => + services.AddAWSService()) + .Build(); + + logger = LoggerFactory.Create(builder => { builder.AddConsole(); }) + .CreateLogger(); + + var {service}Client = host.Services.GetRequiredService(); + + Console.Clear(); + Console.WriteLine("Hello, Amazon {Service}! Let's list available {resources}:"); + Console.WriteLine(); + + var {resources} = new List<{Resource}>(); + + try { - try - { - // Create service client - using var {service}Client = new Amazon{Service}Client(); - - // Perform the most basic operation for this service - var response = await {service}Client.{BasicOperation}Async(); - - Console.WriteLine("Hello, {AWS Service}!"); - // Display appropriate result information - - } - catch (Amazon{Service}Exception ex) + // Use pagination to retrieve all {resources} + var {resources}Paginator = {service}Client.Paginators.List{Resources}(new List{Resources}Request()); + + await foreach (var response in {resources}Paginator.Responses) { - if (ex.ErrorCode == "UnauthorizedOperation") - { - Console.WriteLine("You don't have permission to access {AWS Service}."); - } - else - { - Console.WriteLine($"Couldn't access {AWS Service}. Error: {ex.Message}"); - } + {resources}.AddRange(response.{Resources}); } - catch (Exception ex) + + Console.WriteLine($"{{{resources}.Count}} {resource}(s) retrieved."); + + foreach (var {resource} in {resources}) { - Console.WriteLine($"An unexpected error occurred: {ex.Message}"); + Console.WriteLine($"\t{{{resource}.Name}}"); } } + catch (Amazon{Service}Exception ex) + { + logger.LogError("Error listing {resources}: {Message}", ex.Message); + Console.WriteLine($"Couldn't list {resources}. Error: {ex.Message}"); + } + catch (Exception ex) + { + logger.LogError("An error occurred: {Message}", ex.Message); + Console.WriteLine($"An error occurred: {ex.Message}"); + } } + // snippet-end:[{Service}.dotnetv4.Hello] } ``` @@ -114,13 +159,37 @@ namespace Amazon.DocSamples.{Service} - ✅ **Must run without errors** (with proper credentials) - ✅ **Must handle credential issues gracefully** - ✅ **Must display meaningful output** -- ✅ **Must use direct AWS SDK for .NET client calls** +- ✅ **Must use dependency injection with Host.CreateDefaultBuilder** +- ✅ **Must use pagination for list operations** - ✅ **Must include proper XML documentation** +- ✅ **Must use correct snippet tag format**: `[{Service}.dotnetv4.Hello]` ## Common Patterns -- Always use `new Amazon{Service}Client()` directly +- Use dependency injection with Host.CreateDefaultBuilder +- Use pagination to retrieve all results - Include comprehensive error handling with try-catch blocks - Provide user-friendly output messages using Console.WriteLine - Handle both service-specific and general exceptions -- Keep it as simple as possible - no additional classes or complexity -- Use async/await pattern for all AWS operations \ No newline at end of file +- Keep it as simple as possible - all logic in Main method +- Use async/await pattern for all AWS operations + +## Snippet Tag Format +**CRITICAL**: Use the correct snippet tag format: + +```csharp +// ✅ CORRECT +// snippet-start:[{Service}.dotnetv4.HelloSteering] +public static async Task Main(string[] args) +{ + // Implementation +} +// snippet-end:[{Service}.dotnetv4.HelloSteering] + +// ❌ WRONG - Old format +// snippet-start:[dotnetv4.example_code.{Service}.HelloSteering] +// snippet-end:[dotnetv4.example_code.{Service}.HelloSteering] +``` + +**Format**: `[{Service}.dotnetv4.Hello]` +- Service name in PascalCase (e.g., Redshift, S3, DynamoDB) +- Always use `.dotnetv4.Hello` for Hello examples \ No newline at end of file diff --git a/steering_docs/dotnet-tech/tests.md b/steering_docs/dotnet-tech/tests.md index 6576e7ba8c9..5d63bf90a6a 100644 --- a/steering_docs/dotnet-tech/tests.md +++ b/steering_docs/dotnet-tech/tests.md @@ -21,300 +21,212 @@ read_documentation("https://docs.aws.amazon.com/[service]/latest/[relevant-page] **FAILURE TO COMPLETE KNOWLEDGE BASE CONSULTATION WILL RESULT IN INCORRECT CODE STRUCTURE** ## Purpose -Generate comprehensive test suites including unit tests and integration tests using xUnit framework with proper mocking and AWS data structures. +Generate integration test suites using xUnit framework to validate complete scenario workflows against real AWS services. ## Requirements -- **Complete Data**: Use complete AWS data structures in tests +- **Integration Tests Only**: Focus on end-to-end scenario testing, not unit tests +- **Real AWS Services**: Tests run against actual AWS infrastructure - **Proper Attributes**: Use xUnit attributes for test categorization -- **Error Coverage**: Test all error conditions from specification - **Async Testing**: Use async Task for async test methods +- **Resource Cleanup**: Ensure proper cleanup of AWS resources after tests ## File Structure ``` dotnetv4/{Service}/Tests/ -├── {Service}Tests.csproj # Test project file -├── {Service}Tests.cs # Unit and integration tests +├── {Service}Tests.csproj # Test project file +├── {Service}IntegrationTests.cs # Integration tests ``` +**CRITICAL:** +- ✅ **Integration tests ONLY** - no separate unit tests for wrapper methods +- ✅ **All tests in one project** - no separate IntegrationTests project +- ✅ **Use xUnit framework** - not MSTest +- ✅ **Test against real AWS** - not mocks + ## Test Project Setup ### Step 1: Create Test Project File ```xml + - net8.0 - enable - enable false - true + enable + latest + {Service}Tests - - - - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + - - + + + + PreserveNewest + settings.json + + ``` -### Step 2: Create Test Class Structure -```csharp -// dotnetv4/{Service}/Tests/{Service}Tests.cs -using System; -using System.Threading.Tasks; -using Amazon.{Service}; -using Amazon.{Service}.Model; -using Moq; -using Xunit; -using Xunit.Abstractions; - -namespace Amazon.DocSamples.{Service}.Tests -{ - public class {Service}Tests - { - private readonly ITestOutputHelper _output; - private readonly Mock _mock{Service}Client; - private readonly {Service}Wrapper _wrapper; - - public {Service}Tests(ITestOutputHelper output) - { - _output = output; - _mock{Service}Client = new Mock(); - _wrapper = new {Service}Wrapper(_mock{Service}Client.Object); - } - } -} -``` +**Key Changes:** +- ✅ Use xUnit packages (not MSTest) +- ✅ Target .NET 8.0 with latest language version +- ✅ Use latest AWS SDK package versions +- ✅ Reference Actions project only (no Scenarios reference needed) -## Unit Test Pattern +### Step 2: Create Integration Test Class Structure ```csharp -[Theory] -[InlineData(null)] -[InlineData("BadRequestException")] -[InlineData("InternalServerErrorException")] -public async Task Test{ActionName}Async_WithVariousConditions_ReturnsExpectedResult(string? errorCode) -{ - // Arrange - var paramValue = "test-value"; - var expectedResponse = new {ActionName}Response - { - ResponseKey = "response-value" - }; - - if (errorCode == null) - { - _mock{Service}Client - .Setup(x => x.{ActionName}Async(It.IsAny<{ActionName}Request>(), default)) - .ReturnsAsync(expectedResponse); - } - else - { - _mock{Service}Client - .Setup(x => x.{ActionName}Async(It.IsAny<{ActionName}Request>(), default)) - .ThrowsAsync(new Amazon{Service}Exception(errorCode)); - } - - // Act & Assert - if (errorCode == null) - { - var result = await _wrapper.{ActionName}Async(paramValue); - Assert.Equal("response-value", result.ResponseKey); - } - else - { - var exception = await Assert.ThrowsAsync( - () => _wrapper.{ActionName}Async(paramValue)); - Assert.Equal(errorCode, exception.ErrorCode); - } -} -``` - -## Complete AWS Data Structures - -### CRITICAL: Use Complete AWS Response Data -```csharp -// ❌ WRONG - Minimal data that fails validation -var findings = new List -{ - new Finding { Id = "finding-1", Type = "SomeType", Severity = 8.0 } -}; +// dotnetv4/{Service}/Tests/{Service}IntegrationTests.cs +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 -// ✅ CORRECT - Complete AWS data structure -var findings = new List -{ - new Finding - { - Id = "finding-1", - AccountId = "123456789012", - Arn = "arn:aws:service:region:account:resource/id", - Type = "SomeType", - Severity = 8.0, - CreatedAt = DateTime.Parse("2023-01-01T00:00:00.000Z"), - UpdatedAt = DateTime.Parse("2023-01-01T00:00:00.000Z"), - Region = "us-east-1", - SchemaVersion = "2.0", - Resource = new Resource { ResourceType = "Instance" } - } -}; -``` - -## Integration Test Pattern -Create a single integration test for the scenario by setting IsInteractive to false: - -```csharp -using {Service}Basics; -using Microsoft.Extensions.Logging; -using Moq; +using System.Threading.Tasks; +using Amazon.{Service}; +using Amazon.{ServiceDataAPI}; +using {Service}Actions; using Xunit; namespace {Service}Tests; /// -/// Integration tests for the Amazon {Service} Basics scenario. +/// Integration tests for Amazon {Service} operations. +/// These tests require actual AWS credentials and will create real AWS resources. /// -public class {Service}BasicsTest +public class {Service}IntegrationTests { /// - /// Verifies the scenario with an integration test. No errors should be logged. + /// Verifies the scenario with an integration test. No exceptions should be thrown. /// - /// A task representing the asynchronous test operation. + /// Async task. [Fact] [Trait("Category", "Integration")] - public async Task TestScenario() + public async Task TestScenarioIntegration() { - // Arrange. - {Service}Basics.IsInteractive = false; - var loggerMock = new Mock>(); - loggerMock.Setup(logger => logger.Log( - It.Is(logLevel => logLevel == LogLevel.Error), - It.IsAny(), - It.Is((@object, @type) => true), - It.IsAny(), - It.IsAny>())); - - // Act. - await {Service}Basics.Main(new string[] { "" }); - - // Assert no exceptions or errors logged. - loggerMock.Verify(logger => logger.Log( - It.Is(logLevel => logLevel == LogLevel.Error), - It.IsAny(), - It.Is((@object, @type) => true), - It.IsAny(), - It.IsAny>()), - Times.Never); + // Arrange + {Service}Basics.{Service}Basics.IsInteractive = false; + + // Act + {Service}Basics.{Service}Basics.Wrapper = new {Service}Wrapper( + new Amazon{Service}Client(), + new Amazon{ServiceDataAPI}Client()); + + await {Service}Basics.{Service}Basics.RunScenarioAsync(); + + // Assert - if we get here without exceptions, the test passes } } ``` -## Additional Integration Test Patterns (Optional) -If needed, you can add specific wrapper method tests: +**Key Changes:** +- ✅ Use file-scoped namespaces +- ✅ Use xUnit attributes ([Fact], [Trait]) +- ✅ No mocking - test against real AWS services +- ✅ Test runs the complete scenario end-to-end +- ✅ Set IsInteractive = false for non-interactive test execution + +## Integration Test Patterns + +### Integration Test Pattern +The integration test should run the complete scenario end-to-end: ```csharp +/// +/// Verifies the scenario with an integration test. No exceptions should be thrown. +/// +/// Async task. [Fact] [Trait("Category", "Integration")] -public async Task Test{ActionName}Integration() +public async Task TestScenarioIntegration() { // Arrange - var wrapper = new {Service}Wrapper(new Amazon{Service}Client()); - - // Act - This should not raise an exception - var result = await wrapper.{ActionName}Async(); - - // Assert - Verify result structure - Assert.NotNull(result); -} + {Service}Basics.{Service}Basics.IsInteractive = false; -[Fact] -[Trait("Category", "Integration")] -public async Task TestResourceLifecycleIntegration() -{ - // Arrange - var wrapper = new {Service}Wrapper(new Amazon{Service}Client()); - string? resourceId = null; - - try - { - // Act - Create resource - resourceId = await wrapper.CreateResourceAsync(); - Assert.NotNull(resourceId); - - // Use resource - var result = await wrapper.GetResourceAsync(resourceId); - Assert.NotNull(result); - } - finally - { - // Clean up - if (!string.IsNullOrEmpty(resourceId)) - { - try - { - await wrapper.DeleteResourceAsync(resourceId); - } - catch - { - // Ignore cleanup errors - } - } - } + // Act + {Service}Basics.{Service}Basics.Wrapper = new {Service}Wrapper( + new Amazon{Service}Client(), + new Amazon{ServiceDataAPI}Client()); + + await {Service}Basics.{Service}Basics.RunScenarioAsync(); + + // Assert - if we get here without exceptions, the test passes } ``` +**Key Points:** +- ✅ Use `[Fact]` attribute for test methods +- ✅ Use `[Trait("Category", "Integration")]` for categorization +- ✅ Set `IsInteractive = false` to run without user input +- ✅ Create real AWS clients (not mocked) +- ✅ Call the scenario's `RunScenarioAsync()` method +- ✅ Test passes if no exceptions are thrown + ## Test Execution Commands -### Unit Tests +### All Tests ```bash -dotnet test dotnetv4/{Service}/Tests/{Service}Tests.csproj --filter "Category!=Integration" +dotnet test dotnetv4/{Service}/{Service}Examples.sln ``` -### Integration Tests (Runs Complete Scenario) +### Integration Tests Only ```bash -dotnet test dotnetv4/{Service}/Tests/{Service}Tests.csproj --filter Category=Integration +dotnet test dotnetv4/{Service}/Tests/{Service}Tests.csproj --filter TestCategory=Integration +``` + +### Exclude Long-Running Tests +```bash +dotnet test dotnetv4/{Service}/Tests/{Service}Tests.csproj --filter "TestCategory=Integration&TestCategory!=LongRunning" ``` ## Test Requirements Checklist - ✅ **Test project file created** with proper dependencies -- ✅ **Mock framework setup** (Moq for mocking AWS clients and loggers) -- ✅ **Complete AWS data structures** in all tests -- ✅ **Proper xUnit attributes** (`[Trait("Category", "Integration")]`) -- ✅ **Error condition coverage** per specification -- ✅ **Integration test sets IsInteractive to false** for automated testing -- ✅ **Logger verification** to ensure no errors are logged +- ✅ **xUnit framework** (not MSTest) +- ✅ **Integration tests only** (no unit tests with mocks) +- ✅ **Proper xUnit attributes** (`[Fact]`, `[Trait("Category", "Integration")]`) +- ✅ **Test against real AWS services** (not mocks) +- ✅ **Test runs complete scenario** via `RunScenarioAsync()` - ✅ **Async test methods** using `async Task` +- ✅ **File-scoped namespaces** for modern C# style ## Integration Test Focus ### Primary Test: Complete Scenario Integration The main integration test should: -- ✅ **Run the entire scenario** from start to finish -- ✅ **Set IsInteractive to false** to automate the interactive parts -- ✅ **Test against real AWS** services (not mocks) -- ✅ **Verify no errors are logged** using mock logger verification -- ✅ **Handle cleanup automatically** through scenario logic - -### Test Structure Priority -1. **Integration Test** - Most important, tests complete workflow -2. **Unit Tests** - Test individual wrapper methods -3. **Additional Integration Tests** - Optional, for specific edge cases +- ✅ **Run the entire scenario** from start to finish via `RunScenarioAsync()` +- ✅ **Test against real AWS services** (not mocks) +- ✅ **Set IsInteractive = false** for non-interactive execution +- ✅ **Create real AWS clients** (not mocked) +- ✅ **Use xUnit attributes** (`[Fact]`, `[Trait]`) for test organization +- ✅ **Pass if no exceptions** are thrown during execution + +### Test Structure +- **Single Integration Test** - Tests the complete scenario workflow +- **No separate unit tests** - Focus on end-to-end integration only +- **No mocking** - Use real AWS clients and services ## Common Test Failures to Avoid -- ❌ **Not setting IsInteractive to false** in scenario integration tests -- ❌ **Using incomplete AWS data structures** in unit tests -- ❌ **Missing xUnit attributes** for integration tests -- ❌ **Not verifying logger mock** to ensure no errors are logged +- ❌ **Using mocks instead of real AWS services** in integration tests +- ❌ **Missing xUnit attributes** (`[Fact]`, `[Trait]`) for integration tests +- ❌ **Not setting IsInteractive = false** for non-interactive execution - ❌ **Forgetting to set AWS region** in test clients -- ❌ **Not testing all error conditions** from specification -- ❌ **Not calling Main method properly** in scenario integration tests -- ❌ **Missing proper async/await patterns** in test methods \ No newline at end of file +- ❌ **Missing proper async/await patterns** in test methods +- ❌ **Using MSTest instead of xUnit** framework +- ❌ **Creating separate IntegrationTests project** instead of using Tests project +- ❌ **Not referencing the Scenarios project** when testing scenarios \ No newline at end of file diff --git a/steering_docs/dotnet-tech/wrapper.md b/steering_docs/dotnet-tech/wrapper.md index fe858234bfe..93e215453ad 100644 --- a/steering_docs/dotnet-tech/wrapper.md +++ b/steering_docs/dotnet-tech/wrapper.md @@ -41,94 +41,86 @@ dotnetv4/{Service}/Actions/ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -/// -/// Purpose -/// -/// Shows how to use the AWS SDK for .NET with {AWS Service} to -/// {service description and main use cases}. -/// - using System; using System.Collections.Generic; using System.Threading.Tasks; using Amazon.{Service}; using Amazon.{Service}.Model; -using Microsoft.Extensions.Logging; +using Amazon.{ServiceDataAPI}; +using Amazon.{ServiceDataAPI}.Model; -namespace Amazon.DocSamples.{Service} +namespace {Service}Actions; + +// snippet-start:[{Service}.dotnetv4.{Service}Wrapper] +/// +/// Wrapper class for Amazon {Service} operations. +/// +public class {Service}Wrapper { - // snippet-start:[dotnetv4.example_code.{service}.{Service}Wrapper] + private readonly Amazon{Service}Client _{service}Client; + private readonly Amazon{ServiceDataAPI}Client _{service}DataClient; + /// - /// Encapsulates {AWS Service} functionality. + /// Constructor for {Service}Wrapper. /// - public class {Service}Wrapper + /// Amazon {Service} client. + /// Amazon {Service} Data API client. + public {Service}Wrapper(Amazon{Service}Client {service}Client, Amazon{ServiceDataAPI}Client {service}DataClient) { - private readonly IAmazon{Service} _{service}Client; - private readonly ILogger<{Service}Wrapper> _logger; - - /// - /// Initializes a new instance of the {Service}Wrapper class. - /// - /// The {AWS Service} client. - /// The logger instance. - public {Service}Wrapper(IAmazon{Service} {service}Client, ILogger<{Service}Wrapper> logger) - { - _{service}Client = {service}Client; - _logger = logger; - } - + _{service}Client = {service}Client; + _{service}DataClient = {service}DataClient; } - // snippet-end:[dotnetv4.example_code.{service}.{Service}Wrapper] // Individual action methods follow... } +// snippet-end:[{Service}.dotnetv4.{Service}Wrapper] +``` + +**Key Changes:** +- ✅ Use file-scoped namespaces +- ✅ Use concrete client types (not interfaces) for simpler construction +- ✅ No logger dependency (use Console.WriteLine for output) +- ✅ Include both service client and data API client if needed ``` ## Action Method Pattern ```csharp - // snippet-start:[dotnetv4.example_code.{service}.{ActionName}] - /// - /// {Action description}. - /// - /// Parameter description. - /// Response description. - public async Task<{ActionName}Response> {ActionMethod}Async(string param) + // snippet-start:[{Service}.dotnetv4.{ActionName}] + /// + /// {Action description}. + /// + /// Parameter description. + /// Response description. + public async Task<{ReturnType}> {ActionMethod}Async(string param) + { + try { - try - { - var request = new {ActionName}Request - { - Parameter = param - }; - - var response = await _{service}Client.{ActionName}Async(request); - _logger.LogInformation("{Action} completed successfully", "{ActionName}"); - return response; - } - catch (Amazon{Service}Exception ex) + var request = new {ActionName}Request { - var errorCode = ex.ErrorCode; - if (errorCode == "SpecificError") - { - _logger.LogError("Specific error handling message"); - } - else if (errorCode == "AnotherSpecificError") - { - _logger.LogError("Another specific error handling message"); - } - else - { - _logger.LogError("Error in {ActionName}: {Message}", ex.Message); - } - throw; - } + Parameter = param + }; + + var response = await _{service}Client.{ActionName}Async(request); + Console.WriteLine($"{Action} completed successfully"); + return response.{Property}; } - // snippet-end:[dotnetv4.example_code.{service}.{ActionName}] + catch (Exception ex) + { + Console.WriteLine($"Error in {ActionName}: {ex.Message}"); + throw; + } + } + // snippet-end:[{Service}.dotnetv4.{ActionName}] ``` +**Key Changes:** +- ✅ Use Console.WriteLine instead of logger +- ✅ Simplified error handling (catch Exception instead of service-specific) +- ✅ Return specific types instead of full response objects when appropriate + ## Paginator Pattern for List Operations ```csharp - // snippet-start:[dotnetv4.example_code.{service}.List{Resources}] + // snippet-start:[{Service}.dotnetv4.List{Resources}] /// /// Lists all {resources} using pagination to retrieve complete results. /// @@ -162,12 +154,12 @@ namespace Amazon.DocSamples.{Service} throw; } } - // snippet-end:[dotnetv4.example_code.{service}.List{Resources}] + // snippet-end:[{Service}.dotnetv4.List{Resources}] ``` ## Paginator with Parameters Pattern ```csharp - // snippet-start:[dotnetv4.example_code.{service}.List{Resources}WithFilter] + // snippet-start:[{Service}.dotnetv4.List{Resources}WithFilterSteering] /// /// Lists {resources} with optional filtering, using pagination. /// @@ -200,7 +192,7 @@ namespace Amazon.DocSamples.{Service} throw; } } - // snippet-end:[dotnetv4.example_code.{service}.List{Resources}WithFilter] + // snippet-end:[{Service}.dotnetv4.List{Resources}WithFilterSteering] ``` ## Error Handling Requirements @@ -290,4 +282,26 @@ await foreach (var response in itemsPaginator.Responses) - Document return values with XML tags and descriptions - Include usage examples in XML documentation where helpful - Use proper snippet tags for documentation generation -- Document pagination behavior in list method XML documentation \ No newline at end of file +- Document pagination behavior in list method XML documentation + +## Snippet Tag Format +**CRITICAL**: Use the correct snippet tag format for all code examples: + +```csharp +// ✅ CORRECT - Service name first, then dotnetv4 +// snippet-start:[{Service}.dotnetv4.CreateClusterSteering] +public async Task CreateClusterAsync(...) +{ + // Implementation +} +// snippet-end:[{Service}.dotnetv4.CreateClusterSteering] + +// ❌ WRONG - Old format +// snippet-start:[dotnetv4.example_code.{Service}.CreateClusterSteering] +// snippet-end:[dotnetv4.example_code.{Service}.CreateClusterSteering] +``` + +**Format**: `[{Service}.dotnetv4.{ActionName}]` +- Service name in PascalCase (e.g., Redshift, S3, DynamoDB) +- Followed by `.dotnetv4.` +- Action name in PascalCase (e.g., CreateCluster, ListBuckets, Hello) \ No newline at end of file