< Summary - Helper.Tests

Information
Class: Configuration.Helper.WebConnectionStringBuilder
Assembly: Configuration.Helper
File(s): D:\a\NuGetPackages\NuGetPackages\src\Helper\Configuration.Helper\WebConnectionStringBuilder.cs
Tag: 3_8508158812
Line coverage
100%
Covered lines: 114
Uncovered lines: 0
Coverable lines: 114
Total lines: 377
Line coverage: 100%
Branch coverage
88%
Covered branches: 23
Total branches: 26
Branch coverage: 88.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_Url()100%22100%
set_Url(...)100%11100%
get_UserName()100%11100%
set_UserName(...)100%11100%
get_Password()100%11100%
set_Password(...)100%11100%
get_HomeRealmUri()100%11100%
set_HomeRealmUri(...)100%11100%
get_AuthenticationType()100%11100%
set_AuthenticationType(...)100%11100%
get_RequireNewInstance()100%11100%
set_RequireNewInstance(...)100%11100%
get_ClientId()100%11100%
set_ClientId(...)100%11100%
get_ClientSecret()100%11100%
set_ClientSecret(...)100%11100%
get_RedirectUri()100%11100%
set_RedirectUri(...)100%11100%
get_TokenCacheStorePath()100%11100%
set_TokenCacheStorePath(...)100%11100%
get_LoginPrompt()100%11100%
set_LoginPrompt(...)100%11100%
get_StoreName()100%11100%
set_StoreName(...)100%11100%
get_Thumbprint()100%11100%
set_Thumbprint(...)100%11100%
get_SkipDiscovery()100%11100%
set_SkipDiscovery(...)100%11100%
get_IntegratedSecurity()100%11100%
set_IntegratedSecurity(...)100%11100%
get_Domain()100%11100%
set_Domain(...)100%11100%
.ctor()100%11100%
.ctor(...)100%22100%
GetProperty(...)83.33%66100%
SetProperty(...)100%22100%
RemoveValue(...)87.5%88100%
SetValue(...)100%44100%
ConvertToBool(...)50%22100%
ConvertToAuthType(...)100%11100%
ConvertToLoginPromptType(...)100%11100%

File(s)

D:\a\NuGetPackages\NuGetPackages\src\Helper\Configuration.Helper\WebConnectionStringBuilder.cs

#LineLine coverage
 1// Ignore Spelling: Auth Thumbprint
 2
 3using System.Data.Common;
 4
 5namespace Configuration.Helper;
 6
 7/// <summary>
 8/// Provides a simple way to create and manage the contents of connection
 9/// strings used for a Microsoft Dataverse connection.</summary>
 10/// <remarks>
 11/// See<a href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/xrm-tooling/use-connection-strings-
 12/// Use connection strings in XRM tooling to connect to Microsoft Dataverse</a> and
 13/// <a href="https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/xrm-tooling/use-conn
 14/// Use connection strings in XRM tooling</a> for more information.
 15/// </remarks>
 16public class WebConnectionStringBuilder : DbConnectionStringBuilder
 17{
 18  #region Key Aliases
 19
 20  private static class Alias
 21  {
 122    internal static readonly string[] url = { @"Url", "ServiceUri", "Service Uri", "Server" };
 123    internal static readonly string[] userName = { "UserName", "User Name", "UserId", " User Id" };
 124    internal static readonly string[] password = { "Password" };
 125    internal static readonly string[] homeRealmUri = { "HomeRealmUri", "Home Realm Uri" };
 126    internal static readonly string[] authType = { "AuthType", "AuthenticationType" };
 127    internal static readonly string[] requireNewInstance = { "RequireNewInstance" };
 128    internal static readonly string[] clientId = { "ClientId", "AppId", "ApplicationId" };
 129    internal static readonly string[] clientSecret = { "ClientSecret", "Secret" };
 130    internal static readonly string[] redirectUri = { "RedirectUri", "ReplyUrl" };
 131    internal static readonly string[] tokenCacheStorePath = { "TokenCacheStorePath" };
 132    internal static readonly string[] loginPrompt = { "LoginPrompt" };
 133    internal static readonly string[] storeName = { "StoreName", "CertificateStoreName" };
 134    internal static readonly string[] thumbprint = { @"Thumbprint", "CertThumbprint" };
 135    internal static readonly string[] skipDiscovery = { "SkipDiscovery" };
 136    internal static readonly string[] integratedSecurity = { "Integrated Security" };
 137    internal static readonly string[] domain = { "Domain" };
 38  }
 39
 40  #endregion
 41
 42  #region Authentication Types
 43
 44  /// <summary>Dynamics 365 Web service authentication types.</summary>
 45  /// <remarks>
 46  /// Only OAuth, Certificate, ClientSecret and Office365 are permitted values
 47  /// for Dataverse environments.<br/>
 48  /// See<a href="https://learn.microsoft.com/en-us/powerapps/developer/data-platform/authentication" target="_blank">
 49  /// Authenticate with Microsoft Dataverse web services</a>
 50  /// for more information.
 51  /// </remarks>
 52  public enum AuthType
 53  {
 54    /// <summary>Open standard authorization protocol for access delegation.</summary>
 55    OAuth,
 56    /// <summary>Client secrets to enable server-to-server authentication scenarios.</summary>
 57    ClientSecret,
 58    /// <summary>Certificates to enable server-to-server authentication scenarios.</summary>
 59    Certificate,
 60    /// <summary>Use of the WS-Trust authentication security protocol is no longer recommended</summary>
 61    Office365,
 62    /// <summary>Dynamics 365 On-premises Active Directory authentication.</summary>
 63    AD,
 64    /// <summary>Dynamics 365 Internet-facing deployment authentication.</summary>
 65    IFD
 66  }
 67
 68  #endregion
 69
 70  #region Login Prompt Types
 71
 72  /// <summary>Dynamics 365 Web service login types.</summary>
 73  /// <remarks>The item with a value of zero is the default.</remarks>
 74  public enum LoginPromptType
 75  {
 76    /// <summary>Does not prompt the user to specify credentials.</summary>
 77    Never = 0,
 78    /// <summary>Always prompts the user to specify credentials.</summary>
 79    Always,
 80    /// <summary>Allows the user to select in the login control interface whether to display the prompt or not.</summary
 81    Auto
 82  }
 83
 84  #endregion
 85
 86  #region Properties
 87
 88  /// <summary>
 89  /// Gets or sets the URL to the Dataverse environment. The URL can use
 90  /// HTTP or HTTPS protocol, and the port is optional.
 91  /// </summary>
 92  public string Url
 93  {
 94    get
 1295    {
 96      const string lastChar = @"/";
 1297      string value = GetProperty( Alias.url );
 98      // Make sure the URL ends with a delimiting character
 1299      if( value.Length > 0 & !value.EndsWith( lastChar ) & !value.EndsWith( '\\' ) )
 6100      {
 6101        return value + lastChar;
 102      }
 6103      return value;
 12104    }
 36105    set { SetProperty( value, Alias.url ); }
 106  }
 107
 108  /// <summary>Gets or sets the user name associated with the credentials.</summary>
 109  public string UserName
 110  {
 18111    get { return GetProperty( Alias.userName ); }
 9112    set { SetProperty( value, Alias.userName ); }
 113  }
 114
 115  /// <summary>Gets or sets the password for the user name associated with the credentials.</summary>
 116  public string Password
 117  {
 18118    get { return GetProperty( Alias.password ); }
 9119    set { SetProperty( value, Alias.password ); }
 120  }
 121
 122  /// <summary>Gets or sets the Home Realm Uniform Resource Identifier.</summary>
 123  /// <remarks>
 124  /// Set this property to a non-null value when a second AD FS instance is configured as an
 125  /// identity provider to the AD FS instance that Dynamics 365 has been configured with
 126  /// for claims authentication. The parameter value is the URI of the WS-Trust metadata
 127  /// endpoint of the second AD FS instance.
 128  /// </remarks>
 129  public string HomeRealmUri
 130  {
 18131    get { return GetProperty( Alias.homeRealmUri ); }
 3132    set { SetProperty( value, Alias.homeRealmUri ); }
 133  }
 134
 135  /// <summary>Gets or sets the authentication type to connect to Dataverse environment.</summary>
 136  public AuthType AuthenticationType
 137  {
 18138    get { return ConvertToAuthType( GetProperty( Alias.authType ) ); }
 18139    set { SetProperty( value.ToString(), Alias.authType ); }
 140  }
 141
 142  /// <summary>
 143  /// Gets or sets whether to reuse an existing connection if recalled
 144  /// while the connection is still active.
 145  /// </summary>
 146  /// <remarks>The default is false.</remarks>
 147  public bool RequireNewInstance
 148  {
 18149    get { return ConvertToBool( GetProperty( Alias.requireNewInstance ) ); }
 3150    set { SetProperty( value.ToString().ToLower(), Alias.requireNewInstance ); }
 151  }
 152
 153  /// <summary>
 154  /// Gets or sets the ClientID assigned when the registered application
 155  /// in Azure Active Directory or Active Directory Federation Services (AD FS).
 156  /// </summary>
 157  public string ClientId
 158  {
 18159    get { return GetProperty( Alias.clientId ); }
 24160    set { SetProperty( value, Alias.clientId ); }
 161  }
 162
 163  /// <summary>Gets or sets the secret when authentication type is set to ClientSecret.</summary>
 164  public string ClientSecret
 165  {
 18166    get { return GetProperty( Alias.clientSecret ); }
 3167    set { SetProperty( value, Alias.clientSecret ); }
 168  }
 169
 170  /// <summary>
 171  /// Gets or sets the redirect URI of the application registered in Azure
 172  /// Active Directory or Active Directory Federation Services (AD FS).
 173  /// </summary>
 174  public string RedirectUri
 175  {
 18176    get { return GetProperty( Alias.redirectUri ); }
 3177    set { SetProperty( value, Alias.redirectUri ); }
 178  }
 179
 180  /// <summary>
 181  /// Gets or sets the full path to the location where the user token cache should be stored.
 182  /// </summary>
 183  /// <remarks>
 184  /// Required only with a web service configured for OAuth authentication.
 185  /// </remarks>
 186  public string TokenCacheStorePath
 187  {
 18188    get { return GetProperty( Alias.tokenCacheStorePath ); }
 3189    set { SetProperty( value, Alias.tokenCacheStorePath ); }
 190  }
 191
 192  /// <summary>
 193  /// Gets or sets whether the user is prompted for credentials if the credentials are not supplied.
 194  /// </summary>
 195  /// <remarks>
 196  /// Required only with a web service configured for OAuth authentication.
 197  /// </remarks>
 198  public LoginPromptType LoginPrompt
 199  {
 18200    get { return ConvertToLoginPromptType( GetProperty( Alias.loginPrompt ) ); }
 3201    set { SetProperty( value.ToString(), Alias.loginPrompt ); }
 202  }
 203
 204  /// <summary>
 205  /// Gets or sets the store name where the certificate identified by
 206  /// thumb-print can be found. When set, Thumb-print is required.
 207  /// </summary>
 208  public string StoreName
 209  {
 18210    get { return GetProperty( Alias.storeName ); }
 3211    set { SetProperty( value, Alias.storeName ); }
 212  }
 213
 214  /// <summary>
 215  /// Gets or sets the thumb-print of the certificate to be utilized during
 216  /// an S2S connection. When set, AppID is required and UserID and Password
 217  /// values are ignored.
 218  /// </summary>
 219  public string Thumbprint
 220  {
 18221    get { return GetProperty( Alias.thumbprint ); }
 3222    set { SetProperty( value, Alias.thumbprint ); }
 223  }
 224
 225  /// <summary>
 226  /// Gets or sets whether to call instance discovery to determine the connection
 227  /// URI for a given instance.
 228  /// As of NuGet release Microsoft.CrmSdk.XrmTooling.CoreAssembly Version 9.0.2.7
 229  /// </summary>
 230  public bool SkipDiscovery
 231  {
 18232    get { return ConvertToBool( GetProperty( Alias.skipDiscovery ) ); }
 3233    set { SetProperty( value.ToString().ToLower(), Alias.skipDiscovery ); }
 234  }
 235
 236  /// <summary>
 237  /// Gets or sets whether to use current windows credentials to attempt to create
 238  /// a token for the instances.
 239  /// As of NuGet release Microsoft.CrmSdk.XrmTooling.CoreAssembly Version 9.1.0.21
 240  /// </summary>
 241  public bool IntegratedSecurity
 242  {
 18243    get { return ConvertToBool( GetProperty( Alias.integratedSecurity ) ); }
 3244    set { SetProperty( value.ToString().ToLower(), Alias.integratedSecurity ); }
 245  }
 246
 247  /// <summary>Gets or sets the domain that will verify user credentials.</summary>
 248  public string Domain
 249  {
 18250    get { return GetProperty( GetProperty( Alias.domain ) ); }
 3251    set { SetProperty( value, Alias.domain ); }
 252  }
 253
 254  #endregion
 255
 256  #region Constructors
 257
 258  /// <summary>Initializes a new instance of the WebConnectionStringBuilder class.</summary>
 6259  public WebConnectionStringBuilder()
 12260  { }
 261
 262  /// <summary>
 263  /// Initializes a new instance of the WebConnectionStringBuilder class using a supplied connection string.
 264  /// </summary>
 265  /// <param name="connectionString">The basis for the object's internal connection information.
 266  /// Parsed into name/value pairs.</param>
 6267  public WebConnectionStringBuilder( string connectionString )
 6268  {
 6269    if( !string.IsNullOrWhiteSpace( connectionString ) )
 6270    {
 6271      ConnectionString = connectionString.Trim();
 6272    }
 6273  }
 274
 275  #endregion
 276
 277  #region Private Methods
 278
 279  /// <summary>Get the value for a property key.</summary>
 280  /// <param name="keyAliases">Collection of keywords.</param>
 281  /// <returns>An empty string is returned if the key is not found.</returns>
 282  private string GetProperty( params string[] keyAliases )
 108283  {
 660284    foreach( string alias in keyAliases )
 174285    {
 174286      if( TryGetValue( alias, out object? value ) )
 60287      { string? wrk = value.ToString(); if( wrk is not null ) { return wrk.Trim(); } }
 162288    }
 289
 96290    return string.Empty;
 108291  }
 292
 293  /// <summary>Sets the value for a property key.</summary>
 294  /// <param name="val">Value to set.</param>
 295  /// <param name="keyAliases">Collection of keywords.</param>
 296  private void SetProperty( string val, params string[] keyAliases )
 43297  {
 43298    val = val.Trim();
 299
 300    // If value is empty string then remove the parameter
 43301    if( val.Length == 0 )
 6302    {
 6303      RemoveValue( keyAliases );
 6304    }
 305    else
 37306    {
 307      // Set the new value
 37308      SetValue( val, keyAliases );
 37309    }
 43310  }
 311
 312  /// <summary>Removes a parameter from the connection string.</summary>
 313  /// <param name="keyAliases">Collection of keyword aliases.</param>
 314  /// <returns>
 315  /// The value of the key before it is removed is returned.
 316  /// If the key is not found an empty string is returned.
 317  /// </returns>
 318  private string RemoveValue( params string[] keyAliases )
 6319  {
 6320    string? retValue = null;
 54321    foreach( string alias in keyAliases )
 18322    {
 18323      if( TryGetValue( alias, out object? value ) )
 6324      {
 6325        if( null == retValue )
 6326        {
 6327          retValue = value.ToString();
 6328        }
 6329        Remove( alias );
 6330      }
 18331    }
 332
 6333    return retValue ?? string.Empty;
 6334  }
 335
 336  /// <summary>Set the value for a parameter key.</summary>
 337  /// <param name="newValue">New value</param>
 338  /// <param name="keyAliases">Collection of keywords.</param>
 339  private void SetValue( string newValue, params string[] keyAliases )
 37340  {
 263341    foreach( string alias in keyAliases )
 79342    {
 97343      if( TryGetValue( alias, out _ ) ) { this[alias] = newValue; return; }
 73344    }
 345
 31346    this[keyAliases[0]] = newValue;
 37347  }
 348
 349  /// <summary>Converts a string to a boolean.</summary>
 350  /// <param name="valBool">Boolean string.</param>
 351  /// <param name="dftValue">Default value. False is assumed if a value is not provided.</param>
 352  /// <returns>The default is returned if the string is not a valid boolean.</returns>
 353  private static bool ConvertToBool( string valBool, bool dftValue = false )
 18354  {
 18355    return bool.TryParse( valBool, out bool retValue ) ? retValue : dftValue;
 18356  }
 357
 358  /// <summary>Converts a string to a Dynamics 365 Web service authentication type.</summary>
 359  /// <param name="authType">Dynamics 365 Web service authentication type string.</param>
 360  /// <returns>The default value of AD is returned if the string is not an authentication type.</returns>
 361  private static AuthType ConvertToAuthType( string authType )
 6362  {
 6363    _ = Enum.TryParse( authType.Trim(), out AuthType retValue );
 6364    return retValue;
 6365  }
 366
 367  /// <summary>Converts a string to a Dynamics 365 Web service login type.</summary>
 368  /// <param name="loginType">Dynamics 365 Web login type string.</param>
 369  /// <returns>The default value of Never is returned if the string is not a login type.</returns>
 370  private static LoginPromptType ConvertToLoginPromptType( string loginType )
 6371  {
 6372    _ = Enum.TryParse( loginType.Trim(), out LoginPromptType retValue );
 6373    return retValue;
 6374  }
 375
 376  #endregion
 377}