/// <summary> /// Uses a <see cref="IDbCommand" /> to retrieve a scalar value using the given <paramref name="commandText" />. /// </summary> /// <typeparam name="TResult">The type of the expected result.</typeparam> /// <param name="commandText">The command text to execute.</param> /// <param name="connection">The connection to use for the query.</param> /// <param name="commandTimeout">The command timeout in seconds.</param> /// <returns>The result or the default value of <typeparamref name="TResult" /> if an error occurs.</returns> /// <exception cref="ArgumentException"> /// Is thrown if the <paramref name="commandText" /> or <paramref name="connection" /> are invalid. /// </exception> public static async Task <TResult> GetScalarResultAsync <TResult>(string commandText, IDbConnection connection, int commandTimeout = 30) { CheckUtil.ThrowIfNull(() => connection); CheckUtil.ThrowIfNullOrEmpty(() => commandText); try { using (var command = connection.CreateCommand()) { command.CommandTimeout = commandTimeout; var commandToUse = command as DbCommand; CheckUtil.ThrowIfNull(() => commandToUse); // ReSharper disable once PossibleNullReferenceException commandToUse.CommandText = commandText; var result = await commandToUse.ExecuteScalarAsync(); if (result == null) { return(default(TResult)); } return((TResult)result); } } catch (Exception ex) { ExceptionCallback?.Invoke(ex); return(default(TResult)); } }
/// <summary> /// Retrieves an opened connection to a SQL server. /// </summary> /// <param name="connectionStringOrKey">The connection string or the key to a connection-string-setting in the config.</param> /// <param name="providerName"> /// The name of the provider. (Leave this null, if you set /// <paramref name="connectionStringIsConfigKey" /> to <c>true</c>. /// </param> /// <param name="connectionStringIsConfigKey"> /// Indicates whether <paramref name="connectionStringOrKey" /> should be /// interpreted as a config-key. /// </param> /// <returns>The opened connection of <c>null</c> if an error occured.</returns> /// <exception cref="ArgumentException"> /// Is thrown if the <paramref name="connectionStringOrKey" /> is empty or if no key /// was found in the config. /// </exception> public static async Task <IDbConnection> GetConnectionAsync(string connectionStringOrKey, bool connectionStringIsConfigKey = false, string providerName = null) { CheckUtil.ThrowIfNullOrEmpty(() => connectionStringOrKey); var connectionString = connectionStringOrKey; if (connectionStringIsConfigKey) { // try to get connection string from config connectionString = ConfigurationUtil.GetConnectionString(connectionStringOrKey); providerName = ConfigurationUtil.GetProviderName(connectionStringOrKey); } CheckUtil.ThrowIfNullOrEmpty(() => connectionString); CheckUtil.ThrowIfNullOrEmpty(() => providerName); // connection-string is valid // ReSharper disable once AssignNullToNotNullAttribute var factory = DbProviderFactories.GetFactory(providerName); var connection = factory.CreateConnection(); if (connection == null) { return(null); } connection.ConnectionString = connectionString; try { await connection.OpenAsync(); return(connection); } catch (Exception ex) { ExceptionCallback?.Invoke(ex); return(null); } }
/// <summary> /// Retrieves a DateTime for the given <paramref name="columnName" />. /// </summary> /// <param name="reader">The reader to extend.</param> /// <param name="columnName">The name of the column in the reader result.</param> /// <returns>The value.</returns> public static DateTime?GetDateTimeValue(this IDataReader reader, string columnName) { CheckUtil.ThrowIfNull(() => reader); CheckUtil.ThrowIfNullOrEmpty(() => columnName); var offset = GetColumnOffset(reader, columnName); return(reader.IsDBNull(offset) ? default(DateTime?) : reader.GetDateTime(offset)); }
/// <summary> /// Retrieves a value from a reader. /// </summary> /// <typeparam name="TResult">The expected result.</typeparam> /// <param name="reader">The reader to extend.</param> /// <param name="columnName">The name of the column in the reader result.</param> /// <returns>The value of the column.</returns> public static TResult GetValue <TResult>(this IDataReader reader, string columnName) { CheckUtil.ThrowIfNull(() => reader); CheckUtil.ThrowIfNullOrEmpty(() => columnName); var offset = GetColumnOffset(reader, columnName); var value = reader.GetValue(offset); return((TResult)value); }
/// <summary> /// Retrieves the offset of a column with the specified <paramref name="columnName" />. /// </summary> /// <param name="reader">The reader to extend.</param> /// <param name="columnName">The name of the column in the reader result.</param> /// <returns>The index of the column.</returns> public static int GetColumnOffset(this IDataReader reader, string columnName) { CheckUtil.ThrowIfNull(() => reader); CheckUtil.ThrowIfNullOrEmpty(() => columnName); if (reader.IsClosed) { throw new InvalidOperationException("Reader is closed"); } return(reader.GetOrdinal(columnName)); }
/// <summary> /// Loads an instance of <typeparamref name="TEntity" /> from database using a unique value defined as it's /// <paramref name="key" />. /// </summary> /// <remarks> /// In order to make this method work <see cref="KeyFindExpression" /> must be defined. /// </remarks> /// <param name="key">The key-value to search for.</param> /// <param name="ctx">The EF context to use.</param> /// <returns>The instance or <c>null</c> if no item was found.</returns> public async Task <TEntity> LoadAsync(string key, TContext ctx = null) { CheckUtil.ThrowIfNullOrEmpty(() => key); var expr = KeyFindExpression(key); if (expr == null) { throw new InvalidOperationException("Can not load entities of this type because no KeyFindExpression is defined."); } return(await ExecuteContextWrappedAsync(async c => await GetValidEntities(c).SingleOrDefaultAsync(expr), ctx)); }
/// <summary> /// Compares a hash of the specified plain text value to a given hash /// value. Plain text is hashed with the same salt value as the original /// hash. /// </summary> /// <param name="plainText">Plain text to be verified against the specified hash.</param> /// <param name="hashAlgorithm">Case-insensitve name of the hash algorithm. Allowed values are: "SHA1", "SHA256", "SHA384", "SHA512", "HMAC256", "HMAC384", "HMAC512"</param> /// <param name="hashValue">Base64-encoded hash value produced by ComputeHash function. This value includes the original salt appended to it.</param> /// <param name="urlDecode">Indicates whether the result should be URL encoded.</param> /// <returns><c>true</c> if the <paramref name="plainText"/> will be hashed to <paramref name="hashValue"/>, otherwise <c>false</c>.</returns> public static bool VerifyHash(string plainText, string hashAlgorithm, string hashValue, bool urlDecode = true) { CheckUtil.ThrowIfNullOrEmpty(() => plainText); CheckUtil.ThrowIfNullOrEmpty(() => hashValue); CheckUtil.ThrowIfNullOrEmpty(() => hashAlgorithm); if (!ValidHashAlgorithms.Contains(hashAlgorithm.ToUpper(CultureInfo.InvariantCulture))) { throw new ArgumentException("Provided algorithm is unknown.", "hashAlgorithm"); } var hash = GetAlgorithm(hashAlgorithm); if (hash == null) { throw new InvalidOperationException("Could not obtain hasher."); } // If the caller flagged this call with urlDecode we have to UrlDecode the hashValue. If not, // the decoded value will be the passed one. This variable is important, because at the end // we have to compare the given hashValue and not the decoded one. var decodedHashValue = hashValue; if (urlDecode) { decodedHashValue = WebUtility.UrlDecode(hashValue); } // Convert base64-encoded hash value into a byte array. var hashWithSaltBytes = Convert.FromBase64String(decodedHashValue); // We must know size of hash (without salt). var hashSizeInBytes = hash.HashSize / 8; // Make sure that the specified hash value is long enough. if (hashWithSaltBytes.Length < hashSizeInBytes) { hash.Dispose(); return(false); } // Allocate array to hold original salt bytes retrieved from hash. var saltBytes = new byte[hashWithSaltBytes.Length - hashSizeInBytes]; // Copy salt from the end of the hash to the new array. for (var i = 0; i < saltBytes.Length; i++) { saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i]; } // Compute a new hash string. var expectedHashString = ComputeHash(plainText, hashAlgorithm, saltBytes, urlDecode); hash.Dispose(); // If the computed hash matches the specified hash, the plain text value must be correct. return(hashValue.Equals(expectedHashString, StringComparison.Ordinal)); }
/// <summary> /// Uploads a single image to an Azure blob. /// </summary> /// <param name="container">The storage container to use.</param> /// <param name="image">The image to upload,</param> /// <param name="remoteFileName">The name the file should have in the storage container.</param> /// <param name="remoteFolder">A folder name to use or create in the storage container.</param> /// <returns><c>true</c> if the upload succeeds otherwise <c>false</c>.</returns> public static async Task <bool> UploadImageAsync(CloudBlobContainer container, Image image, string remoteFileName, string remoteFolder = null) { var name = remoteFileName; CheckUtil.ThrowIfNullOrEmpty(() => name); CheckUtil.ThrowIfNull(() => image); if (!remoteFolder.IsNullOrEmpty()) { // ReSharper disable once AssignNullToNotNullAttribute remoteFileName = Path.Combine(remoteFolder, remoteFileName); } var newBlob = container.GetBlockBlobReference(remoteFileName); newBlob.Properties.ContentType = image.GetMimeContentType(); var bytes = image.GetByteArrayFromImage(image.RawFormat); await newBlob.UploadFromByteArrayAsync(bytes, 0, bytes.Length); return(true); }
/// <summary> /// Encrypts a given <paramref name="plainText"/> symetrically using <see cref="RijndaelManaged"/>. /// </summary> /// <param name="plainText">The plain text.</param> /// <param name="key">The secret key.</param> /// <param name="iv">The initialization vector of the alogrithm.</param> /// <returns>The encrypted text coded in Base64.</returns> public static string EncryptText(string plainText, byte[] key, byte[] iv) { CheckUtil.ThrowIfNullOrEmpty(() => plainText); CheckUtil.ThrowIfNull(() => key); CheckUtil.ThrowIfNull(() => iv); string encrypted; using (var rijndael = new RijndaelManaged()) { rijndael.Key = key; rijndael.IV = iv; var encryptor = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV); var memStream = new MemoryStream(); var cryptStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write); using (var writer = new StreamWriter(cryptStream)) { writer.Write(plainText); } encrypted = Convert.ToBase64String(memStream.ToArray()); } return(encrypted); }
/// <summary> /// Decrypts a given <paramref name="cipherText"/> symetrically using <see cref="RijndaelManaged"/>. /// </summary> /// <param name="cipherText">The encrypted Base64-encoded text.</param> /// <param name="key">The secret key.</param> /// <param name="iv">The initialization vector of the alogrithm.</param> /// <returns>The decrypted text.</returns> public static string DecryptText(string cipherText, byte[] key, byte[] iv) { CheckUtil.ThrowIfNullOrEmpty(() => cipherText); CheckUtil.ThrowIfNull(() => key); CheckUtil.ThrowIfNull(() => iv); string plaintext; using (var rijndael = new RijndaelManaged()) { rijndael.Key = key; rijndael.IV = iv; var decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV); var cipherTextBytes = Convert.FromBase64String(cipherText); var memStream = new MemoryStream(cipherTextBytes); var cryptStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read); using (var reader = new StreamReader(cryptStream)) { plaintext = reader.ReadToEnd(); } } return(plaintext); }
/// <summary> /// Executes a given <paramref name="commandText" /> on the <paramref name="connection" />. /// </summary> /// <param name="commandText">The command text to execute.</param> /// <param name="connection">The connection to use for the query.</param> /// <param name="commandTimeout">The command timeout in seconds.</param> /// <returns>The amount of affected rows or -1 if an error occured.</returns> /// <exception cref="ArgumentException"> /// Is thrown if the <paramref name="commandText" /> or <paramref name="connection" /> are invalid. /// </exception> public static async Task <int> ExecuteCommandAsync(string commandText, IDbConnection connection, int commandTimeout = 30) { CheckUtil.ThrowIfNull(() => connection); CheckUtil.ThrowIfNullOrEmpty(() => commandText); try { using (var command = connection.CreateCommand()) { command.CommandTimeout = commandTimeout; var commandToUse = command as DbCommand; CheckUtil.ThrowIfNull(() => commandToUse); // ReSharper disable once PossibleNullReferenceException commandToUse.CommandText = commandText; return(await commandToUse.ExecuteNonQueryAsync()); } } catch (Exception ex) { ExceptionCallback?.Invoke(ex); return(-1); } }
/// <summary> /// Retrieves a reader for a given <paramref name="commandText" /> on the <paramref name="connection" />. /// </summary> /// <param name="commandText">The command text to execute.</param> /// <param name="connection">The connection to use for the query.</param> /// <param name="behavior">The command beavior for the reader.</param> /// <param name="commandTimeout">The command timeout in seconds.</param> /// <returns>The reader or <c>null</c> if an error occurs.</returns> /// <exception cref="ArgumentException"> /// Is thrown if the <paramref name="commandText" /> or <paramref name="connection" /> are invalid. /// </exception> public static async Task <IDataReader> GetReaderAsync(string commandText, IDbConnection connection, CommandBehavior behavior = CommandBehavior.CloseConnection, int commandTimeout = 30) { CheckUtil.ThrowIfNull(() => connection); CheckUtil.ThrowIfNullOrEmpty(() => commandText); try { using (var command = connection.CreateCommand()) { command.CommandTimeout = commandTimeout; var commandToUse = command as DbCommand; CheckUtil.ThrowIfNull(() => commandToUse); // ReSharper disable once PossibleNullReferenceException commandToUse.CommandText = commandText; return(await commandToUse.ExecuteReaderAsync(behavior)); } } catch (Exception ex) { ExceptionCallback?.Invoke(ex); return(null); } }
/// <summary> /// Generates a hash for the given plain text value and returns a /// base64-encoded result. Before the hash is computed, a random salt /// is generated and appended to the plain text. This salt is stored at /// the end of the hash value, so it can be used later for hash /// verification. /// </summary> /// <param name="plainText">Plaintext value to be hashed. The function does not check whether this parameter is null.</param> /// <param name="hashAlgorithm">Case-insensitve name of the hash algorithm. Allowed values are: "SHA1", "SHA256", "SHA384", "SHA512", "HMAC256", "HMAC384", "HMAC512"</param> /// <param name="salt">Salt bytes. This parameter can be null, in which case a random salt value will be generated.</param> /// <param name="urlEncode">Indicates whether the result should be URL encoded.</param> /// <returns>Hash value formatted as a base64-encoded string.</returns> public static string ComputeHash(string plainText, string hashAlgorithm, byte[] salt, bool urlEncode = true) { CheckUtil.ThrowIfNullOrEmpty(() => plainText); if (string.IsNullOrEmpty(hashAlgorithm) || !ValidHashAlgorithms.Contains(hashAlgorithm.ToUpper(CultureInfo.InvariantCulture))) { throw new ArgumentException("Provided algorithm is unknown.", nameof(hashAlgorithm)); } // If salt is not specified, generate it on the fly. if (salt == null) { // Generate a random number for the size of the salt. var randomizer = new Random(); var saltSize = randomizer.Next(MinSaltSize, MaxSaltSize); // Allocate a byte array, which will hold the salt. salt = new byte[saltSize]; // Initialize a random number generator. var rng = new RNGCryptoServiceProvider(); // Fill the salt with cryptographically strong byte values. rng.GetNonZeroBytes(salt); } else if (salt.Length < MinSaltSize || salt.Length > MaxSaltSize) { throw new ArgumentException("Salt length invalid. Must be between 4 and 16", nameof(salt)); } var hash = GetAlgorithm(hashAlgorithm); if (hash == null) { throw new InvalidOperationException("Could not obtain hasher."); } // Convert plain text into a byte array. var plainTextBytes = Encoding.UTF8.GetBytes(plainText); // Allocate array, which will hold plain text and salt. var plainTextWithSaltBytes = new byte[plainTextBytes.Length + salt.Length]; // Copy plain text bytes into resulting array. for (var i = 0; i < plainTextBytes.Length; i++) { plainTextWithSaltBytes[i] = plainTextBytes[i]; } // Append salt bytes to the resulting array. for (var i = 0; i < salt.Length; i++) { plainTextWithSaltBytes[plainTextBytes.Length + i] = salt[i]; } // Compute hash value of our plain text with appended salt. var hashBytes = hash.ComputeHash(plainTextWithSaltBytes); // Create array which will hold hash and original salt bytes. var hashWithSaltBytes = new byte[hashBytes.Length + salt.Length]; // Copy hash bytes into resulting array. for (var i = 0; i < hashBytes.Length; i++) { hashWithSaltBytes[i] = hashBytes[i]; } // Append salt bytes to the result. for (var i = 0; i < salt.Length; i++) { hashWithSaltBytes[hashBytes.Length + i] = salt[i]; } // Convert result into a base64-encoded string. var hashValue = Convert.ToBase64String(hashWithSaltBytes); if (urlEncode) { // Caller wants to url encode the result hashValue = WebUtility.UrlEncode(hashValue); } hash.Dispose(); // Return the result. return(hashValue); }
/// <summary> /// Retrieves the value for a given <paramref name="itemName"/> inside a <paramref name="groupName"/> from a <paramref name="fileName"/>. /// </summary> /// <param name="fileName">The full path to the INI-file.</param> /// <param name="groupName">The name of the group in which the setting is expected or <c>null</c> if the item is in no group.</param> /// <param name="itemName">The name of the item.</param> /// <param name="defaultValue">A default value if no value could be found.</param> /// <typeparam name="T">The type of the result.</typeparam> /// <returns>The value associated with the <paramref name="itemName"/>.</returns> /// <exception cref="FileNotFoundException">Is thrown if the file could not be found.</exception> /// <exception cref="InvalidOperationException">Is thrown in case of any other exception.</exception> public static T GetValue <T>(string fileName, string groupName, string itemName, T defaultValue = default(T)) { CheckUtil.ThrowIfNullOrEmpty(() => fileName); CheckUtil.ThrowIfNullOrEmpty(() => itemName); if (!File.Exists(fileName)) { throw new FileNotFoundException("Provided file not found.", fileName); } string[] linesInFile; try { linesInFile = File.ReadAllLines(fileName); } catch (Exception ex) { throw new InvalidOperationException("Error during read of file.", ex); } if (linesInFile == null || !linesInFile.Any()) { throw new InvalidOperationException("Could not read from file."); } var groupSearch = string.Format(CultureInfo.InvariantCulture, "[{0}]", groupName); var groupFound = !string.IsNullOrEmpty(groupName) && linesInFile.Any(line => line.Equals(groupSearch, StringComparison.OrdinalIgnoreCase)); if (!groupFound) { return(defaultValue); } var inGroup = !string.IsNullOrEmpty(groupName); var retVal = defaultValue; linesInFile.ToList().ForEach( line => { if (line.StartsWith("[")) { // check if we will start the parsing or if we stop the complete process if (inGroup) { // we where already inside the desired group return; } inGroup = line.Equals(groupSearch, StringComparison.OrdinalIgnoreCase); } else { if (inGroup && line.StartsWith(itemName, StringComparison.OrdinalIgnoreCase)) { // this is the item we are looking for var value = line.Split('=')[1].Trim(); if (string.IsNullOrEmpty(value)) { return; } try { retVal = (T)Convert.ChangeType(value, typeof(T)); } catch { } } } }); return(retVal); }