-
Notifications
You must be signed in to change notification settings - Fork 322
Add Azure auth sample app #3988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
91c7b8d
Created sample app to demonstrate how all of the SqlClient packages w…
paulmedynski ac29841
Added the AzureAuthentication sample app to the main solution.
paulmedynski 064bccc
Added tracing and logging support.
paulmedynski 66bbe3e
Added .NET Framework support.
paulmedynski 9d6aa75
Removed BOMs and added package versions to help.
paulmedynski 1b49770
Merge branch 'main' into dev/paul/azure-samples
paulmedynski da3c27e
Lots of tidying-up and polish.
paulmedynski d8fbc3d
Addressed Copilot comments.
paulmedynski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| using System.Diagnostics; | ||
|
|
||
| using Microsoft.Data.SqlClient; | ||
| using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; | ||
|
|
||
| namespace Microsoft.Data.SqlClient.Samples.AzureAuthentication; | ||
|
|
||
| /// <summary> | ||
| /// Console application that validates SqlClient connectivity using Entra ID (formerly Azure Active | ||
| /// Directory) authentication. | ||
| /// </summary> | ||
| public class App : IDisposable | ||
| { | ||
| // ────────────────────────────────────────────────────────────────── | ||
| #region Construction / Disposal | ||
|
|
||
| /// <inheritdoc /> | ||
| public void Dispose() | ||
| { | ||
| _eventListener?.Dispose(); | ||
| } | ||
|
|
||
| #endregion | ||
|
|
||
| // ────────────────────────────────────────────────────────────────── | ||
| #region Internal Methods | ||
|
|
||
| /// <summary> | ||
| /// Options for <see cref="Run"/>. | ||
| /// </summary> | ||
| internal class RunOptions | ||
| { | ||
| /// <summary> | ||
| /// The ADO.NET connection string to use. | ||
| /// </summary> | ||
| public string ConnectionString { get; set; } = string.Empty; | ||
|
|
||
| /// <summary> | ||
| /// When <see langword="true"/>, SqlClient events are emitted to the console. | ||
| /// </summary> | ||
| public bool LogEvents { get; set; } = false; | ||
|
|
||
| /// <summary> | ||
| /// When <see langword="true"/>, execution pauses to allow dotnet-trace attachment. | ||
| /// </summary> | ||
| public bool Trace { get; set; } = false; | ||
|
|
||
| /// <summary> | ||
| /// When <see langword="true"/>, detailed error information is displayed. | ||
| /// </summary> | ||
| public bool Verbose { get; set; } = false; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Runs the connectivity test against SQL Server using the specified options. | ||
| /// </summary> | ||
| /// <param name="options">The options controlling the connectivity test.</param> | ||
| /// <returns>0 on success; non-zero on failure.</returns> | ||
| internal int Run(RunOptions options) | ||
| { | ||
| Out($""" | ||
| {AppName} | ||
| --------------------------- | ||
|
|
||
| Packages used: | ||
| SqlClient: {PackageVersions.MicrosoftDataSqlClient} | ||
| AKV Provider: {PackageVersions.MicrosoftDataSqlClientAlwaysEncryptedAzureKeyVaultProvider} | ||
| Azure: {PackageVersions.AzureExtensionsVersion} | ||
|
|
||
| """); | ||
|
|
||
| try | ||
| { | ||
| // Canonicalize the connection string for emission. | ||
| SqlConnectionStringBuilder builder = new(options.ConnectionString); | ||
|
|
||
| Out($""" | ||
| Connection details: | ||
| Data Source: {builder.DataSource} | ||
| Initial Catalog: {builder.InitialCatalog} | ||
| Authentication: {builder.Authentication} | ||
|
|
||
| """); | ||
|
|
||
| if (options.Verbose) | ||
| { | ||
| Out($""" | ||
| Full connection string: | ||
| {builder} | ||
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| """); | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Err($""" | ||
| Failed to parse connection string: | ||
| {ex.Message} | ||
| """); | ||
|
|
||
| if (options.Verbose) | ||
| { | ||
| Err($" {ex}"); | ||
| } | ||
| return 1; | ||
| } | ||
|
|
||
| // Enable SqlClient event logging if requested. | ||
| if (options.LogEvents) | ||
| { | ||
| string prefix = "[EVENT]"; | ||
| Out($"SqlClient event logging enabled; events will be prefixed with {prefix}"); | ||
|
|
||
| _eventListener = new SqlClientEventListener(Out, prefix); | ||
| } | ||
|
|
||
| // Pause for trace attachment if requested. | ||
| if (options.Trace) | ||
| { | ||
| Out($""" | ||
| Execution paused; attach dotnet-trace and press Enter to resume: | ||
|
|
||
| dotnet-trace collect -p {Process.GetCurrentProcess().Id} --providers Microsoft.Data.SqlClient.EventSource:1FFF:5 | ||
|
|
||
| """); | ||
| Console.ReadLine(); | ||
| } | ||
|
|
||
| // Touch the AKV Provider type to ensure its assembly is present and loadable. | ||
| _ = typeof(SqlColumnEncryptionAzureKeyVaultProvider); | ||
|
|
||
| try | ||
| { | ||
| Out("Testing connectivity..."); | ||
|
|
||
| using SqlConnection connection = new(options.ConnectionString); | ||
| connection.Open(); | ||
|
|
||
| Console.ForegroundColor = ConsoleColor.Green; | ||
| Out("Connected successfully!"); | ||
| Console.ResetColor(); | ||
| Out($" Server version: {connection.ServerVersion}"); | ||
|
|
||
| return 0; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Err($""" | ||
| Connection failed: | ||
| {ex.Message} | ||
| """); | ||
|
|
||
| if (options.Verbose) | ||
| { | ||
| Err($" {ex}"); | ||
| } | ||
|
|
||
| return 1; | ||
| } | ||
| } | ||
|
|
||
| #endregion | ||
|
|
||
| // ────────────────────────────────────────────────────────────────── | ||
| #region Private Helpers | ||
|
|
||
| /// <summary> | ||
| /// Writes an informational message to standard output. | ||
| /// </summary> | ||
| /// <param name="message">The message to write.</param> | ||
| internal static void Out(string message) | ||
| { | ||
| Console.Out.WriteLine(message); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Writes an error message to standard error in red. | ||
| /// </summary> | ||
| /// <param name="message">The message to write.</param> | ||
| internal static void Err(string message) | ||
| { | ||
| Console.ForegroundColor = ConsoleColor.Red; | ||
| Console.Error.WriteLine(message); | ||
| Console.ResetColor(); | ||
| } | ||
|
|
||
| #endregion | ||
|
|
||
| // ────────────────────────────────────────────────────────────────── | ||
| #region Private Fields | ||
|
|
||
| /// <summary> | ||
| /// The display name of the application. | ||
| /// </summary> | ||
| internal const string AppName = "Azure Authentication Tester"; | ||
|
|
||
| /// <summary> | ||
| /// The optional event listener used to capture SqlClient diagnostic events. | ||
| /// </summary> | ||
| private SqlClientEventListener? _eventListener; | ||
|
|
||
| #endregion | ||
| } | ||
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFrameworks>net481;net10.0</TargetFrameworks> | ||
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <RootNamespace>Microsoft.Data.SqlClient.Samples.AzureAuthentication</RootNamespace> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| <LangVersion>latest</LangVersion> | ||
| </PropertyGroup> | ||
|
|
||
| <!-- SqlClient Packages --> | ||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.Data.SqlClient" /> | ||
| <!-- | ||
| We include the AKV Provider to ensure there are no transitive dependency conflicts. It is | ||
| instantiated to ensure its assembly isn't elided, but we don't actually use it. | ||
| --> | ||
| <PackageReference Include="Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider" /> | ||
|
|
||
| <!-- Include the Azure package if a version for it was specified. --> | ||
| <PackageReference | ||
| Include="Microsoft.Data.SqlClient.Extensions.Azure" | ||
| Condition="'$(AzureVersion)' != ''" /> | ||
| </ItemGroup> | ||
|
|
||
| <!-- | ||
| Define AZURE_EXTENSIONS so that C# code can use #if AZURE_EXTENSIONS to guard references to | ||
| types from the optional Extensions.Azure package. Without this, the build would fail when the | ||
| package is absent because the compiler would still try to resolve those type references. See | ||
| PackageVersions.Partial.cs for usage. | ||
| --> | ||
| <PropertyGroup Condition="'$(AzureVersion)' != ''"> | ||
| <DefineConstants>$(DefineConstants);AZURE_EXTENSIONS</DefineConstants> | ||
| </PropertyGroup> | ||
|
|
||
| <!-- Other Packages --> | ||
| <ItemGroup> | ||
| <PackageReference Include="System.CommandLine" /> | ||
| </ItemGroup> | ||
|
|
||
| <!-- Generate code with the SqlClient package versions. --> | ||
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| <Import Project="GeneratePackageVersions.targets" /> | ||
|
|
||
| </Project> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
|
|
||
| <!-- We purposely do not include any parent Directory.Build.props files. --> | ||
|
|
||
| <PropertyGroup> | ||
| <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> | ||
| </PropertyGroup> | ||
|
|
||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
|
|
||
| <!-- We purposely do not include any parent Directory.Packages.props files. --> | ||
|
|
||
| <PropertyGroup> | ||
| <!-- Use SqlClient 7.0.0 Preview 4 if no version was specified. --> | ||
| <SqlClientVersion>7.0.0-preview4.26064.3</SqlClientVersion> | ||
|
|
||
| <!-- Use AKV Provider 7.0.0 Preview 1 if no version was specified. --> | ||
| <AkvProviderVersion>7.0.0-preview1.26064.3</AkvProviderVersion> | ||
| </PropertyGroup> | ||
|
|
||
| <!-- SqlClient Packages --> | ||
| <ItemGroup> | ||
| <PackageVersion Include="Microsoft.Data.SqlClient" Version="$(SqlClientVersion)" /> | ||
| <PackageVersion Include="Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider" Version="$(AkvProviderVersion)" /> | ||
|
|
||
| <!-- Declare a version for the Azure package if one was specified. --> | ||
| <PackageVersion | ||
| Include="Microsoft.Data.SqlClient.Extensions.Azure" | ||
| Version="$(AzureVersion)" | ||
| Condition="'$(AzureVersion)' != ''" /> | ||
| </ItemGroup> | ||
|
|
||
| <!-- Other Packages --> | ||
| <ItemGroup> | ||
| <PackageVersion Include="Azure.Identity" Version="1.17.1" /> | ||
| <PackageVersion Include="System.CommandLine" Version="2.0.3" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| using System.CommandLine; | ||
|
|
||
| namespace Microsoft.Data.SqlClient.Samples.AzureAuthentication; | ||
|
|
||
| /// <summary> | ||
| /// Contains the application entry point responsible for parsing command-line arguments and | ||
| /// delegating execution to <see cref="App"/>. | ||
| /// </summary> | ||
| public static class EntryPoint | ||
| { | ||
| /// <summary> | ||
| /// Application entry point. Parses command-line arguments and executes the connectivity test. | ||
| /// </summary> | ||
| /// <param name="args">Command-line arguments.</param> | ||
| /// <returns>0 on success; non-zero on failure.</returns> | ||
| public static int Main(string[] args) | ||
| { | ||
| Option<string> connectionStringOption = new("--connection-string", "-c") | ||
| { | ||
| Description = | ||
| "The ADO.NET connection string used to connect to SQL Server. " + | ||
| "Supports SQL, Azure AD, and integrated authentication modes.", | ||
| Required = true | ||
| }; | ||
|
|
||
| Option<bool> logOption = new("--log-events", "-l") | ||
| { | ||
| Description = "Enable SqlClient event emission to the console." | ||
| }; | ||
|
|
||
| Option<bool> traceOption = new("--trace", "-t") | ||
| { | ||
| Description = "Pauses execution to allow dotnet-trace to be attached." | ||
| }; | ||
|
|
||
| Option<bool> verboseOption = new("--verbose", "-v") | ||
| { | ||
| Description = "Enable verbose output with detailed error information." | ||
| }; | ||
|
|
||
| RootCommand rootCommand = new( | ||
| $""" | ||
| {App.AppName} | ||
| ----------------------------------------- | ||
|
|
||
| Validates SqlClient connectivity using EntraID (formerly Azure Active Directory) | ||
| authentication. Connects to SQL Server using the supplied connection string, | ||
| which must specify the authentication method. | ||
|
|
||
| Supply specific package versions when building to test different versions of the | ||
| SqlClient suite, for example: | ||
|
|
||
| -p:SqlClientVersion=7.0.0-preview4 | ||
| -p:AkvProviderVersion=7.0.1-preview2 | ||
| -p:AzureVersion=1.0.0-preview1 | ||
|
|
||
| Current package versions: | ||
| SqlClient: {PackageVersions.MicrosoftDataSqlClient} | ||
| AKV Provider: {PackageVersions.MicrosoftDataSqlClientAlwaysEncryptedAzureKeyVaultProvider} | ||
| Azure: {PackageVersions.AzureExtensionsVersion} | ||
| """) | ||
| { | ||
| connectionStringOption, | ||
| logOption, | ||
| traceOption, | ||
| verboseOption | ||
| }; | ||
|
|
||
| rootCommand.SetAction(parseResult => | ||
| { | ||
| App.RunOptions options = new() | ||
| { | ||
| ConnectionString = parseResult.GetValue(connectionStringOption)!, | ||
| LogEvents = parseResult.GetValue(logOption), | ||
| Trace = parseResult.GetValue(traceOption), | ||
| Verbose = parseResult.GetValue(verboseOption) | ||
| }; | ||
|
|
||
| using App app = new(); | ||
| return app.Run(options); | ||
| }); | ||
|
|
||
| return rootCommand.Parse(args).Invoke(); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.