diff --git a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs index c850583834..d1d71a9ca1 100644 --- a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs +++ b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs @@ -150,8 +150,8 @@ namespace Umbraco.Extensions /// Allowed apps /// Roles public static void AddRequiredClaims(this ClaimsIdentity identity, string userId, string username, - string realName, IEnumerable startContentNodes, IEnumerable startMediaNodes, string culture, - string securityStamp, IEnumerable allowedApps, IEnumerable roles) + string? realName, IEnumerable? startContentNodes, IEnumerable? startMediaNodes, string culture, + string securityStamp, IEnumerable allowedApps, IEnumerable roles) { //This is the id that 'identity' uses to check for the user id if (identity.HasClaim(x => x.Type == ClaimTypes.NameIdentifier) == false) diff --git a/src/Umbraco.Core/IO/MediaFileManager.cs b/src/Umbraco.Core/IO/MediaFileManager.cs index b7e30c3b19..c3462913ff 100644 --- a/src/Umbraco.Core/IO/MediaFileManager.cs +++ b/src/Umbraco.Core/IO/MediaFileManager.cs @@ -102,7 +102,7 @@ namespace Umbraco.Cms.Core.IO /// The unique identifier of the property type owning the file. /// The filesystem-relative path to the media file. /// With the old media path scheme, this CREATES a new media path each time it is invoked. - public string GetMediaPath(string filename, Guid cuid, Guid puid) + public string GetMediaPath(string? filename, Guid cuid, Guid puid) { filename = Path.GetFileName(filename); if (filename == null) diff --git a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs index a3c0f1347a..16d5381d9b 100644 --- a/src/Umbraco.Core/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Core/Media/UploadAutoFillProperties.cs @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Core.Media /// The auto-fill configuration. /// Variation language. /// Variation segment. - public void Reset(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string culture, string segment) + public void Reset(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string? culture, string? segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -55,7 +55,7 @@ namespace Umbraco.Cms.Core.Media /// The parameter is the path relative to the filesystem. /// Variation language. /// Variation segment. - public void Populate(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, string culture, string segment) + public void Populate(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, string? culture, string? segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -112,7 +112,7 @@ namespace Umbraco.Cms.Core.Media } } - private void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, Stream? filestream, string culture, string segment) + private void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, Stream? filestream, string? culture, string? segment) { var extension = (Path.GetExtension(filepath) ?? string.Empty).TrimStart(Constants.CharArrays.Period); @@ -123,7 +123,7 @@ namespace Umbraco.Cms.Core.Media SetProperties(content, autoFillConfig, size, filestream?.Length, extension, culture, segment); } - private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, Size? size, long? length, string extension, string culture, string segment) + private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, Size? size, long? length, string extension, string? culture, string? segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -141,7 +141,7 @@ namespace Umbraco.Cms.Core.Media content.Properties[autoFillConfig.ExtensionFieldAlias]!.SetValue(extension, culture, segment); } - private static void ResetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string culture, string segment) + private static void ResetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string? culture, string? segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); diff --git a/src/Umbraco.Core/Models/Blocks/ContentAndSettingsReference.cs b/src/Umbraco.Core/Models/Blocks/ContentAndSettingsReference.cs index 3cfcbf9122..f8677490ee 100644 --- a/src/Umbraco.Core/Models/Blocks/ContentAndSettingsReference.cs +++ b/src/Umbraco.Core/Models/Blocks/ContentAndSettingsReference.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Core.Models.Blocks { public struct ContentAndSettingsReference : IEquatable { - public ContentAndSettingsReference(Udi contentUdi, Udi settingsUdi) + public ContentAndSettingsReference(Udi? contentUdi, Udi? settingsUdi) { ContentUdi = contentUdi ?? throw new ArgumentNullException(nameof(contentUdi)); SettingsUdi = settingsUdi; @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Models.Blocks public Udi ContentUdi { get; } - public Udi SettingsUdi { get; } + public Udi? SettingsUdi { get; } public override bool Equals(object? obj) => obj is ContentAndSettingsReference reference && Equals(reference); diff --git a/src/Umbraco.Core/Models/Editors/ContentPropertyData.cs b/src/Umbraco.Core/Models/Editors/ContentPropertyData.cs index 2b3e38ad13..0255cfd40e 100644 --- a/src/Umbraco.Core/Models/Editors/ContentPropertyData.cs +++ b/src/Umbraco.Core/Models/Editors/ContentPropertyData.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Core.Models.Editors /// public class ContentPropertyData { - public ContentPropertyData(object value, object dataTypeConfiguration) + public ContentPropertyData(object? value, object? dataTypeConfiguration) { Value = value; DataTypeConfiguration = dataTypeConfiguration; @@ -20,12 +20,12 @@ namespace Umbraco.Cms.Core.Models.Editors /// /// The value submitted for the property /// - public object Value { get; } + public object? Value { get; } /// /// The data type configuration for the property. /// - public object DataTypeConfiguration { get; } + public object? DataTypeConfiguration { get; } /// /// Gets or sets the unique identifier of the content owning the property. diff --git a/src/Umbraco.Core/Models/Editors/ContentPropertyFile.cs b/src/Umbraco.Core/Models/Editors/ContentPropertyFile.cs index 6d008bc74f..d1bc9127ce 100644 --- a/src/Umbraco.Core/Models/Editors/ContentPropertyFile.cs +++ b/src/Umbraco.Core/Models/Editors/ContentPropertyFile.cs @@ -38,6 +38,6 @@ /// /// Gets or sets the temporary path where the file has been uploaded. /// - public string? TempFilePath { get; set; } + public string TempFilePath { get; set; } = string.Empty; } } diff --git a/src/Umbraco.Core/Models/IDataValueEditor.cs b/src/Umbraco.Core/Models/IDataValueEditor.cs index e3f7100241..8d4841a114 100644 --- a/src/Umbraco.Core/Models/IDataValueEditor.cs +++ b/src/Umbraco.Core/Models/IDataValueEditor.cs @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core.Models /// /// Converts a value posted by the editor to a property value. /// - object? FromEditor(ContentPropertyData editorValue, object currentValue); + object? FromEditor(ContentPropertyData editorValue, object? currentValue); /// /// Converts a property value to a value for the editor. @@ -80,6 +80,6 @@ namespace Umbraco.Cms.Core.Models /// XNode ConvertDbToXml(IPropertyType propertyType, object value); - string ConvertDbToString(IPropertyType propertyType, object value); + string ConvertDbToString(IPropertyType propertyType, object? value); } } diff --git a/src/Umbraco.Core/Models/Membership/IMembershipUser.cs b/src/Umbraco.Core/Models/Membership/IMembershipUser.cs index 40acb05a55..517416341b 100644 --- a/src/Umbraco.Core/Models/Membership/IMembershipUser.cs +++ b/src/Umbraco.Core/Models/Membership/IMembershipUser.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Models.Membership /// /// Gets or sets the raw password value /// - string RawPasswordValue { get; set; } + string? RawPasswordValue { get; set; } /// /// The user's specific password config (i.e. algorithm type, etc...) @@ -25,8 +25,8 @@ namespace Umbraco.Cms.Core.Models.Membership string? Comments { get; set; } bool IsApproved { get; set; } bool IsLockedOut { get; set; } - DateTime LastLoginDate { get; set; } - DateTime LastPasswordChangeDate { get; set; } + DateTime? LastLoginDate { get; set; } + DateTime? LastPasswordChangeDate { get; set; } DateTime LastLockoutDate { get; set; } /// diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 11b4ec2139..f5a4a87db7 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -41,7 +41,7 @@ namespace Umbraco.Cms.Core.Models.Membership /// /// /// - public User(GlobalSettings globalSettings, string name, string email, string username, string rawPasswordValue) + public User(GlobalSettings globalSettings, string? name, string email, string username, string rawPasswordValue) : this(globalSettings) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); diff --git a/src/Umbraco.Core/Notifications/IStatefulNotification.cs b/src/Umbraco.Core/Notifications/IStatefulNotification.cs index 87d2b58cde..7fa2382038 100644 --- a/src/Umbraco.Core/Notifications/IStatefulNotification.cs +++ b/src/Umbraco.Core/Notifications/IStatefulNotification.cs @@ -4,6 +4,6 @@ namespace Umbraco.Cms.Core.Notifications { public interface IStatefulNotification : INotification { - IDictionary? State { get; set; } + IDictionary State { get; set; } } } diff --git a/src/Umbraco.Core/Notifications/StatefulNotification.cs b/src/Umbraco.Core/Notifications/StatefulNotification.cs index 2ff89578f2..940e8ac45f 100644 --- a/src/Umbraco.Core/Notifications/StatefulNotification.cs +++ b/src/Umbraco.Core/Notifications/StatefulNotification.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.Notifications /// This can be used by event subscribers to store state in the notification so they easily deal with custom state data between /// a starting ("ing") and an ending ("ed") notification /// - public IDictionary? State + public IDictionary State { get => _state ??= new Dictionary(); set => _state = value; diff --git a/src/Umbraco.Core/Packaging/IPackageInstallation.cs b/src/Umbraco.Core/Packaging/IPackageInstallation.cs index 8dbba39133..9a744a91fa 100644 --- a/src/Umbraco.Core/Packaging/IPackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/IPackageInstallation.cs @@ -25,6 +25,6 @@ namespace Umbraco.Cms.Core.Packaging /// /// /// - CompiledPackage ReadPackage(XDocument packageXmlFile); + CompiledPackage ReadPackage(XDocument? packageXmlFile); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IAuditRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IAuditRepository.cs index 37394c9898..6d28a86b64 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IAuditRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IAuditRepository.cs @@ -30,8 +30,8 @@ namespace Umbraco.Cms.Core.Persistence.Repositories IQuery query, long pageIndex, int pageSize, out long totalRecords, Direction orderDirection, - AuditType[] auditTypeFilter, - IQuery customFilter); + AuditType[]? auditTypeFilter, + IQuery? customFilter); IEnumerable Get(AuditType type, IQuery query); } diff --git a/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs index 108a0d5dc2..e9063416af 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories { public interface IDataTypeRepository : IReadWriteQueryRepository { - IEnumerable> Move(IDataType toMove, EntityContainer container); + IEnumerable> Move(IDataType toMove, EntityContainer? container); /// /// Returns a dictionary of content type s and the property type aliases that use a diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs index 639985e7c6..5384ef0813 100644 --- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs @@ -86,7 +86,7 @@ namespace Umbraco.Cms.Core.PropertyEditors : configurationEditorJsonSerializer.Deserialize>(configurationJson); /// - public virtual object FromConfigurationEditor(IDictionary editorValues, object configuration) + public virtual object? FromConfigurationEditor(IDictionary editorValues, object configuration) { // by default, return the posted dictionary // but only keep entries that have a non-null/empty value @@ -124,7 +124,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public virtual IDictionary? ToValueEditor(object? configuration) + public virtual IDictionary ToValueEditor(object? configuration) => ToConfigurationEditor(configuration); } diff --git a/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs index 2d5653f394..d243bb79bf 100644 --- a/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs @@ -59,7 +59,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// The values posted by the configuration editor. /// The current configuration object. - object FromConfigurationEditor(IDictionary editorValues, object configuration); + object? FromConfigurationEditor(IDictionary editorValues, object configuration); /// /// Converts the configuration object to values for the configuration editor. diff --git a/src/Umbraco.Core/PublishedCache/PublishedElement.cs b/src/Umbraco.Core/PublishedCache/PublishedElement.cs index de6eb1b316..1972e8a7f4 100644 --- a/src/Umbraco.Core/PublishedCache/PublishedElement.cs +++ b/src/Umbraco.Core/PublishedCache/PublishedElement.cs @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Core.PublishedCache { // initializes a new instance of the PublishedElement class // within the context of a published snapshot service (eg a published content property value) - public PublishedElement(IPublishedContentType contentType, Guid key, Dictionary? values, bool previewing, + public PublishedElement(IPublishedContentType contentType, Guid key, Dictionary? values, bool previewing, PropertyCacheLevel referenceCacheLevel, IPublishedSnapshotAccessor? publishedSnapshotAccessor) { if (key == Guid.Empty) throw new ArgumentException("Empty guid."); @@ -50,12 +50,12 @@ namespace Umbraco.Cms.Core.PublishedCache : this(contentType, key, values, previewing, PropertyCacheLevel.None, null) { } - private static Dictionary GetCaseInsensitiveValueDictionary(Dictionary values) + private static Dictionary GetCaseInsensitiveValueDictionary(Dictionary values) { // ensure we ignore case for property aliases var comparer = values.Comparer; var ignoreCase = Equals(comparer, StringComparer.OrdinalIgnoreCase) || Equals(comparer, StringComparer.InvariantCultureIgnoreCase) || Equals(comparer, StringComparer.CurrentCultureIgnoreCase); - return ignoreCase ? values : new Dictionary(values, StringComparer.OrdinalIgnoreCase); + return ignoreCase ? values : new Dictionary(values, StringComparer.OrdinalIgnoreCase); } #region ContentType diff --git a/src/Umbraco.Core/Scoping/IScopeContext.cs b/src/Umbraco.Core/Scoping/IScopeContext.cs index 1814486c0e..72523be9e2 100644 --- a/src/Umbraco.Core/Scoping/IScopeContext.cs +++ b/src/Umbraco.Core/Scoping/IScopeContext.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Core.Scoping /// and action with the same key but only the first one is used, the others are ignored. /// The action boolean parameter indicates whether the scope completed or not. /// - T Enlist(string key, Func creator, Action? action = null, int priority = 100); + T? Enlist(string key, Func creator, Action? action = null, int priority = 100); /// /// Gets an enlisted object. @@ -45,7 +45,7 @@ namespace Umbraco.Cms.Core.Scoping /// The type of the object. /// The object unique identifier. /// The enlisted object, if any, else the default value. - T GetEnlisted(string key); + T? GetEnlisted(string key); void ScopeExit(bool completed); } diff --git a/src/Umbraco.Core/Scoping/IScopeProvider.cs b/src/Umbraco.Core/Scoping/IScopeProvider.cs index ab32ee3645..c9c30662b4 100644 --- a/src/Umbraco.Core/Scoping/IScopeProvider.cs +++ b/src/Umbraco.Core/Scoping/IScopeProvider.cs @@ -80,7 +80,7 @@ namespace Umbraco.Cms.Core.Scoping /// /// Gets the scope context. /// - IScopeContext Context { get; } + IScopeContext? Context { get; } /// /// Creates an instance of diff --git a/src/Umbraco.Core/Security/IIdentityUserToken.cs b/src/Umbraco.Core/Security/IIdentityUserToken.cs index d7d3af6adf..0e7f22d72f 100644 --- a/src/Umbraco.Core/Security/IIdentityUserToken.cs +++ b/src/Umbraco.Core/Security/IIdentityUserToken.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Security /// /// Gets or sets user Id for the user who owns this token /// - string UserId { get; set; } + string? UserId { get; set; } /// /// Gets or sets the login provider for the login (i.e. Facebook, Google) diff --git a/src/Umbraco.Core/Security/IdentityUserToken.cs b/src/Umbraco.Core/Security/IdentityUserToken.cs index 4a3c0f21cf..014001a3a9 100644 --- a/src/Umbraco.Core/Security/IdentityUserToken.cs +++ b/src/Umbraco.Core/Security/IdentityUserToken.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.Security /// /// Initializes a new instance of the class. /// - public IdentityUserToken(string loginProvider, string name, string value, string userId) + public IdentityUserToken(string loginProvider, string? name, string? value, string? userId) { LoginProvider = loginProvider ?? throw new ArgumentNullException(nameof(loginProvider)); Name = name ?? throw new ArgumentNullException(nameof(name)); @@ -19,7 +19,7 @@ namespace Umbraco.Cms.Core.Security /// /// Initializes a new instance of the class. /// - public IdentityUserToken(int id, string loginProvider, string name, string value, string userId, DateTime createDate) + public IdentityUserToken(int id, string? loginProvider, string? name, string? value, string userId, DateTime createDate) { Id = id; LoginProvider = loginProvider ?? throw new ArgumentNullException(nameof(loginProvider)); @@ -39,6 +39,6 @@ namespace Umbraco.Cms.Core.Security public string Value { get; set; } /// - public string UserId { get; set; } + public string? UserId { get; set; } } } diff --git a/src/Umbraco.Core/Serialization/IJsonSerializer.cs b/src/Umbraco.Core/Serialization/IJsonSerializer.cs index ef2e712b9a..051055b564 100644 --- a/src/Umbraco.Core/Serialization/IJsonSerializer.cs +++ b/src/Umbraco.Core/Serialization/IJsonSerializer.cs @@ -4,8 +4,8 @@ { string Serialize(object? input); - T Deserialize(string input); + T? Deserialize(string input); - T DeserializeSubset(string input, string key); + T? DeserializeSubset(string input, string key); } } diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index e16ef8cfa3..35fdb1f4d9 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -216,7 +216,7 @@ namespace Umbraco.Cms.Core.Services /// Search text filter. /// Ordering infos. IEnumerable GetPagedOfTypes(int[] contentTypeIds, long pageIndex, int pageSize, out long totalRecords, - IQuery filter, Ordering? ordering = null); + IQuery? filter, Ordering? ordering = null); /// /// Counts documents of a given document type. diff --git a/src/Umbraco.Core/Services/IDataTypeService.cs b/src/Umbraco.Core/Services/IDataTypeService.cs index 727851ef02..f7c222925c 100644 --- a/src/Umbraco.Core/Services/IDataTypeService.cs +++ b/src/Umbraco.Core/Services/IDataTypeService.cs @@ -17,36 +17,36 @@ namespace Umbraco.Cms.Core.Services /// IReadOnlyDictionary> GetReferences(int id); - Attempt> CreateContainer(int parentId, Guid key, string name, int userId = Constants.Security.SuperUserId); - Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId); - EntityContainer GetContainer(int containerId); + Attempt?> CreateContainer(int parentId, Guid key, string name, int userId = Constants.Security.SuperUserId); + Attempt SaveContainer(EntityContainer container, int userId = Constants.Security.SuperUserId); + EntityContainer? GetContainer(int containerId); EntityContainer GetContainer(Guid containerId); IEnumerable GetContainers(string folderName, int level); IEnumerable GetContainers(IDataType dataType); IEnumerable GetContainers(int[] containerIds); - Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId); - Attempt> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId); + Attempt DeleteContainer(int containerId, int userId = Constants.Security.SuperUserId); + Attempt?> RenameContainer(int id, string name, int userId = Constants.Security.SuperUserId); /// /// Gets a by its Name /// /// Name of the /// - IDataType GetDataType(string name); + IDataType? GetDataType(string name); /// /// Gets a by its Id /// /// Id of the /// - IDataType GetDataType(int id); + IDataType? GetDataType(int id); /// /// Gets a by its unique guid Id /// /// Unique guid Id of the DataType /// - IDataType GetDataType(Guid id); + IDataType? GetDataType(Guid id); /// /// Gets all objects or those with the ids passed in @@ -87,6 +87,6 @@ namespace Umbraco.Cms.Core.Services /// Collection of objects with a matching control id IEnumerable GetByEditorAlias(string propertyEditorAlias); - Attempt> Move(IDataType toMove, int parentId); + Attempt?> Move(IDataType toMove, int parentId); } } diff --git a/src/Umbraco.Core/Services/IEntityService.cs b/src/Umbraco.Core/Services/IEntityService.cs index cb72735c02..6d43e37ac5 100644 --- a/src/Umbraco.Core/Services/IEntityService.cs +++ b/src/Umbraco.Core/Services/IEntityService.cs @@ -116,7 +116,7 @@ namespace Umbraco.Cms.Core.Services /// The object type of the entities. /// The unique identifiers of the entities. /// If is empty, returns all entities. - IEnumerable GetAll(UmbracoObjectTypes objectType, Guid[] keys); + IEnumerable GetAll(UmbracoObjectTypes objectType, Guid?[] keys); /// /// Gets entities of a given object type. diff --git a/src/Umbraco.Core/Services/IIdKeyMap.cs b/src/Umbraco.Core/Services/IIdKeyMap.cs index 56be36c5fa..199ee23813 100644 --- a/src/Umbraco.Core/Services/IIdKeyMap.cs +++ b/src/Umbraco.Core/Services/IIdKeyMap.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Core.Services { Attempt GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType); Attempt GetIdForUdi(Udi udi); - Attempt GetUdiForId(int id, UmbracoObjectTypes umbracoObjectType); + Attempt GetUdiForId(int id, UmbracoObjectTypes umbracoObjectType); Attempt GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType); void ClearCache(); void ClearCache(int id); diff --git a/src/Umbraco.Core/Services/IPackagingService.cs b/src/Umbraco.Core/Services/IPackagingService.cs index 719f8e3396..8429898354 100644 --- a/src/Umbraco.Core/Services/IPackagingService.cs +++ b/src/Umbraco.Core/Services/IPackagingService.cs @@ -30,20 +30,20 @@ namespace Umbraco.Cms.Core.Services /// IEnumerable GetAllInstalledPackages(); - InstalledPackage GetInstalledPackageByName(string packageName); + InstalledPackage? GetInstalledPackageByName(string packageName); /// /// Returns the created packages /// /// - IEnumerable GetAllCreatedPackages(); + IEnumerable GetAllCreatedPackages(); /// /// Returns a created package by id /// /// /// - PackageDefinition GetCreatedPackageById(int id); + PackageDefinition? GetCreatedPackageById(int id); void DeleteCreatedPackage(int id, int userId = Constants.Security.SuperUserId); diff --git a/src/Umbraco.Core/Services/IPropertyValidationService.cs b/src/Umbraco.Core/Services/IPropertyValidationService.cs index 466eb39c66..8c7aee93df 100644 --- a/src/Umbraco.Core/Services/IPropertyValidationService.cs +++ b/src/Umbraco.Core/Services/IPropertyValidationService.cs @@ -34,6 +34,6 @@ namespace Umbraco.Cms.Core.Services /// IEnumerable ValidatePropertyValue( IPropertyType propertyType, - object postedValue); + object? postedValue); } } diff --git a/src/Umbraco.Core/Services/IRuntimeState.cs b/src/Umbraco.Core/Services/IRuntimeState.cs index 2b72149042..3c765a0748 100644 --- a/src/Umbraco.Core/Services/IRuntimeState.cs +++ b/src/Umbraco.Core/Services/IRuntimeState.cs @@ -38,17 +38,17 @@ namespace Umbraco.Cms.Core.Services /// /// Gets the current migration state. /// - string CurrentMigrationState { get; } + string? CurrentMigrationState { get; } /// /// Gets the final migration state. /// - string FinalMigrationState { get; } + string? FinalMigrationState { get; } /// /// Gets the exception that caused the boot to fail. /// - BootFailedException BootFailedException { get; } + BootFailedException? BootFailedException { get; } /// /// Determines the runtime level. diff --git a/src/Umbraco.Core/Services/ITwoFactorLoginService.cs b/src/Umbraco.Core/Services/ITwoFactorLoginService.cs index 33a96ad751..f30e371d6a 100644 --- a/src/Umbraco.Core/Services/ITwoFactorLoginService.cs +++ b/src/Umbraco.Core/Services/ITwoFactorLoginService.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Core.Services /// /// Gets the secret for user or member and a specific provider. /// - Task GetSecretForUserAndProviderAsync(Guid userOrMemberKey, string providerName); + Task GetSecretForUserAndProviderAsync(Guid userOrMemberKey, string providerName); /// /// Gets the setup info for a specific user or member and a specific provider. @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.Services /// /// The returned type can be anything depending on the setup providers. You will need to cast it to the type handled by the provider. /// - Task GetSetupInfoAsync(Guid userOrMemberKey, string providerName); + Task GetSetupInfoAsync(Guid userOrMemberKey, string providerName); /// /// Gets all registered providers names. diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs index 2742bf4936..ee16ef64a6 100644 --- a/src/Umbraco.Core/Services/IUserService.cs +++ b/src/Umbraco.Core/Services/IUserService.cs @@ -194,7 +194,7 @@ namespace Umbraco.Cms.Core.Services /// /// Id of group /// - IEnumerable GetAllInGroup(int groupId); + IEnumerable GetAllInGroup(int? groupId); /// /// Gets a list of objects not associated with a given group diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index 65adc8892c..d3b52701bc 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -601,11 +601,15 @@ namespace Umbraco.Cms.Core.Services /// /// Id of group /// - public IEnumerable GetAllInGroup(int groupId) + public IEnumerable GetAllInGroup(int? groupId) { + if (groupId is null) + { + return Array.Empty(); + } using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - return _userRepository.GetAllInGroup(groupId); + return _userRepository.GetAllInGroup(groupId.Value); } } diff --git a/src/Umbraco.Core/Sync/RefreshInstruction.cs b/src/Umbraco.Core/Sync/RefreshInstruction.cs index b02cbc81e0..169b58f5a1 100644 --- a/src/Umbraco.Core/Sync/RefreshInstruction.cs +++ b/src/Umbraco.Core/Sync/RefreshInstruction.cs @@ -66,7 +66,7 @@ namespace Umbraco.Cms.Core.Sync /// When the refresh method is we know how many Ids are being refreshed so we know the instruction /// count which will be taken into account when we store this count in the database. /// - private RefreshInstruction(ICacheRefresher refresher, RefreshMethodType refreshType, string json, int idCount = 1) + private RefreshInstruction(ICacheRefresher refresher, RefreshMethodType refreshType, string? json, int idCount = 1) : this(refresher, refreshType) { JsonIdCount = idCount; @@ -85,9 +85,9 @@ namespace Umbraco.Cms.Core.Sync ICacheRefresher refresher, IJsonSerializer jsonSerializer, MessageType messageType, - IEnumerable ids, - Type idType, - string json) + IEnumerable? ids, + Type? idType, + string? json) { switch (messageType) { diff --git a/src/Umbraco.Core/Trees/TreeNode.cs b/src/Umbraco.Core/Trees/TreeNode.cs index 8ecab61fb3..ccf5a38347 100644 --- a/src/Umbraco.Core/Trees/TreeNode.cs +++ b/src/Umbraco.Core/Trees/TreeNode.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Core.Trees /// The parent id for the current node /// /// - public TreeNode(string nodeId, string parentId, string getChildNodesUrl, string menuUrl) + public TreeNode(string nodeId, string? parentId, string getChildNodesUrl, string menuUrl) { if (nodeId == null) throw new ArgumentNullException(nameof(nodeId)); if (string.IsNullOrWhiteSpace(nodeId)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(nodeId)); diff --git a/src/Umbraco.Core/Udi.cs b/src/Umbraco.Core/Udi.cs index 02979646a0..55efc549eb 100644 --- a/src/Umbraco.Core/Udi.cs +++ b/src/Umbraco.Core/Udi.cs @@ -154,14 +154,14 @@ namespace Umbraco.Cms.Core return UriValue.GetHashCode(); } - public static bool operator ==(Udi udi1, Udi udi2) + public static bool operator ==(Udi? udi1, Udi? udi2) { if (ReferenceEquals(udi1, udi2)) return true; if ((object)udi1 == null || (object)udi2 == null) return false; return udi1.Equals(udi2); } - public static bool operator !=(Udi udi1, Udi udi2) + public static bool operator !=(Udi? udi1, Udi? udi2) { return (udi1 == udi2) == false; } diff --git a/src/Umbraco.Core/Web/IUmbracoContextAccessor.cs b/src/Umbraco.Core/Web/IUmbracoContextAccessor.cs index fd37126b7d..d8e6793f89 100644 --- a/src/Umbraco.Core/Web/IUmbracoContextAccessor.cs +++ b/src/Umbraco.Core/Web/IUmbracoContextAccessor.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace Umbraco.Cms.Core.Web { /// @@ -7,7 +9,7 @@ namespace Umbraco.Cms.Core.Web /// public interface IUmbracoContextAccessor { - bool TryGetUmbracoContext(out IUmbracoContext? umbracoContext); + bool TryGetUmbracoContext([MaybeNullWhen(false)] out IUmbracoContext umbracoContext); void Clear(); void Set(IUmbracoContext umbracoContext); } diff --git a/src/Umbraco.Core/WebAssets/IRuntimeMinifier.cs b/src/Umbraco.Core/WebAssets/IRuntimeMinifier.cs index a3b88633b6..0c8067def6 100644 --- a/src/Umbraco.Core/WebAssets/IRuntimeMinifier.cs +++ b/src/Umbraco.Core/WebAssets/IRuntimeMinifier.cs @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Core.WebAssets /// /// Thrown if any of the paths specified are not absolute /// - void CreateCssBundle(string bundleName, BundlingOptions bundleOptions, params string[] filePaths); + void CreateCssBundle(string bundleName, BundlingOptions bundleOptions, params string[]? filePaths); /// /// Renders the html link tag for the bundle @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Core.WebAssets /// /// Thrown if any of the paths specified are not absolute /// - void CreateJsBundle(string bundleName, BundlingOptions bundleOptions, params string[] filePaths); + void CreateJsBundle(string bundleName, BundlingOptions bundleOptions, params string[]? filePaths); /// /// Renders the html script tag for the bundle diff --git a/src/Umbraco.Core/Xml/XmlHelper.cs b/src/Umbraco.Core/Xml/XmlHelper.cs index 4f6d5ca2f4..4de056e223 100644 --- a/src/Umbraco.Core/Xml/XmlHelper.cs +++ b/src/Umbraco.Core/Xml/XmlHelper.cs @@ -366,7 +366,7 @@ namespace Umbraco.Cms.Core.Xml /// /// true if the specified string appears to be XML; otherwise, false. /// - public static bool CouldItBeXml(string xml) + public static bool CouldItBeXml(string? xml) { if (string.IsNullOrEmpty(xml)) return false; diff --git a/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs index dfe3466fc0..00ab4a3a5c 100644 --- a/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs +++ b/src/Umbraco.Infrastructure/Cache/RepositoryCachePolicyBase.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.Cache get { var ambientScope = _scopeAccessor.AmbientScope; - switch (ambientScope.RepositoryCacheMode) + switch (ambientScope?.RepositoryCacheMode) { case RepositoryCacheMode.Default: return _globalCache; @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.Cache case RepositoryCacheMode.None: return NoAppCache.Instance; default: - throw new NotSupportedException($"Repository cache mode {ambientScope.RepositoryCacheMode} is not supported."); + throw new NotSupportedException($"Repository cache mode {ambientScope?.RepositoryCacheMode} is not supported."); } } } diff --git a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs index 1dff9bb5e1..0be7a18fef 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs @@ -224,7 +224,7 @@ namespace Umbraco.Cms.Infrastructure.Examine { if (completed) { - actions.Execute(); + actions?.Execute(); } }, EnlistPriority); } diff --git a/src/Umbraco.Infrastructure/IPublishedContentQuery.cs b/src/Umbraco.Infrastructure/IPublishedContentQuery.cs index 5b17af02cd..d5f41c0a02 100644 --- a/src/Umbraco.Infrastructure/IPublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/IPublishedContentQuery.cs @@ -12,10 +12,10 @@ namespace Umbraco.Cms.Core /// public interface IPublishedContentQuery { - IPublishedContent Content(int id); + IPublishedContent? Content(int id); IPublishedContent Content(Guid id); - IPublishedContent Content(Udi id); - IPublishedContent Content(object id); + IPublishedContent? Content(Udi id); + IPublishedContent? Content(object id); IPublishedContent ContentSingleAtXPath(string xpath, params XPathVariable[] vars); IEnumerable Content(IEnumerable ids); IEnumerable Content(IEnumerable ids); @@ -25,11 +25,11 @@ namespace Umbraco.Cms.Core IEnumerable ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars); IEnumerable ContentAtRoot(); - IPublishedContent Media(int id); + IPublishedContent? Media(int id); IPublishedContent Media(Guid id); - IPublishedContent Media(Udi id); + IPublishedContent? Media(Udi id); - IPublishedContent Media(object id); + IPublishedContent? Media(object id); IEnumerable Media(IEnumerable ids); IEnumerable Media(IEnumerable ids); IEnumerable Media(IEnumerable ids); diff --git a/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs b/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs index 00adc5018b..01aea4c48f 100644 --- a/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs +++ b/src/Umbraco.Infrastructure/IPublishedContentQueryAccessor.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace Umbraco.Cms.Core { /// @@ -15,6 +17,6 @@ namespace Umbraco.Cms.Core /// public interface IPublishedContentQueryAccessor { - bool TryGetValue(out IPublishedContentQuery publishedContentQuery); + bool TryGetValue([MaybeNullWhen(false)]out IPublishedContentQuery publishedContentQuery); } } diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs index b156597d3a..0a156f536c 100644 --- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs +++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs @@ -35,7 +35,7 @@ namespace Umbraco.Cms.Core.Manifest private readonly ManifestValueValidatorCollection _validators; private readonly ManifestFilterCollection _filters; - private string _path; + private string _path = null!; /// /// Initializes a new instance of the class. @@ -51,30 +51,19 @@ namespace Umbraco.Cms.Core.Manifest ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IDataValueEditorFactory dataValueEditorFactory) - : this(appCaches, validators, filters, "~/App_Plugins", logger, ioHelper, hostingEnvironment) - { - _jsonSerializer = jsonSerializer; - _localizedTextService = localizedTextService; - _shortStringHelper = shortStringHelper; - _dataValueEditorFactory = dataValueEditorFactory; - } - - /// - /// Initializes a new instance of the class. - /// - private ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ManifestFilterCollection filters, string appPluginsPath, ILogger logger, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment) { if (appCaches == null) throw new ArgumentNullException(nameof(appCaches)); _cache = appCaches.RuntimeCache; _validators = validators ?? throw new ArgumentNullException(nameof(validators)); _filters = filters ?? throw new ArgumentNullException(nameof(filters)); - if (appPluginsPath == null) throw new ArgumentNullException(nameof(appPluginsPath)); - if (string.IsNullOrWhiteSpace(appPluginsPath)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(appPluginsPath)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _ioHelper = ioHelper; _hostingEnvironment = hostingEnvironment; - - AppPluginsPath = appPluginsPath; + AppPluginsPath = "~/App_Plugins"; + _jsonSerializer = jsonSerializer; + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _dataValueEditorFactory = dataValueEditorFactory; } public string AppPluginsPath diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterColumnExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterColumnExpression.cs index 1caf4fa2c2..6d1bfe4561 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterColumnExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterColumnExpression.cs @@ -11,8 +11,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Alter.Expressions Column = new ColumnDefinition { ModificationType = ModificationType.Alter }; } - public virtual string SchemaName { get; set; } - public virtual string TableName { get; set; } + public virtual string? SchemaName { get; set; } + public virtual string? TableName { get; set; } public virtual ColumnDefinition Column { get; set; } protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterDefaultConstraintExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterDefaultConstraintExpression.cs index fbe43e95aa..18298c7378 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterDefaultConstraintExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterDefaultConstraintExpression.cs @@ -6,13 +6,13 @@ : base(context) { } - public virtual string TableName { get; set; } + public virtual string? TableName { get; set; } - public virtual string ColumnName { get; set; } + public virtual string? ColumnName { get; set; } - public virtual string ConstraintName { get; set; } + public virtual string? ConstraintName { get; set; } - public virtual object DefaultValue { get; set; } + public virtual object? DefaultValue { get; set; } protected override string GetSql() { diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterTableExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterTableExpression.cs index 9fa7f5f77f..9be5354590 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterTableExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Expressions/AlterTableExpression.cs @@ -6,7 +6,7 @@ : base(context) { } - public virtual string TableName { get; set; } + public virtual string? TableName { get; set; } protected override string GetSql() { diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Table/AlterTableBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Table/AlterTableBuilder.cs index 9266257250..199db34102 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Table/AlterTableBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Alter/Table/AlterTableBuilder.cs @@ -21,9 +21,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Alter.Table public void Do() => Expression.Execute(); - public ColumnDefinition CurrentColumn { get; set; } + public ColumnDefinition CurrentColumn { get; set; } = null!; - public ForeignKeyDefinition CurrentForeignKey { get; set; } + public ForeignKeyDefinition CurrentForeignKey { get; set; } = null!; public override ColumnDefinition GetColumnForType() { @@ -65,7 +65,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Alter.Table return Indexed(null); } - public IAlterTableColumnOptionBuilder Indexed(string indexName) + public IAlterTableColumnOptionBuilder Indexed(string? indexName) { CurrentColumn.IsIndexed = true; @@ -138,7 +138,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Alter.Table return Unique(null); } - public IAlterTableColumnOptionBuilder Unique(string indexName) + public IAlterTableColumnOptionBuilder Unique(string? indexName) { CurrentColumn.IsUnique = true; @@ -170,7 +170,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Alter.Table return ForeignKey(foreignKeyName, null, primaryTableName, primaryColumnName); } - public IAlterTableColumnOptionForeignKeyCascadeBuilder ForeignKey(string foreignKeyName, string primaryTableSchema, + public IAlterTableColumnOptionForeignKeyCascadeBuilder ForeignKey(string? foreignKeyName, string? primaryTableSchema, string primaryTableName, string primaryColumnName) { CurrentColumn.IsForeignKey = true; @@ -208,7 +208,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Alter.Table return ReferencedBy(foreignKeyName, null, foreignTableName, foreignColumnName); } - public IAlterTableColumnOptionForeignKeyCascadeBuilder ReferencedBy(string foreignKeyName, string foreignTableSchema, + public IAlterTableColumnOptionForeignKeyCascadeBuilder ReferencedBy(string? foreignKeyName, string? foreignTableSchema, string foreignTableName, string foreignColumnName) { var fk = new CreateForeignKeyExpression(_context, new ForeignKeyDefinition diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Common/Expressions/CreateColumnExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Common/Expressions/CreateColumnExpression.cs index d19e8346cb..8e701f845e 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Common/Expressions/CreateColumnExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Common/Expressions/CreateColumnExpression.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Common.Expressions Column = new ColumnDefinition { ModificationType = ModificationType.Create }; } - public string TableName { get; set; } + public string? TableName { get; set; } public ColumnDefinition Column { get; set; } protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Column/CreateColumnBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Column/CreateColumnBuilder.cs index 12f575e879..07c11c57cd 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Column/CreateColumnBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Column/CreateColumnBuilder.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Column public void Do() => Expression.Execute(); - public ForeignKeyDefinition CurrentForeignKey { get; set; } + public ForeignKeyDefinition? CurrentForeignKey { get; set; } public override ColumnDefinition GetColumnForType() { @@ -55,7 +55,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Column return Indexed(null); } - public ICreateColumnOptionBuilder Indexed(string indexName) + public ICreateColumnOptionBuilder Indexed(string? indexName) { Expression.Column.IsIndexed = true; @@ -105,7 +105,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Column return Unique(null); } - public ICreateColumnOptionBuilder Unique(string indexName) + public ICreateColumnOptionBuilder Unique(string? indexName) { Expression.Column.IsUnique = true; @@ -137,7 +137,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Column return ForeignKey(foreignKeyName, null, primaryTableName, primaryColumnName); } - public ICreateColumnOptionForeignKeyCascadeBuilder ForeignKey(string foreignKeyName, string primaryTableSchema, + public ICreateColumnOptionForeignKeyCascadeBuilder ForeignKey(string? foreignKeyName, string? primaryTableSchema, string primaryTableName, string primaryColumnName) { Expression.Column.IsForeignKey = true; @@ -175,7 +175,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Column return ReferencedBy(foreignKeyName, null, foreignTableName, foreignColumnName); } - public ICreateColumnOptionForeignKeyCascadeBuilder ReferencedBy(string foreignKeyName, string foreignTableSchema, + public ICreateColumnOptionForeignKeyCascadeBuilder ReferencedBy(string? foreignKeyName, string? foreignTableSchema, string foreignTableName, string foreignColumnName) { var fk = new CreateForeignKeyExpression(_context, new ForeignKeyDefinition @@ -196,13 +196,21 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Column public ICreateColumnOptionForeignKeyCascadeBuilder OnDelete(Rule rule) { - CurrentForeignKey.OnDelete = rule; + if (CurrentForeignKey is not null) + { + CurrentForeignKey.OnDelete = rule; + } + return this; } public ICreateColumnOptionForeignKeyCascadeBuilder OnUpdate(Rule rule) { - CurrentForeignKey.OnUpdate = rule; + if (CurrentForeignKey is not null) + { + CurrentForeignKey.OnUpdate = rule; + } + return this; } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs index 41d6e06d40..9d190b010f 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Expressions/CreateTableExpression.cs @@ -11,8 +11,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Expressions Columns = new List(); } - public virtual string SchemaName { get; set; } - public virtual string TableName { get; set; } + public virtual string? SchemaName { get; set; } + public virtual string? TableName { get; set; } public virtual IList Columns { get; set; } protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Index/CreateIndexBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Index/CreateIndexBuilder.cs index f74f7131f5..a6024c19db 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Index/CreateIndexBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Index/CreateIndexBuilder.cs @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Index /// public void Do() => Expression.Execute(); - public IndexColumnDefinition CurrentColumn { get; set; } + public IndexColumnDefinition? CurrentColumn { get; set; } /// public ICreateIndexOnColumnBuilder OnTable(string tableName) @@ -44,14 +44,22 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Index /// public ICreateIndexOnColumnBuilder Ascending() { - CurrentColumn.Direction = Direction.Ascending; + if (CurrentColumn is not null) + { + CurrentColumn.Direction = Direction.Ascending; + } + return this; } /// public ICreateIndexOnColumnBuilder Descending() { - CurrentColumn.Direction = Direction.Descending; + if (CurrentColumn is not null) + { + CurrentColumn.Direction = Direction.Descending; + } + return this; } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs index f52331c730..86c3dc537a 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs @@ -17,12 +17,16 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.KeysAndIndexe _supportedDatabaseTypes = supportedDatabaseTypes; } - public Type TypeOfDto { get; set; } + public Type? TypeOfDto { get; set; } /// public void Do() { var syntax = _context.SqlContext.SqlSyntax; + if (TypeOfDto is null) + { + return; + } var tableDefinition = DefinitionFactory.GetTableDefinition(TypeOfDto, syntax); // note: of course we are creating the keys and indexes as per the DTO, so diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableBuilder.cs index 41892ef7f4..81e3a702ce 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableBuilder.cs @@ -21,9 +21,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table /// public void Do() => Expression.Execute(); - public ColumnDefinition CurrentColumn { get; set; } + public ColumnDefinition CurrentColumn { get; set; } = null!; - public ForeignKeyDefinition CurrentForeignKey { get; set; } + public ForeignKeyDefinition CurrentForeignKey { get; set; } = null!; public override ColumnDefinition GetColumnForType() { @@ -66,7 +66,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table } /// - public ICreateTableColumnOptionBuilder Indexed(string indexName) + public ICreateTableColumnOptionBuilder Indexed(string? indexName) { CurrentColumn.IsIndexed = true; @@ -146,7 +146,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table } /// - public ICreateTableColumnOptionBuilder Unique(string indexName) + public ICreateTableColumnOptionBuilder Unique(string? indexName) { CurrentColumn.IsUnique = true; @@ -182,7 +182,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table } /// - public ICreateTableColumnOptionForeignKeyCascadeBuilder ForeignKey(string foreignKeyName, string primaryTableSchema, + public ICreateTableColumnOptionForeignKeyCascadeBuilder ForeignKey(string? foreignKeyName, string? primaryTableSchema, string primaryTableName, string primaryColumnName) { CurrentColumn.IsForeignKey = true; @@ -225,7 +225,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table } /// - public ICreateTableColumnOptionForeignKeyCascadeBuilder ReferencedBy(string foreignKeyName, string foreignTableSchema, + public ICreateTableColumnOptionForeignKeyCascadeBuilder ReferencedBy(string? foreignKeyName, string? foreignTableSchema, string foreignTableName, string foreignColumnName) { var fk = new CreateForeignKeyExpression(_context, new ForeignKeyDefinition diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs index ae2098b75a..f0362e42a3 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Create/Table/CreateTableOfDtoBuilder.cs @@ -19,7 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table _supportedDatabaseTypes = supportedDatabaseTypes; } - public Type TypeOfDto { get; set; } + public Type? TypeOfDto { get; set; } public bool WithoutKeysAndIndexes { get; set; } @@ -27,6 +27,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Create.Table public void Do() { var syntax = _context.SqlContext.SqlSyntax; + if (TypeOfDto is null) + { + return; + } var tableDefinition = DefinitionFactory.GetTableDefinition(TypeOfDto, syntax); ExecuteSql(syntax.Format(tableDefinition)); diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Data/DeleteDataBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Data/DeleteDataBuilder.cs index d3435892cf..77d00b29f3 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Data/DeleteDataBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Data/DeleteDataBuilder.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete.Data /// public IExecutableBuilder IsNull(string columnName) { - Expression.Rows.Add(new DeletionDataDefinition { new KeyValuePair(columnName, null) }); + Expression.Rows.Add(new DeletionDataDefinition { new KeyValuePair(columnName, null) }); return this; } @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete.Data var data = new DeletionDataDefinition(); foreach (PropertyDescriptor property in properties) - data.Add(new KeyValuePair(property.Name, property.GetValue(dataAsAnonymousType))); + data.Add(new KeyValuePair(property.Name, property.GetValue(dataAsAnonymousType))); return data; } } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/DeleteBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/DeleteBuilder.cs index 251c13b4e8..c8a3ed5d28 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/DeleteBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/DeleteBuilder.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete } /// - public IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true) + public IExecutableBuilder KeysAndIndexes(string? tableName, bool local = true, bool foreign = true) { if (tableName == null) throw new ArgumentNullException(nameof(tableName)); if (string.IsNullOrWhiteSpace(tableName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(tableName)); diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteColumnExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteColumnExpression.cs index 13f94cc8a5..7cd93133e7 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteColumnExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteColumnExpression.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete.Expressions ColumnNames = new List(); } - public virtual string TableName { get; set; } + public virtual string? TableName { get; set; } public ICollection ColumnNames { get; set; } protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDataExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDataExpression.cs index 9e518dc587..3d57a77dc0 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDataExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDataExpression.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete.Expressions : base(context) { } - public string TableName { get; set; } + public string? TableName { get; set; } public virtual bool IsAllRows { get; set; } public List Rows { get; } = new List(); diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs index fd6950c12d..e653d0f6bf 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs @@ -6,9 +6,9 @@ : base(context) { } - public virtual string TableName { get; set; } - public virtual string ColumnName { get; set; } - public virtual string ConstraintName { get; set; } + public virtual string? TableName { get; set; } + public virtual string? ColumnName { get; set; } + public virtual string? ConstraintName { get; set; } public virtual bool HasDefaultConstraint { get; set; } protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteTableExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteTableExpression.cs index 18ff73cdea..75d453eb88 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteTableExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/Expressions/DeleteTableExpression.cs @@ -6,7 +6,7 @@ : base(context) { } - public virtual string TableName { get; set; } + public virtual string? TableName { get; set; } protected override string GetSql() { diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs index 1cef9e4851..c7411b3b69 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete.KeysAndIndexe _supportedDatabaseTypes = supportedDatabaseTypes; } - public string TableName { get; set; } + public string? TableName { get; set; } public bool DeleteLocal { get; set; } @@ -29,10 +29,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Delete.KeysAndIndexe _context.BuildingExpression = false; //get a list of all constraints - this will include all PK, FK and unique constraints - var tableConstraints = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).LegacyDistinctBy(x => x.Item2).ToList(); + var tableConstraints = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).LegacyDistinctBy(x => x!.Item2).ToList(); //get a list of defined indexes - this will include all indexes, unique indexes and unique constraint indexes - var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).LegacyDistinctBy(x => x.IndexName).ToList(); + var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).LegacyDistinctBy(x => x!.IndexName).ToList(); var uniqueConstraintNames = tableConstraints.Where(x => !x.Item2.InvariantStartsWith("PK_") && !x.Item2.InvariantStartsWith("FK_")).Select(x => x.Item2); var indexNames = indexes.Select(x => x.IndexName).ToList(); diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs index 091d20fa8f..4e9186ace9 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Execute/Expressions/ExecuteSqlStatementExpression.cs @@ -9,16 +9,16 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Execute.Expressions : base(context) { } - public virtual string SqlStatement { get; set; } + public virtual string? SqlStatement { get; set; } - public virtual Sql SqlObject { get; set; } + public virtual Sql? SqlObject { get; set; } public void ExecuteSqlObject() { Execute(SqlObject); } - protected override string GetSql() + protected override string? GetSql() { return SqlStatement; } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/ExpressionBuilderBaseOfNext.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/ExpressionBuilderBaseOfNext.cs index 3ac0344f85..74f1676def 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/ExpressionBuilderBaseOfNext.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/ExpressionBuilderBaseOfNext.cs @@ -15,168 +15,269 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions /// protected ExpressionBuilderBase(TExpression expression) : base(expression) - { } + { + } - public abstract ColumnDefinition GetColumnForType(); + public abstract ColumnDefinition? GetColumnForType(); - private ColumnDefinition Column => GetColumnForType(); + private ColumnDefinition? Column => GetColumnForType(); public TNext AsAnsiString() { - Column.Type = DbType.AnsiString; + if (Column is not null) + { + Column.Type = DbType.AnsiString; + } + return (TNext)(object)this; } public TNext AsAnsiString(int size) { - Column.Type = DbType.AnsiString; - Column.Size = size; + if (Column is not null) + { + Column.Type = DbType.AnsiString; + Column.Size = size; + } + return (TNext)(object)this; } public TNext AsBinary() { - Column.Type = DbType.Binary; + if (Column is not null) + { + Column.Type = DbType.Binary; + } + return (TNext)(object)this; } public TNext AsBinary(int size) { - Column.Type = DbType.Binary; - Column.Size = size; + if (Column is not null) + { + Column.Type = DbType.Binary; + Column.Size = size; + } + return (TNext)(object)this; } public TNext AsBoolean() { - Column.Type = DbType.Boolean; + if (Column is not null) + { + Column.Type = DbType.Boolean; + } + return (TNext)(object)this; } public TNext AsByte() { - Column.Type = DbType.Byte; + if (Column is not null) + { + Column.Type = DbType.Byte; + } + return (TNext)(object)this; } public TNext AsCurrency() { - Column.Type = DbType.Currency; + if (Column is not null) + { + Column.Type = DbType.Currency; + } + return (TNext)(object)this; } public TNext AsDate() { - Column.Type = DbType.Date; + if (Column is not null) + { + Column.Type = DbType.Date; + } + return (TNext)(object)this; } public TNext AsDateTime() { - Column.Type = DbType.DateTime; + if (Column is not null) + { + Column.Type = DbType.DateTime; + } + return (TNext)(object)this; } public TNext AsDecimal() { - Column.Type = DbType.Decimal; + if (Column is not null) + { + Column.Type = DbType.Decimal; + } + return (TNext)(object)this; } public TNext AsDecimal(int size, int precision) { - Column.Type = DbType.Decimal; - Column.Size = size; - Column.Precision = precision; + if (Column is not null) + { + Column.Type = DbType.Decimal; + Column.Size = size; + Column.Precision = precision; + } + return (TNext)(object)this; } public TNext AsDouble() { - Column.Type = DbType.Double; + if (Column is not null) + { + Column.Type = DbType.Double; + } + return (TNext)(object)this; } public TNext AsFixedLengthString(int size) { - Column.Type = DbType.StringFixedLength; - Column.Size = size; + if (Column is not null) + { + Column.Type = DbType.StringFixedLength; + Column.Size = size; + } + return (TNext)(object)this; } public TNext AsFixedLengthAnsiString(int size) { - Column.Type = DbType.AnsiStringFixedLength; - Column.Size = size; + if (Column is not null) + { + Column.Type = DbType.AnsiStringFixedLength; + Column.Size = size; + } + return (TNext)(object)this; } public TNext AsFloat() { - Column.Type = DbType.Single; + if (Column is not null) + { + Column.Type = DbType.Single; + } + return (TNext)(object)this; } public TNext AsGuid() { - Column.Type = DbType.Guid; + if (Column is not null) + { + Column.Type = DbType.Guid; + } + return (TNext)(object)this; } public TNext AsInt16() { - Column.Type = DbType.Int16; + if (Column is not null) + { + Column.Type = DbType.Int16; + } + return (TNext)(object)this; } public TNext AsInt32() { - Column.Type = DbType.Int32; + if (Column is not null) + { + Column.Type = DbType.Int32; + } + return (TNext)(object)this; } public TNext AsInt64() { - Column.Type = DbType.Int64; + if (Column is not null) + { + Column.Type = DbType.Int64; + } + return (TNext)(object)this; } public TNext AsString() { - Column.Type = DbType.String; + if (Column is not null) + { + Column.Type = DbType.String; + } + return (TNext)(object)this; } public TNext AsString(int size) { - Column.Type = DbType.String; - Column.Size = size; + if (Column is not null) + { + Column.Type = DbType.String; + Column.Size = size; + } + return (TNext)(object)this; } public TNext AsTime() { - Column.Type = DbType.Time; + if (Column is not null) + { + Column.Type = DbType.Time; + } + return (TNext)(object)this; } public TNext AsXml() { - Column.Type = DbType.Xml; + if (Column is not null) + { + Column.Type = DbType.Xml; + } + return (TNext)(object)this; } public TNext AsXml(int size) { - Column.Type = DbType.Xml; - Column.Size = size; + if (Column is not null) + { + Column.Type = DbType.Xml; + Column.Size = size; + } + return (TNext)(object)this; } public TNext AsCustom(string customType) { - Column.Type = null; - Column.CustomType = customType; + if (Column is not null) + { + Column.Type = null; + Column.CustomType = customType; + } + return (TNext)(object)this; } } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs index aa5c8ebd23..75664b701e 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Insert.Expressions : base(context) { } - public string TableName { get; set; } + public string? TableName { get; set; } public bool EnabledIdentityInsert { get; set; } public List Rows { get; } = new List(); diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/InsertIntoBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/InsertIntoBuilder.cs index 889f7c04ce..8d27877230 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/InsertIntoBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Insert/InsertIntoBuilder.cs @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Insert var data = new InsertionDataDefinition(); foreach (PropertyDescriptor property in properties) - data.Add(new KeyValuePair(property.Name, property.GetValue(dataAsAnonymousType))); + data.Add(new KeyValuePair(property.Name, property.GetValue(dataAsAnonymousType))); return data; } } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameColumnExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameColumnExpression.cs index 6dd72c78c5..cafbc45108 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameColumnExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameColumnExpression.cs @@ -6,9 +6,9 @@ : base(context) { } - public virtual string TableName { get; set; } - public virtual string OldName { get; set; } - public virtual string NewName { get; set; } + public virtual string? TableName { get; set; } + public virtual string? OldName { get; set; } + public virtual string? NewName { get; set; } /// protected override string GetSql() diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameTableExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameTableExpression.cs index aeaad46eac..77f9de03b3 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameTableExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Rename/Expressions/RenameTableExpression.cs @@ -12,12 +12,12 @@ /// /// Gets or sets the source name. /// - public virtual string OldName { get; set; } + public virtual string? OldName { get; set; } /// /// Gets or sets the target name. /// - public virtual string NewName { get; set; } + public virtual string? NewName { get; set; } /// /// diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Update/Expressions/UpdateDataExpression.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Update/Expressions/UpdateDataExpression.cs index f10737c884..62b6f0acfb 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Update/Expressions/UpdateDataExpression.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Update/Expressions/UpdateDataExpression.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Update.Expressions @@ -9,18 +10,18 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Update.Expressions : base(context) { } - public string TableName { get; set; } + public string? TableName { get; set; } - public List> Set { get; set; } - public List> Where { get; set; } + public List>? Set { get; set; } + public List>? Where { get; set; } public bool IsAllRows { get; set; } protected override string GetSql() { - var updateItems = Set.Select(x => $"{SqlSyntax.GetQuotedColumnName(x.Key)} = {GetQuotedValue(x.Value)}"); + var updateItems = Set?.Select(x => $"{SqlSyntax.GetQuotedColumnName(x.Key)} = {GetQuotedValue(x.Value)}"); var whereClauses = IsAllRows ? null - : Where.Select(x => $"{SqlSyntax.GetQuotedColumnName(x.Key)} {(x.Value == null ? "IS" : "=")} {GetQuotedValue(x.Value)}"); + : Where?.Select(x => $"{SqlSyntax.GetQuotedColumnName(x.Key)} {(x.Value == null ? "IS" : "=")} {GetQuotedValue(x.Value)}"); var whereClause = whereClauses == null ? "(1=1)" @@ -28,7 +29,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Update.Expressions return string.Format(SqlSyntax.UpdateData, SqlSyntax.GetQuotedTableName(TableName), - string.Join(", ", updateItems), + string.Join(", ", updateItems ?? Array.Empty()), whereClause); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Expressions/Update/UpdateDataBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Expressions/Update/UpdateDataBuilder.cs index 47601b37b6..fc7608f148 100644 --- a/src/Umbraco.Infrastructure/Migrations/Expressions/Update/UpdateDataBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Expressions/Update/UpdateDataBuilder.cs @@ -36,13 +36,13 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Expressions.Update return this; } - private static List> GetData(object dataAsAnonymousType) + private static List> GetData(object dataAsAnonymousType) { var properties = TypeDescriptor.GetProperties(dataAsAnonymousType); - var data = new List>(); + var data = new List>(); foreach (PropertyDescriptor property in properties) - data.Add(new KeyValuePair(property.Name, property.GetValue(dataAsAnonymousType))); + data.Add(new KeyValuePair(property.Name, property.GetValue(dataAsAnonymousType))); return data; } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index d84aa51d9b..37231a9487 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install private readonly IMigrationPlanExecutor _migrationPlanExecutor; private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; - private DatabaseSchemaResult _databaseSchemaValidationResult; + private DatabaseSchemaResult? _databaseSchemaValidationResult; /// /// Initializes a new instance of the class. @@ -117,17 +117,17 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install using (var scope = _scopeProvider.CreateScope()) { // look for the super user with default password - var sql = _scopeAccessor.AmbientScope.Database.SqlContext.Sql() + var sql = _scopeAccessor.AmbientScope?.Database.SqlContext.Sql() .SelectCount() .From() .Where(x => x.Id == Constants.Security.SuperUserId && x.Password == "default"); - var result = _scopeAccessor.AmbientScope.Database.ExecuteScalar(sql); + var result = _scopeAccessor.AmbientScope?.Database.ExecuteScalar(sql); var has = result != 1; if (has == false) { // found only 1 user == the default user with default password // however this always exists on uCloud, also need to check if there are other users too - result = _scopeAccessor.AmbientScope.Database.ExecuteScalar("SELECT COUNT(*) FROM umbracoUser"); + result = _scopeAccessor.AmbientScope?.Database.ExecuteScalar("SELECT COUNT(*) FROM umbracoUser"); has = result != 1; } scope.Complete(); @@ -139,7 +139,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install { using (var scope = _scopeProvider.CreateScope(autoComplete: true)) { - return _scopeAccessor.AmbientScope.Database.IsUmbracoInstalled(); + return _scopeAccessor.AmbientScope?.Database.IsUmbracoInstalled() ?? false; } } @@ -199,7 +199,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install Configure(connectionString, providerName, _globalSettings.CurrentValue.InstallMissingDatabase); } - private void Configure(string connectionString, string providerName, bool installMissingDatabase) + private void Configure(string connectionString, string? providerName, bool installMissingDatabase) { // Update existing connection string var umbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, connectionString, providerName); @@ -322,7 +322,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// This assumes that the database exists and the connection string is /// configured and it is possible to connect to the database. /// - public DatabaseSchemaResult ValidateSchema() + public DatabaseSchemaResult? ValidateSchema() { using (var scope = _scopeProvider.CreateScope()) { @@ -332,7 +332,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install } } - private DatabaseSchemaResult ValidateSchema(IScope scope) + private DatabaseSchemaResult? ValidateSchema(IScope scope) { if (_databaseFactory.Initialized == false) return new DatabaseSchemaResult(); @@ -340,7 +340,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install if (_databaseSchemaValidationResult != null) return _databaseSchemaValidationResult; - _databaseSchemaValidationResult = _scopeAccessor.AmbientScope.Database.ValidateSchema(); + _databaseSchemaValidationResult = _scopeAccessor.AmbientScope?.Database.ValidateSchema(); scope.Complete(); @@ -354,7 +354,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// This assumes that the database exists and the connection string is /// configured and it is possible to connect to the database. /// - public Result CreateSchemaAndData() + public Result? CreateSchemaAndData() { using (var scope = _scopeProvider.CreateScope()) { @@ -364,7 +364,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install } } - private Result CreateSchemaAndData(IScope scope) + private Result? CreateSchemaAndData(IScope scope) { try { @@ -376,12 +376,12 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install _logger.LogInformation("Database configuration status: Started"); - var database = _scopeAccessor.AmbientScope.Database; + var database = _scopeAccessor.AmbientScope?.Database; var message = string.Empty; var schemaResult = ValidateSchema(); - var hasInstalledVersion = schemaResult.DetermineHasInstalledVersion(); + var hasInstalledVersion = schemaResult?.DetermineHasInstalledVersion() ?? false; //If the determined version is "empty" its a new install - otherwise upgrade the existing if (!hasInstalledVersion) @@ -424,7 +424,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// configured and it is possible to connect to the database. /// Runs whichever migrations need to run. /// - public Result UpgradeSchemaAndData(UmbracoPlan plan) + public Result? UpgradeSchemaAndData(UmbracoPlan plan) { try { @@ -454,7 +454,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install } } - private Attempt CheckReadyForInstall() + private Attempt CheckReadyForInstall() { if (_databaseFactory.CanConnect == false) { @@ -466,7 +466,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install Percentage = "10" }); } - return Attempt.Succeed(); + return Attempt.Succeed(); } private Result HandleInstallException(Exception ex) @@ -501,7 +501,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// /// Gets or sets the message returned by the operation. /// - public string Message { get; set; } + public string? Message { get; set; } /// /// Gets or sets a value indicating whether the operation succeeded. @@ -511,7 +511,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// /// Gets or sets an install progress pseudo-percentage. /// - public string Percentage { get; set; } + public string? Percentage { get; set; } } #endregion diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 4f2ef1f2e9..6a8c7ea350 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -1,11 +1,9 @@ using System; -using System.Linq; using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Infrastructure.Migrations.Upgrade; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Extensions; @@ -299,7 +297,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install private void CreateDataTypeData() { - void InsertDataTypeDto(int id, string editorAlias, string dbType, string configuration = null) + void InsertDataTypeDto(int id, string editorAlias, string dbType, string? configuration = null) { var dataTypeDto = new DataTypeDto { diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs index 52c86f9ccf..e914c3a176 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data.SqlTypes; using System.Linq; using Microsoft.Extensions.Logging; using NPoco; @@ -89,7 +90,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install private readonly ILoggerFactory _loggerFactory; private readonly IUmbracoVersion _umbracoVersion; - public DatabaseSchemaCreator(IUmbracoDatabase database, ILogger logger, + public DatabaseSchemaCreator(IUmbracoDatabase? database, ILogger logger, ILoggerFactory loggerFactory, IUmbracoVersion umbracoVersion, IEventAggregator eventAggregator) { _database = database ?? throw new ArgumentNullException(nameof(database)); @@ -115,7 +116,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install foreach (Type table in OrderedTables.AsEnumerable().Reverse()) { - TableNameAttribute tableNameAttribute = table.FirstAttribute(); + TableNameAttribute? tableNameAttribute = table.FirstAttribute(); var tableName = tableNameAttribute == null ? table.Name : tableNameAttribute.Value; _logger.LogInformation("Uninstall {TableName}", tableName); @@ -201,7 +202,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install private void ValidateDbConstraints(DatabaseSchemaResult result) { //Check constraints in configured database against constraints in schema - var constraintsInDatabase = SqlSyntax.GetConstraintsPerColumn(_database).LegacyDistinctBy(x => x.Item3).ToList(); + var constraintsInDatabase = SqlSyntax.GetConstraintsPerColumn(_database).LegacyDistinctBy(x => x!.Item3).ToList(); var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("FK_")) .Select(x => x.Item3).ToList(); var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("PK_")) @@ -213,7 +214,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install x.Item3.InvariantStartsWith("FK_") == false && x.Item3.InvariantStartsWith("PK_") == false && x.Item3.InvariantStartsWith("IX_") == false).Select(x => x.Item3).ToList(); var foreignKeysInSchema = - result.TableDefinitions.SelectMany(x => x.ForeignKeys.Select(y => y.Name)).ToList(); + result.TableDefinitions.SelectMany(x => x.ForeignKeys.Select(y => y.Name)).Where(x => x is not null).ToList(); var primaryKeysInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => y.PrimaryKeyName)) .Where(x => x.IsNullOrWhiteSpace() == false).ToList(); @@ -222,7 +223,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install // In theory you could have: FK_ or fk_ ...or really any standard that your development department (or developer) chooses to use. foreach (var unknown in unknownConstraintsInDatabase) { - if (foreignKeysInSchema.InvariantContains(unknown) || primaryKeysInSchema.InvariantContains(unknown)) + if (foreignKeysInSchema!.InvariantContains(unknown) || primaryKeysInSchema.InvariantContains(unknown)) { result.ValidConstraints.Add(unknown); } @@ -234,20 +235,23 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install //Foreign keys: - IEnumerable validForeignKeyDifferences = + IEnumerable validForeignKeyDifferences = foreignKeysInDatabase.Intersect(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase); foreach (var foreignKey in validForeignKeyDifferences) { - result.ValidConstraints.Add(foreignKey); + if (foreignKey is not null) + { + result.ValidConstraints.Add(foreignKey); + } } - IEnumerable invalidForeignKeyDifferences = + IEnumerable invalidForeignKeyDifferences = foreignKeysInDatabase.Except(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase) .Union(foreignKeysInSchema.Except(foreignKeysInDatabase, StringComparer.InvariantCultureIgnoreCase)); foreach (var foreignKey in invalidForeignKeyDifferences) { - result.Errors.Add(new Tuple("Constraint", foreignKey)); + result.Errors.Add(new Tuple("Constraint", foreignKey ?? "NULL")); } @@ -303,19 +307,22 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install var tablesInDatabase = SqlSyntax.GetTablesInSchema(_database).ToList(); var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList(); //Add valid and invalid table differences to the result object - IEnumerable validTableDifferences = + IEnumerable validTableDifferences = tablesInDatabase.Intersect(tablesInSchema, StringComparer.InvariantCultureIgnoreCase); foreach (var tableName in validTableDifferences) { - result.ValidTables.Add(tableName); + if (tableName is not null) + { + result.ValidTables.Add(tableName); + } } - IEnumerable invalidTableDifferences = + IEnumerable invalidTableDifferences = tablesInDatabase.Except(tablesInSchema, StringComparer.InvariantCultureIgnoreCase) .Union(tablesInSchema.Except(tablesInDatabase, StringComparer.InvariantCultureIgnoreCase)); foreach (var tableName in invalidTableDifferences) { - result.Errors.Add(new Tuple("Table", tableName)); + result.Errors.Add(new Tuple("Table", tableName ?? "NULL")); } } @@ -327,19 +334,22 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList(); //Add valid and invalid index differences to the result object - IEnumerable validColIndexDifferences = + IEnumerable validColIndexDifferences = colIndexesInDatabase.Intersect(indexesInSchema, StringComparer.InvariantCultureIgnoreCase); foreach (var index in validColIndexDifferences) { - result.ValidIndexes.Add(index); + if (index is not null) + { + result.ValidIndexes.Add(index); + } } - IEnumerable invalidColIndexDifferences = + IEnumerable invalidColIndexDifferences = colIndexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase) .Union(indexesInSchema.Except(colIndexesInDatabase, StringComparer.InvariantCultureIgnoreCase)); foreach (var index in invalidColIndexDifferences) { - result.Errors.Add(new Tuple("Index", index)); + result.Errors.Add(new Tuple("Index", index ?? "NULL")); } } @@ -376,7 +386,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// } /// /// - public bool TableExists(string tableName) => SqlSyntax.DoesTableExist(_database, tableName); + public bool TableExists(string? tableName) => tableName is not null && SqlSyntax.DoesTableExist(_database, tableName); /// /// Returns whether the table for the specified exists in the database. @@ -455,6 +465,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install List indexSql = SqlSyntax.Format(tableDefinition.Indexes); var tableExist = TableExists(tableName); + if (string.IsNullOrEmpty(tableName)) + { + throw new SqlNullValueException("Tablename was null"); + } if (overwrite && tableExist) { _logger.LogInformation("Table {TableName} already exists, but will be recreated", tableName); @@ -534,7 +548,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// attribute will be used for the table name. If the attribute is not present, the name /// will be used instead. /// - public void DropTable(string tableName) + public void DropTable(string? tableName) { var sql = new Sql(string.Format(SqlSyntax.DropTable, SqlSyntax.GetQuotedTableName(tableName))); _database.Execute(sql); diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreatorFactory.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreatorFactory.cs index a582e1b02a..2c9242f3d5 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreatorFactory.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreatorFactory.cs @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install _eventAggregator = eventAggregator; } - public DatabaseSchemaCreator Create(IUmbracoDatabase database) + public DatabaseSchemaCreator Create(IUmbracoDatabase? database) { return new DatabaseSchemaCreator(database, _logger, _loggerFactory, _umbracoVersion, _eventAggregator); } diff --git a/src/Umbraco.Infrastructure/Migrations/MergeBuilder.cs b/src/Umbraco.Infrastructure/Migrations/MergeBuilder.cs index 6f340fa008..a25c161587 100644 --- a/src/Umbraco.Infrastructure/Migrations/MergeBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/MergeBuilder.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations { private readonly MigrationPlan _plan; private readonly List _migrations = new List(); - private string _withLast; + private string? _withLast; private bool _with; /// diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs b/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs index cb9fab0160..31aba3bb86 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs @@ -35,7 +35,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations public List Expressions => _expressions ?? (_expressions = new List()); - protected virtual string GetSql() + protected virtual string? GetSql() { return ToString(); } @@ -60,7 +60,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations var stmtBuilder = new StringBuilder(); using (var reader = new StringReader(sql)) { - string line; + string? line; while ((line = reader.ReadLine()) != null) { if (line.Trim().Equals("GO", StringComparison.OrdinalIgnoreCase)) @@ -83,7 +83,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations expression.Execute(); } - protected void Execute(Sql sql) + protected void Execute(Sql? sql) { if (_executed) throw new InvalidOperationException("This expression has already been executed."); @@ -130,7 +130,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations /// internal string Name { get; set; } - protected string GetQuotedValue(object val) + protected string GetQuotedValue(object? val) { if (val == null) return "NULL"; diff --git a/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs b/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs index 32d150fcca..ef4e3de38e 100644 --- a/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs +++ b/src/Umbraco.Infrastructure/Migrations/PostMigrations/DeleteLogViewerQueryFile.cs @@ -23,12 +23,12 @@ namespace Umbraco.Cms.Infrastructure.Migrations.PostMigrations /// protected override void Migrate() { - var logViewerQueryFile = MigrateLogViewerQueriesFromFileToDb.GetLogViewerQueryFile(_hostingEnvironment); - - if(File.Exists(logViewerQueryFile)) - { - File.Delete(logViewerQueryFile); - } + // var logViewerQueryFile = MigrateLogViewerQueriesFromFileToDb.GetLogViewerQueryFile(_hostingEnvironment); + // + // if(File.Exists(logViewerQueryFile)) + // { + // File.Delete(logViewerQueryFile); + // } } } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index 2080034554..f2c5662a74 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Semver; @@ -98,7 +99,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade /// /// true when the state contains a version; otherwise, false.D /// - private static bool TryGetInitStateVersion(string state, out string version) + private static bool TryGetInitStateVersion(string state, [MaybeNullWhen(false)] out string version) { if (state.StartsWith(InitPrefix) && state.EndsWith(InitSuffix)) { diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockItemData.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockItemData.cs index a1e7b46b30..a459a055ce 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockItemData.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockItemData.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.Models.Blocks /// not serialized, manually set and used during internally /// [JsonIgnore] - public string? ContentTypeAlias { get; set; } + public string ContentTypeAlias { get; set; } = string.Empty; [JsonProperty("udi")] [JsonConverter(typeof(UdiJsonConverter))] @@ -49,13 +49,13 @@ namespace Umbraco.Cms.Core.Models.Blocks /// public class BlockPropertyValue { - public BlockPropertyValue(object value, IPropertyType propertyType) + public BlockPropertyValue(object? value, IPropertyType propertyType) { Value = value; PropertyType = propertyType ?? throw new ArgumentNullException(nameof(propertyType)); } - public object Value { get; } + public object? Value { get; } public IPropertyType PropertyType { get; } } } diff --git a/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs b/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs index e7286d683f..61b14d15ab 100644 --- a/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs +++ b/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Core.Models throw new InvalidDataException($"The content item {entity.NodeId} has an invalid path: {entity.Path} with parentID: {entity.ParentId}"); } - if (entity.ParentId != default(int) && pathParts[pathParts.Length - 2] != entity.ParentId.ToInvariantString()) + if (entity.ParentId != default(int) && pathParts[pathParts.Length - 2] != entity.ParentId?.ToInvariantString()) { //the 2nd last id in the path must be it's parent id throw new InvalidDataException($"The content item {entity.NodeId} has an invalid path: {entity.Path} with parentID: {entity.ParentId}"); diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/ConstraintDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/ConstraintDefinition.cs index 919c5687a6..87066ce206 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/ConstraintDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/ConstraintDefinition.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions public string? SchemaName { get; set; } public string? ConstraintName { get; set; } public string? TableName { get; set; } - public ICollection Columns = new HashSet(); + public ICollection Columns = new HashSet(); public bool IsPrimaryKeyClustered { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DeletionDataDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DeletionDataDefinition.cs index 7a285534ba..c6033f898d 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DeletionDataDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DeletionDataDefinition.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions { - public class DeletionDataDefinition : List> + public class DeletionDataDefinition : List> { } diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexColumnDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexColumnDefinition.cs index e11129ebf0..6f3e34e0e4 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexColumnDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexColumnDefinition.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions { public class IndexColumnDefinition { - public virtual string Name { get; set; } + public virtual string? Name { get; set; } public virtual Direction Direction { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexDefinition.cs index 822bf79383..8761ae2a29 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/IndexDefinition.cs @@ -5,10 +5,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions { public class IndexDefinition { - public virtual string Name { get; set; } - public virtual string SchemaName { get; set; } - public virtual string TableName { get; set; } - public virtual string ColumnName { get; set; } + public virtual string? Name { get; set; } + public virtual string? SchemaName { get; set; } + public virtual string? TableName { get; set; } + public virtual string? ColumnName { get; set; } public virtual ICollection Columns { get; set; } = new List(); public virtual ICollection IncludeColumns { get; set; } = new List(); diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/InsertionDataDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/InsertionDataDefinition.cs index 077d38b9c7..a09bcaafdf 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/InsertionDataDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/InsertionDataDefinition.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions { - public class InsertionDataDefinition : List> + public class InsertionDataDefinition : List> { } diff --git a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs index ee6ce188de..61601fef95 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs @@ -10,7 +10,7 @@ namespace Umbraco.Extensions { public static class DbConnectionExtensions { - public static bool IsConnectionAvailable(string? connectionString, DbProviderFactory factory) + public static bool IsConnectionAvailable(string? connectionString, DbProviderFactory? factory) { var connection = factory?.CreateConnection(); diff --git a/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs index 5af76d7220..a86deb8802 100644 --- a/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/IUmbracoDatabaseFactory.cs @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence /// /// Configures the database factory. /// - void Configure(string connectionString, string providerName); + void Configure(string? connectionString, string? providerName); /// /// Gets the . diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs index ec3c6480df..9a8b61f9ec 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/ISqlSyntaxProvider.cs @@ -61,8 +61,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax string Format(ColumnDefinition column, string tableName, out IEnumerable sqls); string Format(IndexDefinition index); string Format(ForeignKeyDefinition foreignKey); - string FormatColumnRename(string tableName, string oldName, string newName); - string FormatTableRename(string oldName, string newName); + string FormatColumnRename(string? tableName, string? oldName, string? newName); + string FormatTableRename(string? oldName, string? newName); /// /// Gets a regex matching aliased fields. @@ -130,7 +130,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax /// in which case the function may return true, but is /// unspecified. /// - bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName); + bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, out string constraintName); void ReadLock(IDatabase db, TimeSpan timeout, int lockId); void WriteLock(IDatabase db, TimeSpan timeout, int lockId); diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs index 80970ec637..1529d6c575 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs @@ -27,9 +27,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence private readonly ILogger _logger; private readonly IBulkSqlInsertProvider _bulkSqlInsertProvider; private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; - private readonly RetryPolicy _connectionRetryPolicy; - private readonly RetryPolicy _commandRetryPolicy; - private readonly IEnumerable _mapperCollection; + private readonly RetryPolicy? _connectionRetryPolicy; + private readonly RetryPolicy? _commandRetryPolicy; + private readonly IEnumerable? _mapperCollection; private readonly Guid _instanceGuid = Guid.NewGuid(); private List _commands; @@ -49,9 +49,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence ILogger logger, IBulkSqlInsertProvider bulkSqlInsertProvider, DatabaseSchemaCreatorFactory databaseSchemaCreatorFactory, - RetryPolicy connectionRetryPolicy = null, - RetryPolicy commandRetryPolicy = null, - IEnumerable mapperCollection = null) + RetryPolicy? connectionRetryPolicy = null, + RetryPolicy? commandRetryPolicy = null, + IEnumerable? mapperCollection = null) : base(connectionString, sqlContext.DatabaseType, provider, sqlContext.SqlSyntax.DefaultIsolationLevel) { SqlContext = sqlContext; diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 6093c06a97..5fcccb21a3 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -54,9 +54,9 @@ namespace Umbraco.Cms.Infrastructure.Persistence private bool _upgrading; private bool _initialized; - private DbProviderFactory _dbProviderFactory = null; + private DbProviderFactory? _dbProviderFactory = null; - private DbProviderFactory DbProviderFactory + private DbProviderFactory? DbProviderFactory { get { @@ -86,7 +86,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence IDbProviderFactoryCreator dbProviderFactoryCreator, DatabaseSchemaCreatorFactory databaseSchemaCreatorFactory, NPocoMapperCollection npocoMappers, - string connectionString) + string? connectionString) { _globalSettings = globalSettings; _mappers = mappers ?? throw new ArgumentNullException(nameof(mappers)); @@ -111,7 +111,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence return; // not configured } - Configure(configConnectionString.ConnectionString, configConnectionString.ProviderName); + Configure(configConnectionString.ConnectionString!, configConnectionString.ProviderName!); } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs index ff258d8437..af407f6b00 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs @@ -269,18 +269,18 @@ namespace Umbraco.Cms.Core.PropertyEditors var blockEditorData = _blockEditorValues.DeserializeAndClean(value); if ((blockEditorData == null && validationLimit.Min.HasValue && validationLimit.Min > 0) - || (blockEditorData != null && validationLimit.Min.HasValue && blockEditorData.Layout.Count() < validationLimit.Min)) + || (blockEditorData != null && validationLimit.Min.HasValue && blockEditorData.Layout?.Count() < validationLimit.Min)) { yield return new ValidationResult( _textService.Localize("validation", "entriesShort", new[] { validationLimit.Min.ToString(), - (validationLimit.Min - (blockEditorData?.Layout.Count() ?? 0)).ToString() + (validationLimit.Min - (blockEditorData?.Layout?.Count() ?? 0)).ToString() }), new[] { "minCount" }); } - if (blockEditorData != null && validationLimit.Max.HasValue && blockEditorData.Layout.Count() > validationLimit.Max) + if (blockEditorData != null && validationLimit.Max.HasValue && blockEditorData.Layout?.Count() > validationLimit.Max) { yield return new ValidationResult( _textService.Localize("validation", "entriesExceed", new[] @@ -305,7 +305,7 @@ namespace Umbraco.Cms.Core.PropertyEditors _contentTypeService = contentTypeService; } - protected override IEnumerable GetElementTypeValidation(object value) + protected override IEnumerable GetElementTypeValidation(object? value) { var blockEditorData = _blockEditorValues.DeserializeAndClean(value); if (blockEditorData != null) @@ -383,12 +383,12 @@ namespace Umbraco.Cms.Core.PropertyEditors var contentTypePropertyTypes = new Dictionary>(); // filter out any content that isn't referenced in the layout references - foreach (var block in blockEditorData.BlockValue.ContentData.Where(x => blockEditorData.References.Any(r => r.ContentUdi == x.Udi))) + foreach (var block in blockEditorData.BlockValue.ContentData.Where(x => blockEditorData.References.Any(r => x.Udi is not null && r.ContentUdi == x.Udi))) { ResolveBlockItemData(block, contentTypePropertyTypes); } // filter out any settings that isn't referenced in the layout references - foreach (var block in blockEditorData.BlockValue.SettingsData.Where(x => blockEditorData.References.Any(r => r.SettingsUdi == x.Udi))) + foreach (var block in blockEditorData.BlockValue.SettingsData.Where(x => blockEditorData.References.Any(r => r.SettingsUdi is not null && x.Udi is not null && r.SettingsUdi == x.Udi))) { ResolveBlockItemData(block, contentTypePropertyTypes); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs index ec5cc6a163..28691af7ba 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyHandler.cs @@ -65,23 +65,23 @@ namespace Umbraco.Cms.Core.PropertyEditors { var reference = blockListData.References[i]; var hasContentMap = oldToNew.TryGetValue(reference.ContentUdi, out var contentMap); - Udi settingsMap = null; - var hasSettingsMap = reference.SettingsUdi != null && oldToNew.TryGetValue(reference.SettingsUdi, out settingsMap); + Udi? settingsMap = null; + var hasSettingsMap = reference.SettingsUdi is not null && oldToNew.TryGetValue(reference.SettingsUdi, out settingsMap); if (hasContentMap) { // replace the reference blockListData.References.RemoveAt(i); - blockListData.References.Insert(i, new ContentAndSettingsReference(contentMap, hasSettingsMap ? settingsMap : null)); + blockListData.References.Insert(i, new ContentAndSettingsReference(contentMap!, hasSettingsMap ? settingsMap : null)); } } // build the layout with the new UDIs - var layout = (JArray)blockListData.Layout; - layout.Clear(); + var layout = (JArray?)blockListData.Layout; + layout?.Clear(); foreach (var reference in blockListData.References) { - layout.Add(JObject.FromObject(new BlockListLayoutItem + layout?.Add(JObject.FromObject(new BlockListLayoutItem { ContentUdi = reference.ContentUdi, SettingsUdi = reference.SettingsUdi @@ -98,7 +98,7 @@ namespace Umbraco.Cms.Core.PropertyEditors foreach (var data in blockData) { // check if we need to recurse (make a copy of the dictionary since it will be modified) - foreach (var propertyAliasToBlockItemData in new Dictionary(data.RawPropertyValues)) + foreach (var propertyAliasToBlockItemData in new Dictionary(data.RawPropertyValues)) { if (propertyAliasToBlockItemData.Value is JToken jtoken) { @@ -117,7 +117,7 @@ namespace Umbraco.Cms.Core.PropertyEditors // this gets a little ugly because there could be some other complex editor that contains another block editor // and since we would have no idea how to parse that, all we can do is try JSON Path to find another block editor // of our type - JToken json = null; + JToken? json = null; try { json = JToken.Parse(asString); @@ -182,7 +182,7 @@ namespace Umbraco.Cms.Core.PropertyEditors // this is an arbitrary property that could contain a nested complex editor var propVal = prop.Value?.ToString(); // check if this might contain a nested Block Editor - if (!propVal.IsNullOrWhiteSpace() && propVal.DetectIsJson() && propVal.InvariantContains(Constants.PropertyEditors.Aliases.BlockList)) + if (!propVal.IsNullOrWhiteSpace() && (propVal?.DetectIsJson() ?? false) && propVal.InvariantContains(Constants.PropertyEditors.Aliases.BlockList)) { if (_converter.TryDeserialize(propVal, out var nestedBlockData)) { @@ -204,7 +204,7 @@ namespace Umbraco.Cms.Core.PropertyEditors foreach (var data in blockData) { // This should never happen since a FormatException will be thrown if one is empty but we'll keep this here - if (data.Udi == null) + if (data.Udi is null) throw new InvalidOperationException("Block data cannot contain a null UDI"); // replace the UDIs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs index ac1bc29081..7b4ca284a8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs @@ -30,7 +30,7 @@ namespace Umbraco.Cms.Core.PropertyEditors items.Validators.Add(new ColorListValidator()); } - public override Dictionary ToConfigurationEditor(ColorPickerConfiguration configuration) + public override Dictionary ToConfigurationEditor(ColorPickerConfiguration? configuration) { var configuredItems = configuration?.Items; // ordered object editorItems; @@ -45,7 +45,7 @@ namespace Umbraco.Cms.Core.PropertyEditors editorItems = d; var sortOrder = 0; foreach (var item in configuredItems) - d[item.Id.ToString()] = GetItemValue(item, configuration.UseLabel, sortOrder++); + d[item.Id.ToString()] = GetItemValue(item, configuration!.UseLabel, sortOrder++); } var useLabel = configuration?.UseLabel ?? false; @@ -70,7 +70,7 @@ namespace Umbraco.Cms.Core.PropertyEditors SortOrder = sortOrder }; - if (item.Value.DetectIsJson()) + if (item.Value?.DetectIsJson() ?? false) { try { @@ -93,10 +93,10 @@ namespace Umbraco.Cms.Core.PropertyEditors private class ItemValue { [DataMember(Name ="value")] - public string Color { get; set; } + public string? Color { get; set; } [DataMember(Name ="label")] - public string Label { get; set; } + public string? Label { get; set; } [DataMember(Name ="sortOrder")] public int SortOrder { get; set; } @@ -105,7 +105,7 @@ namespace Umbraco.Cms.Core.PropertyEditors // send: { "items": { "": { "value": "", "label": " /// The configuration. - public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, ImageCropperConfiguration configuration) + public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, ImageCropperConfiguration? configuration) { var crops = new List(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index 563f0830a1..67d6455bac 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -110,7 +110,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// A value indicating whether to log the error. /// The json object corresponding to the property value. /// In case of an error, optionally logs the error and returns null. - private JObject GetJObject(string value, bool writeLog) + private JObject? GetJObject(string value, bool writeLog) { if (string.IsNullOrWhiteSpace(value)) return null; @@ -165,7 +165,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// The deserialized value /// Should the path returned be the application relative path /// - private string GetFileSrcFromPropertyValue(object propVal, out JObject deserializedValue, bool relative = true) + private string? GetFileSrcFromPropertyValue(object? propVal, out JObject? deserializedValue, bool relative = true) { deserializedValue = null; if (propVal == null || !(propVal is string str)) return null; @@ -184,9 +184,9 @@ namespace Umbraco.Cms.Core.PropertyEditors } if (deserializedValue?["src"] == null) return null; - var src = deserializedValue["src"].Value(); + var src = deserializedValue["src"]!.Value(); - return relative ? _mediaFileManager.FileSystem.GetRelativePath(src) : src; + return relative ? _mediaFileManager.FileSystem.GetRelativePath(src!) : src; } /// @@ -213,7 +213,7 @@ namespace Umbraco.Cms.Core.PropertyEditors var sourcePath = _mediaFileManager.FileSystem.GetRelativePath(src); var copyPath = _mediaFileManager.CopyFile(notification.Copy, property.PropertyType, sourcePath); - jo["src"] = _mediaFileManager.FileSystem.GetUrl(copyPath); + jo!["src"] = _mediaFileManager.FileSystem.GetUrl(copyPath); notification.Copy.SetValue(property.Alias, jo.ToString(Formatting.None), propertyValue.Culture, propertyValue.Segment); isUpdated = true; } @@ -267,7 +267,7 @@ namespace Umbraco.Cms.Core.PropertyEditors else { var jo = GetJObject(svalue, false); - string src; + string? src; if (jo == null) { // so we have a non-empty string value that cannot be parsed into a json object diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 0ece3a8683..19f48b4ac3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -53,15 +53,15 @@ namespace Umbraco.Cms.Core.PropertyEditors /// This is called to merge in the prevalue crops with the value that is saved - similar to the property value converter for the front-end /// - public override object ToEditor(IProperty property, string? culture = null, string? segment = null) + public override object? ToEditor(IProperty property, string? culture = null, string? segment = null) { var val = property.GetValue(culture, segment); if (val == null) return null; - ImageCropperValue value; + ImageCropperValue? value; try { - value = JsonConvert.DeserializeObject(val.ToString()); + value = JsonConvert.DeserializeObject(val.ToString()!); } catch { @@ -70,7 +70,7 @@ namespace Umbraco.Cms.Core.PropertyEditors var dataType = _dataTypeService.GetDataType(property.PropertyType.DataTypeId); if (dataType?.Configuration != null) - value.ApplyConfiguration(dataType.ConfigurationAs()); + value?.ApplyConfiguration(dataType.ConfigurationAs()); return value; } @@ -85,7 +85,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// editorValue.Value is used to figure out editorFile and, if it has been cleared, remove the old file - but /// it is editorValue.AdditionalData["files"] that is used to determine the actual file that has been uploaded. /// - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { // Get the current path var currentPath = string.Empty; @@ -109,12 +109,13 @@ namespace Umbraco.Cms.Core.PropertyEditors // Get the new JSON and file path var editorFile = string.Empty; - if (editorValue.Value is JObject editorJson) + var editorJson = (JObject?)editorValue.Value; + if (editorJson is not null) { // Populate current file if (editorJson["src"] != null) { - editorFile = editorJson["src"].Value(); + editorFile = editorJson["src"]?.Value(); } // Clean up redundant/default data @@ -174,7 +175,7 @@ namespace Umbraco.Cms.Core.PropertyEditors return editorJson.ToString(Formatting.None); } - private string ProcessFile(ContentPropertyFile file, Guid cuid, Guid puid) + private string? ProcessFile(ContentPropertyFile file, Guid cuid, Guid puid) { // process the file // no file, invalid file, reject change @@ -198,14 +199,14 @@ namespace Umbraco.Cms.Core.PropertyEditors return filepath; } - public override string ConvertDbToString(IPropertyType propertyType, object value) + public override string ConvertDbToString(IPropertyType propertyType, object? value) { if (value == null || string.IsNullOrEmpty(value.ToString())) - return null; + return string.Empty; // if we don't have a json structure, we will get it from the property type var val = value.ToString(); - if (val.DetectIsJson()) + if (val?.DetectIsJson() ?? false) return val; // more magic here ;-( diff --git a/src/Umbraco.Infrastructure/PropertyEditors/LabelConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/LabelConfigurationEditor.cs index fb1ee554bd..72608885a0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/LabelConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/LabelConfigurationEditor.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override LabelConfiguration FromConfigurationEditor(IDictionary editorValues, LabelConfiguration configuration) + public override LabelConfiguration FromConfigurationEditor(IDictionary editorValues, LabelConfiguration? configuration) { var newConfiguration = new LabelConfiguration(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs index 6a9cd39e3d..b65dcb0ec9 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs @@ -46,10 +46,12 @@ namespace Umbraco.Cms.Core.PropertyEditors /// - protected override IConfigurationEditor CreateConfigurationEditor() => new MediaPicker3ConfigurationEditor(_ioHelper); + protected override IConfigurationEditor CreateConfigurationEditor() => + new MediaPicker3ConfigurationEditor(_ioHelper); /// - protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute); + protected override IDataValueEditor CreateValueEditor() => + DataValueEditorFactory.Create(Attribute); internal class MediaPicker3PropertyValueEditor : DataValueEditor, IDataValueReference { @@ -89,7 +91,7 @@ namespace Umbraco.Cms.Core.PropertyEditors return dtos; } - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { if (editorValue.Value is JArray dtos) { @@ -109,8 +111,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// Note: no FromEditor() and ToEditor() methods /// We do not want to transform the way the data is stored in the DB and would like to keep a raw JSON string /// - - public IEnumerable GetReferences(object value) + public IEnumerable GetReferences(object? value) { foreach (var dto in Deserialize(_jsonSerializer, value)) { @@ -118,7 +119,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } } - internal static IEnumerable Deserialize(IJsonSerializer jsonSerializer,object value) + internal static IEnumerable Deserialize(IJsonSerializer jsonSerializer, object? value) { var rawJson = value is string str ? str : value?.ToString(); if (string.IsNullOrWhiteSpace(rawJson)) @@ -131,18 +132,14 @@ namespace Umbraco.Cms.Core.PropertyEditors // Old comma seperated UDI format foreach (var udiStr in rawJson.Split(Constants.CharArrays.Comma)) { - if (UdiParser.TryParse(udiStr, out GuidUdi udi)) + if (UdiParser.TryParse(udiStr, out Udi? udi) && udi is GuidUdi guidUdi) { yield return new MediaWithCropsDto { Key = Guid.NewGuid(), - MediaKey = udi.Guid, + MediaKey = guidUdi.Guid, Crops = Enumerable.Empty(), - FocalPoint = new ImageCropperValue.ImageCropperFocalPoint - { - Left = 0.5m, - Top = 0.5m - } + FocalPoint = new ImageCropperValue.ImageCropperFocalPoint {Left = 0.5m, Top = 0.5m} }; } } @@ -163,23 +160,20 @@ namespace Umbraco.Cms.Core.PropertyEditors [DataContract] internal class MediaWithCropsDto { - [DataMember(Name = "key")] - public Guid Key { get; set; } + [DataMember(Name = "key")] public Guid Key { get; set; } - [DataMember(Name = "mediaKey")] - public Guid MediaKey { get; set; } + [DataMember(Name = "mediaKey")] public Guid MediaKey { get; set; } - [DataMember(Name = "crops")] - public IEnumerable Crops { get; set; } + [DataMember(Name = "crops")] public IEnumerable? Crops { get; set; } [DataMember(Name = "focalPoint")] - public ImageCropperValue.ImageCropperFocalPoint FocalPoint { get; set; } + public ImageCropperValue.ImageCropperFocalPoint? FocalPoint { get; set; } /// /// Applies the configuration to ensure only valid crops are kept and have the correct width/height. /// /// The configuration. - public void ApplyConfiguration(MediaPicker3Configuration configuration) + public void ApplyConfiguration(MediaPicker3Configuration? configuration) { var crops = new List(); @@ -215,7 +209,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// Because the DTO uses the same JSON keys as the image cropper value for crops and focal point, we can re-use the prune method. /// - public static void Prune(JObject value) => ImageCropperValue.Prune(value); + public static void Prune(JObject? value) => ImageCropperValue.Prune(value); } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerConfigurationEditor.cs index ed560a64b8..f0e009f3ac 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerConfigurationEditor.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Core.PropertyEditors .Config = new Dictionary { { "idType", "udi" } }; } - public override IDictionary ToValueEditor(object configuration) + public override IDictionary ToValueEditor(object? configuration) { // get the configuration fields var d = base.ToValueEditor(configuration); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs index af6d26515a..2ebc9c2f0f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs @@ -60,7 +60,7 @@ namespace Umbraco.Cms.Core.PropertyEditors { } - public IEnumerable GetReferences(object value) + public IEnumerable GetReferences(object? value) { var asString = value is string str ? str : value?.ToString(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationEditor.cs index 77a2a69c9b..41d2861cb3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationEditor.cs @@ -18,18 +18,18 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override Dictionary ToConfigurationEditor(MultiNodePickerConfiguration configuration) + public override Dictionary ToConfigurationEditor(MultiNodePickerConfiguration? configuration) { // sanitize configuration var output = base.ToConfigurationEditor(configuration); - output["multiPicker"] = configuration.MaxNumber > 1; + output["multiPicker"] = configuration?.MaxNumber > 1; return output; } /// - public override IDictionary ToValueEditor(object configuration) + public override IDictionary ToValueEditor(object? configuration) { var d = base.ToValueEditor(configuration); d["multiPicker"] = true; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs index 735aca9829..0455421601 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs @@ -49,11 +49,11 @@ namespace Umbraco.Cms.Core.PropertyEditors } - public IEnumerable GetReferences(object value) + public IEnumerable GetReferences(object? value) { var asString = value == null ? string.Empty : value is string str ? str : value.ToString(); - var udiPaths = asString.Split(','); + var udiPaths = asString!.Split(','); foreach (var udiPath in udiPaths) if (UdiParser.TryParse(udiPath, out var udi)) yield return new UmbracoEntityReference(udi); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs index 6b9bb73b14..0386514b51 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Core.PropertyEditors _publishedUrlProvider = publishedUrlProvider; } - public override object ToEditor(IProperty property, string? culture = null, string? segment = null) + public override object? ToEditor(IProperty property, string? culture = null, string? segment = null) { var value = property.GetValue(culture, segment)?.ToString(); @@ -59,28 +59,33 @@ namespace Umbraco.Cms.Core.PropertyEditors { var links = JsonConvert.DeserializeObject>(value); - var documentLinks = links.FindAll(link => link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Document); - var mediaLinks = links.FindAll(link => link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Media); + var documentLinks = links?.FindAll(link => link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Document); + var mediaLinks = links?.FindAll(link => link.Udi != null && link.Udi.EntityType == Constants.UdiEntityType.Media); var entities = new List(); - if (documentLinks.Count > 0) + if (documentLinks?.Count > 0) { entities.AddRange( - _entityService.GetAll(UmbracoObjectTypes.Document, documentLinks.Select(link => link.Udi.Guid).ToArray()) + _entityService.GetAll(UmbracoObjectTypes.Document, documentLinks.Select(link => link.Udi?.Guid).ToArray()) ); } - if (mediaLinks.Count > 0) + if (mediaLinks?.Count > 0) { entities.AddRange( - _entityService.GetAll(UmbracoObjectTypes.Media, mediaLinks.Select(link => link.Udi.Guid).ToArray()) + _entityService.GetAll(UmbracoObjectTypes.Media, mediaLinks.Select(link => link.Udi?.Guid).ToArray()) ); } var result = new List(); + if (links is null) + { + return result; + } + foreach (var dto in links) { - GuidUdi udi = null; + GuidUdi? udi = null; var icon = "icon-link"; var published = true; var trashed = false; @@ -88,7 +93,7 @@ namespace Umbraco.Cms.Core.PropertyEditors if (dto.Udi != null) { - IUmbracoEntity entity = entities.Find(e => e.Key == dto.Udi.Guid); + IUmbracoEntity? entity = entities.Find(e => e.Key == dto.Udi.Guid); if (entity == null) { continue; @@ -129,6 +134,7 @@ namespace Umbraco.Cms.Core.PropertyEditors Url = url ?? "" }); } + return result; } catch (Exception ex) @@ -145,7 +151,7 @@ namespace Umbraco.Cms.Core.PropertyEditors NullValueHandling = NullValueHandling.Ignore }; - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { var value = editorValue.Value?.ToString(); @@ -157,7 +163,7 @@ namespace Umbraco.Cms.Core.PropertyEditors try { var links = JsonConvert.DeserializeObject>(value); - if (links.Count == 0) + if (links?.Count == 0) { return null; } @@ -186,35 +192,38 @@ namespace Umbraco.Cms.Core.PropertyEditors public class LinkDto { [DataMember(Name = "name")] - public string Name { get; set; } + public string? Name { get; set; } [DataMember(Name = "target")] - public string Target { get; set; } + public string? Target { get; set; } [DataMember(Name = "udi")] - public GuidUdi Udi { get; set; } + public GuidUdi? Udi { get; set; } [DataMember(Name = "url")] - public string Url { get; set; } + public string? Url { get; set; } [DataMember(Name = "queryString")] - public string QueryString { get; set; } + public string? QueryString { get; set; } } - public IEnumerable GetReferences(object value) + public IEnumerable GetReferences(object? value) { var asString = value == null ? string.Empty : value is string str ? str : value.ToString(); if (string.IsNullOrEmpty(asString)) yield break; var links = JsonConvert.DeserializeObject>(asString); - foreach (var link in links) + if (links is not null) { - if (link.Udi != null) // Links can be absolute links without a Udi + foreach (var link in links) { - yield return new UmbracoEntityReference(link.Udi); - } + if (link.Udi != null) // Links can be absolute links without a Udi + { + yield return new UmbracoEntityReference(link.Udi); + } + } } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs index 826016fd20..9d2daeb92e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs @@ -35,7 +35,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override MultipleTextStringConfiguration FromConfigurationEditor(IDictionary editorValues, MultipleTextStringConfiguration configuration) + public override MultipleTextStringConfiguration FromConfigurationEditor(IDictionary editorValues, MultipleTextStringConfiguration? configuration) { // TODO: this isn't pretty //the values from the editor will be min/max fields and we need to format to json in one field @@ -51,12 +51,12 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override Dictionary ToConfigurationEditor(MultipleTextStringConfiguration configuration) + public override Dictionary ToConfigurationEditor(MultipleTextStringConfiguration? configuration) { return new Dictionary { - { "min", configuration.Minimum }, - { "max", configuration.Maximum } + { "min", configuration?.Minimum ?? 0 }, + { "max", configuration?.Maximum ?? 0 }, }; } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs index 71a7a89be5..023a181f18 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -75,7 +75,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// We will also check the pre-values here, if there are more items than what is allowed we'll just trim the end /// - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { var asArray = editorValue.Value as JArray; if (asArray == null || asArray.HasValues == false) @@ -84,13 +84,13 @@ namespace Umbraco.Cms.Core.PropertyEditors } if (!(editorValue.DataTypeConfiguration is MultipleTextStringConfiguration config)) - throw new PanicException($"editorValue.DataTypeConfiguration is {editorValue.DataTypeConfiguration.GetType()} but must be {typeof(MultipleTextStringConfiguration)}"); + throw new PanicException($"editorValue.DataTypeConfiguration is {editorValue.DataTypeConfiguration?.GetType()} but must be {typeof(MultipleTextStringConfiguration)}"); var max = config.Maximum; //The legacy property editor saved this data as new line delimited! strange but we have to maintain that. var array = asArray.OfType() .Where(x => x["value"] != null) - .Select(x => x["value"].Value()); + .Select(x => x["value"]!.Value()); //only allow the max if over 0 if (max > 0) @@ -116,7 +116,7 @@ namespace Umbraco.Cms.Core.PropertyEditors public override object ToEditor(IProperty property, string? culture = null, string? segment = null) { var val = property.GetValue(culture, segment); - return val?.ToString().Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries) + return val?.ToString()?.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries) .Select(x => JObject.FromObject(new {value = x})) ?? new JObject[] { }; } @@ -136,7 +136,7 @@ namespace Umbraco.Cms.Core.PropertyEditors _localizedTextService = localizedTextService; } - public IEnumerable ValidateFormat(object value, string valueType, string format) + public IEnumerable ValidateFormat(object? value, string valueType, string format) { var asArray = value as JArray; if (asArray == null) @@ -146,7 +146,7 @@ namespace Umbraco.Cms.Core.PropertyEditors var textStrings = asArray.OfType() .Where(x => x["value"] != null) - .Select(x => x["value"].Value()); + .Select(x => x["value"]!.Value()); var textStringValidator = new RegexValidator(_localizedTextService); foreach (var textString in textStrings) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs index f61c5c78d0..c9c7c7449e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs @@ -45,8 +45,14 @@ namespace Umbraco.Cms.Core.PropertyEditors /// public override object ToEditor(IProperty property, string? culture = null, string? segment = null) { - var json = base.ToEditor(property, culture, segment).ToString(); - return JsonConvert.DeserializeObject(json) ?? Array.Empty(); + var json = base.ToEditor(property, culture, segment)?.ToString(); + string[]? result = null; + if (json is not null) + { + result = JsonConvert.DeserializeObject(json); + } + + return result ?? Array.Empty(); } /// @@ -56,7 +62,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// /// - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { var json = editorValue.Value as JArray; if (json == null || json.HasValues == false) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs index 0cbd4e1155..13a9f562cf 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs @@ -83,7 +83,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override object Configuration + public override object? Configuration { get => base.Configuration; set @@ -100,13 +100,13 @@ namespace Umbraco.Cms.Core.PropertyEditors #region DB to String - public override string ConvertDbToString(IPropertyType propertyType, object propertyValue) + public override string ConvertDbToString(IPropertyType propertyType, object? propertyValue) { var rows = _nestedContentValues.GetPropertyValues(propertyValue); if (rows.Count == 0) { - return null; + return string.Empty; } foreach (var row in rows.ToList()) @@ -223,7 +223,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// /// - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { if (editorValue.Value == null || string.IsNullOrWhiteSpace(editorValue.Value.ToString())) return null; @@ -260,7 +260,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } #endregion - public IEnumerable GetReferences(object value) + public IEnumerable GetReferences(object? value) { var rawJson = value == null ? string.Empty : value is string str ? str : value.ToString(); @@ -301,7 +301,7 @@ namespace Umbraco.Cms.Core.PropertyEditors _nestedContentValues = nestedContentValues; _contentTypeService = contentTypeService; } - protected override IEnumerable GetElementTypeValidation(object value) + protected override IEnumerable GetElementTypeValidation(object? value) { var rows = _nestedContentValues.GetPropertyValues(value); if (rows.Count == 0) yield break; @@ -357,7 +357,7 @@ namespace Umbraco.Cms.Core.PropertyEditors _contentTypes = new Lazy>(() => contentTypeService.GetAll().ToDictionary(c => c.Alias)); } - private IContentType GetElementType(NestedContentRowValue item) + private IContentType? GetElementType(NestedContentRowValue item) { _contentTypes.Value.TryGetValue(item.ContentTypeAlias, out var contentType); return contentType; @@ -368,15 +368,15 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// /// - public IReadOnlyList GetPropertyValues(object propertyValue) + public IReadOnlyList GetPropertyValues(object? propertyValue) { if (propertyValue == null || string.IsNullOrWhiteSpace(propertyValue.ToString())) return new List(); - if (!propertyValue.ToString().DetectIsJson()) + if (!propertyValue.ToString()!.DetectIsJson()) return new List(); - var rowValues = JsonConvert.DeserializeObject>(propertyValue.ToString()); + var rowValues = JsonConvert.DeserializeObject>(propertyValue.ToString()!); // There was a note here about checking if the result had zero items and if so it would return null, so we'll continue to do that // The original note was: "Issue #38 - Keep recursive property lookups working" @@ -432,8 +432,9 @@ namespace Umbraco.Cms.Core.PropertyEditors /// internal class NestedContentPropertyValue { - public object Value { get; set; } - public IPropertyType PropertyType { get; set; } + public object? Value { get; set; } + + public IPropertyType PropertyType { get; set; } = null!; } /// @@ -445,11 +446,11 @@ namespace Umbraco.Cms.Core.PropertyEditors public Guid Id{ get; set; } [JsonProperty("name")] - public string Name { get; set; } + public string? Name { get; set; } [JsonProperty("ncContentTypeAlias")] - public string ContentTypeAlias { get; set; } - public IPropertyType PropType { get; } + public string ContentTypeAlias { get; set; } = null!; + public IPropertyType? PropType { get; } /// /// The remaining properties will be serialized to a dictionary @@ -461,7 +462,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// "stringValue":"Some String","numericValue":125,"otherNumeric":null /// [JsonExtensionData] - public IDictionary RawPropertyValues { get; set; } + public IDictionary RawPropertyValues { get; set; } = null!; /// /// Used during deserialization to convert the raw property data into data with a property type context diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyHandler.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyHandler.cs index aa825bb0f8..35389d88ff 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyHandler.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyHandler.cs @@ -19,7 +19,7 @@ namespace Umbraco.Cms.Core.PropertyEditors protected override string FormatPropertyValue(string rawJson, bool onlyMissingKeys) => CreateNestedContentKeys(rawJson, onlyMissingKeys, null); // internal for tests - internal string CreateNestedContentKeys(string rawJson, bool onlyMissingKeys, Func createGuid = null) + internal string CreateNestedContentKeys(string rawJson, bool onlyMissingKeys, Func? createGuid = null) { // used so we can test nicely if (createGuid == null) @@ -48,8 +48,8 @@ namespace Umbraco.Cms.Core.PropertyEditors if (prop.Name == NestedContentPropertyEditor.ContentTypeAliasPropertyKey) { // get it's sibling 'key' property - var ncKeyVal = prop.Parent["key"] as JValue; - if ((onlyMissingKeys && ncKeyVal == null) || (!onlyMissingKeys && ncKeyVal != null)) + var ncKeyVal = prop.Parent?["key"] as JValue; + if (((onlyMissingKeys && ncKeyVal == null) || (!onlyMissingKeys && ncKeyVal != null)) && prop.Parent?["key"] is not null) { // create or replace prop.Parent["key"] = createGuid().ToString(); @@ -60,10 +60,10 @@ namespace Umbraco.Cms.Core.PropertyEditors // this is an arbitrary property that could contain a nested complex editor var propVal = prop.Value?.ToString(); // check if this might contain a nested NC - if (!propVal.IsNullOrWhiteSpace() && propVal.DetectIsJson() && propVal.InvariantContains(NestedContentPropertyEditor.ContentTypeAliasPropertyKey)) + if (!propVal.IsNullOrWhiteSpace() && propVal!.DetectIsJson() && propVal!.InvariantContains(NestedContentPropertyEditor.ContentTypeAliasPropertyKey)) { // recurse - var parsed = JToken.Parse(propVal); + var parsed = JToken.Parse(propVal!); UpdateNestedContentKeysRecursively(parsed, onlyMissingKeys, createGuid); // set the value to the updated one prop.Value = parsed.ToString(Formatting.None); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index b8dd935b89..6bba32c113 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -155,7 +155,10 @@ namespace Umbraco.Cms.Core.PropertyEditors var folderName = Path.GetDirectoryName(absoluteTempImagePath); try { - Directory.Delete(folderName, true); + if (folderName is not null) + { + Directory.Delete(folderName, true); + } } catch (Exception ex) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index 857857bbc2..7b8003d9ee 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -65,9 +65,11 @@ namespace Umbraco.Cms.Core.PropertyEditors /// Create a custom value editor /// /// - protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute); + protected override IDataValueEditor CreateValueEditor() => + DataValueEditorFactory.Create(Attribute); - protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor(_ioHelper); + protected override IConfigurationEditor CreateConfigurationEditor() => + new RichTextConfigurationEditor(_ioHelper); public override IPropertyIndexValueFactory PropertyIndexValueFactory => new RichTextPropertyIndexValueFactory(); @@ -106,7 +108,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override object Configuration + public override object? Configuration { get => base.Configuration; set @@ -114,7 +116,9 @@ namespace Umbraco.Cms.Core.PropertyEditors if (value == null) throw new ArgumentNullException(nameof(value)); if (!(value is RichTextConfiguration configuration)) - throw new ArgumentException($"Expected a {typeof(RichTextConfiguration).Name} instance, but got {value.GetType().Name}.", nameof(value)); + throw new ArgumentException( + $"Expected a {typeof(RichTextConfiguration).Name} instance, but got {value.GetType().Name}.", + nameof(value)); base.Configuration = value; HideLabel = configuration.HideLabel; @@ -128,14 +132,15 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// /// - public override object ToEditor(IProperty property, string? culture = null, string? segment = null) + public override object? ToEditor(IProperty property, string? culture = null, string? segment = null) { var val = property.GetValue(culture, segment); if (val == null) return null; - var propertyValueWithMediaResolved = _imageSourceParser.EnsureImageSources(val.ToString()); - var parsed = MacroTagParser.FormatRichTextPersistedDataForEditor(propertyValueWithMediaResolved, new Dictionary()); + var propertyValueWithMediaResolved = _imageSourceParser.EnsureImageSources(val.ToString()!); + var parsed = MacroTagParser.FormatRichTextPersistedDataForEditor(propertyValueWithMediaResolved, + new Dictionary()); return parsed; } @@ -145,20 +150,28 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// /// - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { if (editorValue.Value == null) { return null; } - var userId = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser?.Id ?? Constants.Security.SuperUserId; + var userId = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser?.Id ?? + Constants.Security.SuperUserId; var config = editorValue.DataTypeConfiguration as RichTextConfiguration; var mediaParent = config?.MediaParentId; var mediaParentId = mediaParent == null ? Guid.Empty : mediaParent.Guid; - var parseAndSavedTempImages = _pastedImages.FindAndPersistPastedTempImages(editorValue.Value.ToString(), mediaParentId, userId, _imageUrlGenerator); + if (string.IsNullOrWhiteSpace(editorValue.Value.ToString())) + { + return null; + } + + var parseAndSavedTempImages = + _pastedImages.FindAndPersistPastedTempImages(editorValue.Value.ToString()!, mediaParentId, userId, + _imageUrlGenerator); var editorValueWithMediaUrlsRemoved = _imageSourceParser.RemoveImageSources(parseAndSavedTempImages); var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved); var sanitized = _htmlSanitizer.Sanitize(parsed); @@ -171,16 +184,23 @@ namespace Umbraco.Cms.Core.PropertyEditors /// /// /// - public IEnumerable GetReferences(object value) + public IEnumerable GetReferences(object? value) { var asString = value == null ? string.Empty : value is string str ? str : value.ToString(); - foreach (var udi in _imageSourceParser.FindUdisFromDataAttributes(asString)) + foreach (var udi in _imageSourceParser.FindUdisFromDataAttributes(asString!)) + { yield return new UmbracoEntityReference(udi); + } - var udis = _localLinkParser.FindUdisFromLocalLinks(asString); - foreach (var udi in _localLinkParser.FindUdisFromLocalLinks(asString)) - yield return new UmbracoEntityReference(udi); + IEnumerable udis = _localLinkParser.FindUdisFromLocalLinks(asString!); + foreach (var udi in _localLinkParser.FindUdisFromLocalLinks(asString!)) + { + if (udi is not null) + { + yield return new UmbracoEntityReference(udi); + } + } //TODO: Detect Macros too ... but we can save that for a later date, right now need to do media refs } @@ -188,19 +208,20 @@ namespace Umbraco.Cms.Core.PropertyEditors internal class RichTextPropertyIndexValueFactory : IPropertyIndexValueFactory { - public IEnumerable>> GetIndexValues(IProperty property, string culture, string segment, bool published) + public IEnumerable>> GetIndexValues(IProperty property, + string? culture, string? segment, bool published) { var val = property.GetValue(culture, segment, published); if (!(val is string strVal)) yield break; //index the stripped HTML values - yield return new KeyValuePair>(property.Alias, new object[] { strVal.StripHtml() }); + yield return new KeyValuePair>(property.Alias, + new object[] {strVal.StripHtml()}); //store the raw value - yield return new KeyValuePair>($"{UmbracoExamineFieldNames.RawFieldPrefix}{property.Alias}", new object[] { strVal }); + yield return new KeyValuePair>( + $"{UmbracoExamineFieldNames.RawFieldPrefix}{property.Alias}", new object[] {strVal}); } } } - - } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TagConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TagConfigurationEditor.cs index 1417890452..e32e765a00 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TagConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TagConfigurationEditor.cs @@ -21,19 +21,19 @@ namespace Umbraco.Cms.Core.PropertyEditors Field(nameof(TagConfiguration.StorageType)).Validators.Add(new RequiredValidator(localizedTextService)); } - public override Dictionary ToConfigurationEditor(TagConfiguration configuration) + public override Dictionary ToConfigurationEditor(TagConfiguration? configuration) { var dictionary = base.ToConfigurationEditor(configuration); // the front-end editor expects the string value of the storage type if (!dictionary.TryGetValue("storageType", out var storageType)) storageType = TagsStorageType.Json; //default to Json - dictionary["storageType"] = storageType.ToString(); + dictionary["storageType"] = storageType.ToString()!; return dictionary; } - public override TagConfiguration FromConfigurationEditor(IDictionary editorValues, TagConfiguration configuration) + public override TagConfiguration? FromConfigurationEditor(IDictionary editorValues, TagConfiguration? configuration) { // the front-end editor returns the string value of the storage type // pure Json could do with diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs index 30911b0866..74af61f1e7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs @@ -62,7 +62,7 @@ namespace Umbraco.Cms.Core.PropertyEditors { } /// - public override object FromEditor(ContentPropertyData editorValue, object currentValue) + public override object? FromEditor(ContentPropertyData editorValue, object currentValue) { var value = editorValue?.Value?.ToString(); @@ -71,7 +71,7 @@ namespace Umbraco.Cms.Core.PropertyEditors return null; } - if (editorValue.Value is JArray json) + if (editorValue?.Value is JArray json) { return json.HasValues ? json.Select(x => x.Value()) : null; } @@ -98,7 +98,7 @@ namespace Umbraco.Cms.Core.PropertyEditors private class RequiredJsonValueValidator : IValueRequiredValidator { /// - public IEnumerable ValidateRequired(object value, string valueType) + public IEnumerable ValidateRequired(object? value, string valueType) { if (value == null) { @@ -106,7 +106,7 @@ namespace Umbraco.Cms.Core.PropertyEditors yield break; } - if (value.ToString().DetectIsEmptyJson()) + if (value.ToString()!.DetectIsEmptyJson()) yield return new ValidationResult("Value cannot be empty", new[] { "value" }); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs index 9ef266357d..6e5c46e643 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; @@ -26,9 +27,9 @@ namespace Umbraco.Cms.Core.PropertyEditors contentSettings.OnChange(x => _contentSettings = x); } - public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) + public IEnumerable Validate(object? value, string valueType, object? dataTypeConfiguration) { - string selectedFiles = null; + string? selectedFiles = null; if (value is JObject jobject && jobject["selectedFiles"] is JToken jToken) { selectedFiles = jToken.ToString(); @@ -57,7 +58,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } } - internal static bool IsValidFileExtension(string fileName, ContentSettings contentSettings) + internal static bool IsValidFileExtension(string? fileName, ContentSettings contentSettings) { if (TryGetFileExtension(fileName, out var extension) is false) return false; @@ -65,7 +66,7 @@ namespace Umbraco.Cms.Core.PropertyEditors return contentSettings.IsFileAllowedForUpload(extension); } - internal static bool IsAllowedInDataTypeConfiguration(string filename, object dataTypeConfiguration) + internal static bool IsAllowedInDataTypeConfiguration(string? filename, object? dataTypeConfiguration) { if (TryGetFileExtension(filename, out var extension) is false) return false; @@ -75,17 +76,19 @@ namespace Umbraco.Cms.Core.PropertyEditors // If FileExtensions is empty and no allowed extensions have been specified, we allow everything. // If there are any extensions specified, we need to check that the uploaded extension is one of them. return fileUploadConfiguration.FileExtensions.IsCollectionEmpty() || - fileUploadConfiguration.FileExtensions.Any(x => x.Value.InvariantEquals(extension)); + fileUploadConfiguration.FileExtensions.Any(x => x.Value?.InvariantEquals(extension) ?? false); } return false; } - internal static bool TryGetFileExtension(string fileName, out string extension) + internal static bool TryGetFileExtension(string? fileName, [MaybeNullWhen(false)] out string extension) { extension = null; - if (fileName.IndexOf('.') <= 0) + if (fileName is null || fileName.IndexOf('.') <= 0) + { return false; + } extension = fileName.GetFileExtension().TrimStart("."); return true; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs index 575f7bd9d1..8132e5fefc 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockEditorConverter.cs @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters var key = (data.Udi is GuidUdi gudi) ? gudi.Guid : Guid.Empty; if (key == Guid.Empty && propertyValues.TryGetValue("key", out var keyo)) { - Guid.TryParse(keyo.ToString(), out key); + Guid.TryParse(keyo!.ToString(), out key); } IPublishedElement element = new PublishedElement(publishedContentType, key, propertyValues, preview, referenceCacheLevel, _publishedSnapshotAccessor); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs index ca5647c356..36161c88d4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs @@ -176,7 +176,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters /// Removes redundant crop data/default focal point. /// /// The image cropper value. - public static void Prune(JObject value) + public static void Prune(JObject? value) { if (value is null) throw new ArgumentNullException(nameof(value)); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs index 75253ceba4..09832c8fbb 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/NestedContentValueConverterBase.cs @@ -52,10 +52,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters if (publishedContentType == null || publishedContentType.IsElement == false) return null; - var propertyValues = sourceObject.ToObject>(); + var propertyValues = sourceObject.ToObject>(); if (propertyValues is null || !propertyValues.TryGetValue("key", out var keyo) - || !Guid.TryParse(keyo.ToString(), out var key)) + || !Guid.TryParse(keyo!.ToString(), out var key)) key = Guid.Empty; IPublishedElement element = new PublishedElement(publishedContentType, key, propertyValues, preview, referenceCacheLevel, _publishedSnapshotAccessor); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs index 6b81329557..2d7fda8b2e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueListConfigurationEditor.cs @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Core.PropertyEditors // the sort order that comes back makes no sense /// - public override Dictionary ToConfigurationEditor(ValueListConfiguration configuration) + public override Dictionary ToConfigurationEditor(ValueListConfiguration? configuration) { if (configuration == null) return new Dictionary @@ -67,7 +67,7 @@ namespace Umbraco.Cms.Core.PropertyEditors } /// - public override ValueListConfiguration FromConfigurationEditor(IDictionary editorValues, ValueListConfiguration configuration) + public override ValueListConfiguration FromConfigurationEditor(IDictionary editorValues, ValueListConfiguration? configuration) { var output = new ValueListConfiguration(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueListUniqueValueValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueListUniqueValueValidator.cs index dd5ba9ef92..1f74df8851 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueListUniqueValueValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueListUniqueValueValidator.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// public class ValueListUniqueValueValidator : IValueValidator { - public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) + public IEnumerable Validate(object? value, string valueType, object? dataTypeConfiguration) { // the value we get should be a JArray // [ { "value": , "sortOrder": 1 }, { ... }, ... ] @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Core.PropertyEditors var groupedValues = json.OfType() .Where(x => x["value"] != null) - .Select((x, index) => new { value = x["value"].ToString(), index }) + .Select((x, index) => new { value = x["value"]?.ToString(), index }) .Where(x => x.value.IsNullOrWhiteSpace() == false) .GroupBy(x => x.value); diff --git a/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs b/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs index 4da1ae53c2..f45a666e12 100644 --- a/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs +++ b/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs @@ -38,7 +38,9 @@ namespace Umbraco.Cms.Core.PublishedCache } // for unit tests ONLY +#pragma warning disable CS8618 internal PublishedContentTypeCache(ILogger logger, IPublishedContentTypeFactory publishedContentTypeFactory) +#pragma warning restore CS8618 { _logger = logger; _publishedContentTypeFactory = publishedContentTypeFactory; @@ -119,7 +121,7 @@ namespace Umbraco.Cms.Core.PublishedCache { _lock.EnterWriteLock(); - var toRemove = _typesById.Values.Where(x => x.PropertyTypes.Any(xx => xx.DataType.Id == id)).ToArray(); + var toRemove = _typesById.Values.Where(x => x.PropertyTypes?.Any(xx => xx.DataType.Id == id) ?? false).ToArray(); foreach (var type in toRemove) { _typesByAlias.Remove(GetAliasKey(type)); @@ -245,7 +247,7 @@ namespace Umbraco.Cms.Core.PublishedCache private IPublishedContentType CreatePublishedContentType(PublishedItemType itemType, Guid key) { - IContentTypeComposition contentType = itemType switch + IContentTypeComposition? contentType = itemType switch { PublishedItemType.Content => _contentTypeService.Get(key), PublishedItemType.Media => _mediaTypeService.Get(key), @@ -275,7 +277,7 @@ namespace Umbraco.Cms.Core.PublishedCache private IPublishedContentType CreatePublishedContentType(PublishedItemType itemType, int id) { - IContentTypeComposition contentType = itemType switch + IContentTypeComposition? contentType = itemType switch { PublishedItemType.Content => _contentTypeService.Get(id), PublishedItemType.Media => _mediaTypeService.Get(id), diff --git a/src/Umbraco.Infrastructure/PublishedContentQuery.cs b/src/Umbraco.Infrastructure/PublishedContentQuery.cs index d8119f919c..c765a95b1c 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQuery.cs @@ -72,7 +72,7 @@ namespace Umbraco.Cms.Infrastructure return false; } } - private static bool ConvertIdObjectToUdi(object id, out Udi guidId) + private static bool ConvertIdObjectToUdi(object id, out Udi? guidId) { switch (id) { @@ -93,17 +93,17 @@ namespace Umbraco.Cms.Infrastructure #region Content - public IPublishedContent Content(int id) => ItemById(id, _publishedSnapshot.Content); + public IPublishedContent? Content(int id) => ItemById(id, _publishedSnapshot.Content); public IPublishedContent Content(Guid id) => ItemById(id, _publishedSnapshot.Content); - public IPublishedContent Content(Udi id) + public IPublishedContent? Content(Udi? id) { if (!(id is GuidUdi udi)) return null; return ItemById(udi.Guid, _publishedSnapshot.Content); } - public IPublishedContent Content(object id) + public IPublishedContent? Content(object id) { if (ConvertIdObjectToInt(id, out var intId)) return Content(intId); @@ -139,17 +139,17 @@ namespace Umbraco.Cms.Infrastructure #region Media - public IPublishedContent Media(int id) => ItemById(id, _publishedSnapshot.Media); + public IPublishedContent? Media(int id) => ItemById(id, _publishedSnapshot.Media); public IPublishedContent Media(Guid id) => ItemById(id, _publishedSnapshot.Media); - public IPublishedContent Media(Udi id) + public IPublishedContent? Media(Udi? id) { if (!(id is GuidUdi udi)) return null; return ItemById(udi.Guid, _publishedSnapshot.Media); } - public IPublishedContent Media(object id) + public IPublishedContent? Media(object id) { if (ConvertIdObjectToInt(id, out var intId)) return Media(intId); @@ -174,7 +174,7 @@ namespace Umbraco.Cms.Infrastructure #region Used by Content/Media - private static IPublishedContent ItemById(int id, IPublishedCache cache) + private static IPublishedContent? ItemById(int id, IPublishedCache cache) { var doc = cache.GetById(id); return doc; @@ -235,7 +235,7 @@ namespace Umbraco.Cms.Infrastructure Search(term, 0, 0, out _, culture, indexName); /// - public IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName, ISet loadedFields = null) + public IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName, ISet? loadedFields = null) { if (skip < 0) { @@ -349,7 +349,7 @@ namespace Umbraco.Cms.Infrastructure { //We need to change the current culture to what is requested and then change it back var originalContext = _variationContextAccessor.VariationContext; - if (!_culture.IsNullOrWhiteSpace() && !_culture.InvariantEquals(originalContext.Culture)) + if (!_culture.IsNullOrWhiteSpace() && !_culture.InvariantEquals(originalContext?.Culture)) _variationContextAccessor.VariationContext = new VariationContext(_culture); //now the IPublishedContent returned will be contextualized to the culture specified and will be reset when the enumerator is disposed @@ -364,12 +364,12 @@ namespace Umbraco.Cms.Infrastructure /// private class CultureContextualSearchResultsEnumerator : IEnumerator { - private readonly VariationContext _originalContext; + private readonly VariationContext? _originalContext; private readonly IVariationContextAccessor _variationContextAccessor; private readonly IEnumerator _wrapped; public CultureContextualSearchResultsEnumerator(IEnumerator wrapped, - IVariationContextAccessor variationContextAccessor, VariationContext originalContext) + IVariationContextAccessor variationContextAccessor, VariationContext? originalContext) { _wrapped = wrapped; _variationContextAccessor = variationContextAccessor; diff --git a/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs b/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs index d61900df95..15574423e6 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQueryAccessor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.DependencyInjection; @@ -13,7 +14,7 @@ namespace Umbraco.Cms.Core public PublishedContentQueryAccessor(IScopedServiceProvider scopedServiceProvider) => _scopedServiceProvider = scopedServiceProvider; - public bool TryGetValue(out IPublishedContentQuery publishedContentQuery) + public bool TryGetValue([MaybeNullWhen(false)] out IPublishedContentQuery publishedContentQuery) { publishedContentQuery = _scopedServiceProvider.ServiceProvider?.GetService(); diff --git a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs index bb7afdb6dc..4ce4a0252f 100644 --- a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs +++ b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs @@ -57,6 +57,7 @@ namespace Umbraco.Cms.Core.Routing { return false; } + _logger.LogDebug("Looking for a page to handle 404."); int? domainContentId = null; @@ -72,7 +73,7 @@ namespace Umbraco.Cms.Core.Routing { var route = frequest.AbsolutePathDecoded; var pos = route.LastIndexOf('/'); - IPublishedContent node = null; + IPublishedContent? node = null; while (pos > 1) { route = route.Substring(0, pos); @@ -87,7 +88,7 @@ namespace Umbraco.Cms.Core.Routing if (node != null) { - Domain d = DomainUtilities.FindWildcardDomainInPath(umbracoContext.PublishedSnapshot.Domains.GetAll(true), node.Path, null); + Domain? d = DomainUtilities.FindWildcardDomainInPath(umbracoContext.PublishedSnapshot.Domains?.GetAll(true), node.Path, null); if (d != null) { errorCulture = d.Culture; @@ -102,7 +103,7 @@ namespace Umbraco.Cms.Core.Routing errorCulture, domainContentId); - IPublishedContent content = null; + IPublishedContent? content = null; if (error404.HasValue) { @@ -119,7 +120,7 @@ namespace Umbraco.Cms.Core.Routing _logger.LogDebug("Got nothing."); } - frequest + frequest? .SetPublishedContent(content) .SetIs404(); diff --git a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs index 1aec33e10f..0cd5b3e47a 100644 --- a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs @@ -26,8 +26,8 @@ namespace Umbraco.Cms.Core.Routing if (error404Collection.Length > 1) { // test if a 404 page exists with current culture thread - ContentErrorPage cultureErr = error404Collection.FirstOrDefault(x => x.Culture.InvariantEquals(errorCulture)) - ?? error404Collection.FirstOrDefault(x => x.Culture == "default"); // there should be a default one! + ContentErrorPage? cultureErr = error404Collection.FirstOrDefault(x => x.Culture.InvariantEquals(errorCulture)) + ?? error404Collection.FirstOrDefault(x => x.Culture == "default"); // there should be a default one! if (cultureErr != null) { @@ -77,7 +77,7 @@ namespace Umbraco.Cms.Core.Routing { // we have an xpath statement to execute var xpathResult = UmbracoXPathPathSyntaxParser.ParseXPathQuery( - xpathExpression: errorPage.ContentXPath, + xpathExpression: errorPage.ContentXPath!, nodeContextId: domainContentId, getPath: nodeid => { diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs index 7f99b32b02..869844557f 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs @@ -99,14 +99,14 @@ namespace Umbraco.Cms.Core.Routing { return; } - var contentCache = publishedSnapshot.Content; + var contentCache = publishedSnapshot?.Content; var entityContent = contentCache?.GetById(entity.Id); if (entityContent == null) return; // get the default affected cultures by going up the tree until we find the first culture variant entity (default to no cultures) var defaultCultures = entityContent.AncestorsOrSelf()?.FirstOrDefault(a => a.Cultures.Any())?.Cultures.Keys.ToArray() - ?? new[] { (string)null }; + ?? Array.Empty(); foreach (var x in entityContent.DescendantsOrSelf(_variationContextAccessor)) { // if this entity defines specific cultures, use those instead of the default ones @@ -114,10 +114,10 @@ namespace Umbraco.Cms.Core.Routing foreach (var culture in cultures) { - var route = contentCache.GetRouteById(x.Id, culture); + var route = contentCache?.GetRouteById(x.Id, culture); if (IsNotRoute(route)) continue; - oldRoutes[new ContentIdAndCulture(x.Id, culture)] = new ContentKeyAndOldRoute(x.Key, route); + oldRoutes[new ContentIdAndCulture(x.Id, culture)] = new ContentKeyAndOldRoute(x.Key, route!); } } } @@ -129,13 +129,13 @@ namespace Umbraco.Cms.Core.Routing return; } - var contentCache = publishedSnapshot.Content; + var contentCache = publishedSnapshot?.Content; if (contentCache == null) { _logger.LogWarning("Could not track redirects because there is no current published snapshot available."); return; - } + } foreach (var oldRoute in oldRoutes) { @@ -146,7 +146,7 @@ namespace Umbraco.Cms.Core.Routing } } - private static bool IsNotRoute(string route) + private static bool IsNotRoute(string? route) { // null if content not found // err/- if collision or anomaly or ... diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 851d67e713..8889cddebc 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -34,8 +34,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime private readonly IEventAggregator _eventAggregator; private readonly IHostingEnvironment _hostingEnvironment; private readonly IUmbracoVersion _umbracoVersion; - private readonly IServiceProvider _serviceProvider; - private readonly IHostApplicationLifetime _hostApplicationLifetime; + private readonly IServiceProvider? _serviceProvider; + private readonly IHostApplicationLifetime? _hostApplicationLifetime; private readonly ILogger _logger; private CancellationToken _cancellationToken; @@ -53,8 +53,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime IEventAggregator eventAggregator, IHostingEnvironment hostingEnvironment, IUmbracoVersion umbracoVersion, - IServiceProvider serviceProvider, - IHostApplicationLifetime hostApplicationLifetime) + IServiceProvider? serviceProvider, + IHostApplicationLifetime? hostApplicationLifetime) { State = state; @@ -85,7 +85,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime IEventAggregator eventAggregator, IHostingEnvironment hostingEnvironment, IUmbracoVersion umbracoVersion, - IServiceProvider serviceProvider) + IServiceProvider? serviceProvider) : this( state, loggerFactory, @@ -156,7 +156,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime if (isRestarting == false) { StaticApplicationLogging.Initialize(_loggerFactory); - StaticServiceProvider.Instance = _serviceProvider; + if (_serviceProvider is not null) + { + StaticServiceProvider.Instance = _serviceProvider; + } AppDomain.CurrentDomain.UnhandledException += (_, args) => _logger.LogError(args.ExceptionObject as Exception, $"Unhandled exception in AppDomain{(args.IsTerminating ? " (terminating)" : null)}."); @@ -217,8 +220,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime if (isRestarting == false) { // Add application started and stopped notifications last (to ensure they're always published after starting) - _hostApplicationLifetime.ApplicationStarted.Register(() => _eventAggregator.Publish(new UmbracoApplicationStartedNotification(false))); - _hostApplicationLifetime.ApplicationStopped.Register(() => _eventAggregator.Publish(new UmbracoApplicationStoppedNotification(false))); + _hostApplicationLifetime?.ApplicationStarted.Register(() => _eventAggregator.Publish(new UmbracoApplicationStartedNotification(false))); + _hostApplicationLifetime?.ApplicationStopped.Register(() => _eventAggregator.Publish(new UmbracoApplicationStoppedNotification(false))); } } @@ -230,7 +233,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime private void AcquireMainDom() { - using DisposableTimer timer = _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired."); + using DisposableTimer? timer = _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired."); try { @@ -251,7 +254,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime return; } - using DisposableTimer timer = _profilingLogger.DebugDuration("Determining runtime level.", "Determined."); + using DisposableTimer? timer = _profilingLogger.DebugDuration("Determining runtime level.", "Determined."); try { diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index c81041849a..fe09336f4a 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -25,14 +25,14 @@ namespace Umbraco.Cms.Infrastructure.Runtime public class RuntimeState : IRuntimeState { internal const string PendingPacakgeMigrationsStateKey = "PendingPackageMigrations"; - private readonly IOptions _globalSettings; - private readonly IOptions _unattendedSettings; - private readonly IUmbracoVersion _umbracoVersion; - private readonly IUmbracoDatabaseFactory _databaseFactory; - private readonly ILogger _logger; - private readonly PendingPackageMigrations _packageMigrationState; + private readonly IOptions _globalSettings = null!; + private readonly IOptions _unattendedSettings = null!; + private readonly IUmbracoVersion _umbracoVersion = null!; + private readonly IUmbracoDatabaseFactory _databaseFactory = null!; + private readonly ILogger _logger = null!; + private readonly PendingPackageMigrations _packageMigrationState = null!; private readonly Dictionary _startupState = new Dictionary(); - private readonly IConflictingRouteService _conflictingRouteService; + private readonly IConflictingRouteService _conflictingRouteService = null!; /// /// The initial @@ -94,10 +94,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime public SemVersion SemanticVersion => _umbracoVersion.SemanticVersion; /// - public string CurrentMigrationState { get; private set; } + public string? CurrentMigrationState { get; private set; } /// - public string FinalMigrationState { get; private set; } + public string? FinalMigrationState { get; private set; } /// public RuntimeLevel Level { get; internal set; } = RuntimeLevel.Unknown; @@ -106,7 +106,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime public RuntimeLevelReason Reason { get; internal set; } = RuntimeLevelReason.Unknown; /// - public BootFailedException BootFailedException { get; internal set; } + public BootFailedException? BootFailedException { get; internal set; } /// public IReadOnlyDictionary StartupState => _startupState; @@ -206,7 +206,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } - public void Configure(RuntimeLevel level, RuntimeLevelReason reason, Exception bootFailedException = null) + public void Configure(RuntimeLevel level, RuntimeLevelReason reason, Exception? bootFailedException = null) { Level = level; Reason = reason; diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index 133c0d857a..e4e05817eb 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -30,7 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime private readonly ILogger _logger; private readonly IOptions _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IUmbracoDatabase _db; + private readonly IUmbracoDatabase? _db; private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private SqlServerSyntaxProvider _sqlServerSyntax; private bool _mainDomChanging = false; @@ -49,7 +49,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime IHostingEnvironment hostingEnvironment, DatabaseSchemaCreatorFactory databaseSchemaCreatorFactory, NPocoMapperCollection npocoMappers, - string connectionStringName) + string? connectionStringName) { // unique id for our appdomain, this is more unique than the appdomain id which is just an INT counter to its safer _lockId = Guid.NewGuid().ToString(); @@ -112,7 +112,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime var tempId = Guid.NewGuid().ToString(); - IUmbracoDatabase db = null; + IUmbracoDatabase? db = null; try { @@ -231,7 +231,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime _logger.LogDebug("Task canceled, exiting loop"); return; } - IUmbracoDatabase db = null; + IUmbracoDatabase? db = null; try { @@ -341,7 +341,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime // Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction // since this is executed in a tight loop - ITransaction transaction = null; + ITransaction? transaction = null; try { @@ -412,7 +412,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime _logger.LogDebug("Timeout elapsed, assuming orphan row, acquiring MainDom."); - ITransaction transaction = null; + ITransaction? transaction = null; try { @@ -476,7 +476,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime /// /// /// - private bool IsLockTimeoutException(SqlException sqlException) => sqlException?.Number == 1222; + private bool IsLockTimeoutException(SqlException? sqlException) => sqlException?.Number == 1222; #region IDisposable Support private bool _disposedValue = false; // To detect redundant calls @@ -498,7 +498,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime if (_dbFactory.Configured && _hasTable) { - IUmbracoDatabase db = null; + IUmbracoDatabase? db = null; try { db = _dbFactory.CreateDatabase(); diff --git a/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs b/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs index 1e7185a961..2514944303 100644 --- a/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs +++ b/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Core.Scoping { // dispose the entire chain (if any) // reset (don't commit by default) - Scope scope; + Scope? scope; while ((scope = _scopeProvider.AmbientScope) != null) { scope.Reset(); diff --git a/src/Umbraco.Infrastructure/Scoping/IScopeAccessor.cs b/src/Umbraco.Infrastructure/Scoping/IScopeAccessor.cs index 234ee0232b..c392e28f61 100644 --- a/src/Umbraco.Infrastructure/Scoping/IScopeAccessor.cs +++ b/src/Umbraco.Infrastructure/Scoping/IScopeAccessor.cs @@ -6,6 +6,6 @@ namespace Umbraco.Cms.Infrastructure.Scoping /// Gets the ambient scope. /// /// Returns null if there is no ambient scope. - IDatabaseScope AmbientScope { get; } + IDatabaseScope? AmbientScope { get; } } } diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 063fb26a89..d89fa8fb47 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -36,22 +36,22 @@ namespace Umbraco.Cms.Core.Scoping private readonly ScopeProvider _scopeProvider; private bool _callContext; private bool? _completed; - private IUmbracoDatabase _database; + private IUmbracoDatabase? _database; private bool _disposed; - private ICompletable _fscope; + private ICompletable? _fscope; - private IsolatedCaches _isolatedCaches; + private IsolatedCaches? _isolatedCaches; private IScopedNotificationPublisher? _notificationPublisher; - private StackQueue<(LockType lockType, TimeSpan timeout, Guid instanceId, int lockId)> _queuedLocks; + private StackQueue<(LockType lockType, TimeSpan timeout, Guid instanceId, int lockId)>? _queuedLocks; // This is all used to safely track read/write locks at given Scope levels so that // when we dispose we can verify that everything has been cleaned up correctly. - private HashSet _readLocks; - private Dictionary> _readLocksDictionary; - private HashSet _writeLocks; - private Dictionary> _writeLocksDictionary; + private HashSet? _readLocks; + private Dictionary>? _readLocksDictionary; + private HashSet? _writeLocks; + private Dictionary>? _writeLocksDictionary; // initializes a new scope private Scope( @@ -171,7 +171,7 @@ namespace Umbraco.Cms.Core.Scoping ILogger logger, FileSystems fileSystems, bool detachable, - IScopeContext scopeContext, + IScopeContext? scopeContext, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IScopedNotificationPublisher? scopedNotificationPublisher = null, @@ -204,9 +204,9 @@ namespace Umbraco.Cms.Core.Scoping { } - internal Dictionary> ReadLocks => _readLocksDictionary; + internal Dictionary>? ReadLocks => _readLocksDictionary; - internal Dictionary> WriteLocks => _writeLocksDictionary; + internal Dictionary>? WriteLocks => _writeLocksDictionary; // a value indicating whether to force call-context public bool CallContext @@ -246,15 +246,15 @@ namespace Umbraco.Cms.Core.Scoping public bool Detachable { get; } // the parent scope (in a nested scopes chain) - public Scope ParentScope { get; set; } + public Scope? ParentScope { get; set; } public bool Attached { get; set; } // the original scope (when attaching a detachable scope) - public Scope OrigScope { get; set; } + public Scope? OrigScope { get; set; } // the original context (when attaching a detachable scope) - public IScopeContext OrigContext { get; set; } + public IScopeContext? OrigContext { get; set; } // the context (for attaching & detaching only) public IScopeContext? Context { get; } @@ -277,7 +277,7 @@ namespace Umbraco.Cms.Core.Scoping } } - public IUmbracoDatabase DatabaseOrNull + public IUmbracoDatabase? DatabaseOrNull { get { @@ -531,7 +531,7 @@ namespace Umbraco.Cms.Core.Scoping /// Used for testing. Ensures and gets any queued read locks. /// /// - internal Dictionary> GetReadLocks() + internal Dictionary>? GetReadLocks() { EnsureDbLocks(); // always delegate to root/parent scope. @@ -547,7 +547,7 @@ namespace Umbraco.Cms.Core.Scoping /// Used for testing. Ensures and gets and queued write locks. /// /// - internal Dictionary> GetWriteLocks() + internal Dictionary>? GetWriteLocks() { EnsureDbLocks(); // always delegate to root/parent scope. @@ -594,6 +594,10 @@ namespace Umbraco.Cms.Core.Scoping } else { + if (_database is null) + { + return; + } lock (_lockQueueLocker) { if (_queuedLocks?.Count > 0) @@ -702,7 +706,7 @@ namespace Umbraco.Cms.Core.Scoping /// Lock dictionary to report on. /// String builder to write to. /// The name to report the dictionary as. - private void WriteLockDictionaryToString(Dictionary> dict, StringBuilder builder, + private void WriteLockDictionaryToString(Dictionary>? dict, StringBuilder builder, string dictName) { if (dict?.Count > 0) @@ -785,10 +789,10 @@ namespace Umbraco.Cms.Core.Scoping { if (completed) { - _fscope.Complete(); + _fscope?.Complete(); } - _fscope.Dispose(); + _fscope?.Dispose(); _fscope = null; } } @@ -808,7 +812,7 @@ namespace Umbraco.Cms.Core.Scoping { try { - _scopeProvider.AmbientContext.ScopeExit(completed); + _scopeProvider.AmbientContext?.ScopeExit(completed); } finally { @@ -879,17 +883,17 @@ namespace Umbraco.Cms.Core.Scoping /// Lock ID to increment. /// Instance ID of the scope requesting the lock. /// Reference to the dictionary to increment on - private void IncrementLock(int lockId, Guid instanceId, ref Dictionary> locks) + private void IncrementLock(int lockId, Guid instanceId, ref Dictionary>? locks) { // Since we've already checked that we're the parent in the WriteLockInner method, we don't need to check again. // If it's the very first time a lock has been requested the WriteLocks dict hasn't been instantiated yet. locks ??= new Dictionary>(); // Try and get the dict associated with the scope id. - var locksDictFound = locks.TryGetValue(instanceId, out Dictionary locksDict); + var locksDictFound = locks.TryGetValue(instanceId, out Dictionary? locksDict); if (locksDictFound) { - locksDict.TryGetValue(lockId, out var value); + locksDict!.TryGetValue(lockId, out var value); locksDict[lockId] = value + 1; } else @@ -1066,8 +1070,8 @@ namespace Umbraco.Cms.Core.Scoping /// Delegate used to request the lock from the database with a timeout. /// Optional timeout parameter to specify a timeout. /// Lock identifiers to lock on. - private void LockInner(IUmbracoDatabase db, Guid instanceId, ref Dictionary> locks, - ref HashSet locksSet, + private void LockInner(IUmbracoDatabase db, Guid instanceId, ref Dictionary>? locks, + ref HashSet? locksSet, Action obtainLock, Action obtainLockTimeout, TimeSpan? timeout, params int[] lockIds) @@ -1099,7 +1103,7 @@ namespace Umbraco.Cms.Core.Scoping { // Something went wrong and we didn't get the lock // Since we at this point have determined that we haven't got any lock with an ID of LockID, it's safe to completely remove it instead of decrementing. - locks[instanceId].Remove(lockId); + locks?[instanceId].Remove(lockId); // It needs to be removed from the HashSet as well, because that's how we determine to acquire a lock. locksSet.Remove(lockId); throw; diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs b/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs index 9880bfa556..0522f6385f 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.Scoping { internal class ScopeContext : IScopeContext, IInstanceIdentifiable { - private Dictionary _enlisted; + private Dictionary? _enlisted; public void ScopeExit(bool completed) { @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Core.Scoping return; // TODO: can we create infinite loops? - what about nested events? will they just be plainly ignored = really bad? - List exceptions = null; + List? exceptions = null; List orderedEnlisted; while ((orderedEnlisted = _enlisted.Values.OrderBy(x => x.Priority).ToList()).Count > 0) { @@ -55,22 +55,25 @@ namespace Umbraco.Cms.Core.Scoping private class EnlistedObject : IEnlistedObject { - private readonly Action _action; + private readonly Action? _action; - public EnlistedObject(T item, Action action, int priority) + public EnlistedObject(T? item, Action? action, int priority) { Item = item; Priority = priority; _action = action; } - public T Item { get; } + public T? Item { get; } public int Priority { get; } public void Execute(bool completed) { - _action(completed, Item); + if (_action is not null) + { + _action(completed, Item); + } } } @@ -79,7 +82,7 @@ namespace Umbraco.Cms.Core.Scoping Enlist(key, null, (completed, item) => action(completed), priority); } - public T Enlist(string key, Func creator, Action? action = null, int priority = 100) + public T? Enlist(string key, Func? creator, Action? action = null, int priority = 100) { var enlistedObjects = _enlisted ?? (_enlisted = new Dictionary()); @@ -96,7 +99,7 @@ namespace Umbraco.Cms.Core.Scoping return enlistedOfT.Item; } - public T GetEnlisted(string key) + public T? GetEnlisted(string key) { var enlistedObjects = _enlisted; if (enlistedObjects == null) return default; diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeContextualBase.cs b/src/Umbraco.Infrastructure/Scoping/ScopeContextualBase.cs index bde8f79012..19a25f8d8f 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeContextualBase.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeContextualBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Core.Scoping /// /// /// - public static T Get(IScopeProvider scopeProvider, string key, Func ctor) + public static T? Get(IScopeProvider scopeProvider, string key, Func ctor) where T : ScopeContextualBase { // no scope context = create a non-scoped object @@ -36,9 +36,12 @@ namespace Umbraco.Cms.Core.Scoping // create & enlist the scoped object var w = scopeContext.Enlist("ScopeContextualBase_" + key, () => ctor(true), - (completed, item) => { item.Release(completed); }); + (completed, item) => { item?.Release(completed); }); - w._scoped = true; + if (w is not null) + { + w._scoped = true; + } return w; } diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 0f5fba4d4a..a453b3fcbd 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -33,8 +33,8 @@ namespace Umbraco.Cms.Core.Scoping private CoreDebugSettings _coreDebugSettings; private static readonly AsyncLocal> s_scopeStack = new AsyncLocal>(); private static readonly AsyncLocal> s_scopeContextStack = new AsyncLocal>(); - private static readonly string s_scopeItemKey = typeof(Scope).FullName; - private static readonly string s_contextItemKey = typeof(ScopeProvider).FullName; + private static readonly string s_scopeItemKey = typeof(Scope).FullName!; + private static readonly string s_contextItemKey = typeof(ScopeProvider).FullName!; private readonly IEventAggregator _eventAggregator; public ScopeProvider( @@ -68,33 +68,33 @@ namespace Umbraco.Cms.Core.Scoping private void MoveHttpContextScopeToCallContext() { - var source = (ConcurrentStack)_requestCache.Get(s_scopeItemKey); - ConcurrentStack stack = s_scopeStack.Value; + var source = (ConcurrentStack?)_requestCache.Get(s_scopeItemKey); + ConcurrentStack? stack = s_scopeStack.Value; MoveContexts(s_scopeItemKey, source, stack, (_, v) => s_scopeStack.Value = v); } private void MoveHttpContextScopeContextToCallContext() { - var source = (ConcurrentStack)_requestCache.Get(s_contextItemKey); - ConcurrentStack stack = s_scopeContextStack.Value; + var source = (ConcurrentStack?)_requestCache.Get(s_contextItemKey); + ConcurrentStack? stack = s_scopeContextStack.Value; MoveContexts(s_contextItemKey, source, stack, (_, v) => s_scopeContextStack.Value = v); } private void MoveCallContextScopeToHttpContext() { - ConcurrentStack source = s_scopeStack.Value; - var stack = (ConcurrentStack)_requestCache.Get(s_scopeItemKey); + ConcurrentStack? source = s_scopeStack.Value; + var stack = (ConcurrentStack?)_requestCache.Get(s_scopeItemKey); MoveContexts(s_scopeItemKey, source, stack, (k, v) => _requestCache.Set(k, v)); } private void MoveCallContextScopeContextToHttpContext() { - ConcurrentStack source = s_scopeContextStack.Value; - var stack = (ConcurrentStack)_requestCache.Get(s_contextItemKey); + ConcurrentStack? source = s_scopeContextStack.Value; + var stack = (ConcurrentStack?)_requestCache.Get(s_contextItemKey); MoveContexts(s_contextItemKey, source, stack, (k, v) => _requestCache.Set(k, v)); } - private void MoveContexts(string key, ConcurrentStack source, ConcurrentStack stack, Action> setter) + private void MoveContexts(string key, ConcurrentStack? source, ConcurrentStack? stack, Action> setter) where T : class, IInstanceIdentifiable { if (source == null) @@ -124,9 +124,9 @@ namespace Umbraco.Cms.Core.Scoping source.Clear(); } - private void SetCallContextScope(IScope value) + private void SetCallContextScope(IScope? value) { - ConcurrentStack stack = s_scopeStack.Value; + ConcurrentStack? stack = s_scopeStack.Value; #if DEBUG_SCOPES // first, null-register the existing value @@ -164,9 +164,9 @@ namespace Umbraco.Cms.Core.Scoping } } - private void SetCallContextScopeContext(IScopeContext value) + private void SetCallContextScopeContext(IScopeContext? value) { - ConcurrentStack stack = s_scopeContextStack.Value; + ConcurrentStack? stack = s_scopeContextStack.Value; if (value == null) { @@ -187,7 +187,7 @@ namespace Umbraco.Cms.Core.Scoping } - private T GetHttpContextObject(string key, bool required = true) + private T? GetHttpContextObject(string key, bool required = true) where T : class { if (!_requestCache.IsAvailable && required) @@ -195,11 +195,11 @@ namespace Umbraco.Cms.Core.Scoping throw new Exception("Request cache is unavailable."); } - var stack = (ConcurrentStack)_requestCache.Get(key); - return stack != null && stack.TryPeek(out T peek) ? peek : null; + var stack = (ConcurrentStack?)_requestCache.Get(key); + return stack != null && stack.TryPeek(out T? peek) ? peek : null; } - private bool SetHttpContextObject(string key, T value, bool required = true) + private bool SetHttpContextObject(string key, T? value, bool required = true) { if (!_requestCache.IsAvailable) { @@ -230,7 +230,7 @@ namespace Umbraco.Cms.Core.Scoping } } #endif - var stack = (ConcurrentStack)_requestCache.Get(key); + var stack = (ConcurrentStack?)_requestCache.Get(key); if (value == null) { @@ -262,19 +262,19 @@ namespace Umbraco.Cms.Core.Scoping /// /// The current execution context may be request based (HttpContext) or on a background thread (AsyncLocal) /// - public IScopeContext AmbientContext + public IScopeContext? AmbientContext { get { // try http context, fallback onto call context - IScopeContext value = GetHttpContextObject(s_contextItemKey, false); + IScopeContext? value = GetHttpContextObject(s_contextItemKey, false); if (value != null) { return value; } - ConcurrentStack stack = s_scopeContextStack.Value; - if (stack == null || !stack.TryPeek(out IScopeContext peek)) + ConcurrentStack? stack = s_scopeContextStack.Value; + if (stack == null || !stack.TryPeek(out IScopeContext? peek)) { return null; } @@ -287,7 +287,7 @@ namespace Umbraco.Cms.Core.Scoping #region Ambient Scope - IDatabaseScope IScopeAccessor.AmbientScope => AmbientScope; + IDatabaseScope? IScopeAccessor.AmbientScope => AmbientScope; /// /// Gets or set the Ambient (Current) for the current execution context. @@ -295,19 +295,19 @@ namespace Umbraco.Cms.Core.Scoping /// /// The current execution context may be request based (HttpContext) or on a background thread (AsyncLocal) /// - public Scope AmbientScope + public Scope? AmbientScope { get { // try http context, fallback onto call context - IScope value = GetHttpContextObject(s_scopeItemKey, false); + IScope? value = GetHttpContextObject(s_scopeItemKey, false); if (value != null) { return (Scope)value; } - ConcurrentStack stack = s_scopeStack.Value; - if (stack == null || !stack.TryPeek(out IScope peek)) + ConcurrentStack? stack = s_scopeStack.Value; + if (stack == null || !stack.TryPeek(out IScope? peek)) { return null; } @@ -316,7 +316,7 @@ namespace Umbraco.Cms.Core.Scoping } } - public void PopAmbientScope(Scope scope) + public void PopAmbientScope(Scope? scope) { // pop the stack from all contexts SetHttpContextObject(s_scopeItemKey, null, false); @@ -327,13 +327,13 @@ namespace Umbraco.Cms.Core.Scoping // if creating a child scope with callContext: true (thus forcing CallContext) // when there is actually a current HttpContext available. // It's weird but is required for Deploy somehow. - bool parentScopeCallContext = (scope.ParentScope?.CallContext ?? false); - if (scope.CallContext && !parentScopeCallContext) + bool parentScopeCallContext = (scope?.ParentScope?.CallContext ?? false); + if ((scope?.CallContext ?? false) && !parentScopeCallContext) { MoveCallContextScopeToHttpContext(); MoveCallContextScopeContextToHttpContext(); } - else if (!scope.CallContext && parentScopeCallContext) + else if ((!scope?.CallContext ?? false) && parentScopeCallContext) { MoveHttpContextScopeToCallContext(); MoveHttpContextScopeContextToCallContext(); @@ -367,7 +367,7 @@ namespace Umbraco.Cms.Core.Scoping } } - public void PushAmbientScopeContext(IScopeContext scopeContext) + public void PushAmbientScopeContext(IScopeContext? scopeContext) { if (scopeContext is null) { @@ -389,7 +389,7 @@ namespace Umbraco.Cms.Core.Scoping public IScope CreateDetachedScope( IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, - IScopedNotificationPublisher scopedNotificationPublisher = null, + IScopedNotificationPublisher? scopedNotificationPublisher = null, bool? scopeFileSystems = null) => new Scope(this, _coreDebugSettings, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, true, null, isolationLevel, repositoryCacheMode, scopedNotificationPublisher, scopeFileSystems); @@ -425,7 +425,7 @@ namespace Umbraco.Cms.Core.Scoping /// public IScope DetachScope() { - Scope ambientScope = AmbientScope; + Scope? ambientScope = AmbientScope; if (ambientScope == null) { throw new InvalidOperationException("There is no ambient scope."); @@ -439,12 +439,12 @@ namespace Umbraco.Cms.Core.Scoping PopAmbientScope(ambientScope); PopAmbientScopeContext(); - Scope originalScope = AmbientScope; + Scope? originalScope = AmbientScope; if (originalScope != ambientScope.OrigScope) { - throw new InvalidOperationException($"The detatched scope ({ambientScope.GetDebugInfo()}) does not match the original ({originalScope.GetDebugInfo()})"); + throw new InvalidOperationException($"The detatched scope ({ambientScope.GetDebugInfo()}) does not match the original ({originalScope?.GetDebugInfo()})"); } - IScopeContext originalScopeContext = AmbientContext; + IScopeContext? originalScopeContext = AmbientContext; if (originalScopeContext != ambientScope.OrigContext) { throw new InvalidOperationException($"The detatched scope context does not match the original"); @@ -460,16 +460,16 @@ namespace Umbraco.Cms.Core.Scoping public IScope CreateScope( IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, - IScopedNotificationPublisher notificationPublisher = null, + IScopedNotificationPublisher? notificationPublisher = null, bool? scopeFileSystems = null, bool callContext = false, bool autoComplete = false) { - Scope ambientScope = AmbientScope; + Scope? ambientScope = AmbientScope; if (ambientScope == null) { - IScopeContext ambientContext = AmbientContext; - ScopeContext newContext = ambientContext == null ? new ScopeContext() : null; + IScopeContext? ambientContext = AmbientContext; + ScopeContext? newContext = ambientContext == null ? new ScopeContext() : null; var scope = new Scope(this, _coreDebugSettings, _eventAggregator, _loggerFactory.CreateLogger(), _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, notificationPublisher, scopeFileSystems, callContext, autoComplete); // assign only if scope creation did not throw! PushAmbientScope(scope); @@ -486,10 +486,10 @@ namespace Umbraco.Cms.Core.Scoping } /// - public IScopeContext Context => AmbientContext; + public IScopeContext? Context => AmbientContext; // for testing - internal ConcurrentStack GetCallContextScopeValue() => s_scopeStack.Value; + internal ConcurrentStack? GetCallContextScopeValue() => s_scopeStack.Value; #if DEBUG_SCOPES // this code needs TLC diff --git a/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Content.cs b/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Content.cs index c80e61af0e..8e9840d448 100644 --- a/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Content.cs +++ b/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Content.cs @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Infrastructure.Search // Used to track permanent deletions so we can bulk delete from the index // when needed. For example, when emptying the recycle bin, else it will // individually update the index which will be much slower. - HashSet deleteBatch = null; + HashSet? deleteBatch = null; foreach (var payload in (ContentCacheRefresher.JsonPayload[])args.MessageObject) { @@ -90,7 +90,7 @@ namespace Umbraco.Cms.Infrastructure.Search continue; } - IContent published = null; + IContent? published = null; if (content.Published && _contentService.IsPathPublished(content)) { published = content; diff --git a/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Media.cs b/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Media.cs index 4ac1d1ca09..aee7ea30b8 100644 --- a/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Media.cs +++ b/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Media.cs @@ -41,7 +41,7 @@ namespace Umbraco.Cms.Infrastructure.Search // Used to track permanent deletions so we can bulk delete from the index // when needed. For example, when emptying the recycle bin, else it will // individually update the index which will be much slower. - HashSet deleteBatch = null; + HashSet? deleteBatch = null; foreach (var payload in (MediaCacheRefresher.JsonPayload[])args.MessageObject) { @@ -102,7 +102,7 @@ namespace Umbraco.Cms.Infrastructure.Search } } } - } + } } if (deleteBatch != null) diff --git a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs index 98dabd22b8..190819f1ef 100644 --- a/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Infrastructure/Search/UmbracoTreeSearcher.cs @@ -61,11 +61,11 @@ namespace Umbraco.Cms.Infrastructure.Search /// /// If set to true, user and group start node permissions will be ignored. /// - public IEnumerable ExamineSearch( + public IEnumerable? ExamineSearch( string query, UmbracoEntityTypes entityType, int pageSize, - long pageIndex, out long totalFound, string? culture = null, string searchFrom = null, bool ignoreUserStartNodes = false) + long pageIndex, out long totalFound, string? culture = null, string? searchFrom = null, bool ignoreUserStartNodes = false) { var pagedResult = _backOfficeExamineSearcher.Search(query, entityType, pageSize, pageIndex, out totalFound, searchFrom, ignoreUserStartNodes); @@ -92,7 +92,7 @@ namespace Umbraco.Cms.Infrastructure.Search /// /// /// - public IEnumerable EntitySearch(UmbracoObjectTypes objectType, string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null) + public IEnumerable EntitySearch(UmbracoObjectTypes objectType, string query, int pageSize, long pageIndex, out long totalFound, string? searchFrom = null) { //if it's a GUID, match it Guid.TryParse(query, out var g); @@ -114,6 +114,10 @@ namespace Umbraco.Cms.Infrastructure.Search { var m = _mapper.Map(result); + if (m is null) + { + continue; + } //if no icon could be mapped, it will be set to document, so change it to picture if (m.Icon == Constants.Icons.DefaultIcon) { @@ -141,7 +145,7 @@ namespace Umbraco.Cms.Infrastructure.Search /// /// /// - private IEnumerable MediaFromSearchResults(IEnumerable results) + private IEnumerable? MediaFromSearchResults(IEnumerable results) => _mapper.Map>(results); /// @@ -163,7 +167,11 @@ namespace Umbraco.Cms.Infrastructure.Search } ); - if (int.TryParse(entity.Id.ToString(),NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + if (entity is null) + { + continue; + } + if (int.TryParse(entity.Id?.ToString(),NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { //if it varies by culture, return the default language URL if (result.Values.TryGetValue(UmbracoExamineFieldNames.VariesByCultureFieldName, out var varies) && varies == "y") diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeClaimsPrincipalFactory.cs b/src/Umbraco.Infrastructure/Security/BackOfficeClaimsPrincipalFactory.cs index c86bda44e0..ca8234164c 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeClaimsPrincipalFactory.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeClaimsPrincipalFactory.cs @@ -32,7 +32,7 @@ namespace Umbraco.Cms.Core.Security // since it's setting an authentication type which is not what we want. // so we override this method to change it. - // get the base + // get the base ClaimsIdentity baseIdentity = await base.GenerateClaimsAsync(user); // now create a new one with the correct authentication type @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Core.Security // ensure our required claims are there id.AddRequiredClaims( - user.Id, + user.Id!, user.UserName, user.Name, user.CalculatedContentStartNodeIds, diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs b/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs index df4d704781..9f948716c6 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs @@ -15,8 +15,8 @@ namespace Umbraco.Cms.Core.Security public class BackOfficeIdentityUser : UmbracoIdentityUser { private string _culture; - private IReadOnlyCollection _groups; - private string[] _allowedSections; + private IReadOnlyCollection _groups = null!; + private string[]? _allowedSections; private int[] _startMediaIds; private int[] _startContentIds; private DateTime? _inviteDateUtc; @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Core.Security /// Used to construct a new instance without an identity /// /// This is allowed to be null (but would need to be filled in if trying to persist this instance) - public static BackOfficeIdentityUser CreateNew(GlobalSettings globalSettings, string username, string email, string culture, string name = null) + public static BackOfficeIdentityUser CreateNew(GlobalSettings globalSettings, string username, string email, string culture, string? name = null) { if (string.IsNullOrWhiteSpace(username)) { @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Core.Security user.UserName = username; user.Email = email; - user.Id = null; + user.Id = string.Empty; user.HasIdentity = false; user._culture = culture; user.Name = name; @@ -74,8 +74,8 @@ namespace Umbraco.Cms.Core.Security Id = UserIdToString(userId); } - public int[] CalculatedMediaStartNodeIds { get; set; } - public int[] CalculatedContentStartNodeIds { get; set; } + public int[]? CalculatedMediaStartNodeIds { get; set; } + public int[]? CalculatedContentStartNodeIds { get; set; } /// /// Gets or sets invite date @@ -99,7 +99,7 @@ namespace Umbraco.Cms.Core.Security value = new int[0]; } - BeingDirty.SetPropertyValueAndDetectChanges(value, ref _startContentIds, nameof(StartContentIds), s_startIdsComparer); + BeingDirty.SetPropertyValueAndDetectChanges(value, ref _startContentIds!, nameof(StartContentIds), s_startIdsComparer); } } @@ -116,7 +116,7 @@ namespace Umbraco.Cms.Core.Security value = new int[0]; } - BeingDirty.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, nameof(StartMediaIds), s_startIdsComparer); + BeingDirty.SetPropertyValueAndDetectChanges(value, ref _startMediaIds!, nameof(StartMediaIds), s_startIdsComparer); } } @@ -131,7 +131,7 @@ namespace Umbraco.Cms.Core.Security public string Culture { get => _culture; - set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _culture, nameof(Culture)); + set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _culture!, nameof(Culture)); } /// @@ -148,7 +148,7 @@ namespace Umbraco.Cms.Core.Security foreach (IdentityUserRole identityUserRole in _groups.Select(x => new IdentityUserRole { RoleId = x.Alias, - UserId = Id?.ToString() + UserId = Id.ToString() })) { roles.Add(identityUserRole); @@ -163,7 +163,7 @@ namespace Umbraco.Cms.Core.Security public Guid Key => UserIdToInt(Id).ToGuid(); - private static int UserIdToInt(string userId) + private static int UserIdToInt(string? userId) { if(int.TryParse(userId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs index 4fff80ced6..25f39cca07 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs @@ -144,7 +144,7 @@ namespace Umbraco.Cms.Core.Security using (IScope scope = _scopeProvider.CreateScope()) { - IUser found = _userService.GetUserById(asInt); + IUser? found = _userService.GetUserById(asInt); if (found != null) { // we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it. @@ -194,7 +194,7 @@ namespace Umbraco.Cms.Core.Security } var userId = UserIdToInt(user.Id); - IUser found = _userService.GetUserById(userId); + IUser? found = _userService.GetUserById(userId); if (found != null) { _userService.Delete(found); @@ -211,13 +211,13 @@ namespace Umbraco.Cms.Core.Security cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); - IUser user = _userService.GetUserById(UserIdToInt(userId)); + IUser? user = _userService.GetUserById(UserIdToInt(userId)); if (user == null) { - return Task.FromResult((BackOfficeIdentityUser)null); + return Task.FromResult((BackOfficeIdentityUser?)null)!; } - return Task.FromResult(AssignLoginsCallback(_mapper.Map(user))); + return Task.FromResult(AssignLoginsCallback(_mapper.Map(user)))!; } /// @@ -228,12 +228,12 @@ namespace Umbraco.Cms.Core.Security IUser user = _userService.GetByUsername(userName); if (user == null) { - return Task.FromResult((BackOfficeIdentityUser)null); + return Task.FromResult((BackOfficeIdentityUser)null!); } - BackOfficeIdentityUser result = AssignLoginsCallback(_mapper.Map(user)); + BackOfficeIdentityUser? result = AssignLoginsCallback(_mapper.Map(user)); - return Task.FromResult(result); + return Task.FromResult(result)!; } /// @@ -241,12 +241,12 @@ namespace Umbraco.Cms.Core.Security { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); - IUser user = _userService.GetByEmail(email); - BackOfficeIdentityUser result = user == null + IUser? user = _userService.GetByEmail(email); + BackOfficeIdentityUser? result = user == null ? null : _mapper.Map(user); - return Task.FromResult(AssignLoginsCallback(result)); + return Task.FromResult(AssignLoginsCallback(result))!; } /// @@ -274,9 +274,12 @@ namespace Umbraco.Cms.Core.Security } ICollection logins = user.Logins; - var instance = new IdentityUserLogin(login.LoginProvider, login.ProviderKey, user.Id.ToString()); - IdentityUserLogin userLogin = instance; - logins.Add(userLogin); + if (user.Id is not null) + { + var instance = new IdentityUserLogin(login.LoginProvider, login.ProviderKey, user.Id.ToString()); + IdentityUserLogin userLogin = instance; + logins.Add(userLogin); + } return Task.CompletedTask; } @@ -291,7 +294,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - IIdentityUserLogin userLogin = user.Logins.SingleOrDefault(l => l.LoginProvider == loginProvider && l.ProviderKey == providerKey); + IIdentityUserLogin? userLogin = user.Logins.SingleOrDefault(l => l.LoginProvider == loginProvider && l.ProviderKey == providerKey); if (userLogin != null) { user.Logins.Remove(userLogin); @@ -320,16 +323,16 @@ namespace Umbraco.Cms.Core.Security ThrowIfDisposed(); BackOfficeIdentityUser user = await FindUserAsync(userId, cancellationToken); - if (user == null) + if (user is null || user.Id is null) { - return null; + return null!; } IList logins = await GetLoginsAsync(user, cancellationToken); - UserLoginInfo found = logins.FirstOrDefault(x => x.ProviderKey == providerKey && x.LoginProvider == loginProvider); + UserLoginInfo? found = logins.FirstOrDefault(x => x.ProviderKey == providerKey && x.LoginProvider == loginProvider); if (found == null) { - return null; + return null!; } return new IdentityUserLogin @@ -350,7 +353,7 @@ namespace Umbraco.Cms.Core.Security var logins = _externalLoginService.Find(loginProvider, providerKey).ToList(); if (logins.Count == 0) { - return Task.FromResult((IdentityUserLogin)null); + return Task.FromResult((IdentityUserLogin)null!); } IIdentityUserLogin found = logins[0]; @@ -378,10 +381,10 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(normalizedRoleName)); } - IUserGroup userGroup = _userService.GetUserGroupByAlias(normalizedRoleName); + IUserGroup? userGroup = _userService.GetUserGroupByAlias(normalizedRoleName); - IEnumerable users = _userService.GetAllInGroup(userGroup.Id); - IList backOfficeIdentityUsers = users.Select(x => _mapper.Map(x)).ToList(); + IEnumerable users = _userService.GetAllInGroup(userGroup?.Id); + IList backOfficeIdentityUsers = users.Select(x => _mapper.Map(x)).Where(x => x != null).ToList()!; return Task.FromResult(backOfficeIdentityUsers); } @@ -389,10 +392,10 @@ namespace Umbraco.Cms.Core.Security /// protected override Task> FindRoleAsync(string normalizedRoleName, CancellationToken cancellationToken) { - IUserGroup group = _userService.GetUserGroupByAlias(normalizedRoleName); + IUserGroup? group = _userService.GetUserGroupByAlias(normalizedRoleName); if (group == null) { - return Task.FromResult((IdentityRole)null); + return Task.FromResult((IdentityRole)null!); } return Task.FromResult(new IdentityRole(group.Name) @@ -407,14 +410,14 @@ namespace Umbraco.Cms.Core.Security BackOfficeIdentityUser user = await FindUserAsync(userId, cancellationToken); if (user == null) { - return null; + return null!; } - IdentityUserRole found = user.Roles.FirstOrDefault(x => x.RoleId.InvariantEquals(roleId)); - return found; + IdentityUserRole? found = user.Roles.FirstOrDefault(x => x.RoleId.InvariantEquals(roleId)); + return found!; } - private BackOfficeIdentityUser AssignLoginsCallback(BackOfficeIdentityUser user) + private BackOfficeIdentityUser? AssignLoginsCallback(BackOfficeIdentityUser? user) { if (user != null) { @@ -433,12 +436,12 @@ namespace Umbraco.Cms.Core.Security // don't assign anything if nothing has changed as this will trigger the track changes of the model if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.LastLoginDateUtc)) || (user.LastLoginDate != default && identityUser.LastLoginDateUtc.HasValue == false) - || (identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)) + || (identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate?.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)) { anythingChanged = true; // if the LastLoginDate is being set to MinValue, don't convert it ToLocalTime - DateTime dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc.Value.ToLocalTime(); + DateTime? dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc?.ToLocalTime(); user.LastLoginDate = dt; } @@ -451,10 +454,10 @@ namespace Umbraco.Cms.Core.Security if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.LastPasswordChangeDateUtc)) || (user.LastPasswordChangeDate != default && identityUser.LastPasswordChangeDateUtc.HasValue == false) - || (identityUser.LastPasswordChangeDateUtc.HasValue && user.LastPasswordChangeDate.ToUniversalTime() != identityUser.LastPasswordChangeDateUtc.Value)) + || (identityUser.LastPasswordChangeDateUtc.HasValue && user.LastPasswordChangeDate?.ToUniversalTime() != identityUser.LastPasswordChangeDateUtc.Value)) { anythingChanged = true; - user.LastPasswordChangeDate = identityUser.LastPasswordChangeDateUtc.Value.ToLocalTime(); + user.LastPasswordChangeDate = identityUser.LastPasswordChangeDateUtc?.ToLocalTime(); } if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.EmailConfirmed)) @@ -548,7 +551,7 @@ namespace Umbraco.Cms.Core.Security if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.Roles))) { - var identityUserRoles = identityUser.Roles.Select(x => x.RoleId).ToArray(); + var identityUserRoles = identityUser.Roles.Select(x => x.RoleId).Where(x => x is not null).ToArray(); anythingChanged = true; @@ -556,7 +559,7 @@ namespace Umbraco.Cms.Core.Security user.ClearGroups(); // go lookup all these groups - IReadOnlyUserGroup[] groups = _userService.GetUserGroupsByAlias(identityUserRoles).Select(x => x.ToReadOnlyGroup()).ToArray(); + IReadOnlyUserGroup[] groups = _userService.GetUserGroupsByAlias(identityUserRoles!).Select(x => x.ToReadOnlyGroup()).ToArray(); // use all of the ones assigned and add them foreach (IReadOnlyUserGroup group in groups) @@ -608,7 +611,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - IIdentityUserToken token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); + IIdentityUserToken? token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); if (token == null) { user.LoginTokens.Add(new IdentityUserToken(loginProvider, name, value, user.Id)); @@ -639,7 +642,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - IIdentityUserToken token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); + IIdentityUserToken? token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); if (token != null) { user.LoginTokens.Remove(token); @@ -656,7 +659,7 @@ namespace Umbraco.Cms.Core.Security /// tracking ORMs like EFCore. /// /// - public override Task GetTokenAsync(BackOfficeIdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) + public override Task GetTokenAsync(BackOfficeIdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -665,7 +668,7 @@ namespace Umbraco.Cms.Core.Security { throw new ArgumentNullException(nameof(user)); } - IIdentityUserToken token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); + IIdentityUserToken? token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); return Task.FromResult(token?.Value); } diff --git a/src/Umbraco.Infrastructure/Security/IMemberManager.cs b/src/Umbraco.Infrastructure/Security/IMemberManager.cs index f851b205d5..d7558e163f 100644 --- a/src/Umbraco.Infrastructure/Security/IMemberManager.cs +++ b/src/Umbraco.Infrastructure/Security/IMemberManager.cs @@ -30,9 +30,9 @@ namespace Umbraco.Cms.Core.Security /// Allowed individual members. /// True or false if the currently logged in member is authorized Task IsMemberAuthorizedAsync( - IEnumerable allowTypes = null, - IEnumerable allowGroups = null, - IEnumerable allowMembers = null); + IEnumerable? allowTypes = null, + IEnumerable? allowGroups = null, + IEnumerable? allowMembers = null); /// /// Check if a member is logged in diff --git a/src/Umbraco.Infrastructure/Security/IMemberUserStore.cs b/src/Umbraco.Infrastructure/Security/IMemberUserStore.cs index 578b2f2860..7ecddac3ba 100644 --- a/src/Umbraco.Infrastructure/Security/IMemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/IMemberUserStore.cs @@ -8,6 +8,6 @@ namespace Umbraco.Cms.Core.Security /// public interface IMemberUserStore : IUserStore { - IPublishedContent GetPublishedMember(MemberIdentityUser user); + IPublishedContent? GetPublishedMember(MemberIdentityUser user); } } diff --git a/src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs b/src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs index 3b51233f61..d3c616af0a 100644 --- a/src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs @@ -72,16 +72,16 @@ namespace Umbraco.Cms.Core.Security target.CalculatedContentStartNodeIds = source.CalculateContentStartNodeIds(_entityService, _appCaches); target.Email = source.Email; target.UserName = source.Username; - target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate.ToUniversalTime(); - target.LastLoginDateUtc = source.LastLoginDate.ToUniversalTime(); + target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate?.ToUniversalTime(); + target.LastLoginDateUtc = source.LastLoginDate?.ToUniversalTime(); target.InviteDateUtc = source.InvitedDate?.ToUniversalTime(); target.EmailConfirmed = source.EmailConfirmedDate.HasValue; target.Name = source.Name; target.AccessFailedCount = source.FailedPasswordAttempts; target.PasswordHash = GetPasswordHash(source.RawPasswordValue); target.PasswordConfig = source.PasswordConfiguration; - target.StartContentIds = source.StartContentIds; - target.StartMediaIds = source.StartMediaIds; + target.StartContentIds = source.StartContentIds ?? Array.Empty(); + target.StartMediaIds = source.StartMediaIds ?? Array.Empty(); target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString(); // project CultureInfo to string target.IsApproved = source.IsApproved; target.SecurityStamp = source.SecurityStamp; @@ -93,8 +93,8 @@ namespace Umbraco.Cms.Core.Security { target.Email = source.Email; target.UserName = source.Username; - target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate.ToUniversalTime(); - target.LastLoginDateUtc = source.LastLoginDate.ToUniversalTime(); + target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate?.ToUniversalTime(); + target.LastLoginDateUtc = source.LastLoginDate?.ToUniversalTime(); target.EmailConfirmed = source.EmailConfirmedDate.HasValue; target.Name = source.Name; target.AccessFailedCount = source.FailedPasswordAttempts; @@ -112,6 +112,6 @@ namespace Umbraco.Cms.Core.Security // NB: same comments re AutoMapper as per BackOfficeUser } - private static string GetPasswordHash(string storedPass) => storedPass.StartsWith(Constants.Security.EmptyPasswordPrefix) ? null : storedPass; + private static string? GetPasswordHash(string? storedPass) => storedPass?.StartsWith(Constants.Security.EmptyPasswordPrefix) ?? false ? null : storedPass; } } diff --git a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs index 9e29316056..a2c29ed99f 100644 --- a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs @@ -12,11 +12,11 @@ namespace Umbraco.Cms.Core.Security /// public class MemberIdentityUser : UmbracoIdentityUser { - private string _comments; + private string? _comments; // Custom comparer for enumerables private static readonly DelegateEqualityComparer> s_groupsComparer = new DelegateEqualityComparer>( - (groups, enumerable) => groups.Select(x => x.Alias).UnsortedSequenceEqual(enumerable.Select(x => x.Alias)), + (groups, enumerable) => groups?.Select(x => x.Alias).UnsortedSequenceEqual(enumerable?.Select(x => x.Alias)) ?? false, groups => groups.GetHashCode()); /// @@ -35,7 +35,7 @@ namespace Umbraco.Cms.Core.Security /// /// Used to construct a new instance without an identity /// - public static MemberIdentityUser CreateNew(string username, string email, string memberTypeAlias, bool isApproved, string name = null) + public static MemberIdentityUser CreateNew(string username, string email, string memberTypeAlias, bool isApproved, string? name = null) { if (string.IsNullOrWhiteSpace(username)) { @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Core.Security user.Email = email; user.MemberTypeAlias = memberTypeAlias; user.IsApproved = isApproved; - user.Id = null; + user.Id = null!; user.HasIdentity = false; user.Name = name; user.EnableChangeTracking(); @@ -58,7 +58,7 @@ namespace Umbraco.Cms.Core.Security /// /// Gets or sets the member's comments /// - public string Comments + public string? Comments { get => _comments; set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _comments, nameof(Comments)); @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Core.Security /// /// Gets or sets the alias of the member type /// - public string MemberTypeAlias { get; set; } + public string? MemberTypeAlias { get; set; } private static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); diff --git a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs index e470bf0a6c..71a48e19c5 100644 --- a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs +++ b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs @@ -80,7 +80,7 @@ namespace Umbraco.Cms.Core.Security // Else we need to detect what the password is. This will be the case // for upgrades since no password config will exist. - byte[] decodedHashedPassword = null; + byte[]? decodedHashedPassword = null; bool isAspNetIdentityHash = false; try @@ -96,7 +96,7 @@ namespace Umbraco.Cms.Core.Security // check for default ASP.NET Identity password hash flags if (isAspNetIdentityHash) { - if (decodedHashedPassword[0] == 0x00 || decodedHashedPassword[0] == 0x01) + if (decodedHashedPassword?[0] == 0x00 || decodedHashedPassword?[0] == 0x01) { return base.VerifyHashedPassword(user, hashedPassword, providedPassword); } diff --git a/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs b/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs index 03339fbd33..70743f3660 100644 --- a/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs @@ -77,7 +77,7 @@ namespace Umbraco.Cms.Core.Security return Task.FromResult(IdentityResult.Failed(_intParseError)); } - IMemberGroup memberGroup = _memberGroupService.GetById(roleId); + IMemberGroup? memberGroup = _memberGroupService.GetById(roleId); if (memberGroup != null) { if (MapToMemberGroup(role, memberGroup)) @@ -109,7 +109,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentException("The Id of the role is not an integer"); } - IMemberGroup memberGroup = _memberGroupService.GetById(roleId); + IMemberGroup? memberGroup = _memberGroupService.GetById(roleId); if (memberGroup != null) { _memberGroupService.Delete(memberGroup); @@ -133,7 +133,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(role)); } - return Task.FromResult(role.Id); + return Task.FromResult(role.Id)!; } /// @@ -147,7 +147,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(role)); } - return Task.FromResult(role.Name); + return Task.FromResult(role.Name)!; } /// @@ -182,7 +182,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(roleId)); } - IMemberGroup memberGroup; + IMemberGroup? memberGroup; // member group can be found by int or Guid, so try both if (!int.TryParse(roleId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int id)) @@ -201,7 +201,7 @@ namespace Umbraco.Cms.Core.Security memberGroup = _memberGroupService.GetById(id); } - return Task.FromResult(memberGroup == null ? null : MapFromMemberGroup(memberGroup)); + return Task.FromResult(memberGroup == null ? null : MapFromMemberGroup(memberGroup))!; } /// @@ -215,7 +215,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(name)); } IMemberGroup memberGroup = _memberGroupService.GetByName(name); - return Task.FromResult(memberGroup == null ? null : MapFromMemberGroup(memberGroup)); + return Task.FromResult(memberGroup == null ? null : MapFromMemberGroup(memberGroup))!; } /// diff --git a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs index 420d66b0b4..24fab739e5 100644 --- a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs @@ -104,8 +104,8 @@ namespace Umbraco.Cms.Core.Security IMember memberEntity = _memberService.CreateMember( user.UserName, user.Email, - user.Name.IsNullOrWhiteSpace() ? user.UserName : user.Name, - user.MemberTypeAlias.IsNullOrWhiteSpace() ? Constants.Security.DefaultMemberTypeAlias : user.MemberTypeAlias); + user.Name.IsNullOrWhiteSpace() ? user.UserName : user.Name!, + user.MemberTypeAlias.IsNullOrWhiteSpace() ? Constants.Security.DefaultMemberTypeAlias : user.MemberTypeAlias!); UpdateMemberProperties(memberEntity, user); @@ -113,7 +113,7 @@ namespace Umbraco.Cms.Core.Security _memberService.Save(memberEntity); //We need to add roles now that the member has an Id. It do not work implicit in UpdateMemberProperties - _memberService.AssignRoles(new[] { memberEntity.Id }, user.Roles.Select(x => x.RoleId).ToArray()); + _memberService.AssignRoles(new[] { memberEntity.Id }, user.Roles.Select(x => x.RoleId).Where(x => x is not null).ToArray()!); if (!memberEntity.HasIdentity) { @@ -176,7 +176,7 @@ namespace Umbraco.Cms.Core.Security } using IScope scope = _scopeProvider.CreateScope(autoComplete: true); - IMember found = _memberService.GetById(asInt); + IMember? found = _memberService.GetById(asInt); if (found != null) { // we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it. @@ -225,7 +225,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - IMember found = _memberService.GetById(UserIdToInt(user.Id)); + IMember? found = _memberService.GetById(UserIdToInt(user.Id)); if (found != null) { _memberService.Delete(found); @@ -253,13 +253,13 @@ namespace Umbraco.Cms.Core.Security } - IMember user = Guid.TryParse(userId, out var key) ? _memberService.GetByKey(key) : _memberService.GetById(UserIdToInt(userId)); + IMember? user = Guid.TryParse(userId, out var key) ? _memberService.GetByKey(key) : _memberService.GetById(UserIdToInt(userId)); if (user == null) { - return Task.FromResult((MemberIdentityUser)null); + return Task.FromResult((MemberIdentityUser)null!); } - return Task.FromResult(AssignLoginsCallback(_mapper.Map(user))); + return Task.FromResult(AssignLoginsCallback(_mapper.Map(user)))!; } /// @@ -270,10 +270,10 @@ namespace Umbraco.Cms.Core.Security IMember user = _memberService.GetByUsername(userName); if (user == null) { - return Task.FromResult((MemberIdentityUser)null); + return Task.FromResult((MemberIdentityUser)null!); } - MemberIdentityUser result = AssignLoginsCallback(_mapper.Map(user)); + MemberIdentityUser result = AssignLoginsCallback(_mapper.Map(user))!; return Task.FromResult(result); } @@ -283,12 +283,12 @@ namespace Umbraco.Cms.Core.Security { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); - IMember member = _memberService.GetByEmail(email); - MemberIdentityUser result = member == null + IMember? member = _memberService.GetByEmail(email); + MemberIdentityUser? result = member == null ? null : _mapper.Map(member); - return Task.FromResult(AssignLoginsCallback(result)); + return Task.FromResult(AssignLoginsCallback(result))!; } /// @@ -317,13 +317,16 @@ namespace Umbraco.Cms.Core.Security } ICollection logins = user.Logins; - var instance = new IdentityUserLogin( - login.LoginProvider, - login.ProviderKey, - user.Id.ToString()); + if (user.Id is not null) + { + var instance = new IdentityUserLogin( + login.LoginProvider, + login.ProviderKey, + user.Id.ToString()); - IdentityUserLogin userLogin = instance; - logins.Add(userLogin); + IdentityUserLogin userLogin = instance; + logins.Add(userLogin); + } return Task.CompletedTask; } @@ -348,7 +351,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(providerKey)); } - IIdentityUserLogin userLogin = user.Logins.SingleOrDefault(l => l.LoginProvider == loginProvider && l.ProviderKey == providerKey); + IIdentityUserLogin? userLogin = user.Logins.SingleOrDefault(l => l.LoginProvider == loginProvider && l.ProviderKey == providerKey); if (userLogin != null) { user.Logins.Remove(userLogin); @@ -389,24 +392,31 @@ namespace Umbraco.Cms.Core.Security MemberIdentityUser user = await FindUserAsync(userId, cancellationToken); if (user == null) { - return await Task.FromResult((IdentityUserLogin)null); + return await Task.FromResult((IdentityUserLogin)null!); } IList logins = await GetLoginsAsync(user, cancellationToken); - UserLoginInfo found = logins.FirstOrDefault(x => x.ProviderKey == providerKey && x.LoginProvider == loginProvider); + UserLoginInfo? found = logins.FirstOrDefault(x => x.ProviderKey == providerKey && x.LoginProvider == loginProvider); if (found == null) { - return await Task.FromResult((IdentityUserLogin)null); + return await Task.FromResult((IdentityUserLogin)null!); } - return new IdentityUserLogin + if (user.Id is not null) { - LoginProvider = found.LoginProvider, - ProviderKey = found.ProviderKey, - // TODO: We don't store this value so it will be null - ProviderDisplayName = found.ProviderDisplayName, - UserId = user.Id - }; + return new IdentityUserLogin + { + LoginProvider = found.LoginProvider, + ProviderKey = found.ProviderKey, + // TODO: We don't store this value so it will be null + ProviderDisplayName = found.ProviderDisplayName, + UserId = user.Id + }; + } + else + { + return null!; + } } /// @@ -428,7 +438,7 @@ namespace Umbraco.Cms.Core.Security var logins = _externalLoginService.Find(loginProvider, providerKey).ToList(); if (logins.Count == 0) { - return Task.FromResult((IdentityUserLogin)null); + return Task.FromResult((IdentityUserLogin)null!); } IIdentityUserLogin found = logins[0]; @@ -496,7 +506,7 @@ namespace Umbraco.Cms.Core.Security IEnumerable members = _memberService.GetMembersByMemberType(roleName); - IList membersIdentityUsers = members.Select(x => _mapper.Map(x)).ToList(); + IList membersIdentityUsers = members.Select(x => _mapper.Map(x)!).ToList(); return Task.FromResult(membersIdentityUsers); } @@ -509,10 +519,10 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(roleName)); } - IMemberGroup group = _memberService.GetAllRoles().SingleOrDefault(x => x.Name == roleName); + IMemberGroup? group = _memberService.GetAllRoles().SingleOrDefault(x => x.Name == roleName); if (group == null) { - return Task.FromResult((UmbracoIdentityRole)null); + return Task.FromResult((UmbracoIdentityRole)null!); } return Task.FromResult(new UmbracoIdentityRole(group.Name) @@ -528,14 +538,14 @@ namespace Umbraco.Cms.Core.Security MemberIdentityUser user = await FindUserAsync(userId, cancellationToken); if (user == null) { - return null; + return null!; } - IdentityUserRole found = user.Roles.FirstOrDefault(x => x.RoleId.InvariantEquals(roleId)); - return found; + IdentityUserRole? found = user.Roles.FirstOrDefault(x => x.RoleId.InvariantEquals(roleId)); + return found!; } - private MemberIdentityUser AssignLoginsCallback(MemberIdentityUser user) + private MemberIdentityUser? AssignLoginsCallback(MemberIdentityUser? user) { if (user != null) { @@ -553,21 +563,21 @@ namespace Umbraco.Cms.Core.Security // don't assign anything if nothing has changed as this will trigger the track changes of the model if (identityUser.IsPropertyDirty(nameof(MemberIdentityUser.LastLoginDateUtc)) || (member.LastLoginDate != default && identityUser.LastLoginDateUtc.HasValue == false) - || (identityUser.LastLoginDateUtc.HasValue && member.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)) + || (identityUser.LastLoginDateUtc.HasValue && member.LastLoginDate?.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)) { changeType = MemberDataChangeType.LoginOnly; // if the LastLoginDate is being set to MinValue, don't convert it ToLocalTime - DateTime dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc.Value.ToLocalTime(); + DateTime? dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc?.ToLocalTime(); member.LastLoginDate = dt; } if (identityUser.IsPropertyDirty(nameof(MemberIdentityUser.LastPasswordChangeDateUtc)) || (member.LastPasswordChangeDate != default && identityUser.LastPasswordChangeDateUtc.HasValue == false) - || (identityUser.LastPasswordChangeDateUtc.HasValue && member.LastPasswordChangeDate.ToUniversalTime() != identityUser.LastPasswordChangeDateUtc.Value)) + || (identityUser.LastPasswordChangeDateUtc.HasValue && member.LastPasswordChangeDate?.ToUniversalTime() != identityUser.LastPasswordChangeDateUtc.Value)) { changeType = MemberDataChangeType.FullSave; - member.LastPasswordChangeDate = identityUser.LastPasswordChangeDateUtc.Value.ToLocalTime(); + member.LastPasswordChangeDate = identityUser.LastPasswordChangeDateUtc?.ToLocalTime(); } if (identityUser.IsPropertyDirty(nameof(MemberIdentityUser.Comments)) @@ -589,7 +599,7 @@ namespace Umbraco.Cms.Core.Security && member.Name != identityUser.Name && identityUser.Name.IsNullOrWhiteSpace() == false) { changeType = MemberDataChangeType.FullSave; - member.Name = identityUser.Name; + member.Name = identityUser.Name ?? string.Empty; } if (identityUser.IsPropertyDirty(nameof(MemberIdentityUser.Email)) @@ -665,13 +675,13 @@ namespace Umbraco.Cms.Core.Security return changeType; } - public IPublishedContent GetPublishedMember(MemberIdentityUser user) + public IPublishedContent? GetPublishedMember(MemberIdentityUser user) { if (user == null) { return null; } - IMember member = _memberService.GetByKey(user.Key); + IMember? member = _memberService.GetByKey(user.Key); if (member == null) { return null; @@ -695,7 +705,7 @@ namespace Umbraco.Cms.Core.Security /// tracking ORMs like EFCore. /// /// - public override Task GetTokenAsync(MemberIdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) + public override Task GetTokenAsync(MemberIdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -704,7 +714,7 @@ namespace Umbraco.Cms.Core.Security { throw new ArgumentNullException(nameof(user)); } - IIdentityUserToken token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); + IIdentityUserToken? token = user.LoginTokens.FirstOrDefault(x => x.LoginProvider.InvariantEquals(loginProvider) && x.Name.InvariantEquals(name)); return Task.FromResult(token?.Value); } diff --git a/src/Umbraco.Infrastructure/Security/UmbracoIdentityRole.cs b/src/Umbraco.Infrastructure/Security/UmbracoIdentityRole.cs index 0b0285d852..ebf3bf5943 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoIdentityRole.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoIdentityRole.cs @@ -7,10 +7,10 @@ namespace Umbraco.Cms.Core.Security { public class UmbracoIdentityRole : IdentityRole, IRememberBeingDirty { - private string _id; - private string _name; + private string? _id; + private string? _name; - public UmbracoIdentityRole(string roleName) : base(roleName) + public UmbracoIdentityRole(string? roleName) : base(roleName) { } @@ -32,7 +32,7 @@ namespace Umbraco.Cms.Core.Security } /// - public override string Id + public override string? Id { get => _id; set @@ -43,7 +43,7 @@ namespace Umbraco.Cms.Core.Security } /// - public override string Name + public override string? Name { get => _name; set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); diff --git a/src/Umbraco.Infrastructure/Security/UmbracoIdentityUser.cs b/src/Umbraco.Infrastructure/Security/UmbracoIdentityUser.cs index 05e70076c6..36a652889f 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoIdentityUser.cs @@ -29,20 +29,20 @@ namespace Umbraco.Cms.Core.Security /// public abstract class UmbracoIdentityUser : IdentityUser, IRememberBeingDirty { - private string _name; - private string _passwordConfig; - private string _id; - private string _email; - private string _userName; + private string? _name; + private string? _passwordConfig; + private string _id = null!; + private string _email = null!; + private string _userName = null!; private DateTime? _lastLoginDateUtc; private bool _emailConfirmed; private int _accessFailedCount; - private string _passwordHash; + private string? _passwordHash; private DateTime? _lastPasswordChangeDateUtc; - private ObservableCollection _logins; - private ObservableCollection _tokens; - private Lazy> _getLogins; - private Lazy> _getTokens; + private ObservableCollection? _logins; + private ObservableCollection? _tokens; + private Lazy>? _getLogins; + private Lazy>? _getTokens; private ObservableCollection> _roles; /// @@ -92,7 +92,7 @@ namespace Umbraco.Cms.Core.Security public override string Email { get => _email; - set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _email, nameof(Email)); + set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _email!, nameof(Email)); } /// @@ -107,7 +107,7 @@ namespace Umbraco.Cms.Core.Security /// /// Gets or sets the salted/hashed form of the user password /// - public override string PasswordHash + public override string? PasswordHash { get => _passwordHash; set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _passwordHash, nameof(PasswordHash)); @@ -212,9 +212,12 @@ namespace Umbraco.Cms.Core.Security // if (_getTokens != null && !_getTokens.IsValueCreated) if (_getTokens?.IsValueCreated != true) { - foreach (IIdentityUserToken l in _getTokens.Value) + if (_getTokens is not null) { - _tokens.Add(l); + foreach (IIdentityUserToken l in _getTokens.Value) + { + _tokens.Add(l); + } } } @@ -249,7 +252,7 @@ namespace Umbraco.Cms.Core.Security public override string UserName { get => _userName; - set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _userName, nameof(UserName)); + set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _userName!, nameof(UserName)); } /// @@ -277,7 +280,7 @@ namespace Umbraco.Cms.Core.Security /// /// Gets or sets the user's real name /// - public string Name + public string? Name { get => _name; set => BeingDirty.SetPropertyValueAndDetectChanges(value, ref _name, nameof(Name)); @@ -286,7 +289,7 @@ namespace Umbraco.Cms.Core.Security /// /// Gets or sets the password config /// - public string PasswordConfig + public string? PasswordConfig { // TODO: Implement this for members: AB#11550 get => _passwordConfig; @@ -337,11 +340,14 @@ namespace Umbraco.Cms.Core.Security /// /// Adding a role this way will not reflect on the user's group's collection or it's allowed sections until the user is persisted /// - public void AddRole(string role) => Roles.Add(new IdentityUserRole + public void AddRole(string role) { - UserId = Id, - RoleId = role - }); + Roles.Add(new IdentityUserRole + { + UserId = Id, + RoleId = role + }); + } /// /// Used to set a lazy call back to populate the user's Login list @@ -355,10 +361,10 @@ namespace Umbraco.Cms.Core.Security /// The lazy value internal void SetTokensCallback(Lazy> callback) => _getTokens = callback ?? throw new ArgumentNullException(nameof(callback)); - private void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => BeingDirty.OnPropertyChanged(nameof(Logins)); + private void Logins_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) => BeingDirty.OnPropertyChanged(nameof(Logins)); - private void LoginTokens_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => BeingDirty.OnPropertyChanged(nameof(LoginTokens)); + private void LoginTokens_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) => BeingDirty.OnPropertyChanged(nameof(LoginTokens)); - private void Roles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => BeingDirty.OnPropertyChanged(nameof(Roles)); + private void Roles_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) => BeingDirty.OnPropertyChanged(nameof(Roles)); } } diff --git a/src/Umbraco.Infrastructure/Security/UmbracoPasswordHasher.cs b/src/Umbraco.Infrastructure/Security/UmbracoPasswordHasher.cs index da08bc8713..b1e13497f7 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoPasswordHasher.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoPasswordHasher.cs @@ -49,8 +49,8 @@ namespace Umbraco.Cms.Core.Security if (!user.PasswordConfig.IsNullOrWhiteSpace()) { // check if the (legacy) password security supports this hash algorith and if so then use it - var deserialized = _jsonSerializer.Deserialize(user.PasswordConfig); - if (LegacyPasswordSecurity.SupportHashAlgorithm(deserialized.HashAlgorithm)) + var deserialized = _jsonSerializer.Deserialize(user.PasswordConfig!); + if (deserialized?.HashAlgorithm is not null && LegacyPasswordSecurity.SupportHashAlgorithm(deserialized.HashAlgorithm)) { var result = LegacyPasswordSecurity.VerifyPassword(deserialized.HashAlgorithm, providedPassword, hashedPassword); @@ -72,7 +72,7 @@ namespace Umbraco.Cms.Core.Security // The PBKDF2.ASPNETCORE.V2 settings are: // PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations. - switch (deserialized.HashAlgorithm) + switch (deserialized?.HashAlgorithm) { case Constants.Security.AspNetCoreV3PasswordHashAlgorithmName: return base.VerifyHashedPassword(user, hashedPassword, providedPassword); diff --git a/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs b/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs index 111a05d816..0504ddb85b 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoUserManager.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Core.Security where TUser : UmbracoIdentityUser where TPasswordConfig : class, IPasswordConfiguration, new() { - private PasswordGenerator _passwordGenerator; + private PasswordGenerator? _passwordGenerator; /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs index aaaaed55e7..ef10380785 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Core.Security [EditorBrowsable(EditorBrowsableState.Never)] public override IQueryable Users => throw new NotImplementedException(); - protected static int UserIdToInt(string userId) + protected static int UserIdToInt(string? userId) { if(int.TryParse(userId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { @@ -74,7 +74,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(normalizedRoleName)); } - IdentityUserRole userRole = user.Roles.SingleOrDefault(r => r.RoleId == normalizedRoleName); + IdentityUserRole? userRole = user.Roles.SingleOrDefault(r => r.RoleId == normalizedRoleName); if (userRole == null) { @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Core.Security } /// - public override Task GetSecurityStampAsync(TUser user, CancellationToken cancellationToken = default) + public override Task GetSecurityStampAsync(TUser user, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -129,7 +129,7 @@ namespace Umbraco.Cms.Core.Security // the stamp cannot be null, so if it is currently null then we'll just return a hash of the password return Task.FromResult(user.SecurityStamp.IsNullOrWhiteSpace() - ? user.PasswordHash.GenerateHash() + ? user.PasswordHash?.GenerateHash() : user.SecurityStamp); } @@ -198,7 +198,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(normalizedRoleName)); } - IdentityUserRole userRole = user.Roles.SingleOrDefault(r => r.RoleId == normalizedRoleName); + IdentityUserRole? userRole = user.Roles.SingleOrDefault(r => r.RoleId == normalizedRoleName); if (userRole != null) { diff --git a/src/Umbraco.Infrastructure/Serialization/AutoInterningStringConverter.cs b/src/Umbraco.Infrastructure/Serialization/AutoInterningStringConverter.cs index b8a6baaec8..222535d196 100644 --- a/src/Umbraco.Infrastructure/Serialization/AutoInterningStringConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/AutoInterningStringConverter.cs @@ -20,18 +20,18 @@ namespace Umbraco.Cms.Infrastructure.Serialization throw new NotImplementedException($"{nameof(AutoInterningStringConverter)} should not be used globally"); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; // Check is in case the value is a non-string literal such as an integer. var s = reader.TokenType == JsonToken.String - ? string.Intern((string)reader.Value) - : string.Intern((string)JToken.Load(reader)); + ? string.Intern((string)reader.Value!) + : string.Intern((string)JToken.Load(reader)!); return s; } public override bool CanWrite => false; - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException(); + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) => throw new NotImplementedException(); } } diff --git a/src/Umbraco.Infrastructure/Serialization/AutoInterningStringKeyCaseInsensitiveDictionaryConverter.cs b/src/Umbraco.Infrastructure/Serialization/AutoInterningStringKeyCaseInsensitiveDictionaryConverter.cs index cff3aa69a2..262c732e1d 100644 --- a/src/Umbraco.Infrastructure/Serialization/AutoInterningStringKeyCaseInsensitiveDictionaryConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/AutoInterningStringKeyCaseInsensitiveDictionaryConverter.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Serialization { } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.StartObject) { @@ -30,7 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Serialization switch (reader.TokenType) { case JsonToken.PropertyName: - var key = string.Intern(reader.Value.ToString()); + var key = string.Intern(reader.Value!.ToString()!); if (!reader.Read()) throw new Exception("Unexpected end when reading object."); diff --git a/src/Umbraco.Infrastructure/Serialization/ForceInt32Converter.cs b/src/Umbraco.Infrastructure/Serialization/ForceInt32Converter.cs index e6d8499910..71c879f746 100644 --- a/src/Umbraco.Infrastructure/Serialization/ForceInt32Converter.cs +++ b/src/Umbraco.Infrastructure/Serialization/ForceInt32Converter.cs @@ -11,16 +11,16 @@ namespace Umbraco.Cms.Infrastructure.Serialization return objectType == typeof (object) || objectType == typeof (int); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jsonValue = serializer.Deserialize(reader); - return jsonValue.Type == JTokenType.Integer + return jsonValue?.Type == JTokenType.Integer ? jsonValue.Value() : serializer.Deserialize(reader); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Infrastructure/Serialization/FuzzyBooleanConverter.cs b/src/Umbraco.Infrastructure/Serialization/FuzzyBooleanConverter.cs index b98e8c93a0..118abe3470 100644 --- a/src/Umbraco.Infrastructure/Serialization/FuzzyBooleanConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/FuzzyBooleanConverter.cs @@ -7,19 +7,19 @@ namespace Umbraco.Cms.Infrastructure.Serialization { public override bool CanWrite => false; - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotSupportedException(); } public override bool CanRead => true; - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var value = reader.Value; if (value is bool) return value; - switch (value.ToString().ToLower().Trim()) + switch (value?.ToString()?.ToLower().Trim()) { case "true": case "yes": diff --git a/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs b/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs index dd228ac008..a9ad6a900d 100644 --- a/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs +++ b/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs @@ -19,11 +19,11 @@ namespace Umbraco.Cms.Infrastructure.Serialization NullValueHandling = NullValueHandling.Ignore }; - public string Serialize(object input) => JsonConvert.SerializeObject(input, JsonSerializerSettings); + public string Serialize(object? input) => JsonConvert.SerializeObject(input, JsonSerializerSettings); - public T Deserialize(string input) => JsonConvert.DeserializeObject(input, JsonSerializerSettings); + public T? Deserialize(string input) => JsonConvert.DeserializeObject(input, JsonSerializerSettings); - public T DeserializeSubset(string input, string key) + public T? DeserializeSubset(string input, string key) { if (key == null) throw new ArgumentNullException(nameof(key)); diff --git a/src/Umbraco.Infrastructure/Serialization/JsonReadConverter.cs b/src/Umbraco.Infrastructure/Serialization/JsonReadConverter.cs index fe684bd784..028bfac767 100644 --- a/src/Umbraco.Infrastructure/Serialization/JsonReadConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/JsonReadConverter.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Serialization } /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { // Load JObject from stream var jObject = JObject.Load(reader); @@ -42,11 +42,11 @@ namespace Umbraco.Cms.Infrastructure.Serialization protected virtual void Deserialize(JObject jobject, T target, JsonSerializer serializer) { // Populate the object properties - serializer.Populate(jobject.CreateReader(), target); + serializer.Populate(jobject.CreateReader(), target!); } /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotSupportedException("JsonReadConverter instances do not support writing."); } diff --git a/src/Umbraco.Infrastructure/Serialization/JsonToStringConverter.cs b/src/Umbraco.Infrastructure/Serialization/JsonToStringConverter.cs index 3cf23154c8..3aa03f8cd6 100644 --- a/src/Umbraco.Infrastructure/Serialization/JsonToStringConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/JsonToStringConverter.cs @@ -9,12 +9,12 @@ namespace Umbraco.Cms.Infrastructure.Serialization /// internal class JsonToStringConverter : JsonConverter { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { throw new NotImplementedException(); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { if (reader.ValueType == typeof(string)) { diff --git a/src/Umbraco.Infrastructure/Serialization/KnownTypeUdiJsonConverter.cs b/src/Umbraco.Infrastructure/Serialization/KnownTypeUdiJsonConverter.cs index c79071bc8d..ee93430bad 100644 --- a/src/Umbraco.Infrastructure/Serialization/KnownTypeUdiJsonConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/KnownTypeUdiJsonConverter.cs @@ -12,12 +12,12 @@ namespace Umbraco.Cms.Infrastructure.Serialization return typeof(Udi).IsAssignableFrom(objectType); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue(value.ToString()); + writer.WriteValue(value?.ToString()); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jo = JToken.ReadFrom(reader); var val = jo.ToObject(); diff --git a/src/Umbraco.Infrastructure/Serialization/NoTypeConverterJsonConverter.cs b/src/Umbraco.Infrastructure/Serialization/NoTypeConverterJsonConverter.cs index 0b5c9acc49..a44116e360 100644 --- a/src/Umbraco.Infrastructure/Serialization/NoTypeConverterJsonConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/NoTypeConverterJsonConverter.cs @@ -40,12 +40,12 @@ namespace Umbraco.Cms.Infrastructure.Serialization return typeof(T).IsAssignableFrom(objectType); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { return JsonSerializer.CreateDefault(JsonSerializerSettings).Deserialize(reader, objectType); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { JsonSerializer.CreateDefault(JsonSerializerSettings).Serialize(writer, value); } diff --git a/src/Umbraco.Infrastructure/Serialization/UdiJsonConverter.cs b/src/Umbraco.Infrastructure/Serialization/UdiJsonConverter.cs index 0b1f74918b..ce63bbbb55 100644 --- a/src/Umbraco.Infrastructure/Serialization/UdiJsonConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/UdiJsonConverter.cs @@ -12,12 +12,12 @@ namespace Umbraco.Cms.Infrastructure.Serialization return typeof (Udi).IsAssignableFrom(objectType); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue(value.ToString()); + writer.WriteValue(value?.ToString()); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jo = JToken.ReadFrom(reader); var val = jo.ToObject(); diff --git a/src/Umbraco.Infrastructure/Serialization/UdiRangeJsonConverter.cs b/src/Umbraco.Infrastructure/Serialization/UdiRangeJsonConverter.cs index 4cf71b9c5a..88f084092e 100644 --- a/src/Umbraco.Infrastructure/Serialization/UdiRangeJsonConverter.cs +++ b/src/Umbraco.Infrastructure/Serialization/UdiRangeJsonConverter.cs @@ -12,12 +12,12 @@ namespace Umbraco.Cms.Infrastructure.Serialization return typeof(UdiRange).IsAssignableFrom(objectType); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue(value.ToString()); + writer.WriteValue(value?.ToString()); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var jo = JToken.ReadFrom(reader); var val = jo.ToObject(); diff --git a/src/Umbraco.Infrastructure/Services/IdKeyMap.cs b/src/Umbraco.Infrastructure/Services/IdKeyMap.cs index 0c6c57dbfd..c851408a6f 100644 --- a/src/Umbraco.Infrastructure/Services/IdKeyMap.cs +++ b/src/Umbraco.Infrastructure/Services/IdKeyMap.cs @@ -173,11 +173,11 @@ namespace Umbraco.Cms.Core.Services //if it's unknown don't include the nodeObjectType in the query if (umbracoObjectType == UmbracoObjectTypes.Unknown) { - val = _scopeAccessor.AmbientScope.Database.ExecuteScalar("SELECT id FROM umbracoNode WHERE uniqueId=@id", new { id = key}); + val = _scopeAccessor.AmbientScope?.Database.ExecuteScalar("SELECT id FROM umbracoNode WHERE uniqueId=@id", new { id = key}); } else { - val = _scopeAccessor.AmbientScope.Database.ExecuteScalar("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)", + val = _scopeAccessor.AmbientScope?.Database.ExecuteScalar("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)", new { id = key, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Cms.Core.Constants.ObjectTypes.IdReservation }); } scope.Complete(); @@ -215,12 +215,12 @@ namespace Umbraco.Cms.Core.Services return GetIdForKey(guidUdi.Guid, umbracoType); } - public Attempt GetUdiForId(int id, UmbracoObjectTypes umbracoObjectType) + public Attempt GetUdiForId(int id, UmbracoObjectTypes umbracoObjectType) { var keyAttempt = GetKeyForId(id, umbracoObjectType); return keyAttempt.Success - ? Attempt.Succeed(new GuidUdi(UdiEntityTypeHelper.FromUmbracoObjectType(umbracoObjectType), keyAttempt.Result)) - : Attempt.Fail(); + ? Attempt.Succeed(new GuidUdi(UdiEntityTypeHelper.FromUmbracoObjectType(umbracoObjectType), keyAttempt.Result)) + : Attempt.Fail(); } public Attempt GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType) @@ -261,11 +261,11 @@ namespace Umbraco.Cms.Core.Services //if it's unknown don't include the nodeObjectType in the query if (umbracoObjectType == UmbracoObjectTypes.Unknown) { - val = _scopeAccessor.AmbientScope.Database.ExecuteScalar("SELECT uniqueId FROM umbracoNode WHERE id=@id", new { id }); + val = _scopeAccessor.AmbientScope?.Database.ExecuteScalar("SELECT uniqueId FROM umbracoNode WHERE id=@id", new { id }); } else { - val = _scopeAccessor.AmbientScope.Database.ExecuteScalar("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)", + val = _scopeAccessor.AmbientScope?.Database.ExecuteScalar("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)", new { id, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Cms.Core.Constants.ObjectTypes.IdReservation }); } scope.Complete(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs index f62361a883..2b856ec98f 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Core.Services.Implement _isAvailable = new Lazy(DetermineIsAvailable); } - public void Add(AuditType type, int userId, int objectId, string entityType, string comment, string? parameters = null) + public void Add(AuditType type, int userId, int objectId, string? entityType, string comment, string? parameters = null) { using (var scope = ScopeProvider.CreateScope()) { @@ -156,7 +156,7 @@ namespace Umbraco.Cms.Core.Services.Implement } /// - public IAuditEntry Write(int performingUserId, string perfomingDetails, string performingIp, DateTime eventDateUtc, int affectedUserId, string affectedDetails, string eventType, string eventDetails) + public IAuditEntry Write(int performingUserId, string perfomingDetails, string performingIp, DateTime eventDateUtc, int affectedUserId, string? affectedDetails, string eventType, string eventDetails) { if (performingUserId < 0 && performingUserId != Cms.Core.Constants.Security.SuperUserId) throw new ArgumentOutOfRangeException(nameof(performingUserId)); if (string.IsNullOrWhiteSpace(perfomingDetails)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(perfomingDetails)); diff --git a/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs b/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs index a037cd1095..749924ecfc 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs @@ -218,7 +218,7 @@ namespace Umbraco.Cms.Core.Services.Implement } // Deserialize remote instructions & skip if it fails. - if (!TryDeserializeInstructions(instruction, out JArray jsonInstructions)) + if (!TryDeserializeInstructions(instruction, out JArray? jsonInstructions)) { lastId = instruction.Id; // skip continue; @@ -245,7 +245,7 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Attempts to deserialize the instructions to a JArray. /// - private bool TryDeserializeInstructions(CacheInstruction instruction, out JArray jsonInstructions) + private bool TryDeserializeInstructions(CacheInstruction instruction, out JArray? jsonInstructions) { try { @@ -265,17 +265,25 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Parses out the individual instructions to be processed. /// - private static List GetAllInstructions(IEnumerable jsonInstructions) + private static List GetAllInstructions(IEnumerable? jsonInstructions) { var result = new List(); - foreach (JToken jsonItem in jsonInstructions) + if (jsonInstructions is not null) + { + return result; + } + + foreach (JToken jsonItem in jsonInstructions!) { // Could be a JObject in which case we can convert to a RefreshInstruction. // Otherwise it could be another JArray - in which case we'll iterate that. if (jsonItem is JObject jsonObj) { - RefreshInstruction instruction = jsonObj.ToObject(); - result.Add(instruction); + RefreshInstruction? instruction = jsonObj.ToObject(); + if (instruction is not null) + { + result.Add(instruction); + } } else { @@ -402,19 +410,32 @@ namespace Umbraco.Cms.Core.Services.Implement refresher.Refresh(id); } - private void RefreshByIds(CacheRefresherCollection cacheRefreshers, Guid uniqueIdentifier, string jsonIds) + private void RefreshByIds(CacheRefresherCollection cacheRefreshers, Guid uniqueIdentifier, string? jsonIds) { ICacheRefresher refresher = GetRefresher(cacheRefreshers, uniqueIdentifier); - foreach (var id in JsonConvert.DeserializeObject(jsonIds)) + if (jsonIds is null) { - refresher.Refresh(id); + return; + } + + var ids = JsonConvert.DeserializeObject(jsonIds); + if (ids is not null) + { + foreach (var id in ids) + { + refresher.Refresh(id); + } } } - private void RefreshByJson(CacheRefresherCollection cacheRefreshers, Guid uniqueIdentifier, string jsonPayload) + private void RefreshByJson(CacheRefresherCollection cacheRefreshers, Guid uniqueIdentifier, string? jsonPayload) { IJsonCacheRefresher refresher = GetJsonRefresher(cacheRefreshers, uniqueIdentifier); - refresher.Refresh(jsonPayload); + if (jsonPayload is not null) + { + refresher.Refresh(jsonPayload); + } + } private void RemoveById(CacheRefresherCollection cacheRefreshers, Guid uniqueIdentifier, int id) @@ -425,7 +446,7 @@ namespace Umbraco.Cms.Core.Services.Implement private ICacheRefresher GetRefresher(CacheRefresherCollection cacheRefreshers, Guid id) { - ICacheRefresher refresher = cacheRefreshers[id]; + ICacheRefresher? refresher = cacheRefreshers[id]; if (refresher == null) { throw new InvalidOperationException("Cache refresher with ID \"" + id + "\" does not exist."); diff --git a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs index f52b1f5b05..54c171a1a6 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs @@ -58,7 +58,7 @@ namespace Umbraco.Cms.Core.Services.Implement #region Containers - public Attempt> CreateContainer(int parentId, Guid key, string name, int userId = Cms.Core.Constants.Security.SuperUserId) + public Attempt?> CreateContainer(int parentId, Guid key, string name, int userId = Cms.Core.Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -96,7 +96,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - public EntityContainer GetContainer(int containerId) + public EntityContainer? GetContainer(int containerId) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { @@ -142,7 +142,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - public Attempt SaveContainer(EntityContainer container, int userId = Cms.Core.Constants.Security.SuperUserId) + public Attempt SaveContainer(EntityContainer container, int userId = Cms.Core.Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); @@ -177,7 +177,7 @@ namespace Umbraco.Cms.Core.Services.Implement return OperationResult.Attempt.Succeed(evtMsgs); } - public Attempt DeleteContainer(int containerId, int userId = Cms.Core.Constants.Security.SuperUserId) + public Attempt DeleteContainer(int containerId, int userId = Cms.Core.Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -211,7 +211,7 @@ namespace Umbraco.Cms.Core.Services.Implement return OperationResult.Attempt.Succeed(evtMsgs); } - public Attempt> RenameContainer(int id, string name, int userId = Cms.Core.Constants.Security.SuperUserId) + public Attempt?> RenameContainer(int id, string name, int userId = Cms.Core.Constants.Security.SuperUserId) { var evtMsgs = EventMessagesFactory.Get(); using (var scope = ScopeProvider.CreateScope()) @@ -254,7 +254,7 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Name of the /// - public IDataType GetDataType(string name) + public IDataType? GetDataType(string name) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { @@ -269,7 +269,7 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Id of the /// - public IDataType GetDataType(int id) + public IDataType? GetDataType(int id) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { @@ -284,7 +284,7 @@ namespace Umbraco.Cms.Core.Services.Implement /// /// Unique guid Id of the DataType /// - public IDataType GetDataType(Guid id) + public IDataType? GetDataType(Guid id) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { @@ -326,7 +326,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - private void ConvertMissingEditorOfDataTypeToLabel(IDataType dataType) + private void ConvertMissingEditorOfDataTypeToLabel(IDataType? dataType) { if (dataType == null) { @@ -348,7 +348,7 @@ namespace Umbraco.Cms.Core.Services.Implement } } - public Attempt> Move(IDataType toMove, int parentId) + public Attempt?> Move(IDataType toMove, int parentId) { var evtMsgs = EventMessagesFactory.Get(); var moveInfo = new List>(); @@ -366,7 +366,7 @@ namespace Umbraco.Cms.Core.Services.Implement try { - EntityContainer container = null; + EntityContainer? container = null; if (parentId > 0) { container = _dataTypeContainerRepository.Get(parentId); @@ -492,10 +492,13 @@ namespace Umbraco.Cms.Core.Services.Implement { foreach (var propertyGroup in contentType.PropertyGroups) { - var types = propertyGroup.PropertyTypes.Where(x => x.DataTypeId == dataType.Id).ToList(); - foreach (var propertyType in types) + var types = propertyGroup.PropertyTypes?.Where(x => x.DataTypeId == dataType.Id).ToList(); + if (types is not null) { - propertyGroup.PropertyTypes.Remove(propertyType); + foreach (var propertyType in types) + { + propertyGroup.PropertyTypes?.Remove(propertyType); + } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs b/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs index 8cb981f5da..65ea915433 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs @@ -47,9 +47,9 @@ namespace Umbraco.Cms.Core.Services.Implement #region Installation - public CompiledPackage GetCompiledPackageInfo(XDocument xml) => _packageInstallation.ReadPackage(xml); + public CompiledPackage GetCompiledPackageInfo(XDocument? xml) => _packageInstallation.ReadPackage(xml); - public InstallationSummary InstallCompiledPackageData(XDocument packageXml, int userId = Constants.Security.SuperUserId) + public InstallationSummary InstallCompiledPackageData(XDocument? packageXml, int userId = Constants.Security.SuperUserId) { CompiledPackage compiledPackage = GetCompiledPackageInfo(packageXml); @@ -98,16 +98,16 @@ namespace Umbraco.Cms.Core.Services.Implement _createdPackages.Delete(id); } - public IEnumerable GetAllCreatedPackages() => _createdPackages.GetAll(); + public IEnumerable GetAllCreatedPackages() => _createdPackages.GetAll(); - public PackageDefinition GetCreatedPackageById(int id) => _createdPackages.GetById(id); + public PackageDefinition? GetCreatedPackageById(int id) => _createdPackages.GetById(id); public bool SaveCreatedPackage(PackageDefinition definition) => _createdPackages.SavePackage(definition); public string ExportCreatedPackage(PackageDefinition definition) => _createdPackages.ExportPackage(definition); - public InstalledPackage GetInstalledPackageByName(string packageName) - => GetAllInstalledPackages().Where(x => x.PackageName.InvariantEquals(packageName)).FirstOrDefault(); + public InstalledPackage? GetInstalledPackageByName(string packageName) + => GetAllInstalledPackages().Where(x => x.PackageName?.InvariantEquals(packageName) ?? false).FirstOrDefault(); public IEnumerable GetAllInstalledPackages() { @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Core.Services.Implement // Collect the package from the package migration plans foreach(PackageMigrationPlan plan in _packageMigrationPlans) { - if (!installedPackages.TryGetValue(plan.PackageName, out InstalledPackage installedPackage)) + if (!installedPackages.TryGetValue(plan.PackageName, out InstalledPackage? installedPackage)) { installedPackage = new InstalledPackage { @@ -141,7 +141,7 @@ namespace Umbraco.Cms.Core.Services.Implement // Collect and merge the packages from the manifests foreach(PackageManifest package in _manifestParser.GetManifests()) { - if (!installedPackages.TryGetValue(package.PackageName, out InstalledPackage installedPackage)) + if (!installedPackages.TryGetValue(package.PackageName, out InstalledPackage? installedPackage)) { installedPackage = new InstalledPackage { diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index 92968510fa..db81c3f79f 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Core.Services.Implement var regs = _serverRegistrationRepository.GetMany().ToArray(); var hasSchedulingPublisher = regs.Any(x => ((ServerRegistration) x).IsSchedulingPublisher); - var server = regs.FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); + var server = regs.FirstOrDefault(x => x.ServerIdentity?.InvariantEquals(serverIdentity) ?? false); if (server == null) { @@ -101,7 +101,7 @@ namespace Umbraco.Cms.Core.Services.Implement ((ServerRegistrationRepository) _serverRegistrationRepository).ClearCache(); // ensure we have up-to-date cache // ensure we have up-to-date cache - var server = _serverRegistrationRepository.GetMany().FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); + var server = _serverRegistrationRepository.GetMany().FirstOrDefault(x => x.ServerIdentity?.InvariantEquals(serverIdentity) ?? false); if (server == null) return; server.IsActive = server.IsSchedulingPublisher = false; _serverRegistrationRepository.Save(server); // will trigger a cache reload // will trigger a cache reload diff --git a/src/Umbraco.Infrastructure/Services/Implement/TwoFactorLoginService.cs b/src/Umbraco.Infrastructure/Services/Implement/TwoFactorLoginService.cs index cdcc6b19e9..da5190e27e 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/TwoFactorLoginService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/TwoFactorLoginService.cs @@ -57,14 +57,18 @@ namespace Umbraco.Cms.Core.Services var providersOnUser = (await _twoFactorLoginRepository.GetByUserOrMemberKeyAsync(userOrMemberKey)) .Select(x => x.ProviderName).ToArray(); - return providersOnUser.Where(IsKnownProviderName); + return providersOnUser.Where(IsKnownProviderName)!; } /// /// The provider needs to be registered as either a member provider or backoffice provider to show up. /// - private bool IsKnownProviderName(string providerName) + private bool IsKnownProviderName(string? providerName) { + if (providerName is null) + { + return false; + } if (_identityOptions.Value.Tokens.ProviderMap.ContainsKey(providerName)) { return true; @@ -85,14 +89,14 @@ namespace Umbraco.Cms.Core.Services } /// - public async Task GetSecretForUserAndProviderAsync(Guid userOrMemberKey, string providerName) + public async Task GetSecretForUserAndProviderAsync(Guid userOrMemberKey, string providerName) { using IScope scope = _scopeProvider.CreateScope(autoComplete: true); return (await _twoFactorLoginRepository.GetByUserOrMemberKeyAsync(userOrMemberKey)).FirstOrDefault(x => x.ProviderName == providerName)?.Secret; } /// - public async Task GetSetupInfoAsync(Guid userOrMemberKey, string providerName) + public async Task GetSetupInfoAsync(Guid userOrMemberKey, string providerName) { var secret = await GetSecretForUserAndProviderAsync(userOrMemberKey, providerName); @@ -104,7 +108,7 @@ namespace Umbraco.Cms.Core.Services secret = GenerateSecret(); - if (!_twoFactorSetupGenerators.TryGetValue(providerName, out ITwoFactorProvider generator)) + if (!_twoFactorSetupGenerators.TryGetValue(providerName, out ITwoFactorProvider? generator)) { throw new InvalidOperationException($"No ITwoFactorSetupGenerator found for provider: {providerName}"); } @@ -125,7 +129,7 @@ namespace Umbraco.Cms.Core.Services /// public bool ValidateTwoFactorSetup(string providerName, string secret, string code) { - if (!_twoFactorSetupGenerators.TryGetValue(providerName, out ITwoFactorProvider generator)) + if (!_twoFactorSetupGenerators.TryGetValue(providerName, out ITwoFactorProvider? generator)) { throw new InvalidOperationException($"No ITwoFactorSetupGenerator found for provider: {providerName}"); } diff --git a/src/Umbraco.Infrastructure/Suspendable.cs b/src/Umbraco.Infrastructure/Suspendable.cs index 022a641094..15f6ce4330 100644 --- a/src/Umbraco.Infrastructure/Suspendable.cs +++ b/src/Umbraco.Infrastructure/Suspendable.cs @@ -49,8 +49,8 @@ namespace Umbraco.Cms.Infrastructure s_tried = false; - ICacheRefresher pageRefresher = cacheRefresherCollection[ContentCacheRefresher.UniqueId]; - pageRefresher.RefreshAll(); + ICacheRefresher? pageRefresher = cacheRefresherCollection[ContentCacheRefresher.UniqueId]; + pageRefresher?.RefreshAll(); } } diff --git a/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs index bc58342d82..420cac9d27 100644 --- a/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/BatchedDatabaseServerMessenger.cs @@ -45,11 +45,11 @@ namespace Umbraco.Cms.Infrastructure.Sync } /// - protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) + protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable? ids = null, string? json = null) { var idsA = ids?.ToArray(); - if (GetArrayType(idsA, out Type arrayType) == false) + if (GetArrayType(idsA, out Type? arrayType) == false) { throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids)); } @@ -60,7 +60,7 @@ namespace Umbraco.Cms.Infrastructure.Sync /// public override void SendMessages() { - ICollection batch = GetBatch(false); + ICollection? batch = GetBatch(false); if (batch == null) { return; @@ -72,7 +72,7 @@ namespace Umbraco.Cms.Infrastructure.Sync CacheInstructionService.DeliverInstructionsInBatches(instructions, LocalIdentity); } - private ICollection GetBatch(bool create) + private ICollection? GetBatch(bool create) { var key = nameof(BatchedDatabaseServerMessenger); @@ -82,7 +82,7 @@ namespace Umbraco.Cms.Infrastructure.Sync } // No thread-safety here because it'll run in only 1 thread (request) at a time. - var batch = (ICollection)_requestCache.Get(key); + var batch = (ICollection?)_requestCache.Get(key); if (batch == null && create) { batch = new List(); @@ -95,11 +95,11 @@ namespace Umbraco.Cms.Infrastructure.Sync private void BatchMessage( ICacheRefresher refresher, MessageType messageType, - IEnumerable ids = null, - Type idType = null, - string json = null) + IEnumerable? ids = null, + Type? idType = null, + string? json = null) { - ICollection batch = GetBatch(true); + ICollection? batch = GetBatch(true); IEnumerable instructions = RefreshInstruction.GetInstructions(refresher, JsonSerializer, messageType, ids, idType, json); // Batch if we can, else write to DB immediately. diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index b6dcc4d432..065b9b8640 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -122,12 +122,12 @@ namespace Umbraco.Cms.Infrastructure.Sync protected override void DeliverRemote( ICacheRefresher refresher, MessageType messageType, - IEnumerable ids = null, - string json = null) + IEnumerable? ids = null, + string? json = null) { var idsA = ids?.ToArray(); - if (GetArrayType(idsA, out Type idType) == false) + if (GetArrayType(idsA, out Type? idType) == false) { throw new ArgumentException("All items must be of the same type, either int or Guid.", nameof(ids)); } diff --git a/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs b/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs index 462eb88239..134b5c9a92 100644 --- a/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs +++ b/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs @@ -9,9 +9,9 @@ namespace Umbraco.Cms.Infrastructure.Sync { public sealed class LastSyncedFileManager { - private string _distCacheFile; + private string? _distCacheFile; private bool _lastIdReady; - private object _lastIdLock; + private object? _lastIdLock; private int _lastId; private readonly IHostingEnvironment _hostingEnvironment; @@ -24,6 +24,10 @@ namespace Umbraco.Cms.Infrastructure.Sync /// The id. public void SaveLastSyncedId(int id) { + if (_lastIdLock is null) + { + return; + } lock (_lastIdLock) { if (!_lastIdReady) diff --git a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs index 536d1d9aa0..9692dcc8b5 100644 --- a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs +++ b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Sync } // ensures that all items in the enumerable are of the same type, either int or Guid. - protected static bool GetArrayType(IEnumerable ids, out Type arrayType) + protected static bool GetArrayType(IEnumerable? ids, out Type? arrayType) { arrayType = null; if (ids == null) return true; @@ -176,7 +176,7 @@ namespace Umbraco.Cms.Infrastructure.Sync /// /// Since this is only for non strongly typed it will throw for message types that by instance /// - protected void DeliverLocal(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) + protected void DeliverLocal(ICacheRefresher refresher, MessageType messageType, IEnumerable? ids = null, string? json = null) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); @@ -205,7 +205,10 @@ namespace Umbraco.Cms.Infrastructure.Sync var jsonRefresher = refresher as IJsonCacheRefresher; if (jsonRefresher == null) throw new InvalidOperationException("The cache refresher " + refresher.GetType() + " is not of type " + typeof(IJsonCacheRefresher)); - jsonRefresher.Refresh(json); + if (json is not null) + { + jsonRefresher.Refresh(json); + } break; case MessageType.RemoveById: @@ -283,7 +286,7 @@ namespace Umbraco.Cms.Infrastructure.Sync // refresher.Notify(payload); //} - protected abstract void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null); + protected abstract void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable? ids = null, string? json = null); //protected abstract void DeliverRemote(ICacheRefresher refresher, object payload); @@ -304,7 +307,7 @@ namespace Umbraco.Cms.Infrastructure.Sync DeliverRemote(refresher, MessageType.RefreshByJson, null, json); } - protected virtual void Deliver(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) + protected virtual void Deliver(ICacheRefresher refresher, MessageType messageType, IEnumerable? ids = null, string? json = null) { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); diff --git a/src/Umbraco.Infrastructure/Sync/SyncBootStateAccessor.cs b/src/Umbraco.Infrastructure/Sync/SyncBootStateAccessor.cs index ff6823177a..4fb7ca59d5 100644 --- a/src/Umbraco.Infrastructure/Sync/SyncBootStateAccessor.cs +++ b/src/Umbraco.Infrastructure/Sync/SyncBootStateAccessor.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Sync private SyncBootState _syncBootState; private bool _syncBootStateReady; - private object _syncBootStateLock; + private object? _syncBootStateLock; public SyncBootStateAccessor( ILogger logger, diff --git a/src/Umbraco.Infrastructure/TagQuery.cs b/src/Umbraco.Infrastructure/TagQuery.cs index 284416d9d4..b54d6e38d8 100644 --- a/src/Umbraco.Infrastructure/TagQuery.cs +++ b/src/Umbraco.Infrastructure/TagQuery.cs @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Core } /// - public IEnumerable GetContentByTag(string tag, string group = null, string? culture = null) + public IEnumerable GetContentByTag(string tag, string? group = null, string? culture = null) { var ids = _tagService.GetTaggedContentByTag(tag, group, culture) .Select(x => x.EntityId); @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Core } /// - public IEnumerable GetMediaByTag(string tag, string group = null, string? culture = null) + public IEnumerable GetMediaByTag(string tag, string? group = null, string? culture = null) { var ids = _tagService.GetTaggedMediaByTag(tag, group, culture) .Select(x => x.EntityId); @@ -65,37 +65,37 @@ namespace Umbraco.Cms.Core } /// - public IEnumerable GetAllTags(string group = null, string? culture = null) + public IEnumerable GetAllTags(string? group = null, string? culture = null) { return _mapper.MapEnumerable(_tagService.GetAllTags(group, culture)); } /// - public IEnumerable GetAllContentTags(string group = null, string? culture = null) + public IEnumerable GetAllContentTags(string? group = null, string? culture = null) { return _mapper.MapEnumerable(_tagService.GetAllContentTags(group, culture)); } /// - public IEnumerable GetAllMediaTags(string group = null, string? culture = null) + public IEnumerable GetAllMediaTags(string? group = null, string? culture = null) { return _mapper.MapEnumerable(_tagService.GetAllMediaTags(group, culture)); } /// - public IEnumerable GetAllMemberTags(string group = null, string? culture = null) + public IEnumerable GetAllMemberTags(string? group = null, string? culture = null) { return _mapper.MapEnumerable(_tagService.GetAllMemberTags(group, culture)); } /// - public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null, string? culture = null) + public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string? group = null, string? culture = null) { return _mapper.MapEnumerable(_tagService.GetTagsForProperty(contentId, propertyTypeAlias, group, culture)); } /// - public IEnumerable GetTagsForEntity(int contentId, string group = null, string? culture = null) + public IEnumerable GetTagsForEntity(int contentId, string? group = null, string? culture = null) { return _mapper.MapEnumerable(_tagService.GetTagsForEntity(contentId, group, culture)); } diff --git a/src/Umbraco.Infrastructure/Trees/TreeRootNode.cs b/src/Umbraco.Infrastructure/Trees/TreeRootNode.cs index 63ad681969..7f006a056d 100644 --- a/src/Umbraco.Infrastructure/Trees/TreeRootNode.cs +++ b/src/Umbraco.Infrastructure/Trees/TreeRootNode.cs @@ -143,7 +143,7 @@ namespace Umbraco.Cms.Core.Models.Trees /// The node's children collection /// [DataMember(Name = "children")] - public TreeNodeCollection Children { get; private set; } + public TreeNodeCollection? Children { get; private set; } /// /// Returns true if there are any children @@ -152,6 +152,6 @@ namespace Umbraco.Cms.Core.Models.Trees /// This is used in the UI to configure a full screen section/app /// [DataMember(Name = "containsTrees")] - public bool ContainsTrees => Children.Count > 0 || !_isSingleNodeTree; + public bool ContainsTrees => Children?.Count > 0 || !_isSingleNodeTree; } } diff --git a/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs b/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs index 34c3f65652..37370d73d2 100644 --- a/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs +++ b/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs @@ -98,8 +98,8 @@ namespace Umbraco.Cms.Infrastructure.WebAssets // custom back office assets, and any scripts found in package manifests // that have the default bundle options. - IEnumerable jsAssets = (customAssets.TryGetValue(AssetType.Javascript, out IEnumerable customScripts) ? customScripts : Enumerable.Empty()) - .Union(propertyEditorAssets.TryGetValue(AssetType.Javascript, out IEnumerable scripts) ? scripts : Enumerable.Empty()); + IEnumerable jsAssets = (customAssets.TryGetValue(AssetType.Javascript, out IEnumerable? customScripts) ? customScripts : Enumerable.Empty()) + .Union(propertyEditorAssets.TryGetValue(AssetType.Javascript, out IEnumerable? scripts) ? scripts : Enumerable.Empty()); _runtimeMinifier.CreateJsBundle( UmbracoExtensionsJsBundleName, @@ -108,17 +108,17 @@ namespace Umbraco.Cms.Infrastructure.WebAssets GetScriptsForBackOfficeExtensions(jsAssets))); // Create a bundle per package manifest that is declaring an Independent bundle type - RegisterPackageBundlesForIndependentOptions(_parser.CombinedManifest.Scripts, AssetType.Javascript); + RegisterPackageBundlesForIndependentOptions(_parser.CombinedManifest?.Scripts, AssetType.Javascript); // Create a single non-optimized (no file processing) bundle for all manifests declaring None as a bundle option - RegisterPackageBundlesForNoneOption(_parser.CombinedManifest.Scripts, UmbracoNonOptimizedPackageJsBundleName); + RegisterPackageBundlesForNoneOption(_parser.CombinedManifest?.Scripts, UmbracoNonOptimizedPackageJsBundleName); // This bundle includes all CSS from property editor assets, // custom back office assets, and any CSS found in package manifests // that have the default bundle options. - IEnumerable cssAssets = (customAssets.TryGetValue(AssetType.Css, out IEnumerable customStyles) ? customStyles : Enumerable.Empty()) - .Union(propertyEditorAssets.TryGetValue(AssetType.Css, out IEnumerable styles) ? styles : Enumerable.Empty()); + IEnumerable cssAssets = (customAssets.TryGetValue(AssetType.Css, out IEnumerable? customStyles) ? customStyles : Enumerable.Empty()) + .Union(propertyEditorAssets.TryGetValue(AssetType.Css, out IEnumerable? styles) ? styles : Enumerable.Empty()); _runtimeMinifier.CreateCssBundle( UmbracoCssBundleName, @@ -127,23 +127,23 @@ namespace Umbraco.Cms.Infrastructure.WebAssets GetStylesheetsForBackOffice(cssAssets))); // Create a bundle per package manifest that is declaring an Independent bundle type - RegisterPackageBundlesForIndependentOptions(_parser.CombinedManifest.Stylesheets, AssetType.Css); + RegisterPackageBundlesForIndependentOptions(_parser.CombinedManifest?.Stylesheets, AssetType.Css); // Create a single non-optimized (no file processing) bundle for all manifests declaring None as a bundle option - RegisterPackageBundlesForNoneOption(_parser.CombinedManifest.Stylesheets, UmbracoNonOptimizedPackageCssBundleName); + RegisterPackageBundlesForNoneOption(_parser.CombinedManifest?.Stylesheets, UmbracoNonOptimizedPackageCssBundleName); } public static string GetIndependentPackageBundleName(ManifestAssets manifestAssets, AssetType assetType) => $"{manifestAssets.PackageName.ToLowerInvariant()}-{(assetType == AssetType.Css ? "css" : "js")}"; private void RegisterPackageBundlesForNoneOption( - IReadOnlyDictionary> combinedPackageManifestAssets, + IReadOnlyDictionary>? combinedPackageManifestAssets, string bundleName) { var assets = new HashSet(StringComparer.InvariantCultureIgnoreCase); // Create a bundle per package manifest that is declaring the matching BundleOptions - if (combinedPackageManifestAssets.TryGetValue(BundleOptions.None, out IReadOnlyList manifestAssetList)) + if (combinedPackageManifestAssets?.TryGetValue(BundleOptions.None, out IReadOnlyList? manifestAssetList) ?? false) { foreach(var asset in manifestAssetList.SelectMany(x => x.Assets)) { @@ -159,16 +159,16 @@ namespace Umbraco.Cms.Infrastructure.WebAssets } private void RegisterPackageBundlesForIndependentOptions( - IReadOnlyDictionary> combinedPackageManifestAssets, + IReadOnlyDictionary>? combinedPackageManifestAssets, AssetType assetType) { // Create a bundle per package manifest that is declaring the matching BundleOptions - if (combinedPackageManifestAssets.TryGetValue(BundleOptions.Independent, out IReadOnlyList manifestAssetList)) + if (combinedPackageManifestAssets?.TryGetValue(BundleOptions.Independent, out IReadOnlyList? manifestAssetList) ?? false) { foreach (ManifestAssets manifestAssets in manifestAssetList) { string bundleName = GetIndependentPackageBundleName(manifestAssets, assetType); - string[] filePaths = FormatPaths(manifestAssets.Assets.ToArray()); + string[]? filePaths = FormatPaths(manifestAssets.Assets.ToArray()); switch (assetType) { @@ -189,12 +189,12 @@ namespace Umbraco.Cms.Infrastructure.WebAssets /// Returns scripts used to load the back office /// /// - private string[] GetScriptsForBackOfficeExtensions(IEnumerable propertyEditorScripts) + private string[] GetScriptsForBackOfficeExtensions(IEnumerable propertyEditorScripts) { var scripts = new HashSet(StringComparer.InvariantCultureIgnoreCase); // only include scripts with the default bundle options here - if (_parser.CombinedManifest.Scripts.TryGetValue(BundleOptions.Default, out IReadOnlyList manifestAssets)) + if (_parser.CombinedManifest?.Scripts.TryGetValue(BundleOptions.Default, out IReadOnlyList? manifestAssets) ?? false) { foreach (string script in manifestAssets.SelectMany(x => x.Assets)) { @@ -202,9 +202,12 @@ namespace Umbraco.Cms.Infrastructure.WebAssets } } - foreach (string script in propertyEditorScripts) + foreach (string? script in propertyEditorScripts) { - scripts.Add(script); + if (script is not null) + { + scripts.Add(script); + } } return scripts.ToArray(); @@ -214,22 +217,22 @@ namespace Umbraco.Cms.Infrastructure.WebAssets /// Returns the list of scripts for back office initialization /// /// - private string[] GetScriptsForBackOfficeCore() + private string[]? GetScriptsForBackOfficeCore() { var resources = JsonConvert.DeserializeObject(Resources.JsInitialize); - return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()).ToArray(); + return resources?.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()).ToArray(); } /// /// Returns stylesheets used to load the back office /// /// - private string[] GetStylesheetsForBackOffice(IEnumerable propertyEditorStyles) + private string[] GetStylesheetsForBackOffice(IEnumerable propertyEditorStyles) { var stylesheets = new HashSet(StringComparer.InvariantCultureIgnoreCase); // only include css with the default bundle options here - if (_parser.CombinedManifest.Stylesheets.TryGetValue(BundleOptions.Default, out IReadOnlyList manifestAssets)) + if (_parser.CombinedManifest?.Stylesheets.TryGetValue(BundleOptions.Default, out IReadOnlyList? manifestAssets) ?? false) { foreach (string script in manifestAssets.SelectMany(x => x.Assets)) { @@ -237,9 +240,12 @@ namespace Umbraco.Cms.Infrastructure.WebAssets } } - foreach (string stylesheet in propertyEditorStyles) + foreach (string? stylesheet in propertyEditorStyles) { - stylesheets.Add(stylesheet); + if (stylesheet is not null) + { + stylesheets.Add(stylesheet); + } } return stylesheets.ToArray(); @@ -249,20 +255,20 @@ namespace Umbraco.Cms.Infrastructure.WebAssets /// Returns the scripts used for tinymce /// /// - private string[] GetScriptsForTinyMce() + private string[]? GetScriptsForTinyMce() { var resources = JsonConvert.DeserializeObject(Resources.TinyMceInitialize); - return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()).ToArray(); + return resources?.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()).ToArray(); } /// /// Returns the scripts used for preview /// /// - private string[] GetScriptsForPreview() + private string[]? GetScriptsForPreview() { var resources = JsonConvert.DeserializeObject(Resources.PreviewInitialize); - return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()).ToArray(); + return resources?.Where(x => x.Type == JTokenType.String).Select(x => x.ToString()).ToArray(); } /// @@ -270,11 +276,11 @@ namespace Umbraco.Cms.Infrastructure.WebAssets /// /// /// - private string[] FormatPaths(params string[] assets) + private string[]? FormatPaths(params string[]? assets) { var umbracoPath = _globalSettings.GetUmbracoMvcArea(_hostingEnvironment); - return assets + return assets? .Where(x => x.IsNullOrWhiteSpace() == false) .Select(x => !x.StartsWith("/") && Uri.IsWellFormedUriString(x, UriKind.Relative) // most declarations with be made relative to the /umbraco folder, so things