diff --git a/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs b/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs index 18f79e5602..4f5916822e 100644 --- a/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs @@ -14,22 +14,6 @@ namespace Umbraco.Core.Configuration.Models private static string DefaultModelsDirectory => "~/umbraco/models"; - /// - /// Gets or sets a value indicating whether the whole models experience is enabled. - /// - /// - /// If this is false then absolutely nothing happens. - /// Default value is false which means that unless we have this setting, nothing happens. - /// - // TODO: This setting makes no sense at all, this basically just disables haveing models be able to reset dynamically - // and configure some dashboards but the models are all still built and active! - // Can this be truly disabled or not? - // Then there's other ways to disable things - EnableFactory also causes odd flags but again, how can this be disabled? - // The other ways that flags change are ModelsMode. - // TODO: Make these make sense and test what is possible - // Confirmed A) Enabled = false, ModelsMode = Nothing, EnabledFagtory = false == EXPLODES, null refs because these things are needed unless you replace nucache. - public bool Enable { get; set; } = true; - /// /// Gets or sets a value for the models mode. /// @@ -41,12 +25,6 @@ namespace Umbraco.Core.Configuration.Models /// That value could be overriden by other (attribute in user's code...). Return default if no value was supplied. public string ModelsNamespace { get; set; } - /// - /// Gets or sets a value indicating whether we should enable the models factory. - /// - /// Default value is true because no factory is enabled by default in Umbraco. - public bool EnableFactory { get; set; } = true; - /// /// Gets or sets a value indicating whether we should flag out-of-date models. /// diff --git a/src/Umbraco.Core/Configuration/ModelsMode.cs b/src/Umbraco.Core/Configuration/ModelsMode.cs index 2483367394..c3b32b1cab 100644 --- a/src/Umbraco.Core/Configuration/ModelsMode.cs +++ b/src/Umbraco.Core/Configuration/ModelsMode.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Configuration +namespace Umbraco.Core.Configuration { /// /// Defines the models generation modes. @@ -6,9 +6,12 @@ public enum ModelsMode { /// - /// Do not generate models. + /// Do not generate strongly typed models. /// - Nothing = 0, // default value + /// + /// This means that only IPublishedContent instances will be used. + /// + Nothing = 0, /// /// Generate models in memory. diff --git a/src/Umbraco.Core/Configuration/ModelsModeExtensions.cs b/src/Umbraco.Core/Configuration/ModelsModeExtensions.cs index 8d1b51cd28..6aae79ff8a 100644 --- a/src/Umbraco.Core/Configuration/ModelsModeExtensions.cs +++ b/src/Umbraco.Core/Configuration/ModelsModeExtensions.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration; namespace Umbraco.Configuration { @@ -11,29 +11,18 @@ namespace Umbraco.Configuration /// Gets a value indicating whether the mode is LiveAnything or PureLive. /// public static bool IsLive(this ModelsMode modelsMode) - { - return - modelsMode == ModelsMode.PureLive - || modelsMode == ModelsMode.LiveAppData; - } + => modelsMode == ModelsMode.PureLive || modelsMode == ModelsMode.LiveAppData; /// /// Gets a value indicating whether the mode is LiveAnything but not PureLive. /// public static bool IsLiveNotPure(this ModelsMode modelsMode) - { - return - modelsMode == ModelsMode.LiveAppData; - } + => modelsMode == ModelsMode.LiveAppData; /// /// Gets a value indicating whether the mode supports explicit generation (as opposed to pure live). /// public static bool SupportsExplicitGeneration(this ModelsMode modelsMode) - { - return - modelsMode == ModelsMode.AppData - || modelsMode == ModelsMode.LiveAppData; - } + => modelsMode == ModelsMode.AppData || modelsMode == ModelsMode.LiveAppData; } } diff --git a/src/Umbraco.Core/PublishedModelFactoryExtensions.cs b/src/Umbraco.Core/PublishedModelFactoryExtensions.cs index db18bfd8a9..3794bc6954 100644 --- a/src/Umbraco.Core/PublishedModelFactoryExtensions.cs +++ b/src/Umbraco.Core/PublishedModelFactoryExtensions.cs @@ -10,11 +10,6 @@ namespace Umbraco.Core /// public static class PublishedModelFactoryExtensions { - /// - /// Returns true if the current is an implementation of - /// - public static bool IsLiveFactory(this IPublishedModelFactory factory) => factory is ILivePublishedModelFactory; - /// /// Returns true if the current is an implementation of and is enabled /// diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs index ef5ff14954..c34f4516e4 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Editors; @@ -17,62 +18,75 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice { private readonly IOptions _config; - public ContentTypeModelValidatorBase(IOptions config) - { - _config = config; - } + public ContentTypeModelValidatorBase(IOptions config) => _config = config; protected override IEnumerable Validate(TModel model) { - //don't do anything if we're not enabled - if (!_config.Value.Enable) yield break; + // don't do anything if we're not enabled + if (_config.Value.ModelsMode == ModelsMode.Nothing) + { + yield break; + } - //list of reserved/disallowed aliases for content/media/member types - more can be added as the need arises + // list of reserved/disallowed aliases for content/media/member types - more can be added as the need arises var reservedModelAliases = new[] { "system" }; - if(reservedModelAliases.Contains(model.Alias, StringComparer.OrdinalIgnoreCase)) + if (reservedModelAliases.Contains(model.Alias, StringComparer.OrdinalIgnoreCase)) { yield return new ValidationResult($"The model alias {model.Alias} is a reserved term and cannot be used", new[] { "Alias" }); } - var properties = model.Groups.SelectMany(x => x.Properties) + TProperty[] properties = model.Groups.SelectMany(x => x.Properties) .Where(x => x.Inherited == false) .ToArray(); - foreach (var prop in properties) + foreach (TProperty prop in properties) { - var propertyGroup = model.Groups.Single(x => x.Properties.Contains(prop)); + PropertyGroupBasic propertyGroup = model.Groups.Single(x => x.Properties.Contains(prop)); if (model.Alias.ToLowerInvariant() == prop.Alias.ToLowerInvariant()) - yield return new ValidationResult(string.Format("With Models Builder enabled, you can't have a property with a the alias \"{0}\" when the content type alias is also \"{0}\".", prop.Alias), new[] - { - $"Groups[{model.Groups.IndexOf(propertyGroup)}].Properties[{propertyGroup.Properties.IndexOf(prop)}].Alias" - }); + { + string[] memberNames = new[] + { + $"Groups[{model.Groups.IndexOf(propertyGroup)}].Properties[{propertyGroup.Properties.IndexOf(prop)}].Alias" + }; - //we need to return the field name with an index so it's wired up correctly + yield return new ValidationResult( + string.Format("With Models Builder enabled, you can't have a property with a the alias \"{0}\" when the content type alias is also \"{0}\".", prop.Alias), + memberNames); + } + + // we need to return the field name with an index so it's wired up correctly var groupIndex = model.Groups.IndexOf(propertyGroup); var propertyIndex = propertyGroup.Properties.IndexOf(prop); - var validationResult = ValidateProperty(prop, groupIndex, propertyIndex); + ValidationResult validationResult = ValidateProperty(prop, groupIndex, propertyIndex); if (validationResult != null) + { yield return validationResult; + } } } private ValidationResult ValidateProperty(PropertyTypeBasic property, int groupIndex, int propertyIndex) { - //don't let them match any properties or methods in IPublishedContent - //TODO: There are probably more! + // don't let them match any properties or methods in IPublishedContent + // TODO: There are probably more! var reservedProperties = typeof(IPublishedContent).GetProperties().Select(x => x.Name).ToArray(); var reservedMethods = typeof(IPublishedContent).GetMethods().Select(x => x.Name).ToArray(); var alias = property.Alias; if (reservedProperties.InvariantContains(alias) || reservedMethods.InvariantContains(alias)) - return new ValidationResult( - $"The alias {alias} is a reserved term and cannot be used", new[] + { + string[] memberNames = new[] { $"Groups[{groupIndex}].Properties[{propertyIndex}].Alias" - }); + }; + + return new ValidationResult( + $"The alias {alias} is a reserved term and cannot be used", + memberNames); + } return null; } diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs index 6b413ad4a1..e03df097e8 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs @@ -27,38 +27,46 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice public string Text() { - if (!_config.Enable) - return "Version: " + ApiVersion.Current.Version + "
 
ModelsBuilder is disabled
(the .Enable key is missing, or its value is not 'true')."; - var sb = new StringBuilder(); - sb.Append("Version: "); + sb.Append("

Version: "); sb.Append(ApiVersion.Current.Version); - sb.Append("
 
"); + sb.Append("

"); - sb.Append("ModelsBuilder is enabled, with the following configuration:"); + sb.Append("

ModelsBuilder is enabled, with the following configuration:

"); sb.Append("
    "); - sb.Append("
  • The models factory is "); + sb.Append("
  • The models mode is '"); + sb.Append(_config.ModelsMode.ToString()); + sb.Append("'. "); - // TODO: Test this - if models factory is entirely disabled will umbraco work at all? - // if not, is there a point to this? - sb.Append(_config.EnableFactory || _config.ModelsMode == ModelsMode.PureLive - ? "enabled" - : "not enabled. Umbraco will not use models"); + switch (_config.ModelsMode) + { + case ModelsMode.Nothing: + sb.Append("Strongly typed models are not generated. All content and cache will operate from instance of IPublishedContent only."); + break; + case ModelsMode.PureLive: + sb.Append("Strongly typed models are re-generated on startup and anytime schema changes (i.e. Content Type) are made. No recompilation necessary but the generated models are not available to code outside of Razor."); + break; + case ModelsMode.AppData: + sb.Append("Strongly typed models are generated on demand. Recompilation is necessary and models are available to all CSharp code."); + break; + case ModelsMode.LiveAppData: + sb.Append("Strong typed models are generated on demand and anytime schema changes (i.e. Content Type) are made. Recompilation is necessary and models are available to all CSharp code."); + break; + } - sb.Append(".
  • "); + sb.Append(""); - sb.Append(_config.ModelsMode != ModelsMode.Nothing - ? $"
  • {_config.ModelsMode} models are enabled.
  • " - : "
  • No models mode is specified: models will not be generated.
  • "); + if (_config.ModelsMode != ModelsMode.Nothing) + { + sb.Append($"
  • Models namespace is {_config.ModelsNamespace}.
  • "); - sb.Append($"
  • Models namespace is {_config.ModelsNamespace}.
  • "); - - sb.Append("
  • Tracking of out-of-date models is "); - sb.Append(_config.FlagOutOfDateModels ? "enabled" : "not enabled"); - sb.Append(".
  • "); + sb.Append("
  • Tracking of out-of-date models is "); + sb.Append(_config.FlagOutOfDateModels ? "enabled" : "not enabled"); + sb.Append(".
  • "); + } sb.Append("
"); diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs index 0b67498f01..9c12e9b649 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Umbraco.Configuration; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Exceptions; using Umbraco.Core.Hosting; @@ -98,17 +99,14 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice return GetDashboardResult(); } - private Dashboard GetDashboardResult() + private Dashboard GetDashboardResult() => new Dashboard { - return new Dashboard - { - Enable = _config.Enable, - Text = _dashboardReport.Text(), - CanGenerate = _dashboardReport.CanGenerate(), - OutOfDateModels = _dashboardReport.AreModelsOutOfDate(), - LastError = _dashboardReport.LastError(), - }; - } + Mode = _config.ModelsMode, + Text = _dashboardReport.Text(), + CanGenerate = _dashboardReport.CanGenerate(), + OutOfDateModels = _dashboardReport.AreModelsOutOfDate(), + LastError = _dashboardReport.LastError(), + }; [DataContract] public class BuildResult @@ -122,8 +120,8 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice [DataContract] public class Dashboard { - [DataMember(Name = "enable")] - public bool Enable; + [DataMember(Name = "mode")] + public ModelsMode Mode; [DataMember(Name = "text")] public string Text; [DataMember(Name = "canGenerate")] diff --git a/src/Umbraco.ModelsBuilder.Embedded/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.ModelsBuilder.Embedded/DependencyInjection/UmbracoBuilderExtensions.cs index 45ca4a9078..0c01dad0fb 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/DependencyInjection/UmbracoBuilderExtensions.cs @@ -105,7 +105,7 @@ namespace Umbraco.ModelsBuilder.Embedded.DependencyInjection { return factory.GetRequiredService(); } - else if (config.EnableFactory) + else { TypeLoader typeLoader = factory.GetRequiredService(); IPublishedValueFallback publishedValueFallback = factory.GetRequiredService(); @@ -114,8 +114,6 @@ namespace Umbraco.ModelsBuilder.Embedded.DependencyInjection .Concat(typeLoader.GetTypes()); // content models return new PublishedModelFactory(types, publishedValueFallback); } - - return null; }); return builder; diff --git a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs index d7fc051500..9ee4d96482 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs @@ -1,34 +1,31 @@ using System; using System.Threading; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; using Umbraco.Configuration; -using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; +using Umbraco.Extensions; using Umbraco.ModelsBuilder.Embedded.Building; using Umbraco.Web.Cache; -using Umbraco.Core.Configuration.Models; -using Microsoft.Extensions.Options; -using Umbraco.Extensions; namespace Umbraco.ModelsBuilder.Embedded { // supports LiveAppData - but not PureLive public sealed class LiveModelsProvider { - private static Mutex _mutex; - private static int _req; + private static Mutex s_mutex; + private static int s_req; private readonly ILogger _logger; private readonly ModelsBuilderSettings _config; private readonly ModelsGenerator _modelGenerator; private readonly ModelsGenerationError _mbErrors; private readonly IHostingEnvironment _hostingEnvironment; - // we do not manage pure live here - internal bool IsEnabled => _config.ModelsMode.IsLiveNotPure(); - + /// + /// Initializes a new instance of the class. + /// public LiveModelsProvider(ILogger logger, IOptions config, ModelsGenerator modelGenerator, ModelsGenerationError mbErrors, IHostingEnvironment hostingEnvironment) { _logger = logger; @@ -38,18 +35,23 @@ namespace Umbraco.ModelsBuilder.Embedded _hostingEnvironment = hostingEnvironment; } + // we do not manage pure live here + internal bool IsEnabled => _config.ModelsMode.IsLiveNotPure(); + internal void Install() { // just be sure if (!IsEnabled) + { return; + } // initialize mutex // ApplicationId will look like "/LM/W3SVC/1/Root/AppName" // name is system-wide and must be less than 260 chars var name = _hostingEnvironment.ApplicationId + "/UmbracoLiveModelsProvider"; - _mutex = new Mutex(false, name); //TODO: Replace this with MainDom? Seems we now have 2x implementations of almost the same thing + s_mutex = new Mutex(false, name); //TODO: Replace this with MainDom? Seems we now have 2x implementations of almost the same thing // anything changes, and we want to re-generate models. ContentTypeCacheRefresher.CacheUpdated += RequestModelsGeneration; @@ -72,13 +74,13 @@ namespace Umbraco.ModelsBuilder.Embedded { //HttpContext.Current.Items[this] = true; _logger.LogDebug("Requested to generate models."); - Interlocked.Exchange(ref _req, 1); + Interlocked.Exchange(ref s_req, 1); } public void GenerateModelsIfRequested() { //if (HttpContext.Current.Items[this] == null) return; - if (Interlocked.Exchange(ref _req, 0) == 0) return; + if (Interlocked.Exchange(ref s_req, 0) == 0) return; // cannot use a simple lock here because we don't want another AppDomain // to generate while we do... and there could be 2 AppDomains if the app restarts. @@ -87,7 +89,7 @@ namespace Umbraco.ModelsBuilder.Embedded { _logger.LogDebug("Generate models..."); const int timeout = 2 * 60 * 1000; // 2 mins - _mutex.WaitOne(timeout); // wait until it is safe, and acquire + s_mutex.WaitOne(timeout); // wait until it is safe, and acquire _logger.LogInformation("Generate models now."); GenerateModels(); _mbErrors.Clear(); @@ -104,7 +106,7 @@ namespace Umbraco.ModelsBuilder.Embedded } finally { - _mutex.ReleaseMutex(); // release + s_mutex.ReleaseMutex(); // release } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderNotificationHandler.cs b/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderNotificationHandler.cs index 2e969eae17..002ff67a4b 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderNotificationHandler.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderNotificationHandler.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Options; using Umbraco.Configuration; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.IO; @@ -65,7 +66,7 @@ namespace Umbraco.ModelsBuilder.Embedded _modelBinder.ModelBindingException += ContentModelBinder_ModelBindingException; - if (_config.Enable) + if (_config.ModelsMode != ModelsMode.Nothing) { FileService.SavingTemplate += FileService_SavingTemplate; } @@ -126,7 +127,7 @@ namespace Umbraco.ModelsBuilder.Embedded { var settings = new Dictionary { - {"enabled", _config.Enable} + {"mode", _config.ModelsMode.ToString()} }; return settings; @@ -138,13 +139,6 @@ namespace Umbraco.ModelsBuilder.Embedded /// private void FileService_SavingTemplate(IFileService sender, SaveEventArgs e) { - // don't do anything if the factory is not enabled - // because, no factory = no models (even if generation is enabled) - if (!_config.EnableFactory) - { - return; - } - // don't do anything if this special key is not found if (!e.AdditionalData.ContainsKey("CreateTemplateForContentType")) { diff --git a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs index 3bb9660dcf..4e209cfb28 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs @@ -132,7 +132,7 @@ namespace Umbraco.ModelsBuilder.Embedded } /// - public bool Enabled => _config.Enable; + public bool Enabled => _config.ModelsMode == ModelsMode.PureLive; /// /// Handle the event when a reference cannot be resolved from the default context and return our custom MB assembly reference if we have one diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs index 6e9d6d29a7..d22ac70d8d 100644 --- a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs @@ -45,7 +45,7 @@ namespace Umbraco.Web.Common.Filters public void OnException(ExceptionContext filterContext) { var disabled = _exceptionFilterSettings?.Disabled ?? false; - if (_publishedModelFactory.IsLiveFactory() + if (_publishedModelFactory.IsLiveFactoryEnabled() && !disabled && !filterContext.ExceptionHandled && (filterContext.Exception is ModelBindingException || filterContext.Exception is InvalidCastException) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js index 9cec15d519..eb401ebe5f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js @@ -28,7 +28,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje generateModels: function () { var deferred = $q.defer(); var modelsResource = $injector.has("modelsBuilderManagementResource") ? $injector.get("modelsBuilderManagementResource") : null; - var modelsBuilderEnabled = Umbraco.Sys.ServerVariables.umbracoPlugins.modelsBuilder.enabled; + var modelsBuilderEnabled = Umbraco.Sys.ServerVariables.umbracoPlugins.modelsBuilder.mode !== "Nothing"; if (modelsBuilderEnabled && modelsResource) { modelsResource.buildModels().then(function (result) { deferred.resolve(result); @@ -49,7 +49,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje checkModelsBuilderStatus: function () { var deferred = $q.defer(); var modelsResource = $injector.has("modelsBuilderManagementResource") ? $injector.get("modelsBuilderManagementResource") : null; - var modelsBuilderEnabled = (Umbraco && Umbraco.Sys && Umbraco.Sys.ServerVariables && Umbraco.Sys.ServerVariables.umbracoPlugins && Umbraco.Sys.ServerVariables.umbracoPlugins.modelsBuilder && Umbraco.Sys.ServerVariables.umbracoPlugins.modelsBuilder.enabled === true); + var modelsBuilderEnabled = (Umbraco && Umbraco.Sys && Umbraco.Sys.ServerVariables && Umbraco.Sys.ServerVariables.umbracoPlugins && Umbraco.Sys.ServerVariables.umbracoPlugins.modelsBuilder && Umbraco.Sys.ServerVariables.umbracoPlugins.modelsBuilder.mode !== "Nothing"); if (modelsBuilderEnabled && modelsResource) { modelsResource.getModelsOutOfDateStatus().then(function (result) {