diff --git a/src/Umbraco.Core/Persistence/DatabaseDebugHelper.cs b/src/Umbraco.Core/Persistence/DatabaseDebugHelper.cs index 0bbd6f5bd5..f6f3d8d802 100644 --- a/src/Umbraco.Core/Persistence/DatabaseDebugHelper.cs +++ b/src/Umbraco.Core/Persistence/DatabaseDebugHelper.cs @@ -3,9 +3,11 @@ using System; using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Data.SqlServerCe; using System.Linq; using System.Reflection; using System.Text; +using Umbraco.Core.Persistence.FaultHandling; namespace Umbraco.Core.Persistence { @@ -29,11 +31,7 @@ namespace Umbraco.Core.Persistence { lock (Commands) { - var tuple = Commands.FirstOrDefault(x => - { - IDbCommand c; - return x.Item2.TryGetTarget(out c) && c == command; - }); + var tuple = Commands.FirstOrDefault(x => x.Item2.TryGetTarget(out var c) && c == command); return tuple == null ? "?" : tuple.Item1; } } @@ -42,28 +40,30 @@ namespace Umbraco.Core.Persistence { con = con.UnwrapUmbraco(); - var ceCon = con as System.Data.SqlServerCe.SqlCeConnection; - if (ceCon != null) return null; // "NotSupported: SqlCE"; + if (con is SqlCeConnection) return null; // "NotSupported: SqlCE"; - var dbCon = con as DbConnection; - return dbCon == null - ? "NotSupported: " + con.GetType() - : GetReferencedObjects(dbCon); + return con is DbConnection dbCon + ? GetReferencedObjects(dbCon) + : "NotSupported: " + con.GetType(); } public static string GetReferencedObjects(DbConnection con) { - var t = con.GetType(); + if (con.UnwrapUmbraco() is DbConnection ucon && !(ucon is SqlCeConnection)) + con = ucon; + else + return "NotSupported: " + con.GetType(); + var t = con.GetType(); var field = t.GetField("_innerConnection", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) throw new Exception("panic: _innerConnection (" + t + ")."); var innerConnection = field.GetValue(con); - var tin = innerConnection.GetType(); + var tin = innerConnection.GetType(); var fi = con is System.Data.SqlClient.SqlConnection - ? tin.BaseType.BaseType.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic) - : tin.BaseType.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic); + ? tin.BaseType?.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic) + : tin.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic); if (fi == null) //return ""; throw new Exception("panic: referenceCollection."); @@ -73,7 +73,7 @@ namespace Umbraco.Core.Persistence //return ""; throw new Exception("panic: innerCollection."); - field = rc.GetType().BaseType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic); + field = rc.GetType().BaseType?.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) throw new Exception("panic: items."); var items = field.GetValue(rc); var prop = items.GetType().GetProperty("Length", BindingFlags.Instance | BindingFlags.Public); @@ -116,21 +116,26 @@ namespace Umbraco.Core.Persistence i, inUse, objTarget.GetType(), objTarget.GetHashCode()); DbCommand cmd = null; - if (objTarget is DbDataReader) + switch (objTarget) { - //var rdr = objTarget as DbDataReader; - try - { - cmd = objTarget.GetType().GetProperty("Command", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(objTarget, null) as DbCommand; - } - catch (Exception e) - { - result.AppendFormat("\t\tObjTarget: DbDataReader, Exception: {0}" + Environment.NewLine, e); - } - } - else if (objTarget is DbCommand) - { - cmd = objTarget as DbCommand; + case DbDataReader _: + //var rdr = objTarget as DbDataReader; + try + { + var commandProp = objTarget.GetType().GetProperty("Command", BindingFlags.Instance | BindingFlags.NonPublic); + if (commandProp == null) + throw new Exception($"panic: failed to get Command property of {objTarget.GetType().FullName}."); + cmd = commandProp.GetValue(objTarget, null) as DbCommand; + } + catch (Exception e) + { + result.AppendFormat("\t\tObjTarget: DbDataReader, Exception: {0}" + Environment.NewLine, e); + } + + break; + case DbCommand command: + cmd = command; + break; } if (cmd == null) { @@ -152,7 +157,9 @@ namespace Umbraco.Core.Persistence if (pi.PropertyType != typeof (DbConnection) || pi.Name != "Connection") continue; - var con1 = pi.GetValue(cmd, null) as DbConnection; + var con0 = pi.GetValue(cmd, null); + if (!(con0 is DbConnection con1)) + throw new Exception($"panic: expected DbConnection, got {con0?.GetType().FullName ?? "null"}."); result.AppendFormat("\t\t\tConnection type=\"{0}\" state=\"{1}\" hashCode=\"{2}\"" + Environment.NewLine, con1.GetType(), con1.State, con1.GetHashCode()); diff --git a/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs b/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs index 4eccfe800f..8f501c0aaa 100644 --- a/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs +++ b/src/Umbraco.Core/Persistence/DbConnectionExtensions.cs @@ -5,6 +5,7 @@ using System.Data.SqlClient; using System.Data.SqlServerCe; using System.Linq; using MySql.Data.MySqlClient; +using StackExchange.Profiling.Data; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.FaultHandling; @@ -78,18 +79,13 @@ namespace Umbraco.Core.Persistence /// OnConnectionOpened); this unwraps and returns the original database connection. internal static IDbConnection UnwrapUmbraco(this IDbConnection connection) { - IDbConnection unwrapped; - - var c = connection; + var unwrapped = connection; + IDbConnection c; do { - unwrapped = c; - - var profiled = unwrapped as StackExchange.Profiling.Data.ProfiledDbConnection; - if (profiled != null) unwrapped = profiled.InnerConnection; - - var retrying = unwrapped as RetryDbConnection; - if (retrying != null) unwrapped = retrying.Inner; + c = unwrapped; + if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.InnerConnection; + if (unwrapped is RetryDbConnection retrying) unwrapped = retrying.Inner; } while (c != unwrapped); @@ -100,22 +96,23 @@ namespace Umbraco.Core.Persistence { try { - if (connection is SqlConnection) + switch (connection) { - var builder = new SqlConnectionStringBuilder(connection.ConnectionString); - return $"DataSource: {builder.DataSource}, InitialCatalog: {builder.InitialCatalog}"; - } - - if (connection is SqlCeConnection) - { - var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString); - return $"DataSource: {builder.DataSource}"; - } - - if (connection is MySqlConnection) - { - var builder = new MySqlConnectionStringBuilder(connection.ConnectionString); - return $"Server: {builder.Server}, Database: {builder.Database}"; + case SqlConnection _: + { + var builder = new SqlConnectionStringBuilder(connection.ConnectionString); + return $"DataSource: {builder.DataSource}, InitialCatalog: {builder.InitialCatalog}"; + } + case SqlCeConnection _: + { + var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString); + return $"DataSource: {builder.DataSource}"; + } + case MySqlConnection _: + { + var builder = new MySqlConnectionStringBuilder(connection.ConnectionString); + return $"Server: {builder.Server}, Database: {builder.Database}"; + } } } catch (Exception ex) diff --git a/src/Umbraco.Core/Persistence/FaultHandling/RetryDbConnection.cs b/src/Umbraco.Core/Persistence/FaultHandling/RetryDbConnection.cs index ed438ccbc1..ca10097ec4 100644 --- a/src/Umbraco.Core/Persistence/FaultHandling/RetryDbConnection.cs +++ b/src/Umbraco.Core/Persistence/FaultHandling/RetryDbConnection.cs @@ -177,8 +177,7 @@ namespace Umbraco.Core.Persistence.FaultHandling set { if (value == null) throw new ArgumentNullException(nameof(value)); - var connection = value as RetryDbConnection; - if (connection == null) throw new ArgumentException("Value is not a FaultHandlingDbConnection instance."); + if (!(value is RetryDbConnection connection)) throw new ArgumentException("Value is not a FaultHandlingDbConnection instance."); if (_connection != null && _connection != connection) throw new Exception("Value is another FaultHandlingDbConnection instance."); _connection = connection; _inner.Connection = connection.Inner; diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index 9f591bac8c..d205b695f8 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -149,7 +149,7 @@ namespace Umbraco.Core.Persistence #if DEBUG_DATABASES // determines the database connection SPID for debugging - if (DatabaseType == DBType.MySql) + if (DatabaseType.IsMySql()) { using (var command = connection.CreateCommand()) { @@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence _spid = Convert.ToInt32(command.ExecuteScalar()); } } - else if (DatabaseType == DBType.SqlServer) + else if (DatabaseType.IsSqlServer()) { using (var command = connection.CreateCommand()) { @@ -183,7 +183,7 @@ namespace Umbraco.Core.Persistence } #if DEBUG_DATABASES - public override void OnConnectionClosing(IDbConnection conn) + protected override void OnConnectionClosing(DbConnection conn) { _spid = -1; base.OnConnectionClosing(conn); @@ -212,7 +212,7 @@ namespace Umbraco.Core.Persistence #if DEBUG_DATABASES // detects whether the command is already in use (eg still has an open reader...) - DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + Thread.CurrentThread.ManagedThreadId + "]"); + DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]"); var refsobj = DatabaseDebugHelper.GetReferencedObjects(cmd.Connection); if (refsobj != null) _logger.Debug("Oops!" + Environment.NewLine + refsobj); #endif