Skip to content

Commit

Permalink
Add SqlConnectionEncryptOptionConverter class which is used to conver…
Browse files Browse the repository at this point in the history
…t string Encrypt option into SqlConnectionEncryptionOption type.
  • Loading branch information
arellegue committed Jun 8, 2023
1 parent f478be5 commit 5c505a1
Show file tree
Hide file tree
Showing 8 changed files with 200 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0"?>
<docs>
<members name="SqlConnectionEncryptOptionConverter">
<SqlConnectionEncryptOption>
<summary>Converts a string Sql Connection Encrypt option into SqlConnectionEncryptOption object</summary>
<remarks>
<para>
## Remarks
Implicit conversions have been added to maintain backwards compatibility with boolean behahavior for the <see cref="Microsoft.Data.SqlClient.SqlConnectionStringBuilder.Encrypt" /> property. When converting from a boolean, a value of `true` converts to <see cref="Microsoft.Data.SqlClient.SqlConnectionEncryptOption.Mandatory" /> and a value of `false` converts to <see cref="Microsoft.Data.SqlClient.SqlConnectionEncryptOption.Optional"/>. When converting to a boolean, <see cref="Microsoft.Data.SqlClient.SqlConnectionEncryptOption.Mandatory"/>, <see cref="Microsoft.Data.SqlClient.SqlConnectionEncryptOption.Strict"/> , and `null` convert to `true` and <see cref="Microsoft.Data.SqlClient.SqlConnectionEncryptOption.Optional"/> converts `false`.
</para>
</remarks>
</SqlConnectionEncryptOption>
<CanConvertFrom>
<summary>
If the source type is a string then conversion is allowed <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/>.
</summary>
<param name="value">A string containing the value to convert.</param>
<returns>
<see langword="true" /> if the <paramref name="value"/> parameter can be converted successfully; otherwise, <see langword="false" />.
</returns>
<remarks>This method does not throw an exception.</remarks>
</CanConvertFrom>
<ConvertFrom>
<summary>
Converts the specified string representation of a logical value to its <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/> equivalent.
</summary>
<param name="value">A string containing the value to convert.</param>
<param name="result">
An object that is equivalent to <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/>.
</param>
<returns>
An object that is equivalent to <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/> with value of <paramref name="value"/> if conversion was successful;
otherwise, an exception is thrown.
</returns>
<remarks>This method throws an exception if conversion fails.</remarks>
</ConvertFrom>
<ConvertTo>
<summary>
Converts an object <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/> value to its string representation.
</summary>
<param name="value">An object <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/> containing the value to convert.</param>
<param name="result">
A string representation of the value of <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/>.
</param>
<returns>
A string representation of the value of <see cref="T:Microsoft.Data.SqlClient.SqlConnectionEncryptOption"/>.
</returns>
<remarks>This method does not throw an exception if conversion fails.</remarks>
</ConvertTo>
</members>
</docs>
1 change: 1 addition & 0 deletions src/Microsoft.Data.SqlClient.sln
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient",
..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionAttestationProtocol.xml
..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionColumnEncryptionSetting.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionColumnEncryptionSetting.xml
..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionEncryptOption.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionEncryptOption.xml
..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionEncryptOptionConverter.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionEncryptOptionConverter.xml
..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionStringBuilder.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionStringBuilder.xml
..\doc\snippets\Microsoft.Data.SqlClient\SqlCredential.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlCredential.xml
..\doc\snippets\Microsoft.Data.SqlClient\SqlDataAdapter.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlDataAdapter.xml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlConnectionEncryptOption.cs">
<Link>Microsoft\Data\SqlClient\SqlConnectionEncryptOption.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlConnectionEncryptOptionConverter.cs">
<Link>Microsoft\Data\SqlClient\SqlConnectionEncryptOptionConverter.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlConnectionPoolGroupProviderInfo.cs">
<Link>Microsoft\Data\SqlClient\SqlConnectionPoolGroupProviderInfo.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlConnectionEncryptOption.cs">
<Link>Microsoft\Data\SqlClient\SqlConnectionEncryptOption.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlConnectionEncryptOptionConverter.cs">
<Link>Microsoft\Data\SqlClient\SqlConnectionEncryptOptionConverter.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlConnectionPoolGroupProviderInfo.cs">
<Link>Microsoft\Data\SqlClient\SqlConnectionPoolGroupProviderInfo.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
// See the LICENSE file in the project root for more information.

using System;
using System.ComponentModel;
using Microsoft.Data.Common;

namespace Microsoft.Data.SqlClient
{
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml' path='docs/members[@name="SqlConnectionEncryptOption"]/SqlConnectionEncryptOption/*'/>
[TypeConverter(typeof(SqlConnectionEncryptOptionConverter))]
public sealed class SqlConnectionEncryptOption
{
private const string TRUE = "True";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.


using System;
using System.ComponentModel;
using System.Globalization;
using System.Drawing;

namespace Microsoft.Data.SqlClient
{
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOptionConverter.xml' path='docs/members[@name="SqlConnectionEncryptOptionConverter"]/SqlConnectionEncryptOptionConverter/*'/>
public class SqlConnectionEncryptOptionConverter : TypeConverter
{
// Overrides the CanConvertFrom method of TypeConverter.
// The ITypeDescriptorContext interface provides the context for the
// conversion. Typically, this interface is used at design time to
// provide information about the design-time container.
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOptionConverter.xml' path='docs/members[@name="SqlConnectionEncryptOptionConverter"]/SqlConnectionEncryptOptionConverter/CanConvertFrom/*'/>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
// Overrides the ConvertFrom method of TypeConverter.
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOptionConverter.xml' path='docs/members[@name="SqlConnectionEncryptOptionConverter"]/SqlConnectionEncryptOptionConverter/ConvertFrom/*'/>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
return SqlConnectionEncryptOption.Parse(value.ToString());
}
throw new Exception("Value to convert must be of string type!");
}
// Overrides the ConvertTo method of TypeConverter.
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOptionConverter.xml' path='docs/members[@name="SqlConnectionEncryptOptionConverter"]/SqlConnectionEncryptOptionConverter/ConvertTo/*'/>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<Compile Include="..\..\src\Microsoft\Data\Common\MultipartIdentifier.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="$(SystemDiagnosticsDiagnosticSourceVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit;

namespace Microsoft.Data.SqlClient.Tests
Expand Down Expand Up @@ -468,6 +474,36 @@ public void EncryptTryParseInvalidValuesReturnsFalse(string value)
Assert.Null(result);
}

[Theory]
[InlineData("false","False")]
[InlineData("true", "True")]
[InlineData("strict", "Strict")]
[InlineData("mandatory","True")]
[InlineData("optional", "False")]
[InlineData("yes", "True")]
[InlineData("no", "False")]
[InlineData("absolutely", "True")]
[InlineData("affirmative", "True")]
[InlineData("never", "True")]
[InlineData("always", "True")]
[InlineData("none", "True")]
public void ConnectionStringFromJsonTests(string value, string expectedValue)
{
ExecuteConnectionStringFromJsonTests(value, expectedValue);
}

[Theory]
[InlineData("absolutely")]
[InlineData("affirmative")]
[InlineData("never")]
[InlineData("always")]
[InlineData("none")]
[InlineData(" for sure ")]
public void ConnectionStringFromJsonThrowsException(string value)
{
ExecuteConnectionStringFromJsonThrowsException(value);
}

internal void ExecuteConnectionStringTests(string connectionString)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString);
Expand Down Expand Up @@ -495,5 +531,62 @@ internal static void CheckEncryptType(SqlConnectionStringBuilder builder, SqlCon
Assert.IsType<SqlConnectionEncryptOption>(builder.Encrypt);
Assert.Equal(expectedValue, builder.Encrypt);
}

internal void ExecuteConnectionStringFromJsonTests(string encryptOption, string result)
{
var settings = LoadSettingsFromJsonStream<UserDbConnectionStringSettings>(encryptOption);
var connectionString = settings!.UserDb!.ToString();
Assert.Contains($"Encrypt={result}", connectionString, StringComparison.InvariantCultureIgnoreCase);
}

internal void ExecuteConnectionStringFromJsonThrowsException(string encryptOption)
{
Assert.Throws<System.InvalidOperationException>(() => LoadSettingsFromJsonStream<UserDbConnectionStringSettings>(encryptOption));
}

TSettings LoadSettingsFromJsonStream<TSettings>(string encryptOption) where TSettings : class
{
TSettings settingsOut = null;

Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((ctx, configBuilder) =>
{
// Note: Inside string interpolation, a { should be {{ and a } should be }}
// First, declare a stringified JSON
var json = $"{{ \"UserDb\": {{ \"UserComponents\": {{ \"NetworkLibrary\": \"DBMSSOCN\", \"UserID\": \"user\", \"Password\": \"password\", \"DataSource\": \"localhost\", \"InitialCatalog\": \"catalog\", \"Encrypt\": \"{encryptOption}\" }}}}}}";

// Load the stringified JSON as a stream into the configuration builder
configBuilder.AddJsonStream(new MemoryStream(Encoding.ASCII.GetBytes(json)));
configBuilder.AddEnvironmentVariables();
})
.ConfigureServices((ctx, services) =>
{
var configuration = ctx.Configuration;
services.AddOptions();
services.Configure<TSettings>(ctx.Configuration);
settingsOut = configuration.Get<TSettings>();
})
.Build();

return settingsOut;
}
}

// These 2 classes will be used by ConnectionStringFromJsonTests only
internal class UserDbConnectionStringSettings
{
[Required]
public UserSqlConnectionString UserDb { get; set; }
}

internal class UserSqlConnectionString
{
public SqlConnectionStringBuilder UserComponents { get; set; } = new();

public override string ToString()
{
return UserComponents!.ConnectionString;
}
}

}

0 comments on commit 5c505a1

Please sign in to comment.