diff --git a/src/Elmah.AzureTableStorage/AzureTableStorageErrorLog.cs b/src/Elmah.AzureTableStorage/AzureTableStorageErrorLog.cs index 4ba5e9c..a3d8d1b 100644 --- a/src/Elmah.AzureTableStorage/AzureTableStorageErrorLog.cs +++ b/src/Elmah.AzureTableStorage/AzureTableStorageErrorLog.cs @@ -14,10 +14,13 @@ namespace Elmah.AzureTableStorage public class AzureTableStorageErrorLog : ErrorLog { private readonly CloudTable _cloudTable; - private const string TableName = "Elmah"; + + private static volatile string TableName = "Elmah"; private const int MaxAppNameLength = 60; + private const int MaxTableNameLength = 60; + /// /// Initializes a new instance of the class /// using a dictionary of configured settings. @@ -28,27 +31,45 @@ public AzureTableStorageErrorLog(IDictionary config) if (config == null) throw new ArgumentNullException("config"); - var connectionString = ElmahHelper.GetConnectionString(config); + #region Read properties of ErrorLog config item // - // If there is no connection string to use then throw an - // exception to abort construction. + // Set the application name as this implementation provides + // per-application isolation over a single store. // - if (connectionString.Length == 0) - throw new ApplicationException("Connection string is missing for the Azure Table Storage error log."); - - var cloudStorageAccount = CloudStorageAccount.Parse(connectionString); - var tableClient = cloudStorageAccount.CreateCloudTableClient(); - _cloudTable = tableClient.GetTableReference(TableName); - _cloudTable.CreateIfNotExists(); + var appName = config.Find("applicationName", string.Empty); // - // Set the application name as this implementation provides - // per-application isolation over a single store. + // Set the table name. This implementation provides + // table-per-application-config isolation over a single store. // - var appName = config.Find("applicationName", string.Empty); + var tableName = config.Find("tableName", string.Empty); + + #endregion Read properties of ErrorLog config item + + #region Read properties of ErrorLog connection string + + var cfgBuilder = new System.Data.Common.DbConnectionStringBuilder(); + var originalConnectionString = ElmahHelper.GetConnectionString(config); + cfgBuilder.ConnectionString = originalConnectionString; + + // Try to override ApplicationName from connection string + if (cfgBuilder.ContainsKey("ApplicationName")) + { + appName = (string)cfgBuilder["ApplicationName"]; + cfgBuilder.Remove("ApplicationName"); + } + + // Try to override TableName from connection string + if (cfgBuilder.ContainsKey("TableName")) + { + tableName = (string)cfgBuilder["TableName"]; + cfgBuilder.Remove("TableName"); + } + + #endregion Read properties of ErrorLog connection string if (appName.Length > MaxAppNameLength) { @@ -57,7 +78,44 @@ public AzureTableStorageErrorLog(IDictionary config) MaxAppNameLength.ToString("N0"))); } - ApplicationName = appName; + if (tableName.Length > MaxTableNameLength) + { + throw new ApplicationException(string.Format( + "Table name is too long. Maximum length allowed is {0} characters.", + MaxTableNameLength.ToString("N0"))); + } + + if (!string.IsNullOrWhiteSpace(appName)) + { + ApplicationName = appName; + } + + if (!string.IsNullOrWhiteSpace(tableName)) + { + TableName = tableName; + } + + var newConnectionString = string.Join(";", originalConnectionString.Split(';').Where(item => !item.StartsWith("ApplicationName=", StringComparison.OrdinalIgnoreCase) && !item.StartsWith("TableName=", StringComparison.OrdinalIgnoreCase))); + var newConnectionStringBuilder = new System.Data.Common.DbConnectionStringBuilder(); + newConnectionStringBuilder.ConnectionString = newConnectionString; + + if (!cfgBuilder.EquivalentTo(newConnectionStringBuilder)) + { + throw new ApplicationException("Connection string contains invalid parameters."); + } + + // + // If there is no connection string to use then throw an + // exception to abort construction. + // + + if (cfgBuilder.ConnectionString.Length == 0) + throw new ApplicationException("Connection string is missing for the Azure Table Storage error log."); + + var cloudStorageAccount = CloudStorageAccount.Parse(newConnectionString); + var tableClient = cloudStorageAccount.CreateCloudTableClient(); + _cloudTable = tableClient.GetTableReference(TableName); + _cloudTable.CreateIfNotExists(); } ///