From 00c62804a831d2debd36bc7e787b197d44225016 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 29 May 2018 18:30:37 +0200 Subject: [PATCH 01/10] U4-11202 - Fix deadlock in UserRepository --- .../Persistence/NPocoSqlExtensions.cs | 76 ++++++++++++ .../Repositories/Implement/UserRepository.cs | 42 +++---- src/Umbraco.Core/ReflectionUtilities.cs | 110 ++++++++++++++++-- .../Clr/ReflectionUtilitiesTests.cs | 30 +++++ .../Persistence/NPocoTests/NPocoSqlTests.cs | 22 +++- 5 files changed, 248 insertions(+), 32 deletions(-) diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index 178b68b4f8..36777a42fd 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -916,6 +916,82 @@ namespace Umbraco.Core.Persistence #endregion + #region Hints + + /// + /// Appends the relevant ForUpdate hint. + /// + /// The Sql statement. + /// The Sql statement. + public static Sql ForUpdate(this Sql sql) + { + // MySql wants "FOR UPDATE" at the end, and T-Sql wants "WITH (UPDLOCK)" in the FROM statement, + // and we want to implement it in the least expensive way, so parsing the entire string here is + // a no, so we use reflection to work on the Sql expression before it is built. + // TODO propose a clean way to do that type of thing in NPoco + + if (sql.SqlContext.DatabaseType.IsMySql()) + { + sql.Append("FOR UDPATE"); + return sql; + } + + // go find the first FROM clause, and append the lock hint + Sql s = sql; + var updated = false; + + while (s != null) + { + var sqlText = SqlInspector.GetSqlText(s); + if (sqlText.StartsWith("FROM ", StringComparison.OrdinalIgnoreCase)) + { + SqlInspector.SetSqlText(s, sqlText + " WITH (UPDLOCK)"); + updated = true; + break; + } + + s = SqlInspector.GetSqlRhs(sql); + } + + if (updated) + SqlInspector.Reset(sql); + + return sql; + } + + #endregion + + #region Sql Inspection + + private static SqlInspectionUtilities _sqlInspector; + + private static SqlInspectionUtilities SqlInspector => _sqlInspector ?? (_sqlInspector = new SqlInspectionUtilities()); + + private class SqlInspectionUtilities + { + private readonly Func _getSqlText; + private readonly Action _setSqlText; + private readonly Func _getSqlRhs; + private readonly Action _setSqlFinal; + + public SqlInspectionUtilities() + { + (_getSqlText, _setSqlText) = ReflectionUtilities.EmitFieldGetterAndSetter("_sql"); + _getSqlRhs = ReflectionUtilities.EmitFieldGetter("_rhs"); + _setSqlFinal = ReflectionUtilities.EmitFieldSetter("_sqlFinal"); + } + + public string GetSqlText(Sql sql) => _getSqlText(sql); + + public void SetSqlText(Sql sql, string sqlText) => _setSqlText(sql, sqlText); + + public Sql GetSqlRhs(Sql sql) => _getSqlRhs(sql); + + public void Reset(Sql sql) => _setSqlFinal(sql, null); + } + + #endregion + #region Utilities private static string[] GetColumns(this Sql sql, string tableAlias = null, string referenceName = null, Expression>[] columnExpressions = null, bool withAlias = true) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs index 05fe456bbd..0ec5f9353b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs @@ -191,7 +191,20 @@ ORDER BY colName"; public bool ValidateLoginSession(int userId, Guid sessionId) { - var found = Database.FirstOrDefault("WHERE sessionId=@sessionId", new {sessionId = sessionId}); + // with RepeatableRead transaction mode, read-then-update operations can + // cause deadlocks, and the ForUpdate() hint is required to tell the database + // to acquire an exclusive lock when reading + + // that query is going to run a *lot*, make it a template + var t = SqlContext.Templates.Get("Umbraco.Core.UserRepository.ValidateLoginSession", s => s + .Select() + .From() + .Where(x => x.SessionId == SqlTemplate.Arg("sessionId")) + .ForUpdate()); + + var sql = t.Sql(sessionId); + + var found = Database.Query(sql).FirstOrDefault(); if (found == null || found.UserId != userId || found.LoggedOutUtc.HasValue) return false; @@ -211,34 +224,21 @@ ORDER BY colName"; public int ClearLoginSessions(int userId) { - //TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository - //and also business logic models for these objects but that's just so overkill for what we are doing - //and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore - var count = Database.ExecuteScalar("SELECT COUNT(*) FROM umbracoUserLogin WHERE userId=@userId", new { userId = userId }); - Database.Execute("DELETE FROM umbracoUserLogin WHERE userId=@userId", new {userId = userId}); - return count; + return Database.Delete(Sql().Where(x => x.UserId == userId)); } public int ClearLoginSessions(TimeSpan timespan) { - //TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository - //and also business logic models for these objects but that's just so overkill for what we are doing - //and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore - var fromDate = DateTime.UtcNow - timespan; - - var count = Database.ExecuteScalar("SELECT COUNT(*) FROM umbracoUserLogin WHERE lastValidatedUtc=@fromDate", new { fromDate = fromDate }); - Database.Execute("DELETE FROM umbracoUserLogin WHERE lastValidatedUtc=@fromDate", new { fromDate = fromDate }); - return count; + return Database.Delete(Sql().Where(x => x.LastValidatedUtc < fromDate)); } public void ClearLoginSession(Guid sessionId) { - //TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository - //and also business logic models for these objects but that's just so overkill for what we are doing - //and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore - Database.Execute("UPDATE umbracoUserLogin SET loggedOutUtc=@now WHERE sessionId=@sessionId", - new { now = DateTime.UtcNow, sessionId = sessionId }); + // fixme why is that one updating and not deleting? + Database.Execute(Sql() + .Update(u => u.Set(x => x.LoggedOutUtc, DateTime.UtcNow)) + .Where(x => x.SessionId == sessionId)); } protected override IEnumerable PerformGetAll(params int[] ids) @@ -718,7 +718,7 @@ ORDER BY colName"; if (string.IsNullOrWhiteSpace(orderBy)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(orderBy)); Sql filterSql = null; - var customFilterWheres = filter != null ? filter.GetWhereClauses().ToArray() : null; + var customFilterWheres = filter?.GetWhereClauses().ToArray(); var hasCustomFilter = customFilterWheres != null && customFilterWheres.Length > 0; if (hasCustomFilter || includeUserGroups != null && includeUserGroups.Length > 0 diff --git a/src/Umbraco.Core/ReflectionUtilities.cs b/src/Umbraco.Core/ReflectionUtilities.cs index db0cde87db..3cca2b5b62 100644 --- a/src/Umbraco.Core/ReflectionUtilities.cs +++ b/src/Umbraco.Core/ReflectionUtilities.cs @@ -21,6 +21,96 @@ namespace Umbraco.Core /// public static partial class ReflectionUtilities { + #region Fields + + /// + /// Emits a field getter. + /// + /// The declaring type. + /// The field type. + /// The name of the field. + /// A field getter function. + /// Occurs when is null or empty. + /// Occurs when the field does not exist. + /// Occurs when does not match the type of the field. + public static Func EmitFieldGetter(string fieldName) + { + var field = GetField(fieldName); + return EmitFieldGetter(field); + } + + /// + /// Emits a field setter. + /// + /// The declaring type. + /// The field type. + /// The name of the field. + /// A field setter action. + /// Occurs when is null or empty. + /// Occurs when the field does not exist. + /// Occurs when does not match the type of the field. + public static Action EmitFieldSetter(string fieldName) + { + var field = GetField(fieldName); + return EmitFieldSetter(field); + } + + /// + /// Emits a field getter and setter. + /// + /// The declaring type. + /// The field type. + /// The name of the field. + /// A field getter and setter functions. + /// Occurs when is null or empty. + /// Occurs when the field does not exist. + /// Occurs when does not match the type of the field. + public static (Func, Action) EmitFieldGetterAndSetter(string fieldName) + { + var field = GetField(fieldName); + return (EmitFieldGetter(field), EmitFieldSetter(field)); + } + + private static FieldInfo GetField(string fieldName) + { + if (string.IsNullOrWhiteSpace(fieldName)) throw new ArgumentNullOrEmptyException(nameof(fieldName)); + + // get the field + var field = typeof(TDeclaring).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (field == null) throw new InvalidOperationException($"Could not find field {typeof(TDeclaring)}.{fieldName}."); + + // validate field type + if (field.FieldType != typeof(TValue)) // strict + throw new ArgumentException($"Value type {typeof(TValue)} does not match field {typeof(TDeclaring)}.{fieldName} type {field.FieldType}."); + + return field; + } + + private static Func EmitFieldGetter(FieldInfo field) + { + // emit + var (dm, ilgen) = CreateIlGenerator(field.DeclaringType?.Module, new [] { typeof(TDeclaring) }, typeof(TValue)); + ilgen.Emit(OpCodes.Ldarg_0); + ilgen.Emit(OpCodes.Ldfld, field); + ilgen.Return(); + + return (Func) (object) dm.CreateDelegate(typeof(Func)); + } + + private static Action EmitFieldSetter(FieldInfo field) + { + // emit + var (dm, ilgen) = CreateIlGenerator(field.DeclaringType?.Module, new [] { typeof(TDeclaring), typeof(TValue) }, typeof(void)); + ilgen.Emit(OpCodes.Ldarg_0); + ilgen.Emit(OpCodes.Ldarg_1); + ilgen.Emit(OpCodes.Stfld, field); + ilgen.Return(); + + return (Action) (object) dm.CreateDelegate(typeof(Action)); + } + + #endregion + #region Properties /// @@ -207,7 +297,7 @@ namespace Umbraco.Core /// is specified and does not match the function's returned type. public static TLambda EmitCtor(bool mustExist = true, Type declaring = null) { - (_, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(true, true); + var (_, lambdaParameters, lambdaReturned) = AnalyzeLambda(true, true); // determine returned / declaring type if (declaring == null) declaring = lambdaReturned; @@ -239,7 +329,7 @@ namespace Umbraco.Core { if (ctor == null) throw new ArgumentNullException(nameof(ctor)); - (_, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(true, true); + var (_, lambdaParameters, lambdaReturned) = AnalyzeLambda(true, true); return EmitCtorSafe(lambdaParameters, lambdaReturned, ctor); } @@ -281,7 +371,7 @@ namespace Umbraco.Core { if (ctor == null) throw new ArgumentNullException(nameof(ctor)); - (_, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(true, true); + var (_, lambdaParameters, lambdaReturned) = AnalyzeLambda(true, true); // emit - unsafe - use lambda's args and assume they are correct return EmitCtor(lambdaReturned, lambdaParameters, ctor); @@ -293,7 +383,7 @@ namespace Umbraco.Core var ctorParameters = GetParameters(ctor); // emit - (var dm, var ilgen) = CreateIlGenerator(ctor.DeclaringType?.Module, lambdaParameters, declaring); + var (dm, ilgen) = CreateIlGenerator(ctor.DeclaringType?.Module, lambdaParameters, declaring); EmitLdargs(ilgen, lambdaParameters, ctorParameters); ilgen.Emit(OpCodes.Newobj, ctor); // ok to just return, it's only objects ilgen.Return(); @@ -342,7 +432,7 @@ namespace Umbraco.Core { if (string.IsNullOrWhiteSpace(methodName)) throw new ArgumentNullOrEmptyException(nameof(methodName)); - (var lambdaDeclaring, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(true, out var isFunction); + var (lambdaDeclaring, lambdaParameters, lambdaReturned) = AnalyzeLambda(true, out var isFunction); // get the method infos var method = declaring.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, lambdaParameters, null); @@ -374,7 +464,7 @@ namespace Umbraco.Core var methodParameters = method.GetParameters().Select(x => x.ParameterType).ToArray(); var isStatic = method.IsStatic; - (var lambdaDeclaring, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(isStatic, out var isFunction); + var (lambdaDeclaring, lambdaParameters, lambdaReturned) = AnalyzeLambda(isStatic, out var isFunction); // if not static, then the first lambda arg must be the method declaring type if (!isStatic && (methodDeclaring == null || !methodDeclaring.IsAssignableFrom(lambdaDeclaring))) @@ -408,7 +498,7 @@ namespace Umbraco.Core if (method == null) throw new ArgumentNullException(nameof(method)); var isStatic = method.IsStatic; - (var lambdaDeclaring, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(isStatic, out _); + var (lambdaDeclaring, lambdaParameters, lambdaReturned) = AnalyzeLambda(isStatic, out _); // emit - unsafe - use lambda's args and assume they are correct return EmitMethod(lambdaDeclaring, lambdaReturned, lambdaParameters, method); @@ -433,7 +523,7 @@ namespace Umbraco.Core throw new ArgumentNullOrEmptyException(nameof(methodName)); // validate lambda type - (var lambdaDeclaring, var lambdaParameters, var lambdaReturned) = AnalyzeLambda(false, out var isFunction); + var (lambdaDeclaring, lambdaParameters, lambdaReturned) = AnalyzeLambda(false, out var isFunction); // get the method infos var method = lambdaDeclaring.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, lambdaParameters, null); @@ -464,7 +554,7 @@ namespace Umbraco.Core var methodArgTypes = GetParameters(method, withDeclaring: !method.IsStatic); // emit IL - (var dm, var ilgen) = CreateIlGenerator(method.DeclaringType?.Module, parameters, lambdaReturned); + var (dm, ilgen) = CreateIlGenerator(method.DeclaringType?.Module, parameters, lambdaReturned); EmitLdargs(ilgen, parameters, methodArgTypes); ilgen.CallMethod(method); EmitOutputAdapter(ilgen, lambdaReturned, method.ReturnType); @@ -486,7 +576,7 @@ namespace Umbraco.Core { var typeLambda = typeof(TLambda); - (var declaring, var parameters, var returned) = AnalyzeLambda(isStatic, out var maybeFunction); + var (declaring, parameters, returned) = AnalyzeLambda(isStatic, out var maybeFunction); if (isFunction) { diff --git a/src/Umbraco.Tests/Clr/ReflectionUtilitiesTests.cs b/src/Umbraco.Tests/Clr/ReflectionUtilitiesTests.cs index 0b3d5235c8..31f936213d 100644 --- a/src/Umbraco.Tests/Clr/ReflectionUtilitiesTests.cs +++ b/src/Umbraco.Tests/Clr/ReflectionUtilitiesTests.cs @@ -528,6 +528,26 @@ namespace Umbraco.Tests.Clr Assert.AreEqual(1, values5D["intValue2"]); // JsonProperty changes property name } + [Test] + public void EmitFieldGetterSetterEmits() + { + var getter1 = ReflectionUtilities.EmitFieldGetter("Field1"); + var getter2 = ReflectionUtilities.EmitFieldGetter("Field2"); + var c = new Class1(); + Assert.AreEqual(33, getter1(c)); + Assert.AreEqual(66, getter2(c)); + + var setter2 = ReflectionUtilities.EmitFieldSetter("Field2"); + setter2(c, 99); + Assert.AreEqual(99, getter2(c)); + + // works on readonly fields! + var (getter3, setter3) = ReflectionUtilities.EmitFieldGetterAndSetter("Field3"); + Assert.AreEqual(22, getter3(c)); + setter3(c, 44); + Assert.AreEqual(44, getter3(c)); + } + // fixme - missing tests specifying 'returned' on method, property #region IL Code @@ -550,6 +570,12 @@ namespace Umbraco.Tests.Clr // conv.i4 public void SetIntValue2(Class4 object4, object d) => object4.IntValue = (int) (double) d; + // get field + public int GetIntField(Class1 object1) => object1.Field1; + + // set field + public void SetIntField(Class1 object1, int i) => object1.Field1 = i; + #endregion #region Test Objects @@ -583,6 +609,10 @@ namespace Umbraco.Tests.Clr public int Value2 { set { } } public int Value3 { get { return 42; } set { } } private int ValueP1 => 42; + + public int Field1 = 33; + private int Field2 = 66; + public readonly int Field3 = 22; } public class Class2 { } diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs index a7b75cbd6d..6fa2af74cf 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Persistence; @@ -293,5 +294,24 @@ namespace Umbraco.Tests.Persistence.NPocoTests Debug.Print(sql.SQL); } + + [Test] + public void ForUpdate() + { + var sessionId = Guid.NewGuid(); + + var sql = Sql() + .SelectAll() + .From() + .Where(x => x.SessionId == sessionId); + + sql.WriteToConsole(); + Assert.AreEqual("SELECT * FROM [umbracoUserLogin] WHERE (([umbracoUserLogin].[sessionId] = @0))", sql.SQL.NoCrLf()); + + sql = sql.ForUpdate(); + + sql.WriteToConsole(); + Assert.AreEqual("SELECT * FROM [umbracoUserLogin] WITH (UPDLOCK) WHERE (([umbracoUserLogin].[sessionId] = @0))", sql.SQL.NoCrLf()); + } } } From 8f87381c01c8b0e5ccb6cecef29e09690e2281c4 Mon Sep 17 00:00:00 2001 From: Claus Date: Thu, 31 May 2018 10:23:09 +0200 Subject: [PATCH 02/10] fixed typo --- src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index 36777a42fd..9c1f0d9a07 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -932,7 +932,7 @@ namespace Umbraco.Core.Persistence if (sql.SqlContext.DatabaseType.IsMySql()) { - sql.Append("FOR UDPATE"); + sql.Append("FOR UPDATE"); return sql; } From e0f97feb1c367f200dee5077eb80e79d8c4fd215 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 11:26:24 +0200 Subject: [PATCH 03/10] Update Benchmarks csproj --- src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 1ef1851ae1..19236e0163 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -14,9 +14,7 @@ - + false AnyCPU From 38eae906402ac7f3d2bb2b4818babc7b4796f9a6 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 11:56:31 +0200 Subject: [PATCH 04/10] Cleanup and get rid of warnings --- .../Events/CancellableObjectEventArgs.cs | 8 ++--- src/Umbraco.Core/Events/MoveEventArgs.cs | 31 +++++-------------- src/Umbraco.Core/IO/MediaFileSystem.cs | 14 ++++++--- .../Logging/WebProfilerProvider.cs | 1 + .../Migrations/Install/DatabaseBuilder.cs | 5 ++- .../RemoveStylesheetDataAndTablesAgain.cs | 11 +++++-- .../Packaging/PackageInstallation.cs | 18 +++++------ src/Umbraco.Core/Properties/AssemblyInfo.cs | 7 +++-- src/Umbraco.Core/Runtime/CoreRuntime.cs | 4 +-- src/Umbraco.Core/Strings/CleanStringType.cs | 11 +++---- src/Umbraco.Tests.Benchmarks/app.config | 8 ++--- src/Umbraco.Tests/App.config | 8 ++--- src/Umbraco.Web/Properties/AssemblyInfo.cs | 3 -- 13 files changed, 58 insertions(+), 71 deletions(-) diff --git a/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs b/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs index 748ecb31ed..8c8362251a 100644 --- a/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs +++ b/src/Umbraco.Core/Events/CancellableObjectEventArgs.cs @@ -97,14 +97,14 @@ namespace Umbraco.Core.Events public bool Equals(CancellableObjectEventArgs other) { - if (ReferenceEquals(null, other)) return false; + if (other is null) return false; if (ReferenceEquals(this, other)) return true; return base.Equals(other) && EqualityComparer.Default.Equals(EventObject, other.EventObject); } public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; + if (obj is null) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((CancellableObjectEventArgs)obj); @@ -154,7 +154,7 @@ namespace Umbraco.Core.Events public bool Equals(CancellableEnumerableObjectEventArgs other) { - if (ReferenceEquals(null, other)) return false; + if (other is null) return false; if (ReferenceEquals(this, other)) return true; return EventObject.SequenceEqual(other.EventObject); @@ -162,7 +162,7 @@ namespace Umbraco.Core.Events public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; + if (obj is null) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((CancellableEnumerableObjectEventArgs)obj); diff --git a/src/Umbraco.Core/Events/MoveEventArgs.cs b/src/Umbraco.Core/Events/MoveEventArgs.cs index afc1f57111..9ae5840349 100644 --- a/src/Umbraco.Core/Events/MoveEventArgs.cs +++ b/src/Umbraco.Core/Events/MoveEventArgs.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Events /// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation /// public MoveEventArgs(bool canCancel, EventMessages eventMessages, params MoveEventInfo[] moveInfo) - : base(default(TEntity), canCancel, eventMessages) + : base(default, canCancel, eventMessages) { if (moveInfo.FirstOrDefault() == null) { @@ -27,7 +27,6 @@ namespace Umbraco.Core.Events MoveInfoCollection = moveInfo; //assign the legacy props EventObject = moveInfo.First().Entity; - ParentId = moveInfo.First().NewParentId; } /// @@ -38,7 +37,7 @@ namespace Umbraco.Core.Events /// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation /// public MoveEventArgs(EventMessages eventMessages, params MoveEventInfo[] moveInfo) - : base(default(TEntity), eventMessages) + : base(default, eventMessages) { if (moveInfo.FirstOrDefault() == null) { @@ -48,7 +47,6 @@ namespace Umbraco.Core.Events MoveInfoCollection = moveInfo; //assign the legacy props EventObject = moveInfo.First().Entity; - ParentId = moveInfo.First().NewParentId; } /// @@ -59,7 +57,7 @@ namespace Umbraco.Core.Events /// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation /// public MoveEventArgs(bool canCancel, params MoveEventInfo[] moveInfo) - : base(default(TEntity), canCancel) + : base(default, canCancel) { if (moveInfo.FirstOrDefault() == null) { @@ -69,7 +67,6 @@ namespace Umbraco.Core.Events MoveInfoCollection = moveInfo; //assign the legacy props EventObject = moveInfo.First().Entity; - ParentId = moveInfo.First().NewParentId; } /// @@ -79,7 +76,7 @@ namespace Umbraco.Core.Events /// A colleciton of MoveEventInfo objects that exposes all entities that have been moved during a single move operation /// public MoveEventArgs(params MoveEventInfo[] moveInfo) - : base(default(TEntity)) + : base(default) { if (moveInfo.FirstOrDefault() == null) { @@ -89,22 +86,17 @@ namespace Umbraco.Core.Events MoveInfoCollection = moveInfo; //assign the legacy props EventObject = moveInfo.First().Entity; - ParentId = moveInfo.First().NewParentId; } [Obsolete("Use the overload that specifies the MoveEventInfo object")] public MoveEventArgs(TEntity eventObject, bool canCancel, int parentId) : base(eventObject, canCancel) - { - ParentId = parentId; - } + { } [Obsolete("Use the overload that specifies the MoveEventInfo object")] public MoveEventArgs(TEntity eventObject, int parentId) : base(eventObject) - { - ParentId = parentId; - } + { } /// /// Gets all MoveEventInfo objects used to create the object @@ -124,7 +116,6 @@ namespace Umbraco.Core.Events //assign the legacy props EventObject = first.Entity; - ParentId = first.NewParentId; } } @@ -137,22 +128,16 @@ namespace Umbraco.Core.Events get { return EventObject; } } - /// - /// Gets the Id of the object's new parent - /// - [Obsolete("Retrieve the ParentId from the MoveInfoCollection property instead")] - public int ParentId { get; private set; } - public bool Equals(MoveEventArgs other) { - if (ReferenceEquals(null, other)) return false; + if (other is null) return false; if (ReferenceEquals(this, other)) return true; return base.Equals(other) && MoveInfoCollection.Equals(other.MoveInfoCollection); } public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; + if (obj is null) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((MoveEventArgs) obj); diff --git a/src/Umbraco.Core/IO/MediaFileSystem.cs b/src/Umbraco.Core/IO/MediaFileSystem.cs index 5534936a04..2c9773a9cb 100644 --- a/src/Umbraco.Core/IO/MediaFileSystem.cs +++ b/src/Umbraco.Core/IO/MediaFileSystem.cs @@ -115,6 +115,9 @@ namespace Umbraco.Core.IO if (FileExists(file) == false) return; DeleteFile(file); +#pragma warning disable 162 // unreachable code + // Not implemented yet, so need to disable warnings + // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (UseTheNewMediaPathScheme == false) { // old scheme: filepath is "/" OR "-" @@ -130,6 +133,7 @@ namespace Umbraco.Core.IO var dir = Path.GetDirectoryName(file); DeleteDirectory(dir, true); } +#pragma warning restore 162 } catch (Exception e) { @@ -155,6 +159,9 @@ namespace Umbraco.Core.IO filename = IOHelper.SafeFileName(filename.ToLowerInvariant()); string folder; +#pragma warning disable 162 // unreachable code + // Not implemented yet, so need to disable warnings + // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (UseTheNewMediaPathScheme == false) { // old scheme: filepath is "/" OR "-" @@ -169,6 +176,7 @@ namespace Umbraco.Core.IO // for a single content cannot store two different files with the same name folder = Combine(cuid, puid).ToHexString(/*'/', 2, 4*/); // could use ext to fragment path eg 12/e4/f2/... } +#pragma warning restore 162 var filepath = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories ? Path.Combine(folder, filename).Replace('\\', '/') @@ -213,9 +221,8 @@ namespace Umbraco.Core.IO var sep = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories ? "/" : "-"; var pos = prevpath.IndexOf(sep, StringComparison.Ordinal); var s = pos > 0 ? prevpath.Substring(0, pos) : null; - int ignored; - var folder = (pos > 0 && int.TryParse(s, out ignored)) ? s : GetNextFolder(); + var folder = (pos > 0 && int.TryParse(s, out _)) ? s : GetNextFolder(); // ReSharper disable once AssignNullToNotNullAttribute var filepath = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories @@ -246,8 +253,7 @@ namespace Umbraco.Core.IO var directories = GetDirectories(""); foreach (var directory in directories) { - long folderNumber; - if (long.TryParse(directory, out folderNumber) && folderNumber > _folderCounter) + if (long.TryParse(directory, out var folderNumber) && folderNumber > _folderCounter) _folderCounter = folderNumber; } diff --git a/src/Umbraco.Core/Logging/WebProfilerProvider.cs b/src/Umbraco.Core/Logging/WebProfilerProvider.cs index 8fe657a01b..35ecd002c8 100644 --- a/src/Umbraco.Core/Logging/WebProfilerProvider.cs +++ b/src/Umbraco.Core/Logging/WebProfilerProvider.cs @@ -92,6 +92,7 @@ namespace Umbraco.Core.Logging } // obsolete but that's the one that's called ;-( + [Obsolete] public override MiniProfiler Start(ProfileLevel level, string sessionName = null) { return Start(sessionName); diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index a3fd35df44..50640e2dde 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -134,7 +134,7 @@ namespace Umbraco.Core.Migrations.Install { SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe, logger); - var path = Path.Combine(GlobalSettings.FullPathToRoot, "App_Data", "Umbraco.sdf"); + var path = Path.Combine(IOHelper.GetRootDirectorySafe(), "App_Data", "Umbraco.sdf"); if (File.Exists(path) == false) { // this should probably be in a "using (new SqlCeEngine)" clause but not sure @@ -173,8 +173,7 @@ namespace Umbraco.Core.Migrations.Install /// The name the provider (Sql, Sql Azure, Sql Ce, MySql). public void ConfigureDatabaseConnection(string server, string databaseName, string user, string password, string databaseProvider) { - string providerName; - var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out providerName); + var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out var providerName); SaveConnectionString(connectionString, providerName, _logger); _databaseFactory.Configure(connectionString, providerName); diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs index 77fb24ddbc..d27ed11a21 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0 { @@ -14,19 +15,23 @@ namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0 public override void Migrate() { + // these have been obsoleted, need to copy the values here + var stylesheetPropertyObjectType = new Guid("5555da4f-a123-42b2-4488-dcdfb25e4111"); + var stylesheetObjectType = new Guid("9F68DA4F-A3A8-44C2-8226-DCBD125E4840"); + //Clear all stylesheet data if the tables exist var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray(); if (tables.InvariantContains("cmsStylesheetProperty")) { Delete.FromTable("cmsStylesheetProperty").AllRows().Do(); - Delete.FromTable("umbracoNode").Row(new { nodeObjectType = Constants.ObjectTypes.StylesheetProperty }).Do(); + Delete.FromTable("umbracoNode").Row(new { nodeObjectType = stylesheetPropertyObjectType }).Do(); Delete.Table("cmsStylesheetProperty").Do(); } if (tables.InvariantContains("cmsStylesheet")) { Delete.FromTable("cmsStylesheet").AllRows().Do(); - Delete.FromTable("umbracoNode").Row(new { nodeObjectType = Constants.ObjectTypes.Stylesheet }).Do(); + Delete.FromTable("umbracoNode").Row(new { nodeObjectType = stylesheetObjectType }).Do(); Delete.Table("cmsStylesheet").Do(); } diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index bee9efb612..b28fcb4347 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Packaging public PackageInstallation(IPackagingService packagingService, IMacroService macroService, IFileService fileService, IPackageExtraction packageExtraction) - : this(packagingService, macroService, fileService, packageExtraction, GlobalSettings.FullPathToRoot) + : this(packagingService, macroService, fileService, packageExtraction, IOHelper.GetRootDirectorySafe()) {} public PackageInstallation(IPackagingService packagingService, IMacroService macroService, @@ -212,9 +212,8 @@ namespace Umbraco.Core.Packaging private XDocument GetConfigXmlDoc(string packageFilePath) { - string filePathInPackage; - string configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFilePath, - Constants.Packaging.PackageXmlFileName, out filePathInPackage); + var configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFilePath, + Constants.Packaging.PackageXmlFileName, out _); return XDocument.Parse(configXmlContent); } @@ -294,15 +293,13 @@ namespace Umbraco.Core.Packaging }; - XAttribute attr = elemet.Attribute(Constants.Packaging.RunatNodeAttribute); + var attr = elemet.Attribute(Constants.Packaging.RunatNodeAttribute); - ActionRunAt runAt; - if (attr != null && Enum.TryParse(attr.Value, true, out runAt)) { packageAction.RunAt = runAt; } + if (attr != null && Enum.TryParse(attr.Value, true, out ActionRunAt runAt)) { packageAction.RunAt = runAt; } attr = elemet.Attribute(Constants.Packaging.UndoNodeAttribute); - bool undo; - if (attr != null && bool.TryParse(attr.Value, out undo)) { packageAction.Undo = undo; } + if (attr != null && bool.TryParse(attr.Value, out var undo)) { packageAction.Undo = undo; } return packageAction; @@ -570,8 +567,7 @@ namespace Umbraco.Core.Packaging private static int IntValue(XElement xElement, int defaultValue = 0) { - int val; - return xElement == null ? defaultValue : int.TryParse(xElement.Value, out val) ? val : defaultValue; + return xElement == null ? defaultValue : int.TryParse(xElement.Value, out var val) ? val : defaultValue; } private static string UpdatePathPlaceholders(string path) diff --git a/src/Umbraco.Core/Properties/AssemblyInfo.cs b/src/Umbraco.Core/Properties/AssemblyInfo.cs index 5e411e681c..1391aaa9ed 100644 --- a/src/Umbraco.Core/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Core/Properties/AssemblyInfo.cs @@ -34,7 +34,8 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("Umbraco.Forms.Web")] // Umbraco Headless -[assembly: InternalsVisibleTo("Umbraco.Headless")] +[assembly: InternalsVisibleTo("Umbraco.Headless")] -// v8 -[assembly: InternalsVisibleTo("Umbraco.Compat7")] +// code analysis +// IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")] diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 35ac5aff86..a3652b3330 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -45,8 +45,8 @@ namespace Umbraco.Core.Runtime public virtual void Boot(ServiceContainer container) { // some components may want to initialize with the UmbracoApplicationBase - // well, they should not - we should not do this - however, Compat7 wants - // it, so let's do it, but we should remove this eventually. + // well, they should not - we should not do this + // TODO remove this eventually. container.RegisterInstance(_app); Compose(container); diff --git a/src/Umbraco.Core/Strings/CleanStringType.cs b/src/Umbraco.Core/Strings/CleanStringType.cs index c8c99be869..7367aa8b4b 100644 --- a/src/Umbraco.Core/Strings/CleanStringType.cs +++ b/src/Umbraco.Core/Strings/CleanStringType.cs @@ -68,13 +68,10 @@ namespace Umbraco.Core.Strings /// /// Flag mask for encoding. /// - CodeMask = Unicode | Utf8 | Ascii | TryAscii, - - /// - /// Unicode encoding. - /// - [Obsolete("Use .Utf8 instead.")] - Unicode = 0x0100, + CodeMask = Utf8 | Ascii | TryAscii, + + // Unicode encoding is obsolete, use Utf8 + //Unicode = 0x0100, /// /// Utf8 encoding. diff --git a/src/Umbraco.Tests.Benchmarks/app.config b/src/Umbraco.Tests.Benchmarks/app.config index d9d475681a..d71468cbdb 100644 --- a/src/Umbraco.Tests.Benchmarks/app.config +++ b/src/Umbraco.Tests.Benchmarks/app.config @@ -11,11 +11,11 @@ - + - + @@ -275,11 +275,11 @@ - + - + diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 6339a1ced4..c197ee9bf7 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -113,11 +113,11 @@ - + - + @@ -157,11 +157,11 @@ - + - + diff --git a/src/Umbraco.Web/Properties/AssemblyInfo.cs b/src/Umbraco.Web/Properties/AssemblyInfo.cs index 2e8c612aba..84ffe1e2f4 100644 --- a/src/Umbraco.Web/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Web/Properties/AssemblyInfo.cs @@ -36,9 +36,6 @@ using System.Runtime.InteropServices; // Umbraco Headless [assembly: InternalsVisibleTo("Umbraco.Headless")] -// v8 -[assembly: InternalsVisibleTo("Umbraco.Compat7")] - // code analysis // IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")] From 2248e310d90d623544ce769f6bf11148512d2158 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 11:59:30 +0200 Subject: [PATCH 05/10] Cleanup and get rid of more warnings --- src/Umbraco.Examine/Config/IndexSets.cs | 11 +++-------- src/Umbraco.Examine/Properties/AssemblyInfo.cs | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Examine/Config/IndexSets.cs b/src/Umbraco.Examine/Config/IndexSets.cs index 4aa90b99d7..c6ad1476c3 100644 --- a/src/Umbraco.Examine/Config/IndexSets.cs +++ b/src/Umbraco.Examine/Config/IndexSets.cs @@ -4,16 +4,11 @@ namespace Umbraco.Examine.Config { public sealed class IndexSets : ConfigurationSection { - #region Singleton definition - protected IndexSets() { } - static IndexSets() - { - Instance = ConfigurationManager.GetSection(SectionName) as IndexSets; + private IndexSets() { } - } - public static IndexSets Instance { get; } + public static IndexSets Instance { get; } = ConfigurationManager.GetSection(SectionName) as IndexSets; #endregion @@ -23,4 +18,4 @@ namespace Umbraco.Examine.Config [ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)] public IndexSetCollection Sets => (IndexSetCollection)base[""]; } -} \ No newline at end of file +} diff --git a/src/Umbraco.Examine/Properties/AssemblyInfo.cs b/src/Umbraco.Examine/Properties/AssemblyInfo.cs index c08fd23daf..6713111968 100644 --- a/src/Umbraco.Examine/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Examine/Properties/AssemblyInfo.cs @@ -8,3 +8,7 @@ using System.Runtime.CompilerServices; // Umbraco Cms [assembly: InternalsVisibleTo("Umbraco.Tests")] + +// code analysis +// IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")] From 3862ff907639b7d778cc5cc8b50d0b37730c9d6e Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 16:40:06 +0200 Subject: [PATCH 06/10] Cleanup and get rid of other warnings --- src/Umbraco.Core/Components/BootLoader.cs | 9 +++------ .../PublishedContent/PublishedContentTypeFactory.cs | 13 ++----------- src/Umbraco.Examine/UmbracoContentIndexer.cs | 3 +-- src/Umbraco.Web/UmbracoModule.cs | 2 +- 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Core/Components/BootLoader.cs b/src/Umbraco.Core/Components/BootLoader.cs index 0b2374a6bb..d292ff8d62 100644 --- a/src/Umbraco.Core/Components/BootLoader.cs +++ b/src/Umbraco.Core/Components/BootLoader.cs @@ -29,8 +29,7 @@ namespace Umbraco.Core.Components /// The application container. public BootLoader(IServiceContainer container) { - if (container == null) throw new ArgumentNullException(nameof(container)); - _container = container; + _container = container ?? throw new ArgumentNullException(nameof(container)); _proflog = container.GetInstance(); _logger = container.GetInstance(); } @@ -176,8 +175,7 @@ namespace Umbraco.Core.Components foreach (var attr in componentType.GetCustomAttributes()) { var type = attr.EnabledType ?? componentType; - EnableInfo enableInfo; - if (enabled.TryGetValue(type, out enableInfo) == false) enableInfo = enabled[type] = new EnableInfo(); + if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo(); var weight = type == componentType ? 1 : 2; if (enableInfo.Weight > weight) continue; @@ -188,8 +186,7 @@ namespace Umbraco.Core.Components { var type = attr.DisabledType ?? componentType; if (type == typeof(UmbracoCoreComponent)) throw new InvalidOperationException("Cannot disable UmbracoCoreComponent."); - EnableInfo enableInfo; - if (enabled.TryGetValue(type, out enableInfo) == false) enableInfo = enabled[type] = new EnableInfo(); + if (enabled.TryGetValue(type, out var enableInfo) == false) enableInfo = enabled[type] = new EnableInfo(); var weight = type == componentType ? 1 : 2; if (enableInfo.Weight > weight) continue; diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs index a98dca4f29..3ba908b9bf 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs @@ -31,13 +31,13 @@ namespace Umbraco.Core.Models.PublishedContent return new PublishedContentType(contentType, this); } - // for tests - fixme what's the point of the factory here? + // for tests internal PublishedContentType CreateContentType(int id, string alias, IEnumerable propertyTypes, ContentVariation variations = ContentVariation.InvariantNeutral) { return new PublishedContentType(id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, variations); } - // for tests - fixme what's the point of the factory here? + // for tests internal PublishedContentType CreateContentType(int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes, ContentVariation variations = ContentVariation.InvariantNeutral) { return new PublishedContentType(id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, variations); @@ -84,15 +84,6 @@ namespace Umbraco.Core.Models.PublishedContent return dataType; } - /// - public void NotifyDataTypeChanges() - { - lock (_publishedDataTypesLocker) - { - _publishedDataTypes = null; - } - } - /// public void NotifyDataTypeChanges(int[] ids) { diff --git a/src/Umbraco.Examine/UmbracoContentIndexer.cs b/src/Umbraco.Examine/UmbracoContentIndexer.cs index 487d238c25..bdbaf04a32 100644 --- a/src/Umbraco.Examine/UmbracoContentIndexer.cs +++ b/src/Umbraco.Examine/UmbracoContentIndexer.cs @@ -294,8 +294,7 @@ namespace Umbraco.Examine do { - long total; - var descendants = MediaService.GetPagedDescendants(mediaParentId, pageIndex, pageSize, out total); + var descendants = MediaService.GetPagedDescendants(mediaParentId, pageIndex, pageSize, out _); //if specific types are declared we need to post filter them //TODO: Update the service layer to join the cmsContentType table so we can query by content type too diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 8c78ead696..d5fb8dee92 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -356,7 +356,7 @@ namespace Umbraco.Web logger.Debug(() => $"Response status: Redirect={(pcr.IsRedirect ? (pcr.IsRedirectPermanent ? "permanent" : "redirect") : "none")}, Is404={(pcr.Is404 ? "true" : "false")}, StatusCode={pcr.ResponseStatusCode}"); - if(pcr.Cacheability != default(HttpCacheability)) + if(pcr.Cacheability != default) response.Cache.SetCacheability(pcr.Cacheability); foreach (var cacheExtension in pcr.CacheExtensions) From 6c5f07f2016cc4b85e217775896d41812eb64df1 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 12:13:18 +0200 Subject: [PATCH 07/10] Fix shutdown message logging - was not logging --- src/Umbraco.Core/UmbracoApplicationBase.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/UmbracoApplicationBase.cs b/src/Umbraco.Core/UmbracoApplicationBase.cs index 353879ec61..06847d0a5a 100644 --- a/src/Umbraco.Core/UmbracoApplicationBase.cs +++ b/src/Umbraco.Core/UmbracoApplicationBase.cs @@ -160,7 +160,10 @@ namespace Umbraco.Core _runtime = null; } - Current.Reset(); // dispose the container and everything + // dispose the container and everything + // but first, capture the looger! + var logger = Current.Logger; + Current.Reset(); if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted) return; @@ -183,12 +186,12 @@ namespace Umbraco.Core var shutdownMsg = $"Application shutdown. Details: {HostingEnvironment.ShutdownReason}\r\n\r\n_shutDownMessage={shutDownMessage}\r\n\r\n_shutDownStack={shutDownStack}"; - Current.Logger.Info(shutdownMsg); + logger.Info(shutdownMsg); } catch (Exception) { //if for some reason that fails, then log the normal output - Current.Logger.Info("Application shutdown. Reason: " + HostingEnvironment.ShutdownReason); + logger.Info("Application shutdown. Reason: " + HostingEnvironment.ShutdownReason); } } From 721a239d4a64748207b957e2a0975136a0a6c1b3 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 12:18:36 +0200 Subject: [PATCH 08/10] Fix ModelsBuilder structure - had circ dependencies etc --- src/Umbraco.ModelsBuilder/Api/ApiHelper.cs | 6 +- .../Api/ModelsBuilderApiController.cs | 15 +- .../Properties/AssemblyInfo.cs | 4 + .../Umbraco.ModelsBuilder.csproj | 3 +- .../Umbraco/LiveModelsProvider.cs | 9 +- .../Umbraco/ModelsBuilderApplication.cs | 175 ------------------ .../ModelsBuilderBackOfficeController.cs | 21 ++- .../Umbraco/ModelsBuilderComponent.cs | 45 ++--- .../Umbraco/OutOfDateModelsStatus.cs | 5 +- .../Umbraco/PureLiveModelFactory.cs | 13 +- .../{Application.cs => UmbracoServices.cs} | 4 +- 11 files changed, 69 insertions(+), 231 deletions(-) delete mode 100644 src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderApplication.cs rename src/Umbraco.ModelsBuilder/Umbraco/{Application.cs => UmbracoServices.cs} (97%) diff --git a/src/Umbraco.ModelsBuilder/Api/ApiHelper.cs b/src/Umbraco.ModelsBuilder/Api/ApiHelper.cs index 3d9f94bbd4..fa6492fe3f 100644 --- a/src/Umbraco.ModelsBuilder/Api/ApiHelper.cs +++ b/src/Umbraco.ModelsBuilder/Api/ApiHelper.cs @@ -5,13 +5,11 @@ using Umbraco.ModelsBuilder.Umbraco; namespace Umbraco.ModelsBuilder.Api { - // internal to be used by Umbraco.ModelsBuilder.Api project internal static class ApiHelper { - public static Dictionary GetModels(string modelsNamespace, IDictionary files) + public static Dictionary GetModels(UmbracoServices umbracoServices, string modelsNamespace, IDictionary files) { - var umbraco = ModelsBuilderComponent.Umbraco; - var typeModels = umbraco.GetAllTypes(); + var typeModels = umbracoServices.GetAllTypes(); var parseResult = new CodeParser().ParseWithReferencedAssemblies(files); var builder = new TextBuilder(typeModels, parseResult, modelsNamespace); diff --git a/src/Umbraco.ModelsBuilder/Api/ModelsBuilderApiController.cs b/src/Umbraco.ModelsBuilder/Api/ModelsBuilderApiController.cs index d74006c50f..444910b069 100644 --- a/src/Umbraco.ModelsBuilder/Api/ModelsBuilderApiController.cs +++ b/src/Umbraco.ModelsBuilder/Api/ModelsBuilderApiController.cs @@ -1,16 +1,12 @@ using System; -using System.Collections.Generic; using System.Net; using System.Net.Http; -using System.Text; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.ModelsBuilder.Building; using Umbraco.ModelsBuilder.Configuration; +using Umbraco.ModelsBuilder.Umbraco; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; namespace Umbraco.ModelsBuilder.Api { @@ -28,6 +24,13 @@ namespace Umbraco.ModelsBuilder.Api { public const string ControllerArea = "ModelsBuilder"; + private readonly UmbracoServices _umbracoServices; + + public ModelsBuilderApiController(UmbracoServices umbracoServices) + { + _umbracoServices = umbracoServices; + } + // invoked by the API [System.Web.Http.HttpPost] // use the http one, not mvc, with api controllers! [ApiBasicAuthFilter("developer")] // have to use our own, non-cookie-based, auth @@ -60,7 +63,7 @@ namespace Umbraco.ModelsBuilder.Api if (!checkResult.Success) return checkResult.Result; - var models = ApiHelper.GetModels(data.Namespace, data.Files); + var models = ApiHelper.GetModels(_umbracoServices, data.Namespace, data.Files); return Request.CreateResponse(HttpStatusCode.OK, models, Configuration.Formatters.JsonFormatter); } diff --git a/src/Umbraco.ModelsBuilder/Properties/AssemblyInfo.cs b/src/Umbraco.ModelsBuilder/Properties/AssemblyInfo.cs index a0a395a8a8..a2f8d1ae1e 100644 --- a/src/Umbraco.ModelsBuilder/Properties/AssemblyInfo.cs +++ b/src/Umbraco.ModelsBuilder/Properties/AssemblyInfo.cs @@ -8,3 +8,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] [assembly: Guid("7020a059-c0d1-43a0-8efd-23591a0c9af6")] + +// code analysis +// IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")] diff --git a/src/Umbraco.ModelsBuilder/Umbraco.ModelsBuilder.csproj b/src/Umbraco.ModelsBuilder/Umbraco.ModelsBuilder.csproj index 0279878b93..b9a5890d57 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco.ModelsBuilder.csproj +++ b/src/Umbraco.ModelsBuilder/Umbraco.ModelsBuilder.csproj @@ -87,11 +87,10 @@ - + - diff --git a/src/Umbraco.ModelsBuilder/Umbraco/LiveModelsProvider.cs b/src/Umbraco.ModelsBuilder/Umbraco/LiveModelsProvider.cs index 1172fee59c..b6c37a3558 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco/LiveModelsProvider.cs +++ b/src/Umbraco.ModelsBuilder/Umbraco/LiveModelsProvider.cs @@ -17,6 +17,7 @@ namespace Umbraco.ModelsBuilder.Umbraco // supports LiveDll and LiveAppData - but not PureLive public sealed class LiveModelsProvider { + private static UmbracoServices _umbracoServices; private static Mutex _mutex; private static int _req; @@ -30,12 +31,14 @@ namespace Umbraco.ModelsBuilder.Umbraco } } - internal static void Install() + internal static void Install(UmbracoServices umbracoServices) { // just be sure if (!IsEnabled) return; + _umbracoServices = umbracoServices; + // initialize mutex // ApplicationId will look like "/LM/W3SVC/1/Root/AppName" // name is system-wide and must be less than 260 chars @@ -110,11 +113,11 @@ namespace Umbraco.ModelsBuilder.Umbraco var config = UmbracoConfig.For.ModelsBuilder(); // EnableDllModels will recycle the app domain - but this request will end properly - ModelsBuilderBackOfficeController.GenerateModels(modelsDirectory, config.ModelsMode.IsAnyDll() ? bin : null); + ModelsBuilderBackOfficeController.GenerateModels(_umbracoServices, modelsDirectory, config.ModelsMode.IsAnyDll() ? bin : null); } } - // have to do this because it's the only way to subscribe to EndRequest + // have to do this because it's the only way to subscribe to EndRequest, // module is installed by assembly attribute at the top of this file public class LiveModelsProviderModule : IHttpModule { diff --git a/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderApplication.cs b/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderApplication.cs deleted file mode 100644 index bf650804c7..0000000000 --- a/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderApplication.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using LightInject; -using Umbraco.Core; -using Umbraco.Core.Components; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; -using Umbraco.ModelsBuilder.Configuration; -using Umbraco.Web; -using Umbraco.Web.UI.JavaScript; - -namespace Umbraco.ModelsBuilder.Umbraco -{ - /// - /// Installs ModelsBuilder into the Umbraco site. - /// - /// - /// Don't bother installing at all, if not RuntimeLevel.Run. - /// - [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - public class ModelsBuilderApplication : UmbracoComponentBase, IUmbracoCoreComponent - { - private IRuntimeState _runtimeState; - - public override void Compose(Composition composition) - { - var config = UmbracoConfig.For.ModelsBuilder(); - - if (config.ModelsMode == ModelsMode.PureLive) - InstallLiveModels(composition.Container); - else if (config.EnableFactory) - InstallDefaultModelsFactory(composition.Container); - - // always setup the dashboard - InstallServerVars(); - } - - public void Initialize(IRuntimeState runtimeState) - { - _runtimeState = runtimeState; - - var config = UmbracoConfig.For.ModelsBuilder(); - - if (config.Enable) - FileService.SavingTemplate += FileService_SavingTemplate; - - if (config.ModelsMode.IsLiveNotPure()) - LiveModelsProvider.Install(); - - if (config.FlagOutOfDateModels) - OutOfDateModelsStatus.Install(); - } - - private void InstallDefaultModelsFactory(IServiceContainer container) - { - var types = Current.TypeLoader.GetTypes(); - var factory = new PublishedModelFactory(types); - container.RegisterSingleton(_ => factory); - } - - private void InstallLiveModels(IServiceContainer container) - { - container.RegisterSingleton(); - - // the following would add @using statement in every view so user's don't - // have to do it - however, then noone understands where the @using statement - // comes from, and it cannot be avoided / removed --- DISABLED - // - /* - // no need for @using in views - // note: - // we are NOT using the in-code attribute here, config is required - // because that would require parsing the code... and what if it changes? - // we can AddGlobalImport not sure we can remove one anyways - var modelsNamespace = Configuration.Config.ModelsNamespace; - if (string.IsNullOrWhiteSpace(modelsNamespace)) - modelsNamespace = Configuration.Config.DefaultModelsNamespace; - System.Web.WebPages.Razor.WebPageRazorHost.AddGlobalImport(modelsNamespace); - */ - } - - private void InstallServerVars() - { - // register our url - for the backoffice api - ServerVariablesParser.Parsing += (sender, serverVars) => - { - if (!serverVars.ContainsKey("umbracoUrls")) - throw new Exception("Missing umbracoUrls."); - var umbracoUrlsObject = serverVars["umbracoUrls"]; - if (umbracoUrlsObject == null) - throw new Exception("Null umbracoUrls"); - if (!(umbracoUrlsObject is Dictionary umbracoUrls)) - throw new Exception("Invalid umbracoUrls"); - - if (!serverVars.ContainsKey("umbracoPlugins")) - throw new Exception("Missing umbracoPlugins."); - if (!(serverVars["umbracoPlugins"] is Dictionary umbracoPlugins)) - throw new Exception("Invalid umbracoPlugins"); - - if (HttpContext.Current == null) throw new InvalidOperationException("HttpContext is null"); - var urlHelper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData())); - - umbracoUrls["modelsBuilderBaseUrl"] = urlHelper.GetUmbracoApiServiceBaseUrl(controller => controller.BuildModels()); - umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings(); - }; - } - - private Dictionary GetModelsBuilderSettings() - { - if (_runtimeState.Level != RuntimeLevel.Run) - return null; - - var settings = new Dictionary - { - {"enabled", UmbracoConfig.For.ModelsBuilder().Enable} - }; - - return settings; - } - - /// - /// Used to check if a template is being created based on a document type, in this case we need to - /// ensure the template markup is correct based on the model name of the document type - /// - /// - /// - private void FileService_SavingTemplate(IFileService sender, Core.Events.SaveEventArgs e) - { - // don't do anything if the factory is not enabled - // because, no factory = no models (even if generation is enabled) - if (!UmbracoConfig.For.ModelsBuilder().EnableFactory) return; - - // don't do anything if this special key is not found - if (!e.AdditionalData.ContainsKey("CreateTemplateForContentType")) return; - - // ensure we have the content type alias - if (!e.AdditionalData.ContainsKey("ContentTypeAlias")) - throw new InvalidOperationException("The additionalData key: ContentTypeAlias was not found"); - - foreach (var template in e.SavedEntities) - { - // if it is in fact a new entity (not been saved yet) and the "CreateTemplateForContentType" key - // is found, then it means a new template is being created based on the creation of a document type - if (!template.HasIdentity && template.Content.IsNullOrWhiteSpace()) - { - // ensure is safe and always pascal cased, per razor standard - // + this is how we get the default model name in Umbraco.ModelsBuilder.Umbraco.Application - var alias = e.AdditionalData["ContentTypeAlias"].ToString(); - var name = template.Name; // will be the name of the content type since we are creating - var className = Application.GetClrName(name, alias); - - var modelNamespace = UmbracoConfig.For.ModelsBuilder().ModelsNamespace; - - // we do not support configuring this at the moment, so just let Umbraco use its default value - //var modelNamespaceAlias = ...; - - var markup = ViewHelper.GetDefaultFileContent( - modelClassName: className, - modelNamespace: modelNamespace/*, - modelNamespaceAlias: modelNamespaceAlias*/); - - //set the template content to the new markup - template.Content = markup; - } - } - } - } -} diff --git a/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderBackOfficeController.cs b/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderBackOfficeController.cs index 0a586fa16b..19c9bda5da 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderBackOfficeController.cs +++ b/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderBackOfficeController.cs @@ -11,6 +11,7 @@ using Umbraco.ModelsBuilder.Building; using Umbraco.ModelsBuilder.Configuration; using Umbraco.ModelsBuilder.Dashboard; using Umbraco.Web.Editors; +using Umbraco.Web.WebApi.Filters; namespace Umbraco.ModelsBuilder.Umbraco { @@ -22,8 +23,16 @@ namespace Umbraco.ModelsBuilder.Umbraco /// correct CSRF security is adhered to for angular and it also ensures that this controller is not subseptipal to /// global WebApi formatters being changed since this is always forced to only return Angular JSON Specific formats. /// + [UmbracoApplicationAuthorize(Core.Constants.Applications.Developer)] public class ModelsBuilderBackOfficeController : UmbracoAuthorizedJsonController { + private readonly UmbracoServices _umbracoServices; + + public ModelsBuilderBackOfficeController(UmbracoServices umbracoServices) + { + _umbracoServices = umbracoServices; + } + // invoked by the dashboard // requires that the user is logged into the backoffice and has access to the developer section // beware! the name of the method appears in modelsbuilder.controller.js @@ -93,7 +102,12 @@ namespace Umbraco.ModelsBuilder.Umbraco }; } - internal static void GenerateModels(string modelsDirectory, string bin) + private void GenerateModels(string modelsDirectory, string bin) + { + GenerateModels(_umbracoServices, modelsDirectory, bin); + } + + internal static void GenerateModels(UmbracoServices umbracoServices, string modelsDirectory, string bin) { if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -101,8 +115,7 @@ namespace Umbraco.ModelsBuilder.Umbraco foreach (var file in Directory.GetFiles(modelsDirectory, "*.generated.cs")) File.Delete(file); - var umbraco = ModelsBuilderComponent.Umbraco; - var typeModels = umbraco.GetAllTypes(); + var typeModels = umbracoServices.GetAllTypes(); var ourFiles = Directory.GetFiles(modelsDirectory, "*.cs").ToDictionary(x => x, File.ReadAllText); var parseResult = new CodeParser().ParseWithReferencedAssemblies(ourFiles); @@ -178,4 +191,4 @@ namespace Umbraco.ModelsBuilder.Umbraco public OutOfDateType Status { get; set; } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderComponent.cs b/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderComponent.cs index ba75b59578..a581319ba5 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderComponent.cs +++ b/src/Umbraco.ModelsBuilder/Umbraco/ModelsBuilderComponent.cs @@ -12,6 +12,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; +using Umbraco.ModelsBuilder.Api; using Umbraco.ModelsBuilder.Configuration; using Umbraco.Web; using Umbraco.Web.PublishedCache.NuCache; @@ -19,59 +20,55 @@ using Umbraco.Web.UI.JavaScript; namespace Umbraco.ModelsBuilder.Umbraco { - // fixme - // nucache components wants models so we need to setup models before - // however for some reason, this creates a cyclic dependency? => need better debugging info - // cos nucache is Core so we need to be Core too - // also... should have a generic "modelsbuilder" and "contentcache" components for dependencies! - [RequiredComponent(typeof(NuCacheComponent))] + [RuntimeLevel(MinLevel = RuntimeLevel.Run)] public class ModelsBuilderComponent : UmbracoComponentBase, IUmbracoCoreComponent { public override void Compose(Composition composition) { base.Compose(composition); - composition.Container.Register(new PerContainerLifetime()); + + composition.Container.Register(new PerContainerLifetime()); var config = UmbracoConfig.For.ModelsBuilder(); if (config.ModelsMode == ModelsMode.PureLive) - InstallLiveModels(composition.Container); + ComposeForLiveModels(composition.Container); else if (config.EnableFactory) - InstallDefaultModelsFactory(composition.Container); + ComposeForDefaultModelsFactory(composition.Container); // always setup the dashboard InstallServerVars(composition.Container.GetInstance().Level); + composition.Container.Register(typeof(ModelsBuilderBackOfficeController), new PerRequestLifeTime()); - // need to do it here 'cos NuCache wants it during compose? - Umbraco = composition.Container.GetInstance(); + // setup the API if enabled (and in debug mode) + if (config.ApiServer) + composition.Container.Register(typeof(ModelsBuilderApiController), new PerRequestLifeTime()); } - public void Initialize(Application application) + public void Initialize(UmbracoServices umbracoServices) { - Umbraco = application; - var config = UmbracoConfig.For.ModelsBuilder(); if (config.Enable) FileService.SavingTemplate += FileService_SavingTemplate; + // fixme LiveModelsProvider should not be static if (config.ModelsMode.IsLiveNotPure()) - LiveModelsProvider.Install(); + LiveModelsProvider.Install(umbracoServices); + // fixme OutOfDateModelsStatus should not be static if (config.FlagOutOfDateModels) OutOfDateModelsStatus.Install(); } - public static Application Umbraco { get; private set; } - - private void InstallDefaultModelsFactory(IServiceContainer container) + private void ComposeForDefaultModelsFactory(IServiceContainer container) { container.RegisterSingleton(factory => new PublishedModelFactory(factory.GetInstance().GetTypes())); } - private void InstallLiveModels(IServiceContainer container) + private void ComposeForLiveModels(IServiceContainer container) { container.RegisterSingleton(); @@ -102,14 +99,12 @@ namespace Umbraco.ModelsBuilder.Umbraco var umbracoUrlsObject = serverVars["umbracoUrls"]; if (umbracoUrlsObject == null) throw new Exception("Null umbracoUrls"); - var umbracoUrls = umbracoUrlsObject as Dictionary; - if (umbracoUrls == null) + if (!(umbracoUrlsObject is Dictionary umbracoUrls)) throw new Exception("Invalid umbracoUrls"); if (!serverVars.ContainsKey("umbracoPlugins")) throw new Exception("Missing umbracoPlugins."); - var umbracoPlugins = serverVars["umbracoPlugins"] as Dictionary; - if (umbracoPlugins == null) + if (!(serverVars["umbracoPlugins"] is Dictionary umbracoPlugins)) throw new Exception("Invalid umbracoPlugins"); if (HttpContext.Current == null) throw new InvalidOperationException("HttpContext is null"); @@ -162,7 +157,7 @@ namespace Umbraco.ModelsBuilder.Umbraco // + this is how we get the default model name in Umbraco.ModelsBuilder.Umbraco.Application var alias = e.AdditionalData["ContentTypeAlias"].ToString(); var name = template.Name; // will be the name of the content type since we are creating - var className = Application.GetClrName(name, alias); + var className = UmbracoServices.GetClrName(name, alias); var modelNamespace = UmbracoConfig.For.ModelsBuilder().ModelsNamespace; @@ -180,4 +175,4 @@ namespace Umbraco.ModelsBuilder.Umbraco } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.ModelsBuilder/Umbraco/OutOfDateModelsStatus.cs b/src/Umbraco.ModelsBuilder/Umbraco/OutOfDateModelsStatus.cs index a5f21f2b2a..a047f21edb 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco/OutOfDateModelsStatus.cs +++ b/src/Umbraco.ModelsBuilder/Umbraco/OutOfDateModelsStatus.cs @@ -43,10 +43,7 @@ namespace Umbraco.ModelsBuilder.Umbraco File.Delete(path); } - public static bool IsEnabled - { - get { return UmbracoConfig.For.ModelsBuilder().FlagOutOfDateModels; } - } + public static bool IsEnabled => UmbracoConfig.For.ModelsBuilder().FlagOutOfDateModels; public static bool IsOutOfDate { diff --git a/src/Umbraco.ModelsBuilder/Umbraco/PureLiveModelFactory.cs b/src/Umbraco.ModelsBuilder/Umbraco/PureLiveModelFactory.cs index c216c92b03..9558c0140e 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco/PureLiveModelFactory.cs +++ b/src/Umbraco.ModelsBuilder/Umbraco/PureLiveModelFactory.cs @@ -36,13 +36,16 @@ namespace Umbraco.ModelsBuilder.Umbraco private int _ver, _skipver; private readonly int _debugLevel; private BuildManager _theBuildManager; + private readonly Lazy _umbracoServices; + private UmbracoServices UmbracoServices => _umbracoServices.Value; private static readonly Regex AssemblyVersionRegex = new Regex("AssemblyVersion\\(\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\"\\)", RegexOptions.Compiled); private const string ProjVirt = "~/App_Data/Models/all.generated.cs"; private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err" }; - public PureLiveModelFactory(ProfilingLogger logger) + public PureLiveModelFactory(Lazy umbracoServices, ProfilingLogger logger) { + _umbracoServices = umbracoServices; _logger = logger; _ver = 1; // zero is for when we had no version _skipver = -1; // nothing to skip @@ -161,8 +164,7 @@ namespace Umbraco.ModelsBuilder.Umbraco if (_debugLevel > 0) _logger.Logger.Debug("RazorBuildProvider.CodeGenerationStarted"); - var provider = sender as RazorBuildProvider; - if (provider == null) return; + if (!(sender is RazorBuildProvider provider)) return; // add the assembly, and add a dependency to a text file that will change on each // compilation as in some environments (could not figure which/why) the BuildManager @@ -309,8 +311,7 @@ namespace Umbraco.ModelsBuilder.Umbraco .ToDictionary(x => x, File.ReadAllText) : new Dictionary(); - var umbraco = ModelsBuilderComponent.Umbraco; - var typeModels = umbraco.GetAllTypes(); + var typeModels = UmbracoServices.GetAllTypes(); var currentHash = HashHelper.Hash(ourFiles, typeModels); var modelsHashFile = Path.Combine(modelsDirectory, "models.hash"); var modelsSrcFile = Path.Combine(modelsDirectory, "models.generated.cs"); @@ -598,4 +599,4 @@ namespace Umbraco.ModelsBuilder.Umbraco #endregion } -} \ No newline at end of file +} diff --git a/src/Umbraco.ModelsBuilder/Umbraco/Application.cs b/src/Umbraco.ModelsBuilder/Umbraco/UmbracoServices.cs similarity index 97% rename from src/Umbraco.ModelsBuilder/Umbraco/Application.cs rename to src/Umbraco.ModelsBuilder/Umbraco/UmbracoServices.cs index df4549cc5c..f0347d9194 100644 --- a/src/Umbraco.ModelsBuilder/Umbraco/Application.cs +++ b/src/Umbraco.ModelsBuilder/Umbraco/UmbracoServices.cs @@ -12,14 +12,14 @@ using Umbraco.ModelsBuilder.Configuration; namespace Umbraco.ModelsBuilder.Umbraco { - public class Application + public class UmbracoServices { private readonly IContentTypeService _contentTypeService; private readonly IMediaTypeService _mediaTypeService; private readonly IMemberTypeService _memberTypeService; private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; - public Application(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, IPublishedContentTypeFactory publishedContentTypeFactory) + public UmbracoServices(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, IPublishedContentTypeFactory publishedContentTypeFactory) { _contentTypeService = contentTypeService; _mediaTypeService = mediaTypeService; From 4f8973a043da9c3f620ef50dccf5fb61edd85a64 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 12:21:55 +0200 Subject: [PATCH 09/10] Fix Upgrader - was updating even when nothing happened --- src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs index 7481444bd8..974ed7b4f8 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/Upgrader.cs @@ -60,7 +60,7 @@ namespace Umbraco.Core.Migrations.Upgrade // save new state if (forceState) _keyValueService.SetValue(StateValueKey, state); - else + else if (currentState != state) _keyValueService.SetValue(StateValueKey, currentState, state); // run post-migrations From 82b5e0be02c3d2eac9fcab7ade4bb253ade585f7 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 31 May 2018 14:02:39 +0200 Subject: [PATCH 10/10] Fix nuspec files --- build/NuSpecs/UmbracoCms.Core.nuspec | 81 +++++++++++++++------------- build/NuSpecs/UmbracoCms.nuspec | 7 ++- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 7aab71e73a..19ecd8182e 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -15,44 +15,49 @@ en-US umbraco - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index 1c306423b7..de5cf0e54f 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -16,7 +16,12 @@ umbraco - + +