diff --git a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs index 940876dc75..e0bbd57397 100644 --- a/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs +++ b/src/Umbraco.Core/Cache/FastDictionaryAppCacheBase.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Core.Cache } /// - public abstract object Get(string key, Func factory); + public abstract object? Get(string key, Func factory); /// public virtual IEnumerable SearchByKey(string keyStartsWith) diff --git a/src/Umbraco.Core/Cache/SafeLazy.cs b/src/Umbraco.Core/Cache/SafeLazy.cs index e57ac21085..387e5c0271 100644 --- a/src/Umbraco.Core/Cache/SafeLazy.cs +++ b/src/Umbraco.Core/Cache/SafeLazy.cs @@ -27,22 +27,22 @@ namespace Umbraco.Cms.Core.Cache }); } - public static object? GetSafeLazyValue(Lazy lazy, bool onlyIfValueIsCreated = false) + public static object? GetSafeLazyValue(Lazy? lazy, bool onlyIfValueIsCreated = false) { // if onlyIfValueIsCreated, do not trigger value creation // must return something, though, to differentiate from null values - if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated; + if (onlyIfValueIsCreated && lazy?.IsValueCreated == false) return ValueNotCreated; // if execution has thrown then lazy.IsValueCreated is false // and lazy.IsValueFaulted is true (but internal) so we use our // own exception holder (see Lazy source code) to return null - if (lazy.Value is ExceptionHolder) return null; + if (lazy?.Value is ExceptionHolder) return null; // we have a value and execution has not thrown so returning // here does not throw - unless we're re-entering, take care of it try { - return lazy.Value; + return lazy?.Value; } catch (InvalidOperationException e) { diff --git a/src/Umbraco.Core/Composing/ComponentComposer.cs b/src/Umbraco.Core/Composing/ComponentComposer.cs index 00bfb0b00f..54b895ce49 100644 --- a/src/Umbraco.Core/Composing/ComponentComposer.cs +++ b/src/Umbraco.Core/Composing/ComponentComposer.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.Composing /// public virtual void Compose(IUmbracoBuilder builder) { - builder.Components().Append(); + builder.Components()?.Append(); } // note: thanks to this class, a component that does not compose anything can be diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs index 366a9bddcb..5cc38f31a7 100644 --- a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs +++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Core.Composing private List? _discovered; public DefaultUmbracoAssemblyProvider( - Assembly entryPointAssembly, + Assembly? entryPointAssembly, ILoggerFactory loggerFactory, IEnumerable? additionalTargetAssemblies = null) { diff --git a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs index f99670d888..56fda7bfeb 100644 --- a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs +++ b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Core.Configuration.Models; [UmbracoOptions("ConnectionStrings")] public class ConnectionStrings { - private string _connectionString; + private string? _connectionString; /// /// The default provider name when not present in configuration. @@ -22,12 +22,12 @@ public class ConnectionStrings /// public const string ProviderNamePostfix = "_ProviderName"; - public string Name { get; set; } + public string? Name { get; set; } - public string ConnectionString + public string? ConnectionString { get => _connectionString; - set => _connectionString = value.ReplaceDataDirectoryPlaceholder(); + set => _connectionString = value?.ReplaceDataDirectoryPlaceholder(); } public string? ProviderName { get; set; } = DefaultProviderName; diff --git a/src/Umbraco.Core/ContentApps/DictionaryContentAppFactory.cs b/src/Umbraco.Core/ContentApps/DictionaryContentAppFactory.cs index b1fb31d2aa..ae8a957df7 100644 --- a/src/Umbraco.Core/ContentApps/DictionaryContentAppFactory.cs +++ b/src/Umbraco.Core/ContentApps/DictionaryContentAppFactory.cs @@ -9,9 +9,9 @@ namespace Umbraco.Cms.Core.ContentApps { private const int Weight = -100; - private ContentApp _dictionaryApp; + private ContentApp? _dictionaryApp; - public ContentApp GetContentAppFor(object source, IEnumerable userGroups) + public ContentApp? GetContentAppFor(object source, IEnumerable userGroups) { switch (source) { diff --git a/src/Umbraco.Core/DependencyInjection/IScopedServiceProvider.cs b/src/Umbraco.Core/DependencyInjection/IScopedServiceProvider.cs index 3b5bf7aebb..d1fabe26db 100644 --- a/src/Umbraco.Core/DependencyInjection/IScopedServiceProvider.cs +++ b/src/Umbraco.Core/DependencyInjection/IScopedServiceProvider.cs @@ -14,6 +14,6 @@ namespace Umbraco.Cms.Core.DependencyInjection /// /// Can be null. /// - IServiceProvider ServiceProvider { get; } + IServiceProvider? ServiceProvider { get; } } } diff --git a/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs index 9351bb52cf..02b356a244 100644 --- a/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/IUmbracoBuilder.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.DependencyInjection IProfiler Profiler { get; } AppCaches AppCaches { get; } - TBuilder WithCollectionBuilder() where TBuilder : ICollectionBuilder; + TBuilder? WithCollectionBuilder() where TBuilder : ICollectionBuilder; void Build(); } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs index 1c5dddbc20..cb40974375 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.CollectionBuilders.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddComponent(this IUmbracoBuilder builder) where T : class, IComponent { - builder.Components().Append(); + builder.Components()?.Append(); return builder; } @@ -33,7 +33,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddContentApp(this IUmbracoBuilder builder) where T : class, IContentAppFactory { - builder.ContentApps().Append(); + builder.ContentApps()?.Append(); return builder; } @@ -45,7 +45,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddContentFinder(this IUmbracoBuilder builder) where T : class, IContentFinder { - builder.ContentFinders().Append(); + builder.ContentFinders()?.Append(); return builder; } @@ -57,7 +57,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddDashboard(this IUmbracoBuilder builder) where T : class, IDashboard { - builder.Dashboards().Add(); + builder.Dashboards()?.Add(); return builder; } @@ -69,7 +69,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddMediaUrlProvider(this IUmbracoBuilder builder) where T : class, IMediaUrlProvider { - builder.MediaUrlProviders().Append(); + builder.MediaUrlProviders()?.Append(); return builder; } @@ -81,7 +81,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddEmbedProvider(this IUmbracoBuilder builder) where T : class, IEmbedProvider { - builder.EmbedProviders().Append(); + builder.EmbedProviders()?.Append(); return builder; } @@ -97,7 +97,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddSection(this IUmbracoBuilder builder) where T : class, ISection { - builder.Sections().Append(); + builder.Sections()?.Append(); return builder; } @@ -109,7 +109,7 @@ namespace Umbraco.Cms.Core.DependencyInjection public static IUmbracoBuilder AddUrlProvider(this IUmbracoBuilder builder) where T : class, IUrlProvider { - builder.UrlProviders().Append(); + builder.UrlProviders()?.Append(); return builder; } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs index a0ff6104a7..f106536169 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs @@ -33,12 +33,12 @@ namespace Umbraco.Cms.Core.DependencyInjection /// internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder) { - builder.CacheRefreshers().Add(() => builder.TypeLoader.GetCacheRefreshers()); - builder.DataEditors().Add(() => builder.TypeLoader.GetDataEditors()); - builder.Actions().Add(() => builder .TypeLoader.GetActions()); + builder.CacheRefreshers()?.Add(() => builder.TypeLoader.GetCacheRefreshers()); + builder.DataEditors()?.Add(() => builder.TypeLoader.GetDataEditors()); + builder.Actions()?.Add(() => builder .TypeLoader.GetActions()); // register known content apps - builder.ContentApps() + builder.ContentApps()? .Append() .Append() .Append() @@ -51,24 +51,24 @@ namespace Umbraco.Cms.Core.DependencyInjection // all built-in finders in the correct order, // devs can then modify this list on application startup - builder.ContentFinders() + builder.ContentFinders()? .Append() .Append() .Append() /*.Append() // disabled, this is an odd finder */ .Append() .Append(); - builder.EditorValidators().Add(() => builder.TypeLoader.GetTypes()); - builder.HealthChecks().Add(() => builder.TypeLoader.GetTypes()); - builder.HealthCheckNotificationMethods().Add(() => builder.TypeLoader.GetTypes()); + builder.EditorValidators()?.Add(() => builder.TypeLoader.GetTypes()); + builder.HealthChecks()?.Add(() => builder.TypeLoader.GetTypes()); + builder.HealthCheckNotificationMethods()?.Add(() => builder.TypeLoader.GetTypes()); builder.TourFilters(); - builder.UrlProviders() + builder.UrlProviders()? .Append() .Append(); - builder.MediaUrlProviders() + builder.MediaUrlProviders()? .Append(); // register back office sections in the order we want them rendered - builder.Sections() + builder.Sections()? .Append() .Append() .Append() @@ -79,7 +79,7 @@ namespace Umbraco.Cms.Core.DependencyInjection .Append(); builder.Components(); // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards - builder.Dashboards() + builder.Dashboards()? .Add() .Add() .Add() @@ -93,9 +93,9 @@ namespace Umbraco.Cms.Core.DependencyInjection .Add() .Add(builder.TypeLoader.GetTypes()); builder.DataValueReferenceFactories(); - builder.PropertyValueConverters().Append(builder.TypeLoader.GetTypes()); - builder.UrlSegmentProviders().Append(); - builder.ManifestValueValidators() + builder.PropertyValueConverters()?.Append(builder.TypeLoader.GetTypes()); + builder.UrlSegmentProviders()?.Append(); + builder.ManifestValueValidators()? .Add() .Add() .Add() @@ -105,7 +105,7 @@ namespace Umbraco.Cms.Core.DependencyInjection builder.ManifestFilters(); builder.MediaUrlGenerators(); // register OEmbed providers - no type scanning - all explicit opt-in of adding types, IEmbedProvider is not IDiscoverable - builder.EmbedProviders() + builder.EmbedProviders()? .Append() .Append() .Append() @@ -119,7 +119,7 @@ namespace Umbraco.Cms.Core.DependencyInjection .Append() .Append() .Append(); - builder.SearchableTrees().Add(() => builder.TypeLoader.GetTypes()); + builder.SearchableTrees()?.Add(() => builder.TypeLoader.GetTypes()); builder.BackOfficeAssets(); } @@ -127,141 +127,141 @@ namespace Umbraco.Cms.Core.DependencyInjection /// Gets the actions collection builder. /// /// The builder. - public static ActionCollectionBuilder Actions(this IUmbracoBuilder builder) + public static ActionCollectionBuilder? Actions(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the content apps collection builder. /// /// The builder. - public static ContentAppFactoryCollectionBuilder ContentApps(this IUmbracoBuilder builder) + public static ContentAppFactoryCollectionBuilder? ContentApps(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the content finders collection builder. /// /// The builder. - public static ContentFinderCollectionBuilder ContentFinders(this IUmbracoBuilder builder) + public static ContentFinderCollectionBuilder? ContentFinders(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the editor validators collection builder. /// /// The builder. - public static EditorValidatorCollectionBuilder EditorValidators(this IUmbracoBuilder builder) + public static EditorValidatorCollectionBuilder? EditorValidators(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the health checks collection builder. /// /// The builder. - public static HealthCheckCollectionBuilder HealthChecks(this IUmbracoBuilder builder) + public static HealthCheckCollectionBuilder? HealthChecks(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); - public static HealthCheckNotificationMethodCollectionBuilder HealthCheckNotificationMethods(this IUmbracoBuilder builder) + public static HealthCheckNotificationMethodCollectionBuilder? HealthCheckNotificationMethods(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the TourFilters collection builder. /// - public static TourFilterCollectionBuilder TourFilters(this IUmbracoBuilder builder) + public static TourFilterCollectionBuilder? TourFilters(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the URL providers collection builder. /// /// The builder. - public static UrlProviderCollectionBuilder UrlProviders(this IUmbracoBuilder builder) + public static UrlProviderCollectionBuilder? UrlProviders(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the media url providers collection builder. /// /// The builder. - public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this IUmbracoBuilder builder) + public static MediaUrlProviderCollectionBuilder? MediaUrlProviders(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the backoffice sections/applications collection builder. /// /// The builder. - public static SectionCollectionBuilder Sections(this IUmbracoBuilder builder) + public static SectionCollectionBuilder? Sections(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the components collection builder. /// - public static ComponentCollectionBuilder Components(this IUmbracoBuilder builder) + public static ComponentCollectionBuilder? Components(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the backoffice dashboards collection builder. /// /// The builder. - public static DashboardCollectionBuilder Dashboards(this IUmbracoBuilder builder) + public static DashboardCollectionBuilder? Dashboards(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the cache refreshers collection builder. /// /// The builder. - public static CacheRefresherCollectionBuilder CacheRefreshers(this IUmbracoBuilder builder) + public static CacheRefresherCollectionBuilder? CacheRefreshers(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the map definitions collection builder. /// /// The builder. - public static MapDefinitionCollectionBuilder MapDefinitions(this IUmbracoBuilder builder) + public static MapDefinitionCollectionBuilder? MapDefinitions(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the data editor collection builder. /// /// The builder. - public static DataEditorCollectionBuilder DataEditors(this IUmbracoBuilder builder) + public static DataEditorCollectionBuilder? DataEditors(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the data value reference factory collection builder. /// /// The builder. - public static DataValueReferenceFactoryCollectionBuilder DataValueReferenceFactories(this IUmbracoBuilder builder) + public static DataValueReferenceFactoryCollectionBuilder? DataValueReferenceFactories(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the property value converters collection builder. /// /// The builder. - public static PropertyValueConverterCollectionBuilder PropertyValueConverters(this IUmbracoBuilder builder) + public static PropertyValueConverterCollectionBuilder? PropertyValueConverters(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the url segment providers collection builder. /// /// The builder. - public static UrlSegmentProviderCollectionBuilder UrlSegmentProviders(this IUmbracoBuilder builder) + public static UrlSegmentProviderCollectionBuilder? UrlSegmentProviders(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the validators collection builder. /// /// The builder. - internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this IUmbracoBuilder builder) + internal static ManifestValueValidatorCollectionBuilder? ManifestValueValidators(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the manifest filter collection builder. /// /// The builder. - public static ManifestFilterCollectionBuilder ManifestFilters(this IUmbracoBuilder builder) + public static ManifestFilterCollectionBuilder? ManifestFilters(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the content finders collection builder. /// /// The builder. - public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this IUmbracoBuilder builder) + public static MediaUrlGeneratorCollectionBuilder? MediaUrlGenerators(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// @@ -269,26 +269,26 @@ namespace Umbraco.Cms.Core.DependencyInjection /// /// The builder. [Obsolete("Use EmbedProviders() instead")] - public static EmbedProvidersCollectionBuilder OEmbedProviders(this IUmbracoBuilder builder) + public static EmbedProvidersCollectionBuilder? OEmbedProviders(this IUmbracoBuilder builder) => EmbedProviders(builder); /// /// Gets the backoffice Embed Providers collection builder. /// /// The builder. - public static EmbedProvidersCollectionBuilder EmbedProviders(this IUmbracoBuilder builder) + public static EmbedProvidersCollectionBuilder? EmbedProviders(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the back office searchable tree collection builder /// - public static SearchableTreeCollectionBuilder SearchableTrees(this IUmbracoBuilder builder) + public static SearchableTreeCollectionBuilder? SearchableTrees(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); /// /// Gets the back office custom assets collection builder /// - public static CustomBackOfficeAssetsCollectionBuilder BackOfficeAssets(this IUmbracoBuilder builder) + public static CustomBackOfficeAssetsCollectionBuilder? BackOfficeAssets(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); } } diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index 94b8b70c1b..3fefcbef97 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -49,7 +49,7 @@ namespace Umbraco.Cms.Core.DependencyInjection { public class UmbracoBuilder : IUmbracoBuilder { - private readonly Dictionary _builders = new Dictionary(); + private readonly Dictionary _builders = new Dictionary(); public IServiceCollection Services { get; } @@ -102,17 +102,17 @@ namespace Umbraco.Cms.Core.DependencyInjection /// /// The type of the collection builder. /// The collection builder. - public TBuilder WithCollectionBuilder() + public TBuilder? WithCollectionBuilder() where TBuilder : ICollectionBuilder { Type typeOfBuilder = typeof(TBuilder); if (_builders.TryGetValue(typeOfBuilder, out ICollectionBuilder? o)) { - return (TBuilder)o; + return (TBuilder?)o; } - TBuilder builder; + TBuilder? builder; if (typeof(TBuilder).GetConstructor(Type.EmptyTypes) != null) { @@ -121,7 +121,7 @@ namespace Umbraco.Cms.Core.DependencyInjection else if (typeof(TBuilder).GetConstructor(new[] { typeof(IUmbracoBuilder) }) != null) { // Handle those collection builders which need a reference to umbraco builder i.e. DistributedLockingCollectionBuilder. - builder = (TBuilder)Activator.CreateInstance(typeof(TBuilder), this); + builder = (TBuilder?)Activator.CreateInstance(typeof(TBuilder), this); } else { @@ -134,9 +134,9 @@ namespace Umbraco.Cms.Core.DependencyInjection public void Build() { - foreach (ICollectionBuilder builder in _builders.Values) + foreach (ICollectionBuilder? builder in _builders.Values) { - builder.RegisterWith(Services); + builder?.RegisterWith(Services); } _builders.Clear(); diff --git a/src/Umbraco.Core/Events/UserNotificationsHandler.cs b/src/Umbraco.Core/Events/UserNotificationsHandler.cs index 61bcde6a1b..96425e644f 100644 --- a/src/Umbraco.Core/Events/UserNotificationsHandler.cs +++ b/src/Umbraco.Core/Events/UserNotificationsHandler.cs @@ -169,7 +169,7 @@ namespace Umbraco.Cms.Core.Events SendNotification(user, entities, action, _hostingEnvironment.ApplicationMainUrl); } - private void SendNotification(IUser sender, IEnumerable entities, IAction? action, Uri siteUri) + private void SendNotification(IUser sender, IEnumerable entities, IAction? action, Uri? siteUri) { if (sender == null) throw new ArgumentNullException(nameof(sender)); diff --git a/src/Umbraco.Core/Exceptions/BootFailedException.cs b/src/Umbraco.Core/Exceptions/BootFailedException.cs index 9c4e484741..eeac07869d 100644 --- a/src/Umbraco.Core/Exceptions/BootFailedException.cs +++ b/src/Umbraco.Core/Exceptions/BootFailedException.cs @@ -58,7 +58,7 @@ namespace Umbraco.Cms.Core.Exceptions /// /// The exception can be null, in which case a default message is used. /// - public static void Rethrow(BootFailedException bootFailedException) + public static void Rethrow(BootFailedException? bootFailedException) { if (bootFailedException == null) throw new BootFailedException(DefaultMessage); diff --git a/src/Umbraco.Core/Extensions/ConnectionStringExtensions.cs b/src/Umbraco.Core/Extensions/ConnectionStringExtensions.cs index 6aa17055f9..6af569e514 100644 --- a/src/Umbraco.Core/Extensions/ConnectionStringExtensions.cs +++ b/src/Umbraco.Core/Extensions/ConnectionStringExtensions.cs @@ -18,7 +18,7 @@ namespace Umbraco.Extensions /// /// Gets a connection string from configuration with placeholders replaced. /// - public static string GetUmbracoConnectionString( + public static string? GetUmbracoConnectionString( this IConfiguration configuration, string connectionStringName = Constants.System.UmbracoConnectionName) => configuration.GetConnectionString(connectionStringName).ReplaceDataDirectoryPlaceholder(); @@ -26,7 +26,7 @@ namespace Umbraco.Extensions /// /// Replaces instances of the |DataDirectory| placeholder in a string with the value of AppDomain DataDirectory. /// - public static string ReplaceDataDirectoryPlaceholder(this string input) + public static string? ReplaceDataDirectoryPlaceholder(this string input) { var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString(); return input?.Replace(ConnectionStrings.DataDirectoryPlaceholder, dataDirectory); diff --git a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs index 64ec9f174b..63dfd5b884 100644 --- a/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/Extensions/PublishedContentExtensions.cs @@ -1054,7 +1054,7 @@ namespace Umbraco.Extensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable? Siblings(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) + public static IEnumerable? Siblings(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) { return SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture)?.Where(x => x.Id != content.Id); } @@ -1071,7 +1071,7 @@ namespace Umbraco.Extensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable? SiblingsOfType(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) + public static IEnumerable? SiblingsOfType(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) { return SiblingsAndSelfOfType(content, publishedSnapshot, variationContextAccessor, contentTypeAlias, culture)?.Where(x => x.Id != content.Id); } @@ -1088,7 +1088,7 @@ namespace Umbraco.Extensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable? Siblings(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) + public static IEnumerable? Siblings(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent { return SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture)?.Where(x => x.Id != content.Id); @@ -1102,11 +1102,11 @@ namespace Umbraco.Extensions /// Variation context accessor. /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The siblings of the content including the node itself. - public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) + public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) { return content.Parent != null ? content.Parent.Children(variationContextAccessor, culture) - : publishedSnapshot.Content.GetAtRoot().WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + : publishedSnapshot?.Content.GetAtRoot().WhereIsInvariantOrHasCulture(variationContextAccessor, culture); } /// @@ -1118,11 +1118,11 @@ namespace Umbraco.Extensions /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The content type alias. /// The siblings of the content including the node itself, of the given content type. - public static IEnumerable? SiblingsAndSelfOfType(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) + public static IEnumerable? SiblingsAndSelfOfType(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string? culture = null) { return content.Parent != null ? content.Parent.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture) - : publishedSnapshot.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + : publishedSnapshot?.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(variationContextAccessor, culture); } /// @@ -1134,12 +1134,12 @@ namespace Umbraco.Extensions /// Variation context accessor. /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The siblings of the content including the node itself, of the given content type. - public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) + public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot? publishedSnapshot, IVariationContextAccessor variationContextAccessor, string? culture = null) where T : class, IPublishedContent { return content.Parent != null ? content.Parent.Children(variationContextAccessor, culture) - : publishedSnapshot.Content.GetAtRoot().OfType().WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + : publishedSnapshot?.Content.GetAtRoot().OfType().WhereIsInvariantOrHasCulture(variationContextAccessor, culture); } #endregion diff --git a/src/Umbraco.Core/Features/UmbracoFeatures.cs b/src/Umbraco.Core/Features/UmbracoFeatures.cs index 8f08d25357..5b6bfd7bfb 100644 --- a/src/Umbraco.Core/Features/UmbracoFeatures.cs +++ b/src/Umbraco.Core/Features/UmbracoFeatures.cs @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Core.Features /// /// Determines whether a controller is enabled. /// - public bool IsControllerEnabled(Type feature) + public bool IsControllerEnabled(Type? feature) { if (typeof(IUmbracoFeature).IsAssignableFrom(feature)) return Disabled.Controllers.Contains(feature) == false; diff --git a/src/Umbraco.Core/HealthChecks/Checks/Security/BaseHttpHeaderCheck.cs b/src/Umbraco.Core/HealthChecks/Checks/Security/BaseHttpHeaderCheck.cs index bb60fd353c..daeea79f02 100644 --- a/src/Umbraco.Core/HealthChecks/Checks/Security/BaseHttpHeaderCheck.cs +++ b/src/Umbraco.Core/HealthChecks/Checks/Security/BaseHttpHeaderCheck.cs @@ -85,7 +85,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security var success = false; // Access the site home page and check for the click-jack protection header or meta tag - var url = _hostingEnvironment.ApplicationMainUrl.GetLeftPart(UriPartial.Authority); + var url = _hostingEnvironment.ApplicationMainUrl?.GetLeftPart(UriPartial.Authority); try { @@ -106,7 +106,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security } catch (Exception ex) { - message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url.ToString(), ex.Message }); + message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url?.ToString(), ex.Message }); } return diff --git a/src/Umbraco.Core/HealthChecks/Checks/Security/ExcessiveHeadersCheck.cs b/src/Umbraco.Core/HealthChecks/Checks/Security/ExcessiveHeadersCheck.cs index dbbf6b701f..99729286c5 100644 --- a/src/Umbraco.Core/HealthChecks/Checks/Security/ExcessiveHeadersCheck.cs +++ b/src/Umbraco.Core/HealthChecks/Checks/Security/ExcessiveHeadersCheck.cs @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security { string message; var success = false; - var url = _hostingEnvironment.ApplicationMainUrl.GetLeftPart(UriPartial.Authority); + var url = _hostingEnvironment.ApplicationMainUrl?.GetLeftPart(UriPartial.Authority); // Access the site home page and check for the headers var request = new HttpRequestMessage(HttpMethod.Head, url); @@ -80,7 +80,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security } catch (Exception ex) { - message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url.ToString(), ex.Message }); + message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url?.ToString(), ex.Message }); } return diff --git a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs index dedf809230..5b761211ac 100644 --- a/src/Umbraco.Core/Hosting/IHostingEnvironment.cs +++ b/src/Umbraco.Core/Hosting/IHostingEnvironment.cs @@ -85,6 +85,6 @@ namespace Umbraco.Cms.Core.Hosting /// /// Ensures that the application know its main Url. /// - void EnsureApplicationMainUrl(Uri currentApplicationUrl); + void EnsureApplicationMainUrl(Uri? currentApplicationUrl); } } diff --git a/src/Umbraco.Core/IO/FileSystemExtensions.cs b/src/Umbraco.Core/IO/FileSystemExtensions.cs index eb5edf127d..354ab33b2f 100644 --- a/src/Umbraco.Core/IO/FileSystemExtensions.cs +++ b/src/Umbraco.Core/IO/FileSystemExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Security.Cryptography; using System.Text; @@ -101,7 +102,7 @@ namespace Umbraco.Extensions /// /// true if the was successfully created; otherwise, false. /// - public static bool TryCreateFileProvider(this IFileSystem fileSystem, out IFileProvider? fileProvider) + public static bool TryCreateFileProvider(this IFileSystem fileSystem, [MaybeNullWhen(false)] out IFileProvider fileProvider) { fileProvider = fileSystem switch { diff --git a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs index 5263ac935f..15286d249f 100644 --- a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs +++ b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs @@ -39,7 +39,7 @@ namespace Umbraco.Cms.Core.Install.InstallSteps public override Task ExecuteAsync(object model) { _siteIdentifierService.TryCreateSiteIdentifier(out _); - return Task.FromResult(null); + return Task.FromResult(null); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Core/InstallLog.cs b/src/Umbraco.Core/InstallLog.cs index 245e917771..3d8ab26af9 100644 --- a/src/Umbraco.Core/InstallLog.cs +++ b/src/Umbraco.Core/InstallLog.cs @@ -13,10 +13,10 @@ namespace Umbraco.Cms.Core public int VersionPatch { get; } public string VersionComment { get; } public string Error { get; } - public string UserAgent { get; } + public string? UserAgent { get; } public string DbProvider { get; set; } - public InstallLog(Guid installId, bool isUpgrade, bool installCompleted, DateTime timestamp, int versionMajor, int versionMinor, int versionPatch, string versionComment, string error, string userAgent, string dbProvider) + public InstallLog(Guid installId, bool isUpgrade, bool installCompleted, DateTime timestamp, int versionMajor, int versionMinor, int versionPatch, string versionComment, string error, string? userAgent, string dbProvider) { InstallId = installId; IsUpgrade = isUpgrade; diff --git a/src/Umbraco.Core/Logging/IProfiler.cs b/src/Umbraco.Core/Logging/IProfiler.cs index d64cb49362..4b2bf6fc48 100644 --- a/src/Umbraco.Core/Logging/IProfiler.cs +++ b/src/Umbraco.Core/Logging/IProfiler.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.Logging /// The name of the step. /// A step. /// The returned is meant to be used within a using (...) {{ ... }} block. - IDisposable Step(string name); + IDisposable? Step(string name); /// /// Starts the profiler. diff --git a/src/Umbraco.Core/Logging/ProfilerExtensions.cs b/src/Umbraco.Core/Logging/ProfilerExtensions.cs index f3c18a0231..67739c2f38 100644 --- a/src/Umbraco.Core/Logging/ProfilerExtensions.cs +++ b/src/Umbraco.Core/Logging/ProfilerExtensions.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Logging /// The name of the step. /// A step. /// The returned is meant to be used within a using (...) {{ ... }} block. - internal static IDisposable Step(this IProfiler profiler, string name) + internal static IDisposable? Step(this IProfiler profiler, string name) { if (profiler == null) throw new ArgumentNullException(nameof(profiler)); return profiler.Step(typeof (T), name); @@ -28,7 +28,7 @@ namespace Umbraco.Cms.Core.Logging /// The name of the step. /// A step. /// The returned is meant to be used within a using (...) {{ ... }} block. - internal static IDisposable Step(this IProfiler profiler, Type reporting, string name) + internal static IDisposable? Step(this IProfiler profiler, Type reporting, string name) { if (profiler == null) throw new ArgumentNullException(nameof(profiler)); if (reporting == null) throw new ArgumentNullException(nameof(reporting)); diff --git a/src/Umbraco.Core/Macros/MacroPropertyModel.cs b/src/Umbraco.Core/Macros/MacroPropertyModel.cs index 1b59992f32..643d154f21 100644 --- a/src/Umbraco.Core/Macros/MacroPropertyModel.cs +++ b/src/Umbraco.Core/Macros/MacroPropertyModel.cs @@ -2,14 +2,16 @@ { public class MacroPropertyModel { - public string? Key { get; set; } + public string Key { get; set; } public string? Value { get; set; } public string? Type { get; set; } public MacroPropertyModel() - { } + { + Key = string.Empty; + } public MacroPropertyModel(string key, string value) { diff --git a/src/Umbraco.Core/Models/ContentModel.cs b/src/Umbraco.Core/Models/ContentModel.cs index e62f51fd16..cead39f019 100644 --- a/src/Umbraco.Core/Models/ContentModel.cs +++ b/src/Umbraco.Core/Models/ContentModel.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Core.Models /// /// Initializes a new instance of the class with a content. /// - public ContentModel(IPublishedContent content) => Content = content ?? throw new ArgumentNullException(nameof(content)); + public ContentModel(IPublishedContent? content) => Content = content ?? throw new ArgumentNullException(nameof(content)); /// /// Gets the content. diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs index 92c1b6cfe6..9c21cf5e80 100644 --- a/src/Umbraco.Core/Models/ContentType.cs +++ b/src/Umbraco.Core/Models/ContentType.cs @@ -64,8 +64,8 @@ namespace Umbraco.Cms.Core.Models /// we should not store direct entity /// [IgnoreDataMember] - public ITemplate DefaultTemplate => - AllowedTemplates.FirstOrDefault(x => x != null && x.Id == DefaultTemplateId); + public ITemplate? DefaultTemplate => + AllowedTemplates?.FirstOrDefault(x => x != null && x.Id == DefaultTemplateId); [DataMember] @@ -82,14 +82,14 @@ namespace Umbraco.Cms.Core.Models /// we should not store direct entity /// [DataMember] - public IEnumerable AllowedTemplates + public IEnumerable? AllowedTemplates { get => _allowedTemplates; set { SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, nameof(AllowedTemplates), TemplateComparer); - if (_allowedTemplates.Any(x => x.Id == _defaultTemplate) == false) + if (_allowedTemplates?.Any(x => x.Id == _defaultTemplate) == false) { DefaultTemplateId = 0; } @@ -170,6 +170,6 @@ namespace Umbraco.Cms.Core.Models (IContentType)DeepCloneWithResetIdentities(newAlias); /// - public override bool IsDirty() => base.IsDirty() || HistoryCleanup.IsDirty(); + public override bool IsDirty() => base.IsDirty() || (HistoryCleanup?.IsDirty() ?? false); } } diff --git a/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs index 6a2dd0d305..2610867a79 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs @@ -157,7 +157,7 @@ namespace Umbraco.Cms.Core.Models.Mapping } // We need to reset the dirty properties, because it is otherwise true, just because the json serializer has set properties - target.HistoryCleanup.ResetDirtyProperties(false); + target.HistoryCleanup!.ResetDirtyProperties(false); if (target.HistoryCleanup.PreventCleanup != source.HistoryCleanup.PreventCleanup) { target.HistoryCleanup.PreventCleanup = source.HistoryCleanup.PreventCleanup; @@ -558,8 +558,8 @@ namespace Umbraco.Cms.Core.Models.Mapping target.AllowedAsRoot = source.AllowAsRoot; - bool allowedContentTypesUnchanged = target.AllowedContentTypes.Select(x => x.Id.Value) - .SequenceEqual(source.AllowedContentTypes); + bool allowedContentTypesUnchanged = target.AllowedContentTypes?.Select(x => x.Id.Value) + .SequenceEqual(source.AllowedContentTypes) ?? false; if (allowedContentTypesUnchanged is false) { @@ -617,7 +617,7 @@ namespace Umbraco.Cms.Core.Models.Mapping // ensure no duplicate alias, then assign the group properties collection EnsureUniqueAliases(destProperties); - if (destGroup is not null && (destGroup.PropertyTypes.SupportsPublishing != isPublishing || destGroup.PropertyTypes.SequenceEqual(destProperties) is false)) + if (destGroup is not null && (destGroup.PropertyTypes?.SupportsPublishing != isPublishing || destGroup.PropertyTypes.SequenceEqual(destProperties) is false)) { destGroup.PropertyTypes = new PropertyTypeCollection(isPublishing, destProperties); destGroups.Add(destGroup); diff --git a/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs index f355cba47d..6d46ffc673 100644 --- a/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Models.Mapping public class DictionaryMapDefinition : IMapDefinition { private readonly ILocalizationService _localizationService; - private readonly CommonMapper _commonMapper; + private readonly CommonMapper? _commonMapper; [Obsolete("Use the constructor with the CommonMapper")] public DictionaryMapDefinition(ILocalizationService localizationService) diff --git a/src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs b/src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs index 82631776ba..9bb53cfc9e 100644 --- a/src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs @@ -121,7 +121,7 @@ namespace Umbraco.Cms.Core.Models.Mapping // check if this property is flagged as sensitive var isSensitiveProperty = memberType?.IsSensitiveProperty(prop.Alias) ?? false; // check permissions for viewing sensitive data - if (isSensitiveProperty && (_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.HasAccessToSensitiveData() == false)) + if (isSensitiveProperty && (_backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.HasAccessToSensitiveData() == false)) { // mark this property as sensitive prop.IsSensitive = true; diff --git a/src/Umbraco.Core/Models/PartialViewMacroModel.cs b/src/Umbraco.Core/Models/PartialViewMacroModel.cs index 1ab2078a76..662894b39f 100644 --- a/src/Umbraco.Core/Models/PartialViewMacroModel.cs +++ b/src/Umbraco.Core/Models/PartialViewMacroModel.cs @@ -11,9 +11,9 @@ namespace Umbraco.Cms.Core.Models public PartialViewMacroModel(IPublishedContent page, int macroId, - string macroAlias, - string macroName, - IDictionary macroParams) + string? macroAlias, + string? macroName, + IDictionary macroParams) { Content = page; MacroParameters = macroParams; @@ -23,9 +23,9 @@ namespace Umbraco.Cms.Core.Models } public IPublishedContent Content { get; } - public string MacroName { get; } - public string MacroAlias { get; } + public string? MacroName { get; } + public string? MacroAlias { get; } public int MacroId { get; } - public IDictionary MacroParameters { get; } + public IDictionary MacroParameters { get; } } } diff --git a/src/Umbraco.Core/Models/PartialViewMacroModelExtensions.cs b/src/Umbraco.Core/Models/PartialViewMacroModelExtensions.cs index 2bc1714dbd..aea801719f 100644 --- a/src/Umbraco.Core/Models/PartialViewMacroModelExtensions.cs +++ b/src/Umbraco.Core/Models/PartialViewMacroModelExtensions.cs @@ -16,7 +16,7 @@ namespace Umbraco.Extensions /// Parameter value if available, the default value that was passed otherwise. public static T? GetParameterValue(this PartialViewMacroModel partialViewMacroModel, string parameterAlias, T defaultValue) { - if (partialViewMacroModel.MacroParameters.ContainsKey(parameterAlias) == false || string.IsNullOrEmpty(partialViewMacroModel.MacroParameters[parameterAlias].ToString())) + if (partialViewMacroModel.MacroParameters.ContainsKey(parameterAlias) == false || string.IsNullOrEmpty(partialViewMacroModel.MacroParameters[parameterAlias]?.ToString())) return defaultValue; var attempt = partialViewMacroModel.MacroParameters[parameterAlias].TryConvertTo(typeof(T)); diff --git a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs index c5f5731b0c..0de838fa0e 100644 --- a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs @@ -50,25 +50,25 @@ namespace Umbraco.Cms.Core.Models.PublishedContent /// The type. /// The model types map. /// The actual CLR type. - public static Type Map(Type type, Dictionary modelTypes) + public static Type Map(Type type, Dictionary? modelTypes) => Map(type, modelTypes, false); - public static Type Map(Type type, Dictionary modelTypes, bool dictionaryIsInvariant) + public static Type Map(Type type, Dictionary? modelTypes, bool dictionaryIsInvariant) { // it may be that senders forgot to send an invariant dictionary (garbage-in) - if (!dictionaryIsInvariant) + if (modelTypes is not null && !dictionaryIsInvariant) modelTypes = new Dictionary(modelTypes, StringComparer.InvariantCultureIgnoreCase); if (type is ModelType modelType) { - if (modelTypes.TryGetValue(modelType.ContentTypeAlias, out var actualType)) + if (modelTypes?.TryGetValue(modelType.ContentTypeAlias, out var actualType) ?? false) return actualType; throw new InvalidOperationException($"Don't know how to map ModelType with content type alias \"{modelType.ContentTypeAlias}\"."); } if (type is ModelTypeArrayType arrayType) { - if (modelTypes.TryGetValue(arrayType.ContentTypeAlias, out var actualType)) + if (modelTypes?.TryGetValue(arrayType.ContentTypeAlias, out var actualType) ?? false) return actualType.MakeArrayType(); throw new InvalidOperationException($"Don't know how to map ModelType with content type alias \"{arrayType.ContentTypeAlias}\"."); } diff --git a/src/Umbraco.Core/Models/RelationItem.cs b/src/Umbraco.Core/Models/RelationItem.cs index f4e7e30aaf..75344914f0 100644 --- a/src/Umbraco.Core/Models/RelationItem.cs +++ b/src/Umbraco.Core/Models/RelationItem.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.Models public string? NodeName { get; set; } [DataMember(Name = "type")] - public string NodeType { get; set; } + public string? NodeType { get; set; } [DataMember(Name = "udi")] public Udi NodeUdi => Udi.Create(NodeType, NodeKey); diff --git a/src/Umbraco.Core/Net/IUserAgentProvider.cs b/src/Umbraco.Core/Net/IUserAgentProvider.cs index fdca8c1dbf..ba4f61b897 100644 --- a/src/Umbraco.Core/Net/IUserAgentProvider.cs +++ b/src/Umbraco.Core/Net/IUserAgentProvider.cs @@ -2,6 +2,6 @@ namespace Umbraco.Cms.Core.Net { public interface IUserAgentProvider { - string GetUserAgent(); + string? GetUserAgent(); } } diff --git a/src/Umbraco.Core/Notifications/MemberTwoFactorRequestedNotification.cs b/src/Umbraco.Core/Notifications/MemberTwoFactorRequestedNotification.cs index 980a531ffd..e06de2624e 100644 --- a/src/Umbraco.Core/Notifications/MemberTwoFactorRequestedNotification.cs +++ b/src/Umbraco.Core/Notifications/MemberTwoFactorRequestedNotification.cs @@ -4,11 +4,11 @@ namespace Umbraco.Cms.Core.Notifications { public class MemberTwoFactorRequestedNotification : INotification { - public MemberTwoFactorRequestedNotification(Guid memberKey) + public MemberTwoFactorRequestedNotification(Guid? memberKey) { MemberKey = memberKey; } - public Guid MemberKey { get; } + public Guid? MemberKey { get; } } } diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs index f4416f85ac..210739c6a2 100644 --- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs +++ b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.PublishedCache /// If is null, the snapshot is not previewing, else it /// is previewing, and what is or is not visible in preview depends on the content of the token, /// which is not specified and depends on the actual published snapshot service implementation. - IPublishedSnapshot CreatePublishedSnapshot(string previewToken); + IPublishedSnapshot CreatePublishedSnapshot(string? previewToken); /// /// Rebuilds internal database caches (but does not reload). diff --git a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs index cc080a0f44..bbf121b457 100644 --- a/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs +++ b/src/Umbraco.Core/PublishedCache/Internal/InternalPublishedSnapshotService.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.PublishedCache.Internal public Task CollectAsync() => Task.CompletedTask; - public IPublishedSnapshot CreatePublishedSnapshot(string previewToken) + public IPublishedSnapshot CreatePublishedSnapshot(string? previewToken) { if (previewToken.IsNullOrWhiteSpace()) { diff --git a/src/Umbraco.Core/Routing/DomainUtilities.cs b/src/Umbraco.Core/Routing/DomainUtilities.cs index c754fd6bb4..61b27c3723 100644 --- a/src/Umbraco.Core/Routing/DomainUtilities.cs +++ b/src/Umbraco.Core/Routing/DomainUtilities.cs @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Core.Routing /// one document per culture), and domains, withing the context of a current Uri, assign /// a culture to that document. /// - public static string? GetCultureFromDomains(int contentId, string contentPath, Uri current, IUmbracoContext umbracoContext, ISiteDomainMapper siteDomainMapper) + public static string? GetCultureFromDomains(int contentId, string contentPath, Uri? current, IUmbracoContext umbracoContext, ISiteDomainMapper siteDomainMapper) { if (umbracoContext == null) throw new InvalidOperationException("A current UmbracoContext is required."); @@ -51,11 +51,11 @@ namespace Umbraco.Cms.Core.Routing : DomainForNode(umbracoContext.Domains, siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current); var rootContentId = domain?.ContentId ?? -1; - var wcDomain = FindWildcardDomainInPath(umbracoContext.Domains.GetAll(true), contentPath, rootContentId); + var wcDomain = FindWildcardDomainInPath(umbracoContext.Domains?.GetAll(true), contentPath, rootContentId); if (wcDomain != null) return wcDomain.Culture; if (domain != null) return domain.Culture; - return umbracoContext.Domains.DefaultCulture; + return umbracoContext.Domains?.DefaultCulture; } #endregion diff --git a/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs b/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs index 44054a7ab4..e5a915d682 100644 --- a/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs +++ b/src/Umbraco.Core/Routing/IPublishedRequestBuilder.cs @@ -69,7 +69,7 @@ namespace Umbraco.Cms.Core.Routing /// /// Sets the culture for the request /// - IPublishedRequestBuilder SetCulture(string culture); + IPublishedRequestBuilder SetCulture(string? culture); /// /// Sets the found for the request diff --git a/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs b/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs index 6ed63d506c..128c81f605 100644 --- a/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs +++ b/src/Umbraco.Core/Routing/PublishedRequestBuilder.cs @@ -94,7 +94,7 @@ namespace Umbraco.Cms.Core.Routing } /// - public IPublishedRequestBuilder SetCulture(string culture) + public IPublishedRequestBuilder SetCulture(string? culture) { Culture = culture; return this; diff --git a/src/Umbraco.Core/Security/IBackofficeSecurity.cs b/src/Umbraco.Core/Security/IBackofficeSecurity.cs index 3bfcd8e1ee..3b3c956cd6 100644 --- a/src/Umbraco.Core/Security/IBackofficeSecurity.cs +++ b/src/Umbraco.Core/Security/IBackofficeSecurity.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Security // needed in most cases. Where an IUser is required this could be an ext method on the ClaimsIdentity/ClaimsPrincipal that passes in // an IUserService, like HttpContext.User.GetUmbracoUser(_userService); // This one isn't as easy to remove as the others below. - IUser CurrentUser { get; } + IUser? CurrentUser { get; } /// /// Gets the current user's id. diff --git a/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs b/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs index 2999ceacf4..7ef33ecdc6 100644 --- a/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs +++ b/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs @@ -2,6 +2,6 @@ namespace Umbraco.Cms.Core.Security { public interface IBackOfficeSecurityAccessor { - IBackOfficeSecurity BackOfficeSecurity { get; } + IBackOfficeSecurity? BackOfficeSecurity { get; } } } diff --git a/src/Umbraco.Core/Templates/IUmbracoComponentRenderer.cs b/src/Umbraco.Core/Templates/IUmbracoComponentRenderer.cs index f67ab0a729..bf521d7c6b 100644 --- a/src/Umbraco.Core/Templates/IUmbracoComponentRenderer.cs +++ b/src/Umbraco.Core/Templates/IUmbracoComponentRenderer.cs @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Core.Templates /// The content id /// The alias. /// The parameters. - Task RenderMacroAsync(int contentId, string alias, IDictionary parameters); + Task RenderMacroAsync(int contentId, string alias, IDictionary? parameters); /// /// Renders the macro with the specified alias, passing in the specified parameters. diff --git a/src/Umbraco.Core/Templates/UmbracoComponentRenderer.cs b/src/Umbraco.Core/Templates/UmbracoComponentRenderer.cs index 16f7a609c3..4aee8036a3 100644 --- a/src/Umbraco.Core/Templates/UmbracoComponentRenderer.cs +++ b/src/Umbraco.Core/Templates/UmbracoComponentRenderer.cs @@ -60,7 +60,7 @@ namespace Umbraco.Cms.Core.Templates public async Task RenderMacroAsync(int contentId, string alias, object parameters) => await RenderMacroAsync(contentId, alias, parameters.ToDictionary()); /// - public async Task RenderMacroAsync(int contentId, string alias, IDictionary parameters) + public async Task RenderMacroAsync(int contentId, string alias, IDictionary? parameters) { if (contentId == default) { @@ -91,7 +91,7 @@ namespace Umbraco.Cms.Core.Templates /// /// Renders the macro with the specified alias, passing in the specified parameters. /// - private async Task RenderMacroAsync(IPublishedContent content, string alias, IDictionary parameters) + private async Task RenderMacroAsync(IPublishedContent content, string alias, IDictionary? parameters) { if (content == null) { diff --git a/src/Umbraco.Core/Udi.cs b/src/Umbraco.Core/Udi.cs index c18bed7a90..2e141e2e66 100644 --- a/src/Umbraco.Core/Udi.cs +++ b/src/Umbraco.Core/Udi.cs @@ -91,9 +91,9 @@ namespace Umbraco.Cms.Core /// The entity type. /// The identifier. /// The Guid Udi for the entity type and identifier. - public static Udi Create(string entityType, Guid id) + public static Udi Create(string? entityType, Guid id) { - if (UdiParser.UdiTypes.TryGetValue(entityType, out var udiType) == false) + if (entityType is null || UdiParser.UdiTypes.TryGetValue(entityType, out var udiType) == false) throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType"); if (udiType != UdiType.GuidUdi) diff --git a/src/Umbraco.Core/Web/CookieManagerExtensions.cs b/src/Umbraco.Core/Web/CookieManagerExtensions.cs index d8c4396ab8..75014000bb 100644 --- a/src/Umbraco.Core/Web/CookieManagerExtensions.cs +++ b/src/Umbraco.Core/Web/CookieManagerExtensions.cs @@ -8,7 +8,7 @@ namespace Umbraco.Extensions { public static class CookieManagerExtensions { - public static string GetPreviewCookieValue(this ICookieManager cookieManager) + public static string? GetPreviewCookieValue(this ICookieManager cookieManager) { return cookieManager.GetCookieValue(Constants.Web.PreviewCookieName); } diff --git a/src/Umbraco.Core/Web/ICookieManager.cs b/src/Umbraco.Core/Web/ICookieManager.cs index 50a71bf135..730b78a705 100644 --- a/src/Umbraco.Core/Web/ICookieManager.cs +++ b/src/Umbraco.Core/Web/ICookieManager.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Core.Web public interface ICookieManager { void ExpireCookie(string cookieName); - string GetCookieValue(string cookieName); + string? GetCookieValue(string cookieName); void SetCookieValue(string cookieName, string value); bool HasCookie(string cookieName); } diff --git a/src/Umbraco.Core/Web/IRequestAccessor.cs b/src/Umbraco.Core/Web/IRequestAccessor.cs index 992b56b75c..9fb4e99d5c 100644 --- a/src/Umbraco.Core/Web/IRequestAccessor.cs +++ b/src/Umbraco.Core/Web/IRequestAccessor.cs @@ -17,6 +17,6 @@ namespace Umbraco.Cms.Core.Web /// /// Returns the current request uri /// - Uri GetRequestUrl(); + Uri? GetRequestUrl(); } } diff --git a/src/Umbraco.Core/Web/ISessionManager.cs b/src/Umbraco.Core/Web/ISessionManager.cs index f2bc0136d0..bd0cab9cd6 100644 --- a/src/Umbraco.Core/Web/ISessionManager.cs +++ b/src/Umbraco.Core/Web/ISessionManager.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Core.Web { public interface ISessionManager { - string GetSessionValue(string sessionName); + string? GetSessionValue(string sessionName); void SetSessionValue(string sessionName, string value); } } diff --git a/src/Umbraco.Core/Web/IUmbracoContext.cs b/src/Umbraco.Core/Web/IUmbracoContext.cs index a7b2402901..d591d23e70 100644 --- a/src/Umbraco.Core/Web/IUmbracoContext.cs +++ b/src/Umbraco.Core/Web/IUmbracoContext.cs @@ -45,14 +45,14 @@ namespace Umbraco.Cms.Core.Web /// /// Gets the domains cache. /// - IDomainCache Domains { get; } + IDomainCache? Domains { get; } /// /// Gets or sets the PublishedRequest object /// //// TODO: Can we refactor this so it's not a settable thing required for routing? //// The only nicer way would be to have a RouteRequest method directly on IUmbracoContext but that means adding another dep to the ctx/factory. - IPublishedRequest PublishedRequest { get; set; } + IPublishedRequest? PublishedRequest { get; set; } /// /// Gets a value indicating whether the request has debugging enabled diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs index c63094821c..7091b89cad 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs @@ -14,10 +14,10 @@ namespace Umbraco.Extensions /// Gets the mappers collection builder. /// /// The builder. - public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder) + public static MapperCollectionBuilder? Mappers(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); - public static NPocoMapperCollectionBuilder NPocoMappers(this IUmbracoBuilder builder) + public static NPocoMapperCollectionBuilder? NPocoMappers(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); @@ -25,7 +25,7 @@ namespace Umbraco.Extensions /// Gets the package migration plans collection builder. /// /// The builder. - public static PackageMigrationPlanCollectionBuilder PackageMigrationPlans(this IUmbracoBuilder builder) + public static PackageMigrationPlanCollectionBuilder? PackageMigrationPlans(this IUmbracoBuilder builder) => builder.WithCollectionBuilder(); } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index 17ca813b3f..0c8b8c3343 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -73,8 +73,8 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(factory => factory.GetRequiredService().SqlContext); - builder.NPocoMappers().Add(); - builder.PackageMigrationPlans().Add(() => builder.TypeLoader.GetPackageMigrationPlans()); + builder.NPocoMappers()?.Add(); + builder.PackageMigrationPlans()?.Add(() => builder.TypeLoader.GetPackageMigrationPlans()); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -93,7 +93,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection // register persistence mappers - required by database factory so needs to be done here // means the only place the collection can be modified is in a runtime - afterwards it // has been frozen and it is too late - builder.Mappers().AddCoreMappers(); + builder.Mappers()?.AddCoreMappers(); // register the scope provider builder.Services.AddSingleton(); // implements IScopeProvider, IScopeAccessor @@ -117,7 +117,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection // register the manifest filter collection builder (collection is empty by default) builder.ManifestFilters(); - builder.MediaUrlGenerators() + builder.MediaUrlGenerators()? .Add() .Add(); @@ -147,7 +147,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection // both TinyMceValueConverter (in Core) and RteMacroRenderingValueConverter (in Web) will be // discovered when CoreBootManager configures the converters. We will remove the basic one defined // in core so that the more enhanced version is active. - builder.PropertyValueConverters() + builder.PropertyValueConverters()? .Remove(); // register *all* checks, except those marked [HideFromTypeFinder] of course @@ -263,7 +263,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection private static IUmbracoBuilder AddPreValueMigrators(this IUmbracoBuilder builder) { - builder.WithCollectionBuilder() + builder.WithCollectionBuilder()? .Append() .Append() .Append() diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs index 42ce7f7932..e1d58a32eb 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.MappingProfiles.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection { builder.Services.AddUnique(); - builder.WithCollectionBuilder() + builder.WithCollectionBuilder()? .Add() .Add() .Add() diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs index 0ee35852a2..a8e1360920 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValue.cs @@ -52,7 +52,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters /// /// Gets a crop. /// - public ImageCropperCrop? GetCrop(string alias) + public ImageCropperCrop? GetCrop(string? alias) { if (Crops == null) return null; @@ -228,7 +228,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters public override bool Equals(object? obj) => ReferenceEquals(this, obj) || obj is ImageCropperValue other && Equals(this, other); - private static bool Equals(ImageCropperValue left, ImageCropperValue? right) + private static bool Equals(ImageCropperValue? left, ImageCropperValue? right) => ReferenceEquals(left, right) // deals with both being null, too || !ReferenceEquals(left, null) && !ReferenceEquals(right, null) && string.Equals(left.Src, right.Src) @@ -238,10 +238,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters private IEnumerable ComparableCrops => Crops?.OrderBy(x => x.Alias) ?? Enumerable.Empty(); - public static bool operator ==(ImageCropperValue left, ImageCropperValue right) + public static bool operator ==(ImageCropperValue? left, ImageCropperValue? right) => Equals(left, right); - public static bool operator !=(ImageCropperValue left, ImageCropperValue right) + public static bool operator !=(ImageCropperValue? left, ImageCropperValue? right) => !Equals(left, right); public override int GetHashCode() @@ -330,7 +330,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters public override bool Equals(object? obj) => ReferenceEquals(this, obj) || obj is ImageCropperCrop other && Equals(this, other); - private static bool Equals(ImageCropperCrop left, ImageCropperCrop? right) + private static bool Equals(ImageCropperCrop? left, ImageCropperCrop? right) => ReferenceEquals(left, right) // deals with both being null, too || !ReferenceEquals(left, null) && !ReferenceEquals(right, null) && string.Equals(left.Alias, right.Alias) @@ -338,10 +338,10 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters && left.Height == right.Height && Equals(left.Coordinates, right.Coordinates); - public static bool operator ==(ImageCropperCrop left, ImageCropperCrop right) + public static bool operator ==(ImageCropperCrop? left, ImageCropperCrop? right) => Equals(left, right); - public static bool operator !=(ImageCropperCrop left, ImageCropperCrop right) + public static bool operator !=(ImageCropperCrop? left, ImageCropperCrop? right) => !Equals(left, right); public override int GetHashCode() @@ -387,7 +387,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters public override bool Equals(object? obj) => ReferenceEquals(this, obj) || obj is ImageCropperCropCoordinates other && Equals(this, other); - private static bool Equals(ImageCropperCropCoordinates left, ImageCropperCropCoordinates? right) + private static bool Equals(ImageCropperCropCoordinates? left, ImageCropperCropCoordinates? right) => ReferenceEquals(left, right) // deals with both being null, too || !ReferenceEquals(left, null) && !ReferenceEquals(right, null) && left.X1 == right.X1 @@ -395,7 +395,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters && left.Y1 == right.Y1 && left.Y2 == right.Y2; - public static bool operator ==(ImageCropperCropCoordinates left, ImageCropperCropCoordinates right) + public static bool operator ==(ImageCropperCropCoordinates? left, ImageCropperCropCoordinates? right) => Equals(left, right); public static bool operator !=(ImageCropperCropCoordinates left, ImageCropperCropCoordinates right) diff --git a/src/Umbraco.Infrastructure/Security/IMemberManager.cs b/src/Umbraco.Infrastructure/Security/IMemberManager.cs index d7558e163f..d9c636e2f7 100644 --- a/src/Umbraco.Infrastructure/Security/IMemberManager.cs +++ b/src/Umbraco.Infrastructure/Security/IMemberManager.cs @@ -14,13 +14,13 @@ namespace Umbraco.Cms.Core.Security /// /// /// - IPublishedContent AsPublishedMember(MemberIdentityUser user); + IPublishedContent? AsPublishedMember(MemberIdentityUser user); /// /// Returns the currently logged in member if there is one, else returns null /// /// - Task GetCurrentMemberAsync(); + Task GetCurrentMemberAsync(); /// /// Checks if the current member is authorized based on the parameters provided. diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 20df726080..80dfc8b73d 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -974,7 +974,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache } } - public IPublishedSnapshot CreatePublishedSnapshot(string previewToken) + public IPublishedSnapshot CreatePublishedSnapshot(string? previewToken) { EnsureCaches(); diff --git a/src/Umbraco.Web.Common/ActionsResults/PublishedContentNotFoundResult.cs b/src/Umbraco.Web.Common/ActionsResults/PublishedContentNotFoundResult.cs index 0eb30bcd03..417ed622bd 100644 --- a/src/Umbraco.Web.Common/ActionsResults/PublishedContentNotFoundResult.cs +++ b/src/Umbraco.Web.Common/ActionsResults/PublishedContentNotFoundResult.cs @@ -13,12 +13,12 @@ namespace Umbraco.Cms.Web.Common.ActionsResults public class PublishedContentNotFoundResult : IActionResult { private readonly IUmbracoContext _umbracoContext; - private readonly string _message; + private readonly string? _message; /// /// Initializes a new instance of the class. /// - public PublishedContentNotFoundResult(IUmbracoContext umbracoContext, string message = null) + public PublishedContentNotFoundResult(IUmbracoContext umbracoContext, string? message = null) { _umbracoContext = umbracoContext; _message = message; @@ -33,13 +33,13 @@ namespace Umbraco.Cms.Web.Common.ActionsResults response.StatusCode = StatusCodes.Status404NotFound; - IPublishedRequest frequest = _umbracoContext.PublishedRequest; + IPublishedRequest? frequest = _umbracoContext.PublishedRequest; var reason = "Cannot render the page at URL '{0}'."; - if (frequest.HasPublishedContent() == false) + if (frequest?.HasPublishedContent() == false) { reason = "No umbraco document matches the URL '{0}'."; } - else if (frequest.HasTemplate() == false) + else if (frequest?.HasTemplate() == false) { reason = "No template exists to render the document at URL '{0}'."; } diff --git a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs index 58f66a6fb8..fc9780016b 100644 --- a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs +++ b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs @@ -99,15 +99,18 @@ namespace Umbraco.Cms.Web.Common.ApplicationBuilder // Get media file provider and request path/URL var mediaFileManager = AppBuilder.ApplicationServices.GetRequiredService(); - if (mediaFileManager.FileSystem.TryCreateFileProvider(out IFileProvider mediaFileProvider)) + if (mediaFileManager.FileSystem.TryCreateFileProvider(out IFileProvider? mediaFileProvider)) { GlobalSettings globalSettings = AppBuilder.ApplicationServices.GetRequiredService>().Value; - IHostingEnvironment hostingEnvironment = AppBuilder.ApplicationServices.GetService(); - string mediaRequestPath = hostingEnvironment.ToAbsolute(globalSettings.UmbracoMediaPath); + IHostingEnvironment? hostingEnvironment = AppBuilder.ApplicationServices.GetService(); + string? mediaRequestPath = hostingEnvironment?.ToAbsolute(globalSettings.UmbracoMediaPath); // Configure custom file provider for media - IWebHostEnvironment webHostEnvironment = AppBuilder.ApplicationServices.GetService(); - webHostEnvironment.WebRootFileProvider = webHostEnvironment.WebRootFileProvider.ConcatComposite(new PrependBasePathFileProvider(mediaRequestPath, mediaFileProvider)); + IWebHostEnvironment? webHostEnvironment = AppBuilder.ApplicationServices.GetService(); + if (webHostEnvironment is not null) + { + webHostEnvironment.WebRootFileProvider = webHostEnvironment.WebRootFileProvider.ConcatComposite(new PrependBasePathFileProvider(mediaRequestPath, mediaFileProvider)); + } } AppBuilder.UseStaticFiles(); diff --git a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoPipelineFilter.cs b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoPipelineFilter.cs index 625cfc41d8..25d006634a 100644 --- a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoPipelineFilter.cs +++ b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoPipelineFilter.cs @@ -15,9 +15,9 @@ namespace Umbraco.Cms.Web.Common.ApplicationBuilder public UmbracoPipelineFilter( string name, - Action prePipeline, - Action postPipeline, - Action endpointCallback) + Action? prePipeline, + Action? postPipeline, + Action? endpointCallback) { Name = name ?? throw new ArgumentNullException(nameof(name)); PrePipeline = prePipeline; @@ -25,9 +25,9 @@ namespace Umbraco.Cms.Web.Common.ApplicationBuilder Endpoints = endpointCallback; } - public Action PrePipeline { get; set; } - public Action PostPipeline { get; set; } - public Action Endpoints { get; set; } + public Action? PrePipeline { get; set; } + public Action? PostPipeline { get; set; } + public Action? Endpoints { get; set; } public string Name { get; } public void OnPrePipeline(IApplicationBuilder app) => PrePipeline?.Invoke(app); diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs index f006fb03f4..7107ab3331 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore { private readonly IOptionsMonitor _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private string _getAbsoluteUrl; + private string? _getAbsoluteUrl; public AspNetCoreBackOfficeInfo(IOptionsMonitor globalSettings, IHostingEnvironment hostingEnviroment) { _globalSettings = globalSettings; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreCookieManager.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreCookieManager.cs index 1ba86eac0c..478e8aa13d 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreCookieManager.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreCookieManager.cs @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore }); } - public string GetCookieValue(string cookieName) + public string? GetCookieValue(string cookieName) { return _httpContextAccessor.HttpContext?.Request.Cookies[cookieName]; } diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs index 13f73e1b41..d672f2ae1c 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -21,8 +21,8 @@ namespace Umbraco.Cms.Web.Common.AspNetCore private readonly IOptionsMonitor _hostingSettings; private readonly IOptionsMonitor _webRoutingSettings; private readonly IWebHostEnvironment _webHostEnvironment; - private string _applicationId; - private string _localTempPath; + private string? _applicationId; + private string? _localTempPath; private UrlMode _urlProviderMode; public AspNetCoreHostingEnvironment( @@ -59,10 +59,10 @@ namespace Umbraco.Cms.Web.Common.AspNetCore public bool IsHosted { get; } = true; /// - public Uri ApplicationMainUrl { get; private set; } + public Uri ApplicationMainUrl { get; private set; } = null!; /// - public string SiteName { get; private set; } + public string SiteName { get; private set; } = null!; /// public string ApplicationId @@ -98,7 +98,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore /// public bool IsDebugMode => _hostingSettings.CurrentValue.Debug; - public Version IISVersion { get; } + public Version? IISVersion { get; } public string LocalTempPath { @@ -177,7 +177,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore return fullPath; } - public void EnsureApplicationMainUrl(Uri currentApplicationUrl) + public void EnsureApplicationMainUrl(Uri? currentApplicationUrl) { // Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that // it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part @@ -208,7 +208,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore } } - private void SetSiteName(string siteName) => + private void SetSiteName(string? siteName) => SiteName = string.IsNullOrWhiteSpace(siteName) ? _webHostEnvironment.ApplicationName : siteName; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCorePasswordHasher.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCorePasswordHasher.cs index a68b27ec86..17c1306789 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCorePasswordHasher.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCorePasswordHasher.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore public string HashPassword(string password) { - return _underlyingHasher.HashPassword(null, password); + return _underlyingHasher.HashPassword(null!, password); } } } diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs index d140b848c8..9924ae9109 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore private readonly IHttpContextAccessor _httpContextAccessor; private WebRoutingSettings _webRoutingSettings; private readonly ISet _applicationUrls = new HashSet(); - private Uri _currentApplicationUrl; + private Uri? _currentApplicationUrl; private object _initLocker = new object(); private bool _hasAppUrl = false; private bool _isInit = false; @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore /// public string GetRequestValue(string name) => GetFormValue(name) ?? GetQueryStringValue(name); - private string GetFormValue(string name) + private string? GetFormValue(string name) { var request = _httpContextAccessor.GetRequiredHttpContext().Request; if (!request.HasFormContentType) @@ -50,10 +50,10 @@ namespace Umbraco.Cms.Web.Common.AspNetCore public string GetQueryStringValue(string name) => _httpContextAccessor.GetRequiredHttpContext().Request.Query[name]; /// - public Uri GetRequestUrl() => _httpContextAccessor.HttpContext != null ? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()) : null; + public Uri? GetRequestUrl() => _httpContextAccessor.HttpContext != null ? new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()) : null; /// - public Uri GetApplicationUrl() + public Uri? GetApplicationUrl() { // Fixme: This causes problems with site swap on azure because azure pre-warms a site by calling into `localhost` and when it does that // it changes the URL to `localhost:80` which actually doesn't work for pinging itself, it only works internally in Azure. The ironic part @@ -76,8 +76,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore } var url = UriHelper.BuildAbsolute(request.Scheme, request.Host); - var change = url != null && !_applicationUrls.Contains(url); - if (change) + if (url != null && !_applicationUrls.Contains(url)) { _applicationUrls.Add(url); diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs index 9732d43e2d..a4d4e53a60 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore /// private bool IsSessionsAvailable => !(_httpContextAccessor.HttpContext?.Features.Get() is null); - public string SessionId + public string? SessionId { get { @@ -32,7 +32,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore } } - public string GetSessionValue(string sessionName) + public string? GetSessionValue(string sessionName) { if(!IsSessionsAvailable) return null; return _httpContextAccessor.HttpContext?.Session.GetString(sessionName); diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUserAgentProvider.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUserAgentProvider.cs index 8e94fc3b80..d8d23e32f6 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUserAgentProvider.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreUserAgentProvider.cs @@ -12,9 +12,9 @@ namespace Umbraco.Cms.Web.Common.AspNetCore _httpContextAccessor = httpContextAccessor; } - public string GetUserAgent() + public string? GetUserAgent() { - return _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString(); + return _httpContextAccessor.HttpContext?.Request.Headers["User-Agent"].ToString(); } } } diff --git a/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs b/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs index 283accb085..bc025d4f06 100644 --- a/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs +++ b/src/Umbraco.Web.Common/Authorization/FeatureAuthorizeHandler.cs @@ -42,15 +42,15 @@ namespace Umbraco.Cms.Web.Common.Authorization { case DefaultHttpContext defaultHttpContext: { - IEndpointFeature endpointFeature = defaultHttpContext.Features.Get(); - endpoint = endpointFeature.Endpoint; + IEndpointFeature? endpointFeature = defaultHttpContext.Features.Get(); + endpoint = endpointFeature?.Endpoint; break; } case Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext authorizationFilterContext: { - IEndpointFeature endpointFeature = authorizationFilterContext.HttpContext.Features.Get(); - endpoint = endpointFeature.Endpoint; + IEndpointFeature? endpointFeature = authorizationFilterContext.HttpContext.Features.Get(); + endpoint = endpointFeature?.Endpoint; break; } @@ -67,7 +67,7 @@ namespace Umbraco.Cms.Web.Common.Authorization } var actionDescriptor = endpoint.Metadata.GetMetadata(); - var controllerType = actionDescriptor.ControllerTypeInfo.AsType(); + var controllerType = actionDescriptor?.ControllerTypeInfo.AsType(); return _umbracoFeatures.IsControllerEnabled(controllerType); } } diff --git a/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs b/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs index 9e384879e3..6f4455dc74 100644 --- a/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs +++ b/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using Microsoft.AspNetCore.Http; @@ -31,14 +32,14 @@ namespace Umbraco.Cms.Core.Cache public bool IsAvailable => TryGetContextItems(out _); - private bool TryGetContextItems(out IDictionary items) + private bool TryGetContextItems([MaybeNullWhen(false)] out IDictionary items) { items = _httpContextAccessor.HttpContext?.Items; return items != null; } /// - public override object Get(string key, Func factory) + public override object? Get(string key, Func factory) { //no place to cache so just return the callback result if (!TryGetContextItems(out var items)) @@ -48,12 +49,12 @@ namespace Umbraco.Cms.Core.Cache key = GetCacheKey(key); - Lazy result; + Lazy? result; try { EnterWriteLock(); - result = items[key] as Lazy; // null if key not found + result = items[key] as Lazy; // null if key not found // cannot create value within the lock, so if result.IsValueCreated is false, just // do nothing here - means that if creation throws, a race condition could cause @@ -86,7 +87,7 @@ namespace Umbraco.Cms.Core.Cache return value; } - public bool Set(string key, object value) + public bool Set(string key, object? value) { //no place to cache so just return the callback result if (!TryGetContextItems(out var items)) @@ -151,7 +152,7 @@ namespace Umbraco.Cms.Core.Cache items.Remove(key); } - protected override object GetEntry(string key) + protected override object? GetEntry(string key) { return !TryGetContextItems(out var items) ? null : items[key]; } @@ -162,7 +163,7 @@ namespace Umbraco.Cms.Core.Cache protected override void EnterReadLock() { - object locker = GetLock(); + object? locker = GetLock(); if (locker == null) { return; @@ -172,7 +173,7 @@ namespace Umbraco.Cms.Core.Cache protected override void EnterWriteLock() { - object locker = GetLock(); + object? locker = GetLock(); if (locker == null) { return; @@ -182,7 +183,7 @@ namespace Umbraco.Cms.Core.Cache protected override void ExitReadLock() { - object locker = GetLock(); + object? locker = GetLock(); if (locker == null) { return; @@ -195,7 +196,7 @@ namespace Umbraco.Cms.Core.Cache protected override void ExitWriteLock() { - object locker = GetLock(); + object? locker = GetLock(); if (locker == null) { return; @@ -208,16 +209,16 @@ namespace Umbraco.Cms.Core.Cache #endregion - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { - if (!TryGetContextItems(out IDictionary items)) + if (!TryGetContextItems(out IDictionary? items)) { yield break; } - foreach (KeyValuePair item in items) + foreach (KeyValuePair item in items) { - yield return new KeyValuePair(item.Key.ToString(), item.Value); + yield return new KeyValuePair(item.Key.ToString()!, item.Value); } } @@ -227,15 +228,15 @@ namespace Umbraco.Cms.Core.Cache /// Ensures and returns the current lock /// /// - private object GetLock() + private object? GetLock() { - HttpContext httpContext = _httpContextAccessor.HttpContext; + HttpContext? httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) { return null; } - RequestLock requestLock = httpContext.Features.Get(); + RequestLock? requestLock = httpContext.Features.Get(); if (requestLock != null) { return requestLock.SyncRoot; diff --git a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs index 0d8c0833e1..4274a1ab16 100644 --- a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Web.Common.Controllers /// protected UmbracoRouteValues GetUmbracoRouteValues(ResultExecutingContext context) { - UmbracoRouteValues routeVals = context.HttpContext.Features.Get(); + UmbracoRouteValues? routeVals = context.HttpContext.Features.Get(); if (routeVals == null) { throw new InvalidOperationException($"No {nameof(UmbracoRouteValues)} feature was found in the HttpContext"); diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs index 4d74dd1767..46d3d4119d 100644 --- a/src/Umbraco.Web.Common/Controllers/RenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs @@ -93,8 +93,8 @@ namespace Umbraco.Cms.Web.Common.Controllers // set the redirect result and do not call next to short circuit context.Result = pcr.IsRedirectPermanent() - ? RedirectPermanent(pcr.RedirectUrl) - : Redirect(pcr.RedirectUrl); + ? RedirectPermanent(pcr.RedirectUrl!) + : Redirect(pcr.RedirectUrl!); break; case UmbracoRouteResult.NotFound: // set the redirect result and do not call next to short circuit @@ -107,10 +107,10 @@ namespace Umbraco.Cms.Web.Common.Controllers // If there it is means that we are proxying/executing this controller // from another controller and we need to merge it's ViewData with this one // since this one will be empty. - ProxyViewDataFeature saveViewData = HttpContext.Features.Get(); + ProxyViewDataFeature? saveViewData = HttpContext.Features.Get(); if (saveViewData != null) { - foreach (KeyValuePair kv in saveViewData.ViewData) + foreach (KeyValuePair kv in saveViewData.ViewData) { ViewData[kv.Key] = kv.Value; } diff --git a/src/Umbraco.Web.Common/Controllers/UmbracoPageController.cs b/src/Umbraco.Web.Common/Controllers/UmbracoPageController.cs index f9840df370..e10e3b5217 100644 --- a/src/Umbraco.Web.Common/Controllers/UmbracoPageController.cs +++ b/src/Umbraco.Web.Common/Controllers/UmbracoPageController.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Web.Common.Controllers /// public abstract class UmbracoPageController : UmbracoController { - private UmbracoRouteValues _umbracoRouteValues; + private UmbracoRouteValues? _umbracoRouteValues; private readonly ICompositeViewEngine _compositeViewEngine; private readonly ILogger _logger; @@ -52,7 +52,7 @@ namespace Umbraco.Cms.Web.Common.Controllers /// /// Gets the current content item. /// - protected virtual IPublishedContent CurrentPage + protected virtual IPublishedContent? CurrentPage { get { @@ -88,11 +88,11 @@ namespace Umbraco.Cms.Web.Common.Controllers /// Ensures that a physical view file exists on disk. /// /// The view name. - protected bool EnsurePhsyicalViewExists(string template) + protected bool EnsurePhsyicalViewExists(string? template) { if (string.IsNullOrWhiteSpace(template)) { - string docTypeAlias = UmbracoRouteValues.PublishedRequest.PublishedContent.ContentType.Alias; + string? docTypeAlias = UmbracoRouteValues.PublishedRequest.PublishedContent?.ContentType.Alias; _logger.LogWarning("No physical template file was found for document type with alias {Alias}", docTypeAlias); return false; } diff --git a/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs b/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs index de660184f1..5c9cf017af 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs @@ -12,6 +12,6 @@ namespace Umbraco.Cms.Web.Common.DependencyInjection public ScopedServiceProvider(IHttpContextAccessor accessor) => _accessor = accessor; /// - public IServiceProvider ServiceProvider => _accessor.HttpContext?.RequestServices; + public IServiceProvider? ServiceProvider => _accessor.HttpContext?.RequestServices; } } diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs index 30331fd812..83144a7466 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs @@ -62,8 +62,11 @@ namespace Umbraco.Extensions var headers = context.Response.GetTypedHeaders(); var cacheControl = headers.CacheControl; - cacheControl.MustRevalidate = false; - cacheControl.Extensions.Add(new NameValueHeaderValue("immutable")); + if (cacheControl is not null) + { + cacheControl.MustRevalidate = false; + cacheControl.Extensions.Add(new NameValueHeaderValue("immutable")); + } headers.CacheControl = cacheControl; } @@ -71,7 +74,7 @@ namespace Umbraco.Extensions return Task.CompletedTask; }; }) - .Configure(options => options.CacheFolder = builder.BuilderHostingEnvironment.MapPathContentRoot(imagingSettings.Cache.CacheFolder)) + .Configure(options => options.CacheFolder = builder.BuilderHostingEnvironment?.MapPathContentRoot(imagingSettings.Cache.CacheFolder)) .AddProcessor(); // Configure middleware to use the registered/shared ImageSharp configuration diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 9f999e7167..5e2779e1dd 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -220,7 +220,7 @@ namespace Umbraco.Extensions return builder; } - public static IUmbracoBuilder AddMvcAndRazor(this IUmbracoBuilder builder, Action mvcBuilding = null) + public static IUmbracoBuilder AddMvcAndRazor(this IUmbracoBuilder builder, Action? mvcBuilding = null) { // TODO: We need to figure out if we can work around this because calling AddControllersWithViews modifies the global app and order is very important // this will directly affect developers who need to call that themselves. @@ -344,7 +344,7 @@ namespace Umbraco.Extensions builder.Services.AddUnique(); var umbracoApiControllerTypes = builder.TypeLoader.GetUmbracoApiControllers().ToList(); - builder.WithCollectionBuilder() + builder.WithCollectionBuilder()? .Add(umbracoApiControllerTypes); builder.Services.AddSingleton(); diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index 8f739ab542..fcd4dcb341 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -122,8 +122,12 @@ namespace Umbraco.Extensions pluginFolder, umbracoPluginSettings); - IWebHostEnvironment webHostEnvironment = app.ApplicationServices.GetService(); - webHostEnvironment.WebRootFileProvider = webHostEnvironment.WebRootFileProvider.ConcatComposite(new PrependBasePathFileProvider(Constants.SystemDirectories.AppPlugins, pluginFileProvider)); + IWebHostEnvironment? webHostEnvironment = app.ApplicationServices.GetService(); + + if (webHostEnvironment is not null) + { + webHostEnvironment.WebRootFileProvider = webHostEnvironment.WebRootFileProvider.ConcatComposite(new PrependBasePathFileProvider(Constants.SystemDirectories.AppPlugins, pluginFileProvider)); + } } return app; diff --git a/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs index 0fd5df73aa..c51a376145 100644 --- a/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/BlockListTemplateExtensions.cs @@ -11,7 +11,7 @@ namespace Umbraco.Extensions public const string DefaultFolder = "blocklist/"; public const string DefaultTemplate = "default"; - public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, BlockListModel model, string template = DefaultTemplate) + public static IHtmlContent GetBlockListHtml(this IHtmlHelper html, BlockListModel? model, string template = DefaultTemplate) { if (model?.Count == 0) return new HtmlString(string.Empty); diff --git a/src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs b/src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs index 055e15ef73..e3c38c00ca 100644 --- a/src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/CacheHelperExtensions.cs @@ -26,7 +26,7 @@ namespace Umbraco.Extensions /// used to cache the partial view, this key could change if it is cached by page or by member /// /// - public static IHtmlContent CachedPartialView( + public static IHtmlContent? CachedPartialView( this AppCaches appCaches, IHostingEnvironment hostingEnvironment, IUmbracoContext umbracoContext, @@ -35,7 +35,7 @@ namespace Umbraco.Extensions object model, TimeSpan cacheTimeout, string cacheKey, - ViewDataDictionary viewData = null + ViewDataDictionary? viewData = null ) { //disable cached partials in debug mode: http://issues.umbraco.org/issue/U4-5940 diff --git a/src/Umbraco.Web.Common/Extensions/ControllerActionEndpointConventionBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ControllerActionEndpointConventionBuilderExtensions.cs index 8da2e26b61..2436787296 100644 --- a/src/Umbraco.Web.Common/Extensions/ControllerActionEndpointConventionBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ControllerActionEndpointConventionBuilderExtensions.cs @@ -24,7 +24,7 @@ namespace Umbraco.Extensions if (convention.Metadata.OfType().FirstOrDefault()?.SuppressMatching != true) { // Get the controller action descriptor - ControllerActionDescriptor actionDescriptor = convention.Metadata.OfType().FirstOrDefault(); + ControllerActionDescriptor? actionDescriptor = convention.Metadata.OfType().FirstOrDefault(); if (actionDescriptor != null) { // This is more or less like the IApplicationModelProvider, it allows us to add filters, etc... to the ControllerActionDescriptor diff --git a/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs index c7b8190523..e984c3ae3f 100644 --- a/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs @@ -19,7 +19,7 @@ namespace Umbraco.Extensions string prefixPathSegment, string defaultAction = "Index", bool includeControllerNameInRoute = true, - object constraints = null) + object? constraints = null) { var controllerName = ControllerExtensions.GetControllerName(controllerType); @@ -75,7 +75,7 @@ namespace Umbraco.Extensions string prefixPathSegment, string defaultAction = "Index", bool includeControllerNameInRoute = true, - object constraints = null) + object? constraints = null) where T : ControllerBase => endpoints.MapUmbracoRoute(typeof(T), rootSegment, areaName, prefixPathSegment, defaultAction, includeControllerNameInRoute, constraints); @@ -89,7 +89,7 @@ namespace Umbraco.Extensions string areaName, bool isBackOffice, string defaultAction = "Index", - object constraints = null) + object? constraints = null) where T : ControllerBase => endpoints.MapUmbracoApiRoute(typeof(T), rootSegment, areaName, isBackOffice, defaultAction, constraints); @@ -103,7 +103,7 @@ namespace Umbraco.Extensions string areaName, bool isBackOffice, string defaultAction = "Index", - object constraints = null) + object? constraints = null) { string prefixPathSegment = isBackOffice ? areaName.IsNullOrWhiteSpace() @@ -130,7 +130,7 @@ namespace Umbraco.Extensions string areaName, string defaultAction = "Index", bool includeControllerNameInRoute = true, - object constraints = null) + object? constraints = null) { // If there is an area name it's a plugin controller, and we should use the area name instead of surface string prefixPathSegment = areaName.IsNullOrWhiteSpace() ? "Surface" : areaName; diff --git a/src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs index 6a35f43758..a1d6ab4977 100644 --- a/src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs @@ -68,7 +68,7 @@ namespace Umbraco.Extensions /// /// /// - public static T GetValue(this FormCollection items, string key) + public static T? GetValue(this FormCollection items, string key) { if (items.TryGetValue(key, out var val) == false || string.IsNullOrEmpty(val)) { @@ -97,7 +97,7 @@ namespace Umbraco.Extensions var converted = val.TryConvertTo(); return converted.Success - ? converted.Result + ? converted.Result! : throw new InvalidOperationException($"The required query string parameter {key} cannot be converted to type {typeof(T)}"); } } diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs index c59e7b1126..dabefbc3ad 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyImageCropperTemplateExtensions.cs @@ -26,7 +26,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, string cropAlias, UrlMode urlMode = UrlMode.Default) => @@ -41,7 +41,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string cropAlias, UrlMode urlMode = UrlMode.Default) + public static string? GetCropUrl(this MediaWithCrops mediaWithCrops, string cropAlias, UrlMode urlMode = UrlMode.Default) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, cropAlias, ImageUrlGenerator, PublishedValueFallback, PublishedUrlProvider, urlMode); /// @@ -54,7 +54,7 @@ namespace Umbraco.Extensions /// /// The image crop URL. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, ImageCropperValue imageCropperValue, string cropAlias, @@ -71,7 +71,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, string propertyAlias, string cropAlias, @@ -88,7 +88,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string propertyAlias, string cropAlias, UrlMode urlMode = UrlMode.Default) + public static string? GetCropUrl(this MediaWithCrops mediaWithCrops, string propertyAlias, string cropAlias, UrlMode urlMode = UrlMode.Default) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, propertyAlias, cropAlias, ImageUrlGenerator, PublishedValueFallback, PublishedUrlProvider, urlMode); /// @@ -113,19 +113,19 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, int? width = null, int? height = null, string propertyAlias = Cms.Core.Constants.Conventions.Media.File, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, bool cacheBuster = true, - string furtherOptions = null, + string? furtherOptions = null, UrlMode urlMode = UrlMode.Default) => mediaItem.GetCropUrl( ImageUrlGenerator, @@ -167,19 +167,19 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this MediaWithCrops mediaWithCrops, int? width = null, int? height = null, string propertyAlias = Cms.Core.Constants.Conventions.Media.File, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, bool cacheBuster = true, - string furtherOptions = null, + string? furtherOptions = null, UrlMode urlMode = UrlMode.Default) => mediaWithCrops.GetCropUrl( ImageUrlGenerator, @@ -220,19 +220,19 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this string imageUrl, int? width = null, int? height = null, - string imageCropperValue = null, - string cropAlias = null, + string? imageCropperValue = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, - string cacheBusterValue = null, - string furtherOptions = null) + string? cacheBusterValue = null, + string? furtherOptions = null) => imageUrl.GetCropUrl( ImageUrlGenerator, width, @@ -269,19 +269,19 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this string imageUrl, ImageCropperValue cropDataSet, int? width = null, int? height = null, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, - string cacheBusterValue = null, - string furtherOptions = null) + string? cacheBusterValue = null, + string? furtherOptions = null) => imageUrl.GetCropUrl( ImageUrlGenerator, cropDataSet, @@ -301,6 +301,6 @@ namespace Umbraco.Extensions public static string GetLocalCropUrl( this MediaWithCrops mediaWithCrops, string alias, - string cacheBusterValue = null) => mediaWithCrops.LocalCrops.Src + mediaWithCrops.LocalCrops.GetCropUrl(alias, ImageUrlGenerator, cacheBusterValue: cacheBusterValue); + string? cacheBusterValue = null) => mediaWithCrops.LocalCrops.Src + mediaWithCrops.LocalCrops.GetCropUrl(alias, ImageUrlGenerator, cacheBusterValue: cacheBusterValue); } } diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs index abbf934e04..ed53832cc5 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -50,7 +50,7 @@ namespace Umbraco.Extensions private static IPublishedValueFallback PublishedValueFallback { get; } = StaticServiceProvider.Instance.GetRequiredService(); - private static IPublishedSnapshot PublishedSnapshot + private static IPublishedSnapshot? PublishedSnapshot { get { @@ -75,7 +75,7 @@ namespace Umbraco.Extensions /// /// The internal published content. /// The strongly typed published content model. - public static IPublishedContent CreateModel( + public static IPublishedContent? CreateModel( this IPublishedContent content) => content.CreateModel(PublishedModelFactory); @@ -84,9 +84,9 @@ namespace Umbraco.Extensions /// /// The content item. /// The specific culture to get the name for. If null is used the current culture is used (Default is null). - public static string Name( + public static string? Name( this IPublishedContent content, - string culture = null) + string? culture = null) => content.Name(VariationContextAccessor, culture); /// @@ -94,9 +94,9 @@ namespace Umbraco.Extensions /// /// The content item. /// The specific culture to get the URL segment for. If null is used the current culture is used (Default is null). - public static string UrlSegment( + public static string? UrlSegment( this IPublishedContent content, - string culture = null) + string? culture = null) => content.UrlSegment(VariationContextAccessor, culture); /// @@ -106,7 +106,7 @@ namespace Umbraco.Extensions /// The specific culture to get the name for. If null is used the current culture is used (Default is null). public static DateTime CultureDate( this IPublishedContent content, - string culture = null) + string? culture = null) => content.CultureDate(VariationContextAccessor, culture); /// @@ -159,8 +159,8 @@ namespace Umbraco.Extensions public static bool HasValue( this IPublishedContent content, string alias, - string culture = null, - string segment = null, + string? culture = null, + string? segment = null, Fallback fallback = default) => content.HasValue(PublishedValueFallback, alias, culture, segment, fallback); @@ -175,7 +175,7 @@ namespace Umbraco.Extensions /// Optional fallback strategy. /// The default value. /// The value of the content's property identified by the alias, if it exists, otherwise a default value. - public static object Value(this IPublishedContent content, string alias, string? culture = null, string? segment = null, Fallback fallback = default, object? defaultValue = default) + public static object? Value(this IPublishedContent content, string alias, string? culture = null, string? segment = null, Fallback fallback = default, object? defaultValue = default) => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue); /// @@ -189,7 +189,7 @@ namespace Umbraco.Extensions /// Optional fallback strategy. /// The default value. /// The value of the content's property identified by the alias, converted to the specified type. - public static T Value(this IPublishedContent content, string alias, string? culture = null, string? segment = null, Fallback fallback = default, T defaultValue = default) + public static T? Value(this IPublishedContent content, string alias, string? culture = null, string? segment = null, Fallback fallback = default, T? defaultValue = default) => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue); /// @@ -218,7 +218,7 @@ namespace Umbraco.Extensions /// public static IEnumerable DescendantsOrSelf( this IEnumerable parentNodes, - string culture = null) + string? culture = null) where T : class, IPublishedContent => parentNodes.DescendantsOrSelf(VariationContextAccessor, culture); @@ -240,7 +240,7 @@ namespace Umbraco.Extensions where T : class, IPublishedContent => content.Descendants(VariationContextAccessor, level, culture); - public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null) + public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string? culture = null) => content.DescendantsOrSelf(VariationContextAccessor, culture); @@ -258,39 +258,39 @@ namespace Umbraco.Extensions where T : class, IPublishedContent => content.DescendantsOrSelf(VariationContextAccessor, level, culture); - public static IPublishedContent Descendant(this IPublishedContent content, string? culture = null) + public static IPublishedContent? Descendant(this IPublishedContent content, string? culture = null) => content.Descendant(VariationContextAccessor, culture); - public static IPublishedContent Descendant(this IPublishedContent content, int level, string? culture = null) + public static IPublishedContent? Descendant(this IPublishedContent content, int level, string? culture = null) => content.Descendant(VariationContextAccessor, level, culture); - public static IPublishedContent DescendantOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) + public static IPublishedContent? DescendantOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) => content.DescendantOfType(VariationContextAccessor, contentTypeAlias, culture); - public static T Descendant(this IPublishedContent content, string? culture = null) + public static T? Descendant(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent => content.Descendant(VariationContextAccessor, culture); - public static T Descendant(this IPublishedContent content, int level, string? culture = null) + public static T? Descendant(this IPublishedContent content, int level, string? culture = null) where T : class, IPublishedContent => content.Descendant(VariationContextAccessor, level, culture); public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string? culture = null) => content.DescendantOrSelf(VariationContextAccessor, culture); - public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string? culture = null) + public static IPublishedContent? DescendantOrSelf(this IPublishedContent content, int level, string? culture = null) => content.DescendantOrSelf(VariationContextAccessor, level, culture); - public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) + public static IPublishedContent? DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) => content.DescendantOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture); - public static T DescendantOrSelf(this IPublishedContent content, string? culture = null) + public static T? DescendantOrSelf(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent => content.DescendantOrSelf(VariationContextAccessor, culture); - public static T DescendantOrSelf(this IPublishedContent content, int level, string? culture = null) + public static T? DescendantOrSelf(this IPublishedContent content, int level, string? culture = null) where T : class, IPublishedContent => content.DescendantOrSelf(VariationContextAccessor, level, culture); @@ -317,7 +317,7 @@ namespace Umbraco.Extensions /// However, if an empty string is specified only invariant children are returned. /// /// - public static IEnumerable Children(this IPublishedContent content, string? culture = null) + public static IEnumerable? Children(this IPublishedContent content, string? culture = null) => content.Children(VariationContextAccessor, culture); /// @@ -330,7 +330,7 @@ namespace Umbraco.Extensions /// /// Children are sorted by their sortOrder. /// - public static IEnumerable Children(this IPublishedContent content, Func predicate, string? culture = null) + public static IEnumerable? Children(this IPublishedContent content, Func predicate, string? culture = null) => content.Children(VariationContextAccessor, predicate, culture); /// @@ -340,7 +340,7 @@ namespace Umbraco.Extensions /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The content type alias. /// The children of the content, of any of the specified types. - public static IEnumerable ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) + public static IEnumerable? ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) => content.ChildrenOfType(VariationContextAccessor, contentTypeAlias, culture); /// @@ -353,31 +353,31 @@ namespace Umbraco.Extensions /// /// Children are sorted by their sortOrder. /// - public static IEnumerable Children(this IPublishedContent content, string? culture = null) + public static IEnumerable? Children(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent => content.Children(VariationContextAccessor, culture); - public static IPublishedContent FirstChild(this IPublishedContent content, string? culture = null) + public static IPublishedContent? FirstChild(this IPublishedContent content, string? culture = null) => content.FirstChild(VariationContextAccessor, culture); /// /// Gets the first child of the content, of a given content type. /// - public static IPublishedContent FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) + public static IPublishedContent? FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) => content.FirstChildOfType(VariationContextAccessor, contentTypeAlias, culture); - public static IPublishedContent FirstChild(this IPublishedContent content, Func predicate, string? culture = null) + public static IPublishedContent? FirstChild(this IPublishedContent content, Func predicate, string? culture = null) => content.FirstChild(VariationContextAccessor, predicate, culture); - public static IPublishedContent FirstChild(this IPublishedContent content, Guid uniqueId, string? culture = null) + public static IPublishedContent? FirstChild(this IPublishedContent content, Guid uniqueId, string? culture = null) => content.FirstChild(VariationContextAccessor, uniqueId, culture); - public static T FirstChild(this IPublishedContent content, string? culture = null) + public static T? FirstChild(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent => content.FirstChild(VariationContextAccessor, culture); - public static T FirstChild(this IPublishedContent content, Func predicate, string? culture = null) + public static T? FirstChild(this IPublishedContent content, Func predicate, string? culture = null) where T : class, IPublishedContent => content.FirstChild(VariationContextAccessor, predicate, culture); @@ -390,7 +390,7 @@ namespace Umbraco.Extensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable Siblings(this IPublishedContent content, string? culture = null) + public static IEnumerable? Siblings(this IPublishedContent content, string? culture = null) => content.Siblings(PublishedSnapshot, VariationContextAccessor, culture); /// @@ -403,7 +403,7 @@ namespace Umbraco.Extensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) + public static IEnumerable? SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) => content.SiblingsOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture); /// @@ -416,7 +416,7 @@ namespace Umbraco.Extensions /// /// Note that in V7 this method also return the content node self. /// - public static IEnumerable Siblings(this IPublishedContent content, string? culture = null) + public static IEnumerable? Siblings(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent => content.Siblings(PublishedSnapshot, VariationContextAccessor, culture); @@ -426,7 +426,7 @@ namespace Umbraco.Extensions /// The content. /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The siblings of the content including the node itself. - public static IEnumerable SiblingsAndSelf(this IPublishedContent content, string? culture = null) + public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, string? culture = null) => content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture); /// @@ -436,7 +436,7 @@ namespace Umbraco.Extensions /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The content type alias. /// The siblings of the content including the node itself, of the given content type. - public static IEnumerable SiblingsAndSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) + public static IEnumerable? SiblingsAndSelfOfType(this IPublishedContent content, string contentTypeAlias, string? culture = null) => content.SiblingsAndSelfOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture); /// @@ -446,7 +446,7 @@ namespace Umbraco.Extensions /// The content. /// The specific culture to filter for. If null is used the current culture is used. (Default is null) /// The siblings of the content including the node itself, of the given content type. - public static IEnumerable SiblingsAndSelf(this IPublishedContent content, string? culture = null) + public static IEnumerable? SiblingsAndSelf(this IPublishedContent content, string? culture = null) where T : class, IPublishedContent => content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture); @@ -496,7 +496,7 @@ namespace Umbraco.Extensions /// public static string MediaUrl( this IPublishedContent content, - string culture = null, + string? culture = null, UrlMode mode = UrlMode.Default, string propertyAlias = Constants.Conventions.Media.File) => content.MediaUrl(PublishedUrlProvider, culture, mode, propertyAlias); @@ -505,14 +505,14 @@ namespace Umbraco.Extensions /// Gets the name of the content item creator. /// /// The content item. - public static string CreatorName(this IPublishedContent content) => + public static string? CreatorName(this IPublishedContent content) => content.CreatorName(UserService); /// /// Gets the name of the content item writer. /// /// The content item. - public static string WriterName(this IPublishedContent content) => + public static string? WriterName(this IPublishedContent content) => content.WriterName(UserService); /// @@ -526,23 +526,23 @@ namespace Umbraco.Extensions /// one document per culture), and domains, withing the context of a current Uri, assign /// a culture to that document. /// - public static string GetCultureFromDomains( + public static string? GetCultureFromDomains( this IPublishedContent content, - Uri current = null) + Uri? current = null) => content.GetCultureFromDomains(UmbracoContextAccessor, SiteDomainHelper, current); public static IEnumerable SearchDescendants( this IPublishedContent content, string term, - string indexName = null) + string? indexName = null) => content.SearchDescendants(ExamineManager, UmbracoContextAccessor, term, indexName); public static IEnumerable SearchChildren( this IPublishedContent content, string term, - string indexName = null) + string? indexName = null) => content.SearchChildren(ExamineManager, UmbracoContextAccessor, term, indexName); diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs index 4d4f5e1992..fe10a33837 100644 --- a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs @@ -27,11 +27,11 @@ namespace Umbraco.Extensions /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// - public static object Value( + public static object? Value( this IPublishedElement content, string alias, - string culture = null, - string segment = null, + string? culture = null, + string? segment = null, Fallback fallback = default, object? defaultValue = default) => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue); @@ -53,13 +53,13 @@ namespace Umbraco.Extensions /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. /// The alias is case-insensitive. /// - public static T Value( + public static T? Value( this IPublishedElement content, string alias, - string culture = null, - string segment = null, + string? culture = null, + string? segment = null, Fallback fallback = default, - T defaultValue = default) + T? defaultValue = default) => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue); /// @@ -75,7 +75,7 @@ namespace Umbraco.Extensions /// /// Gets the value of a property. /// - public static TValue ValueFor(this TModel model, Expression> property, string? culture = null, string? segment = null, Fallback fallback = default, TValue defaultValue = default) + public static TValue? ValueFor(this TModel model, Expression> property, string? culture = null, string? segment = null, Fallback fallback = default, TValue? defaultValue = default) where TModel : IPublishedElement => model.ValueFor(PublishedValueFallback, property, culture, segment, fallback); } diff --git a/src/Umbraco.Web.Common/Extensions/HttpContextExtensions.cs b/src/Umbraco.Web.Common/Extensions/HttpContextExtensions.cs index d6beb90c01..2a2f82e576 100644 --- a/src/Umbraco.Web.Common/Extensions/HttpContextExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/HttpContextExtensions.cs @@ -14,7 +14,7 @@ namespace Umbraco.Extensions /// /// Try to get the basic auth username and password from the http context. /// - public static bool TryGetBasicAuthCredentials(this HttpContext httpContext, out string username, out string password) + public static bool TryGetBasicAuthCredentials(this HttpContext httpContext, out string? username, out string? password) { username = null; password = null; @@ -70,9 +70,12 @@ namespace Umbraco.Extensions return value ?? request.Query[key]; } - public static void SetPrincipalForRequest(this HttpContext context, ClaimsPrincipal principal) + public static void SetPrincipalForRequest(this HttpContext context, ClaimsPrincipal? principal) { - context.User = principal; + if (principal is not null) + { + context.User = principal; + } } @@ -94,7 +97,7 @@ namespace Umbraco.Extensions /// /// Returns the current back office identity if an admin is authenticated otherwise null /// - public static ClaimsIdentity GetCurrentIdentity(this HttpContext http) + public static ClaimsIdentity? GetCurrentIdentity(this HttpContext http) { if (http == null) throw new ArgumentNullException(nameof(http)); if (http.User == null) return null; //there's no user at all so no identity diff --git a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs index 7d9ce136ef..b511ccf8f1 100644 --- a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs @@ -29,8 +29,8 @@ namespace Umbraco.Extensions public static bool IsBackOfficeRequest(this HttpRequest request) { PathString absPath = request.Path; - UmbracoRequestPaths umbReqPaths = request.HttpContext.RequestServices.GetService(); - return umbReqPaths.IsBackOfficeRequest(absPath); + UmbracoRequestPaths? umbReqPaths = request.HttpContext.RequestServices.GetService(); + return umbReqPaths?.IsBackOfficeRequest(absPath) ?? false; } /// @@ -39,11 +39,11 @@ namespace Umbraco.Extensions public static bool IsClientSideRequest(this HttpRequest request) { PathString absPath = request.Path; - UmbracoRequestPaths umbReqPaths = request.HttpContext.RequestServices.GetService(); - return umbReqPaths.IsClientSideRequest(absPath); + UmbracoRequestPaths? umbReqPaths = request.HttpContext.RequestServices.GetService(); + return umbReqPaths?.IsClientSideRequest(absPath) ?? false; } - public static string ClientCulture(this HttpRequest request) + public static string? ClientCulture(this HttpRequest request) => request.Headers.TryGetValue("X-UMB-CULTURE", out var values) ? values[0] : null; /// @@ -56,10 +56,10 @@ namespace Umbraco.Extensions public static bool IsLocal(this HttpRequest request) { var connection = request.HttpContext.Connection; - if (connection.RemoteIpAddress.IsSet()) + if (connection.RemoteIpAddress?.IsSet() ?? false) { // We have a remote address set up - return connection.LocalIpAddress.IsSet() + return connection.LocalIpAddress?.IsSet() ?? false // Is local is same as remote, then we are local ? connection.RemoteIpAddress.Equals(connection.LocalIpAddress) // else we are remote if the remote IP address is not a loopback address @@ -75,7 +75,7 @@ namespace Umbraco.Extensions return address != null && address.ToString() != NullIpAddress; } - public static string GetRawBodyString(this HttpRequest request, Encoding encoding = null) + public static string GetRawBodyString(this HttpRequest request, Encoding? encoding = null) { if (request.Body.CanSeek) { @@ -94,7 +94,7 @@ namespace Umbraco.Extensions } } - public static async Task GetRawBodyStringAsync(this HttpRequest request, Encoding encoding = null) + public static async Task GetRawBodyStringAsync(this HttpRequest request, Encoding? encoding = null) { if (!request.Body.CanSeek) { @@ -143,7 +143,7 @@ namespace Umbraco.Extensions /// /// The current request /// The extracted `ufprt` token. - public static string GetUfprt(this HttpRequest request) + public static string? GetUfprt(this HttpRequest request) { if (request.HasFormContentType && request.Form.TryGetValue("ufprt", out StringValues formVal) && formVal != StringValues.Empty) { diff --git a/src/Umbraco.Web.Common/Extensions/IdentityBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/IdentityBuilderExtensions.cs index 9b80f3e82a..5ec7adc1f3 100644 --- a/src/Umbraco.Web.Common/Extensions/IdentityBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/IdentityBuilderExtensions.cs @@ -20,6 +20,7 @@ namespace Umbraco.Extensions /// The current instance. public static IdentityBuilder AddMemberManager(this IdentityBuilder identityBuilder) where TUserManager : UserManager, TInterface + where TInterface : notnull { identityBuilder.AddUserManager(); // use a UniqueServiceDescriptor so we can check if it's already been added @@ -31,6 +32,7 @@ namespace Umbraco.Extensions public static IdentityBuilder AddRoleManager(this IdentityBuilder identityBuilder) where TRoleManager : RoleManager, TInterface + where TInterface : notnull { identityBuilder.AddRoleManager(); identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TRoleManager)); diff --git a/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateCoreExtensions.cs index f335a81ae7..57779d2082 100644 --- a/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateCoreExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateCoreExtensions.cs @@ -24,7 +24,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, string cropAlias, IImageUrlGenerator imageUrlGenerator, @@ -44,7 +44,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this MediaWithCrops mediaWithCrops, string cropAlias, IImageUrlGenerator imageUrlGenerator, @@ -65,7 +65,7 @@ namespace Umbraco.Extensions /// /// The image crop URL. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, ImageCropperValue imageCropperValue, string cropAlias, @@ -87,7 +87,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, string propertyAlias, string cropAlias, @@ -109,7 +109,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl(this MediaWithCrops mediaWithCrops, + public static string? GetCropUrl(this MediaWithCrops mediaWithCrops, IPublishedValueFallback publishedValueFallback, IPublishedUrlProvider publishedUrlProvider, string propertyAlias, @@ -142,7 +142,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this IPublishedContent mediaItem, IImageUrlGenerator imageUrlGenerator, IPublishedValueFallback publishedValueFallback, @@ -150,14 +150,14 @@ namespace Umbraco.Extensions int? width = null, int? height = null, string propertyAlias = Cms.Core.Constants.Conventions.Media.File, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, bool cacheBuster = true, - string furtherOptions = null, + string? furtherOptions = null, UrlMode urlMode = UrlMode.Default) => mediaItem.GetCropUrl(imageUrlGenerator, publishedValueFallback, publishedUrlProvider, null, false, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, urlMode); /// @@ -185,7 +185,7 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this MediaWithCrops mediaWithCrops, IImageUrlGenerator imageUrlGenerator, IPublishedValueFallback publishedValueFallback, @@ -193,14 +193,14 @@ namespace Umbraco.Extensions int? width = null, int? height = null, string propertyAlias = Constants.Conventions.Media.File, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, bool cacheBuster = true, - string furtherOptions = null, + string? furtherOptions = null, UrlMode urlMode = UrlMode.Default) { if (mediaWithCrops == null) @@ -211,24 +211,24 @@ namespace Umbraco.Extensions return mediaWithCrops.Content.GetCropUrl(imageUrlGenerator, publishedValueFallback, publishedUrlProvider, mediaWithCrops.LocalCrops, false, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, urlMode); } - private static string GetCropUrl( + private static string? GetCropUrl( this IPublishedContent mediaItem, IImageUrlGenerator imageUrlGenerator, IPublishedValueFallback publishedValueFallback, IPublishedUrlProvider publishedUrlProvider, - ImageCropperValue localCrops, + ImageCropperValue? localCrops, bool localCropsOnly, int? width = null, int? height = null, string propertyAlias = Constants.Conventions.Media.File, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, bool cacheBuster = true, - string furtherOptions = null, + string? furtherOptions = null, UrlMode urlMode = UrlMode.Default) { if (mediaItem == null) @@ -302,27 +302,27 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this string imageUrl, IImageUrlGenerator imageUrlGenerator, int? width = null, int? height = null, - string imageCropperValue = null, - string cropAlias = null, + string? imageCropperValue = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, - string cacheBusterValue = null, - string furtherOptions = null) + string? cacheBusterValue = null, + string? furtherOptions = null) { if (string.IsNullOrWhiteSpace(imageUrl)) { return null; } - ImageCropperValue cropDataSet = null; + ImageCropperValue? cropDataSet = null; if (string.IsNullOrEmpty(imageCropperValue) == false && imageCropperValue.DetectIsJson() && (imageCropMode == ImageCropMode.Crop || imageCropMode == null)) { cropDataSet = imageCropperValue.DeserializeImageCropperValue(); @@ -355,20 +355,20 @@ namespace Umbraco.Extensions /// /// The URL of the cropped image. /// - public static string GetCropUrl( + public static string? GetCropUrl( this string imageUrl, IImageUrlGenerator imageUrlGenerator, - ImageCropperValue cropDataSet, + ImageCropperValue? cropDataSet, int? width = null, int? height = null, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, - string cacheBusterValue = null, - string furtherOptions = null) + string? cacheBusterValue = null, + string? furtherOptions = null) { if (string.IsNullOrWhiteSpace(imageUrl)) { @@ -378,7 +378,7 @@ namespace Umbraco.Extensions ImageUrlGenerationOptions options; if (cropDataSet != null && (imageCropMode == ImageCropMode.Crop || imageCropMode == null)) { - ImageCropperValue.ImageCropperCrop crop = cropDataSet.GetCrop(cropAlias); + ImageCropperValue.ImageCropperCrop? crop = cropDataSet.GetCrop(cropAlias); // If a crop was specified, but not found, return null if (crop == null && !string.IsNullOrWhiteSpace(cropAlias)) diff --git a/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs index 82bb8d2c01..e7b08c51f1 100644 --- a/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs @@ -21,7 +21,7 @@ namespace Umbraco.Extensions internal static ImageCropperValue DeserializeImageCropperValue(this string json) { - ImageCropperValue imageCrops = null; + ImageCropperValue? imageCrops = null; if (json.DetectIsJson()) { diff --git a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs index c30eefd918..71f1d5410a 100644 --- a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs @@ -18,10 +18,10 @@ namespace Umbraco.Extensions /// /// Return the back office url if the back office is installed /// - public static string GetBackOfficeUrl(this LinkGenerator linkGenerator, IHostingEnvironment hostingEnvironment) + public static string? GetBackOfficeUrl(this LinkGenerator linkGenerator, IHostingEnvironment hostingEnvironment) { - Type backOfficeControllerType; + Type? backOfficeControllerType; try { backOfficeControllerType = Assembly.Load("Umbraco.Web.BackOffice")?.GetType("Umbraco.Web.BackOffice.Controllers.BackOfficeController"); @@ -42,19 +42,19 @@ namespace Umbraco.Extensions /// Return the Url for a Web Api service /// /// The - public static string GetUmbracoApiService(this LinkGenerator linkGenerator, string actionName, object id = null) + public static string? GetUmbracoApiService(this LinkGenerator linkGenerator, string actionName, object? id = null) where T : UmbracoApiControllerBase => linkGenerator.GetUmbracoControllerUrl( actionName, typeof(T), - new Dictionary() + new Dictionary() { ["id"] = id }); - public static string GetUmbracoApiService(this LinkGenerator linkGenerator, string actionName, IDictionary values) + public static string? GetUmbracoApiService(this LinkGenerator linkGenerator, string actionName, IDictionary? values) where T : UmbracoApiControllerBase => linkGenerator.GetUmbracoControllerUrl(actionName, typeof(T), values); - public static string GetUmbracoApiServiceBaseUrl(this LinkGenerator linkGenerator, Expression> methodSelector) + public static string? GetUmbracoApiServiceBaseUrl(this LinkGenerator linkGenerator, Expression> methodSelector) where T : UmbracoApiControllerBase { var method = ExpressionHelper.GetMethodInfo(methodSelector); @@ -62,13 +62,13 @@ namespace Umbraco.Extensions { throw new MissingMethodException("Could not find the method " + methodSelector + " on type " + typeof(T) + " or the result "); } - return linkGenerator.GetUmbracoApiService(method.Name).TrimEnd(method.Name); + return linkGenerator.GetUmbracoApiService(method.Name)?.TrimEnd(method.Name); } /// /// Return the Url for an Umbraco controller /// - public static string GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, string controllerName, string area, IDictionary dict = null) + public static string? GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, string controllerName, string? area, IDictionary? dict = null) { if (actionName == null) { @@ -92,16 +92,16 @@ namespace Umbraco.Extensions if (dict is null) { - dict = new Dictionary(); + dict = new Dictionary(); } if (!area.IsNullOrWhiteSpace()) { - dict["area"] = area; + dict["area"] = area!; } - IDictionary values = dict.Aggregate( - new ExpandoObject() as IDictionary, + IDictionary values = dict.Aggregate( + new ExpandoObject() as IDictionary, (a, p) => { a.Add(p.Key, p.Value); @@ -114,7 +114,7 @@ namespace Umbraco.Extensions /// /// Return the Url for an Umbraco controller /// - public static string GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, Type controllerType, IDictionary values = null) + public static string? GetUmbracoControllerUrl(this LinkGenerator linkGenerator, string actionName, Type controllerType, IDictionary? values = null) { if (actionName == null) { @@ -148,7 +148,7 @@ namespace Umbraco.Extensions return linkGenerator.GetUmbracoControllerUrl(actionName, ControllerExtensions.GetControllerName(controllerType), area, values); } - public static string GetUmbracoApiService(this LinkGenerator linkGenerator, Expression> methodSelector) + public static string? GetUmbracoApiService(this LinkGenerator linkGenerator, Expression> methodSelector) where T : UmbracoApiController { var method = ExpressionHelper.GetMethodInfo(methodSelector); @@ -159,7 +159,7 @@ namespace Umbraco.Extensions $"Could not find the method {methodSelector} on type {typeof(T)} or the result "); } - if (methodParams.Any() == false) + if (methodParams?.Any() == false) { return linkGenerator.GetUmbracoApiService(method.Name); } diff --git a/src/Umbraco.Web.Common/Extensions/ModelStateExtensions.cs b/src/Umbraco.Web.Common/Extensions/ModelStateExtensions.cs index acc2858ece..7509761305 100644 --- a/src/Umbraco.Web.Common/Extensions/ModelStateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ModelStateExtensions.cs @@ -14,7 +14,7 @@ namespace Umbraco.Extensions /// /// public static bool IsValid(this ModelStateDictionary state, string prefix) => - state.Where(v => v.Key.StartsWith(prefix + ".")).All(v => !v.Value.Errors.Any()); + state.Where(v => v.Key.StartsWith(prefix + ".")).All(v => !v.Value?.Errors.Any() ?? false); public static IDictionary ToErrorDictionary(this ModelStateDictionary modelState) { @@ -36,7 +36,7 @@ namespace Umbraco.Extensions /// /// /// - public static JsonResult ToJsonErrors(this ModelStateDictionary state) => + public static JsonResult? ToJsonErrors(this ModelStateDictionary state) => new JsonResult(new { success = state.IsValid.ToString().ToLower(), @@ -48,7 +48,7 @@ namespace Umbraco.Extensions name = e.Key, errors = e.Value.Errors.Select(x => x.ErrorMessage) .Concat( - e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message)) + e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception!.Message)) } }); } diff --git a/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs index 07bad33b50..28ba55c320 100644 --- a/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs @@ -21,14 +21,14 @@ namespace Umbraco.Extensions /// /// The content item. /// - public static string CreatorName(this IPublishedContent content, IUserService userService) => userService.GetProfileById(content.CreatorId)?.Name; + public static string? CreatorName(this IPublishedContent content, IUserService userService) => userService.GetProfileById(content.CreatorId)?.Name; /// /// Gets the name of the content item writer. /// /// The content item. /// - public static string WriterName(this IPublishedContent content, IUserService userService) => userService.GetProfileById(content.WriterId)?.Name; + public static string? WriterName(this IPublishedContent content, IUserService userService) => userService.GetProfileById(content.WriterId)?.Name; #endregion @@ -47,7 +47,7 @@ namespace Umbraco.Extensions /// one document per culture), and domains, withing the context of a current Uri, assign /// a culture to that document. /// - public static string GetCultureFromDomains(this IPublishedContent content, IUmbracoContextAccessor umbracoContextAccessor, ISiteDomainMapper siteDomainHelper, Uri current = null) + public static string? GetCultureFromDomains(this IPublishedContent content, IUmbracoContextAccessor umbracoContextAccessor, ISiteDomainMapper siteDomainHelper, Uri? current = null) { var umbracoContext = umbracoContextAccessor.GetRequiredUmbracoContext(); return DomainUtilities.GetCultureFromDomains(content.Id, content.Path, current, umbracoContext, siteDomainHelper); @@ -57,7 +57,7 @@ namespace Umbraco.Extensions #region Search - public static IEnumerable SearchDescendants(this IPublishedContent content, IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor, string term, string indexName = null) + public static IEnumerable SearchDescendants(this IPublishedContent content, IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor, string term, string ?indexName = null) { indexName = string.IsNullOrEmpty(indexName) ? Constants.UmbracoIndexes.ExternalIndexName : indexName; if (!examineManager.TryGetIndex(indexName, out var index)) @@ -76,7 +76,7 @@ namespace Umbraco.Extensions return query.Execute().ToPublishedSearchResults(umbracoContext.Content); } - public static IEnumerable SearchChildren(this IPublishedContent content, IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor, string term, string indexName = null) + public static IEnumerable SearchChildren(this IPublishedContent content, IExamineManager examineManager, IUmbracoContextAccessor umbracoContextAccessor, string term, string? indexName = null) { indexName = string.IsNullOrEmpty(indexName) ? Constants.UmbracoIndexes.ExternalIndexName : indexName; if (!examineManager.TryGetIndex(indexName, out var index)) diff --git a/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs b/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs index d6c3fb5715..41d069919a 100644 --- a/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/RazorPageExtensions.cs @@ -11,13 +11,13 @@ namespace Umbraco.Extensions /// /// Renders a section with default content if the section isn't defined /// - public static HtmlString RenderSection(this RazorPage webPage, string name, HtmlString defaultContents) + public static HtmlString? RenderSection(this RazorPage webPage, string name, HtmlString defaultContents) => webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : defaultContents; /// /// Renders a section with default content if the section isn't defined /// - public static HtmlString RenderSection(this RazorPage webPage, string name, string defaultContents) + public static HtmlString? RenderSection(this RazorPage webPage, string name, string defaultContents) => webPage.IsSectionDefined(name) ? webPage.RenderSection(name) : new HtmlString(defaultContents); } diff --git a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs index 4441ae6e42..b8de39bb65 100644 --- a/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ServiceCollectionExtensions.cs @@ -81,8 +81,8 @@ namespace Umbraco.Extensions /// public static TypeLoader AddTypeLoader( this IServiceCollection services, - Assembly entryAssembly, - IHostingEnvironment hostingEnvironment, + Assembly? entryAssembly, + IHostingEnvironment? hostingEnvironment, ILoggerFactory loggerFactory, AppCaches appCaches, IConfiguration configuration, @@ -115,7 +115,7 @@ namespace Umbraco.Extensions typeFinder, runtimeHash, appCaches.RuntimeCache, - new DirectoryInfo(hostingEnvironment.LocalTempPath), + new DirectoryInfo(hostingEnvironment?.LocalTempPath ?? string.Empty), loggerFactory.CreateLogger(), profiler ); diff --git a/src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs b/src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs index ee45db39c9..237fce8f0a 100644 --- a/src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UrlHelperExtensions.cs @@ -27,7 +27,7 @@ namespace Umbraco.Extensions /// /// /// - public static string GetBackOfficeUrl(this IUrlHelper url) + public static string? GetBackOfficeUrl(this IUrlHelper url) { var backOfficeControllerType = Type.GetType("Umbraco.Web.BackOffice.Controllers"); if (backOfficeControllerType == null) return "/"; // this would indicate that the installer is installed without the back office @@ -43,13 +43,13 @@ namespace Umbraco.Extensions /// /// /// - public static string GetUmbracoApiService(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName, object id = null) + public static string? GetUmbracoApiService(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName, object? id = null) where T : UmbracoApiController { return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, actionName, typeof(T), id); } - public static string GetUmbracoApiService(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, Expression> methodSelector) + public static string? GetUmbracoApiService(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, Expression> methodSelector) where T : UmbracoApiController { var method = ExpressionHelper.GetMethodInfo(methodSelector); @@ -59,11 +59,11 @@ namespace Umbraco.Extensions throw new MissingMethodException("Could not find the method " + methodSelector + " on type " + typeof(T) + " or the result "); } - if (methodParams.Any() == false) + if (methodParams?.Any() == false) { return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, method.Name); } - return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, method.Name, methodParams.Values.First()); + return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, method.Name, methodParams?.Values.First()); } /// @@ -75,7 +75,7 @@ namespace Umbraco.Extensions /// /// /// - public static string GetUmbracoApiService(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName, Type apiControllerType, object id = null) + public static string? GetUmbracoApiService(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName, Type apiControllerType, object? id = null) { if (actionName == null) throw new ArgumentNullException(nameof(actionName)); if (string.IsNullOrWhiteSpace(actionName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName)); @@ -92,7 +92,7 @@ namespace Umbraco.Extensions //set the area to the plugin area area = metaData.AreaName; } - return url.GetUmbracoApiService(actionName, ControllerExtensions.GetControllerName(apiControllerType), area, id); + return url.GetUmbracoApiService(actionName, ControllerExtensions.GetControllerName(apiControllerType), area!, id); } /// @@ -103,7 +103,7 @@ namespace Umbraco.Extensions /// /// /// - public static string GetUmbracoApiService(this IUrlHelper url, string actionName, string controllerName, object id = null) + public static string? GetUmbracoApiService(this IUrlHelper url, string actionName, string controllerName, object? id = null) { return url.GetUmbracoApiService(actionName, controllerName, "", id); } @@ -117,7 +117,7 @@ namespace Umbraco.Extensions /// /// /// - public static string GetUmbracoApiService(this IUrlHelper url, string actionName, string controllerName, string area, object id = null) + public static string? GetUmbracoApiService(this IUrlHelper url, string actionName, string controllerName, string area, object? id = null) { if (actionName == null) throw new ArgumentNullException(nameof(actionName)); if (string.IsNullOrWhiteSpace(actionName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(actionName)); @@ -156,13 +156,13 @@ namespace Umbraco.Extensions /// /// /// - public static string GetUmbracoApiServiceBaseUrl(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName) + public static string? GetUmbracoApiServiceBaseUrl(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, string actionName) where T : UmbracoApiController { - return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, actionName).TrimEnd(actionName); + return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, actionName)?.TrimEnd(actionName); } - public static string GetUmbracoApiServiceBaseUrl(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, Expression> methodSelector) + public static string? GetUmbracoApiServiceBaseUrl(this IUrlHelper url, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, Expression> methodSelector) where T : UmbracoApiController { var method = ExpressionHelper.GetMethodInfo(methodSelector); @@ -170,7 +170,7 @@ namespace Umbraco.Extensions { throw new MissingMethodException("Could not find the method " + methodSelector + " on type " + typeof(T) + " or the result "); } - return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, method.Name).TrimEnd(method.Name); + return url.GetUmbracoApiService(umbracoApiControllerTypeCollection, method.Name)?.TrimEnd(method.Name); } /// @@ -219,7 +219,7 @@ namespace Umbraco.Extensions return CreateHtmlString(url, htmlEncode); } - private static IHtmlContent CreateHtmlString(string url, bool htmlEncode) => htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + private static IHtmlContent CreateHtmlString(string? url, bool htmlEncode) => htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); public static IHtmlContent GetCropUrl(this IUrlHelper urlHelper, IPublishedContent mediaItem, string propertyAlias, string cropAlias, bool htmlEncode = true, UrlMode urlMode = UrlMode.Default) { @@ -237,14 +237,14 @@ namespace Umbraco.Extensions int? width = null, int? height = null, string propertyAlias = Constants.Conventions.Media.File, - string cropAlias = null, + string? cropAlias = null, int? quality = null, ImageCropMode? imageCropMode = null, ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = false, bool cacheBuster = true, - string furtherOptions = null, + string? furtherOptions = null, bool htmlEncode = true, UrlMode urlMode = UrlMode.Default) { @@ -269,14 +269,14 @@ namespace Umbraco.Extensions ImageCropAnchor? imageCropAnchor = null, bool preferFocalPoint = false, bool useCropDimensions = true, - string cacheBusterValue = null, - string furtherOptions = null, + string? cacheBusterValue = null, + string? furtherOptions = null, bool htmlEncode = true) { if (imageCropperValue == null) return HtmlString.Empty; var imageUrl = imageCropperValue.Src; - var url = imageUrl.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode, + var url = imageUrl?.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions); return CreateHtmlString(url, htmlEncode); @@ -302,7 +302,7 @@ namespace Umbraco.Extensions /// /// /// - public static string SurfaceAction(this IUrlHelper url, IUmbracoContext umbracoContext, IDataProtectionProvider dataProtectionProvider,string action, string controllerName, object additionalRouteVals) + public static string SurfaceAction(this IUrlHelper url, IUmbracoContext umbracoContext, IDataProtectionProvider dataProtectionProvider,string action, string controllerName, object? additionalRouteVals) { return url.SurfaceAction(umbracoContext, dataProtectionProvider, action, controllerName, "", additionalRouteVals); } @@ -316,7 +316,7 @@ namespace Umbraco.Extensions /// /// /// - public static string SurfaceAction(this IUrlHelper url, IUmbracoContext umbracoContext, IDataProtectionProvider dataProtectionProvider, string action, string controllerName, string area, object additionalRouteVals) + public static string SurfaceAction(this IUrlHelper url, IUmbracoContext umbracoContext, IDataProtectionProvider dataProtectionProvider, string action, string controllerName, string area, object? additionalRouteVals) { if (action == null) throw new ArgumentNullException(nameof(action)); if (string.IsNullOrEmpty(action)) throw new ArgumentException("Value can't be empty.", nameof(action)); diff --git a/src/Umbraco.Web.Common/Extensions/ViewDataExtensions.cs b/src/Umbraco.Web.Common/Extensions/ViewDataExtensions.cs index 8e62ca09cf..83754d7e3b 100644 --- a/src/Umbraco.Web.Common/Extensions/ViewDataExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ViewDataExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ViewFeatures; @@ -59,7 +60,7 @@ namespace Umbraco.Extensions try { - var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(System.Net.WebUtility.UrlDecode(cookieVal))); + var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(System.Net.WebUtility.UrlDecode(cookieVal)!)); // deserialize to T and store in viewdata viewData[cookieName] = serializer.Deserialize(decoded); return true; @@ -70,9 +71,9 @@ namespace Umbraco.Extensions } } - public static string GetUmbracoPath(this ViewDataDictionary viewData) + public static string? GetUmbracoPath(this ViewDataDictionary viewData) { - return (string)viewData[TokenUmbracoPath]; + return (string?)viewData[TokenUmbracoPath]; } public static void SetUmbracoPath(this ViewDataDictionary viewData, string value) @@ -80,9 +81,9 @@ namespace Umbraco.Extensions viewData[TokenUmbracoPath] = value; } - public static string GetInstallApiBaseUrl(this ViewDataDictionary viewData) + public static string? GetInstallApiBaseUrl(this ViewDataDictionary viewData) { - return (string)viewData[TokenInstallApiBaseUrl]; + return (string?)viewData[TokenInstallApiBaseUrl]; } public static void SetInstallApiBaseUrl(this ViewDataDictionary viewData, string value) @@ -90,9 +91,9 @@ namespace Umbraco.Extensions viewData[TokenInstallApiBaseUrl] = value; } - public static string GetUmbracoBaseFolder(this ViewDataDictionary viewData) + public static string? GetUmbracoBaseFolder(this ViewDataDictionary viewData) { - return (string)viewData[TokenUmbracoBaseFolder]; + return (string?)viewData[TokenUmbracoBaseFolder]; } public static void SetUmbracoBaseFolder(this ViewDataDictionary viewData, string value) @@ -104,9 +105,9 @@ namespace Umbraco.Extensions viewData[TokenUmbracoVersion] = version; } - public static SemVersion GetUmbracoVersion(this ViewDataDictionary viewData) + public static SemVersion? GetUmbracoVersion(this ViewDataDictionary viewData) { - return (SemVersion) viewData[TokenUmbracoVersion]; + return (SemVersion?) viewData[TokenUmbracoVersion]; } /// @@ -114,9 +115,9 @@ namespace Umbraco.Extensions /// /// /// - public static BackOfficeExternalLoginProviderErrors GetExternalSignInProviderErrors(this ViewDataDictionary viewData) + public static BackOfficeExternalLoginProviderErrors? GetExternalSignInProviderErrors(this ViewDataDictionary viewData) { - return (BackOfficeExternalLoginProviderErrors)viewData[TokenExternalSignInError]; + return (BackOfficeExternalLoginProviderErrors?)viewData[TokenExternalSignInError]; } /// @@ -129,9 +130,9 @@ namespace Umbraco.Extensions viewData[TokenExternalSignInError] = errors; } - public static string GetPasswordResetCode(this ViewDataDictionary viewData) + public static string? GetPasswordResetCode(this ViewDataDictionary viewData) { - return (string)viewData[TokenPasswordResetCode]; + return (string?)viewData[TokenPasswordResetCode]; } public static void SetPasswordResetCode(this ViewDataDictionary viewData, string value) @@ -144,7 +145,7 @@ namespace Umbraco.Extensions viewData[TokenTwoFactorRequired] = providerNames; } - public static bool TryGetTwoFactorProviderNames(this ViewDataDictionary viewData, out IEnumerable providerNames) + public static bool TryGetTwoFactorProviderNames(this ViewDataDictionary viewData, [MaybeNullWhen(false)] out IEnumerable providerNames) { providerNames = viewData[TokenTwoFactorRequired] as IEnumerable; return providerNames is not null; diff --git a/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs b/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs index cf3fe4cf9e..58c934b311 100644 --- a/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs +++ b/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs @@ -19,7 +19,7 @@ namespace Umbraco.Cms.Web.Common.Filters public void OnActionExecuting(ActionExecutingContext context) { - var culture = context.HttpContext.User.Identity.GetCulture(); + var culture = context.HttpContext.User.Identity?.GetCulture(); if (culture != null) { SetCurrentThreadCulture(culture); diff --git a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs index e09cc83dd3..ac065b5a92 100644 --- a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs @@ -90,7 +90,7 @@ namespace Umbraco.Cms.Web.Common.Filters { public Task RenderAsync(ViewContext context) => Task.CompletedTask; - public string Path { get; } + public string Path { get; } = null!; } } } diff --git a/src/Umbraco.Web.Common/Filters/ExceptionViewModel.cs b/src/Umbraco.Web.Common/Filters/ExceptionViewModel.cs index 082f65cfdf..f53fc80d78 100644 --- a/src/Umbraco.Web.Common/Filters/ExceptionViewModel.cs +++ b/src/Umbraco.Web.Common/Filters/ExceptionViewModel.cs @@ -4,8 +4,8 @@ namespace Umbraco.Cms.Web.Common.Filters { public class ExceptionViewModel { - public string ExceptionMessage { get; set; } - public Type ExceptionType { get; set; } - public string StackTrace { get; set; } + public string? ExceptionMessage { get; set; } + public Type? ExceptionType { get; set; } + public string? StackTrace { get; set; } } } diff --git a/src/Umbraco.Web.Common/Filters/OutgoingNoHyphenGuidFormatAttribute.cs b/src/Umbraco.Web.Common/Filters/OutgoingNoHyphenGuidFormatAttribute.cs index dd0f78fde1..16613b4289 100644 --- a/src/Umbraco.Web.Common/Filters/OutgoingNoHyphenGuidFormatAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/OutgoingNoHyphenGuidFormatAttribute.cs @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Web.Common.Filters /// private class GuidNoHyphenConverter : JsonConverter { - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { switch (reader.TokenType) { @@ -65,9 +65,9 @@ namespace Umbraco.Cms.Web.Common.Filters } } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { - writer.WriteValue(Guid.Empty.Equals(value) ? Guid.Empty.ToString("N") : ((Guid)value).ToString("N")); + writer.WriteValue(Guid.Empty.Equals(value) ? Guid.Empty.ToString("N") : ((Guid?)value)?.ToString("N")); } public override bool CanConvert(Type objectType) diff --git a/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs b/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs index 98f6d2232c..3ad49c1732 100644 --- a/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Web.Common.Filters httpContext.Response.StatusCode = (int)_statusCode; - var disableIisCustomErrors = httpContext.RequestServices.GetService>().Value.TrySkipIisCustomErrors; + var disableIisCustomErrors = httpContext.RequestServices.GetService>()?.Value.TrySkipIisCustomErrors ?? false; var statusCodePagesFeature = httpContext.Features.Get(); if (statusCodePagesFeature != null) diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index b83f647959..136d2f1c8d 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -21,6 +21,9 @@ namespace Umbraco.Cms.Web.Common.Filters { public UmbracoMemberAuthorizeFilter() { + AllowType = string.Empty; + AllowGroup = string.Empty; + AllowMembers = string.Empty; } public UmbracoMemberAuthorizeFilter(string allowType, string allowGroup, string allowMembers) diff --git a/src/Umbraco.Web.Common/Filters/UmbracoVirtualPageFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoVirtualPageFilterAttribute.cs index b2b3ed1d39..6c88239abd 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoVirtualPageFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoVirtualPageFilterAttribute.cs @@ -24,11 +24,11 @@ namespace Umbraco.Cms.Web.Common.Filters /// public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { - Endpoint endpoint = context.HttpContext.GetEndpoint(); + Endpoint? endpoint = context.HttpContext.GetEndpoint(); // Check if there is any delegate in the metadata of the route, this // will occur when using the ForUmbraco method during routing. - CustomRouteContentFinderDelegate contentFinder = endpoint.Metadata.OfType().FirstOrDefault(); + CustomRouteContentFinderDelegate? contentFinder = endpoint?.Metadata.OfType().FirstOrDefault(); if (contentFinder != null) { diff --git a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs index 0c51edd4e1..3337f74a4e 100644 --- a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs @@ -51,14 +51,14 @@ namespace Umbraco.Cms.Web.Common.Filters } - public void ValidateRouteString(string ufprt, string currentController, string currentAction, string currentArea) + public void ValidateRouteString(string? ufprt, string currentController, string currentAction, string? currentArea) { if (ufprt.IsNullOrWhiteSpace()) { throw new HttpUmbracoFormRouteStringException("The required request field \"ufprt\" is not present."); } - if (!EncryptionHelper.DecryptAndValidateEncryptedRouteString(_dataProtectionProvider, ufprt, out var additionalDataParts)) + if (!EncryptionHelper.DecryptAndValidateEncryptedRouteString(_dataProtectionProvider, ufprt!, out var additionalDataParts)) { throw new HttpUmbracoFormRouteStringException("The Umbraco form request route string could not be decrypted."); } diff --git a/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs b/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs index b2085bc175..b170546005 100644 --- a/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs +++ b/src/Umbraco.Web.Common/IUmbracoHelperAccessor.cs @@ -1,7 +1,9 @@ +using System.Diagnostics.CodeAnalysis; + namespace Umbraco.Cms.Web.Common { public interface IUmbracoHelperAccessor { - bool TryGetUmbracoHelper(out UmbracoHelper umbracoHelper); + bool TryGetUmbracoHelper([MaybeNullWhen(false)] out UmbracoHelper umbracoHelper); } } diff --git a/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs index 96022cdcc7..fbe0aaacb5 100644 --- a/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs +++ b/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs @@ -24,9 +24,9 @@ namespace Umbraco.Cms.Web.Common.Localization public UmbracoBackOfficeIdentityCultureProvider(RequestLocalizationOptions localizationOptions) => _localizationOptions = localizationOptions; /// - public override Task DetermineProviderCultureResult(HttpContext httpContext) + public override Task DetermineProviderCultureResult(HttpContext httpContext) { - CultureInfo culture = httpContext.User.Identity.GetCulture(); + CultureInfo? culture = httpContext.User.Identity?.GetCulture(); if (culture is null) { @@ -37,23 +37,23 @@ namespace Umbraco.Cms.Web.Common.Localization { // We need to dynamically change the supported cultures since we won't ever know what languages are used since // they are dynamic within Umbraco. We have to handle this for both UI and Region cultures, in case people run different region and UI languages - var cultureExists = _localizationOptions.SupportedCultures.Contains(culture); + var cultureExists = _localizationOptions.SupportedCultures?.Contains(culture) ?? false; if (!cultureExists) { // add this as a supporting culture - _localizationOptions.SupportedCultures.Add(culture); + _localizationOptions.SupportedCultures?.Add(culture); } - var uiCultureExists = _localizationOptions.SupportedCultures.Contains(culture); + var uiCultureExists = _localizationOptions.SupportedCultures?.Contains(culture) ?? false; if (!uiCultureExists) { // add this as a supporting culture - _localizationOptions.SupportedUICultures.Add(culture); + _localizationOptions.SupportedUICultures?.Add(culture); } - return Task.FromResult(new ProviderCultureResult(culture.Name)); + return Task.FromResult(new ProviderCultureResult(culture.Name)); } } } diff --git a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs index 50e8d859ea..64ce9a6f8e 100644 --- a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs +++ b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs @@ -25,12 +25,12 @@ namespace Umbraco.Cms.Web.Common.Localization public UmbracoPublishedContentCultureProvider(RequestLocalizationOptions localizationOptions) => _localizationOptions = localizationOptions; /// - public override Task DetermineProviderCultureResult(HttpContext httpContext) + public override Task DetermineProviderCultureResult(HttpContext httpContext) { - UmbracoRouteValues routeValues = httpContext.Features.Get(); + UmbracoRouteValues? routeValues = httpContext.Features.Get(); if (routeValues != null) { - string culture = routeValues.PublishedRequest?.Culture; + string? culture = routeValues.PublishedRequest?.Culture; if (culture != null) { lock (_locker) @@ -39,28 +39,28 @@ namespace Umbraco.Cms.Web.Common.Localization // they are dynamic within Umbraco. We have to handle this for both UI and Region cultures, in case people run different region and UI languages // This code to check existence is borrowed from aspnetcore to avoid creating a CultureInfo // https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs#L165 - CultureInfo existingCulture = _localizationOptions.SupportedCultures.FirstOrDefault(supportedCulture => + CultureInfo? existingCulture = _localizationOptions.SupportedCultures?.FirstOrDefault(supportedCulture => StringSegment.Equals(supportedCulture.Name, culture, StringComparison.OrdinalIgnoreCase)); if (existingCulture == null) { // add this as a supporting culture var ci = CultureInfo.GetCultureInfo(culture); - _localizationOptions.SupportedCultures.Add(ci); + _localizationOptions.SupportedCultures?.Add(ci); } - CultureInfo existingUICulture = _localizationOptions.SupportedUICultures.FirstOrDefault(supportedCulture => + CultureInfo? existingUICulture = _localizationOptions.SupportedUICultures?.FirstOrDefault(supportedCulture => StringSegment.Equals(supportedCulture.Name, culture, StringComparison.OrdinalIgnoreCase)); if (existingUICulture == null) { // add this as a supporting culture var ci = CultureInfo.GetCultureInfo(culture); - _localizationOptions.SupportedUICultures.Add(ci); + _localizationOptions.SupportedUICultures?.Add(ci); } } - return Task.FromResult(new ProviderCultureResult(culture)); + return Task.FromResult(new ProviderCultureResult(culture)); } } diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs index 3a80e555c3..3c4bebc9c4 100644 --- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs @@ -108,14 +108,14 @@ namespace Umbraco.Cms.Web.Common.Macros } foreach (var value in model.Properties.Select(x => x.Value)) - id.AppendFormat("{0}-", value.Length <= 255 ? value : value.Substring(0, 255)); + id.AppendFormat("{0}-", value?.Length <= 255 ? value : value?.Substring(0, 255)); return id.ToString(); } // gets this macro content from the cache // ensuring that it is appropriate to use the cache - private MacroContent GetMacroContentFromCache(MacroModel model) + private MacroContent? GetMacroContentFromCache(MacroModel model) { if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) { @@ -170,8 +170,8 @@ namespace Umbraco.Cms.Web.Common.Macros // do not cache if it should cache by member and there's not member if (model.CacheByMember) { - var memberManager = _httpContextAccessor.HttpContext.RequestServices.GetRequiredService(); - var member = await memberManager.GetCurrentMemberAsync(); + var memberManager = _httpContextAccessor.HttpContext?.RequestServices.GetRequiredService(); + MemberIdentityUser? member = await memberManager?.GetCurrentMemberAsync()!; if (member is null) { return; @@ -193,16 +193,16 @@ namespace Umbraco.Cms.Web.Common.Macros // gets the macro source file name // null if the macro is not file-based, or not supported - internal static string GetMacroFileName(MacroModel model) + internal static string? GetMacroFileName(MacroModel model) { - string filename = model.MacroSource; // partial views are saved with their full virtual path + string? filename = model.MacroSource; // partial views are saved with their full virtual path return string.IsNullOrEmpty(filename) ? null : filename; } // gets the macro source file // null if macro is not file-based - private FileInfo GetMacroFile(MacroModel model) + private FileInfo? GetMacroFile(MacroModel model) { var filename = GetMacroFileName(model); if (filename == null) @@ -217,7 +217,7 @@ namespace Umbraco.Cms.Web.Common.Macros } // updates the model properties values according to the attributes - private static void UpdateMacroModelProperties(MacroModel model, IDictionary macroParams) + private static void UpdateMacroModelProperties(MacroModel model, IDictionary? macroParams) { foreach (var prop in model.Properties) { @@ -231,7 +231,7 @@ namespace Umbraco.Cms.Web.Common.Macros #region Render/Execute - public async Task RenderAsync(string macroAlias, IPublishedContent content, IDictionary macroParams) + public async Task RenderAsync(string macroAlias, IPublishedContent? content, IDictionary? macroParams) { var m = _appCaches.RuntimeCache.GetCacheItem(CacheKeys.MacroFromAliasCacheKey + macroAlias, () => _macroService.GetByAlias(macroAlias)); @@ -244,7 +244,7 @@ namespace Umbraco.Cms.Web.Common.Macros return await RenderAsync(macro, content); } - private async Task RenderAsync(MacroModel macro, IPublishedContent content) + private async Task RenderAsync(MacroModel macro, IPublishedContent? content) { if (content == null) throw new ArgumentNullException(nameof(content)); @@ -294,7 +294,7 @@ namespace Umbraco.Cms.Web.Common.Macros /// /// Executes a macro of a given type. /// - private Attempt ExecuteMacroWithErrorWrapper(MacroModel macro, string msgIn, string msgOut, Func getMacroContent, Func msgErr) + private Attempt ExecuteMacroWithErrorWrapper(MacroModel macro, string msgIn, string msgOut, Func getMacroContent, Func msgErr) { using (_profilingLogger.DebugDuration(msgIn, msgOut)) { @@ -305,7 +305,7 @@ namespace Umbraco.Cms.Web.Common.Macros /// /// Executes a macro of a given type. /// - private Attempt ExecuteProfileMacroWithErrorWrapper(MacroModel macro, string msgIn, Func getMacroContent, Func msgErr) + private Attempt ExecuteProfileMacroWithErrorWrapper(MacroModel macro, string msgIn, Func getMacroContent, Func msgErr) { try { @@ -350,7 +350,7 @@ namespace Umbraco.Cms.Web.Common.Macros /// Returns an attempt that is successful if the macro ran successfully. If the macro failed /// to run properly, the attempt fails, though it may contain a content. But for instance that content /// should not be cached. In that case the attempt may also contain an exception. - private Attempt ExecuteMacroOfType(MacroModel model, IPublishedContent content) + private Attempt ExecuteMacroOfType(MacroModel model, IPublishedContent content) { if (model == null) { @@ -380,8 +380,12 @@ namespace Umbraco.Cms.Web.Common.Macros // parses attribute value looking for [@requestKey], [%sessionKey] // supports fallbacks eg "[@requestKey],[%sessionKey],1234" - private string ParseAttribute(string attributeValue) + private string? ParseAttribute(string? attributeValue) { + if (attributeValue is null) + { + return attributeValue; + } // check for potential querystring/cookie variables attributeValue = attributeValue.Trim(); if (attributeValue.StartsWith("[") == false) diff --git a/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs index 0b60de97cb..072ebf78a3 100644 --- a/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs +++ b/src/Umbraco.Web.Common/Macros/PartialViewMacroEngine.cs @@ -59,11 +59,11 @@ namespace Umbraco.Cms.Web.Common.Macros } HttpContext httpContext = _httpContextAccessor.GetRequiredHttpContext(); - + RouteData currentRouteData = httpContext.GetRouteData(); // Check if there's proxied ViewData (i.e. returned from a SurfaceController) - ProxyViewDataFeature proxyViewDataFeature = httpContext.Features.Get(); + ProxyViewDataFeature? proxyViewDataFeature = httpContext.Features.Get(); ViewDataDictionary viewData = proxyViewDataFeature?.ViewData ?? new ViewDataDictionary(_modelMetadataProvider, new ModelStateDictionary()); ITempDataDictionary tempData = proxyViewDataFeature?.TempData ?? _tempDataDictionaryFactory.GetTempData(httpContext); @@ -79,7 +79,7 @@ namespace Umbraco.Cms.Web.Common.Macros var writer = new StringWriter(); var viewComponentContext = new ViewComponentContext( new ViewComponentDescriptor(), - new Dictionary(), + new Dictionary(), HtmlEncoder.Default, viewContext, writer); diff --git a/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs b/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs index 5cab93c00f..8afefc9d16 100644 --- a/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs +++ b/src/Umbraco.Web.Common/Macros/PartialViewMacroViewComponent.cs @@ -38,7 +38,7 @@ namespace Umbraco.Cms.Web.Common.Macros _macro.Id, _macro.Alias, _macro.Name, - _macro.Properties.ToDictionary(x => x.Key, x => (object)x.Value)); + _macro.Properties.ToDictionary(x => x.Key, x => (object?)x.Value)); ViewViewComponentResult result = View(_macro.MacroSource, model); diff --git a/src/Umbraco.Web.Common/Middleware/PreviewAuthenticationMiddleware.cs b/src/Umbraco.Web.Common/Middleware/PreviewAuthenticationMiddleware.cs index 50338f70e3..84b4991b96 100644 --- a/src/Umbraco.Web.Common/Middleware/PreviewAuthenticationMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/PreviewAuthenticationMiddleware.cs @@ -49,7 +49,7 @@ namespace Umbraco.Cms.Web.Common.Middleware // If we've gotten this far it means a preview cookie has been set and a front-end umbraco document request is executing. // In this case, authentication will not have occurred for an Umbraco back office User, however we need to perform the authentication // for the user here so that the preview capability can be authorized otherwise only the non-preview page will be rendered. - if (request.Cookies.TryGetValue(cookieOptions.Cookie.Name, out var cookie)) + if (cookieOptions.Cookie.Name is not null && request.Cookies.TryGetValue(cookieOptions.Cookie.Name, out var cookie)) { var unprotected = cookieOptions.TicketDataFormat.Unprotect(cookie); var backOfficeIdentity = unprotected?.Principal.GetUmbracoIdentity(); @@ -58,7 +58,7 @@ namespace Umbraco.Cms.Web.Common.Middleware // Ok, we've got a real ticket, now we can add this ticket's identity to the current // Principal, this means we'll have 2 identities assigned to the principal which we can // use to authorize the preview and allow for a back office User. - context.User.AddIdentity(backOfficeIdentity); + context.User?.AddIdentity(backOfficeIdentity); } } diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index b03528ec46..be83e15a4b 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Web.Common.Middleware private readonly IVariationContextAccessor _variationContextAccessor; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private SmidgeOptions _smidgeOptions; - private readonly WebProfiler _profiler; + private readonly WebProfiler? _profiler; #pragma warning disable IDE0044 // Add readonly modifier private static bool s_firstBackOfficeRequest; @@ -111,7 +111,7 @@ namespace Umbraco.Cms.Web.Common.Middleware _variationContextAccessor.VariationContext ??= new VariationContext(_defaultCultureAccessor.DefaultCulture); UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); - Uri currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request); + Uri? currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request); _hostingEnvironment.EnsureApplicationMainUrl(currentApplicationUrl); var pathAndQuery = context.Request.GetEncodedPathAndQuery(); @@ -181,8 +181,8 @@ namespace Umbraco.Cms.Web.Common.Middleware } if (_umbracoRequestPaths.IsBackOfficeRequest(absPath) - || absPath.Value.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.CompositeFilePath}") - || absPath.Value.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.BundleFilePath}")) + || (absPath.Value?.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.CompositeFilePath}") ?? false) + || (absPath.Value?.InvariantStartsWith($"/{_smidgeOptions.UrlOptions.BundleFilePath}") ?? false)) { LazyInitializer.EnsureInitialized(ref s_firstBackOfficeRequest, ref s_firstBackOfficeReqestFlag, ref s_firstBackOfficeRequestLocker, () => { @@ -192,7 +192,7 @@ namespace Umbraco.Cms.Web.Common.Middleware } } - private Uri GetApplicationUrlFromCurrentRequest(HttpRequest request) + private Uri? GetApplicationUrlFromCurrentRequest(HttpRequest request) { // We only consider GET and POST. // Especially the DEBUG sent when debugging the application is annoying because it uses http, even when the https is available. diff --git a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs index 21a6af1723..6cc20f4f52 100644 --- a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs +++ b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs @@ -32,7 +32,7 @@ namespace Umbraco.Cms.Web.Common.ModelBinders // only IPublishedContent will ever exist in the request so when this model binder is used as an IModelBinder // in the aspnet pipeline it will really only support converting from IPublishedContent which is contained // in the UmbracoRouteValues --> IContentModel - UmbracoRouteValues umbracoRouteValues = bindingContext.HttpContext.Features.Get(); + UmbracoRouteValues? umbracoRouteValues = bindingContext.HttpContext.Features.Get(); if (umbracoRouteValues is null) { return Task.CompletedTask; @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Web.Common.ModelBinders /// /// Attempts to bind the model /// - public void BindModel(ModelBindingContext bindingContext, object source, Type modelType) + public void BindModel(ModelBindingContext bindingContext, object? source, Type modelType) { // Null model, return if (source == null) @@ -124,7 +124,7 @@ namespace Umbraco.Cms.Web.Common.ModelBinders } // Last chance : try to convert - Attempt attempt2 = source.TryConvertTo(modelType); + Attempt attempt2 = source.TryConvertTo(modelType); if (attempt2.Success) { bindingContext.Result = ModelBindingResult.Success(attempt2.Result); diff --git a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinderProvider.cs b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinderProvider.cs index 1e07d05985..5fe1638394 100644 --- a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinderProvider.cs +++ b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinderProvider.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Web.Common.ModelBinders /// public class ContentModelBinderProvider : IModelBinderProvider { - public IModelBinder GetBinder(ModelBinderProviderContext context) + public IModelBinder? GetBinder(ModelBinderProviderContext context) { var modelType = context.Metadata.ModelType; diff --git a/src/Umbraco.Web.Common/Models/LoginModel.cs b/src/Umbraco.Web.Common/Models/LoginModel.cs index 07bcf8b7ce..304953a925 100644 --- a/src/Umbraco.Web.Common/Models/LoginModel.cs +++ b/src/Umbraco.Web.Common/Models/LoginModel.cs @@ -7,13 +7,13 @@ namespace Umbraco.Cms.Web.Common.Models { [Required] [Display(Name = "User name")] - public string Username { get; set; } + public string Username { get; set; } = null!; [Required] [DataType(DataType.Password)] [Display(Name = "Password")] [StringLength(maximumLength: 256)] - public string Password { get; set; } + public string Password { get; set; } = null!; [Display(Name = "Remember me?")] public bool RememberMe { get; set; } diff --git a/src/Umbraco.Web.Common/Models/PostRedirectModel.cs b/src/Umbraco.Web.Common/Models/PostRedirectModel.cs index ac12a12f0b..a9b929282d 100644 --- a/src/Umbraco.Web.Common/Models/PostRedirectModel.cs +++ b/src/Umbraco.Web.Common/Models/PostRedirectModel.cs @@ -10,6 +10,6 @@ namespace Umbraco.Cms.Web.Common.Models /// The path to redirect to when update is successful, if not specified then the user will be /// redirected to the current Umbraco page /// - public string RedirectUrl { get; set; } + public string? RedirectUrl { get; set; } } } diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryModelFactory.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryModelFactory.cs index 5019bbb4e3..cdf3d774c2 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryModelFactory.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryModelFactory.cs @@ -34,12 +34,12 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder private bool _pendingRebuild; private readonly IProfilingLogger _profilingLogger; private readonly ILogger _logger; - private readonly FileSystemWatcher _watcher; + private readonly FileSystemWatcher? _watcher; private int _ver; - private int _skipver; + private int? _skipver; private readonly int _debugLevel; - private RoslynCompiler _roslynCompiler; - private UmbracoAssemblyLoadContext _currentAssemblyLoadContext; + private RoslynCompiler? _roslynCompiler; + private UmbracoAssemblyLoadContext? _currentAssemblyLoadContext; private readonly Lazy _umbracoServices; // fixme: this is because of circular refs :( private static readonly Regex s_assemblyVersionRegex = new Regex("AssemblyVersion\\(\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\"\\)", RegexOptions.Compiled); private static readonly string[] s_ourFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err", "Compiled" }; @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder private readonly ApplicationPartManager _applicationPartManager; private static readonly Regex s_usingRegex = new Regex("^using(.*);", RegexOptions.Compiled | RegexOptions.Multiline); private static readonly Regex s_aattrRegex = new Regex("^\\[assembly:(.*)\\]", RegexOptions.Compiled | RegexOptions.Multiline); - private readonly Lazy _pureLiveDirectory; + private readonly Lazy _pureLiveDirectory = null!; private bool _disposedValue; @@ -103,7 +103,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder AssemblyLoadContext.Default.Resolving += OnResolvingDefaultAssemblyLoadContext; } - public event EventHandler ModelsChanged; + public event EventHandler? ModelsChanged; private UmbracoServices UmbracoServices => _umbracoServices.Value; @@ -113,7 +113,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder /// /// Can be null /// - public Assembly CurrentModelsAssembly { get; private set; } + public Assembly? CurrentModelsAssembly { get; private set; } /// public object SyncRoot { get; } = new object(); @@ -145,7 +145,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder /// This is required because the razor engine will only try to load things from the default context, it doesn't know anything /// about our context so we need to proxy. /// - private Assembly OnResolvingDefaultAssemblyLoadContext(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) + private Assembly? OnResolvingDefaultAssemblyLoadContext(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) => assemblyName.Name == RoslynCompiler.GeneratedAssemblyName ? _currentAssemblyLoadContext?.LoadFromAssemblyName(assemblyName) : null; @@ -153,7 +153,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder public IPublishedElement CreateModel(IPublishedElement element) { // get models, rebuilding them if needed - Dictionary infos = EnsureModels()?.ModelInfos; + Dictionary? infos = EnsureModels()?.ModelInfos; if (infos == null) { return element; @@ -166,7 +166,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder infos.TryGetValue(contentTypeAlias, out var info); // create model - return info == null ? element : info.Ctor(element, _publishedValueFallback); + return info is null || info.Ctor is null ? element : info.Ctor(element, _publishedValueFallback); } // this runs only once the factory is ready @@ -179,30 +179,36 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder // this runs only once the factory is ready // NOT when building models - public IList CreateModelList(string alias) + public IList CreateModelList(string? alias) { Infos infos = EnsureModels(); // fail fast - if (infos == null) + if (infos is null || alias is null) { return new List(); } - if (!infos.ModelInfos.TryGetValue(alias, out ModelInfo modelInfo)) + if (infos.ModelInfos is null || !infos.ModelInfos.TryGetValue(alias, out ModelInfo? modelInfo)) { return new List(); } - Func ctor = modelInfo.ListCtor; + Func? ctor = modelInfo.ListCtor; if (ctor != null) { return ctor(); } + if (modelInfo.ModelType is null) + { + return new List(); + } + Type listType = typeof(List<>).MakeGenericType(modelInfo.ModelType); ctor = modelInfo.ListCtor = ReflectionUtilities.EmitConstructor>(declaring: listType); - return ctor(); + + return ctor is null ? new List() : ctor(); } /// @@ -360,7 +366,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder _currentAssemblyLoadContext.Unload(); // we need to remove the current part too - ApplicationPart currentPart = _applicationPartManager.ApplicationParts.FirstOrDefault(x => x.Name == RoslynCompiler.GeneratedAssemblyName); + ApplicationPart? currentPart = _applicationPartManager.ApplicationParts.FirstOrDefault(x => x.Name == RoslynCompiler.GeneratedAssemblyName); if (currentPart != null) { _applicationPartManager.ApplicationParts.Remove(currentPart); @@ -454,14 +460,14 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder { assembly = ReloadAssembly(dllPath); - ModelsBuilderAssemblyAttribute attr = assembly.GetCustomAttribute(); + ModelsBuilderAssemblyAttribute? attr = assembly.GetCustomAttribute(); if (attr != null && attr.IsInMemory && attr.SourceHash == currentHash) { // if we were to resume at that revision, then _ver would keep increasing // and that is probably a bad idea - so, we'll always rebuild starting at // ver 1, but we remember we want to skip that one - so we never end up // with the "same but different" version of the assembly in memory - _skipver = assembly.GetName().Version.Revision; + _skipver = assembly.GetName().Version?.Revision; _logger.LogDebug("Loading cached models (dll)."); return assembly; @@ -561,8 +567,13 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder if (File.Exists(dllPathFile)) { var dllPath = File.ReadAllText(dllPathFile); - DirectoryInfo dirInfo = new DirectoryInfo(dllPath).Parent; - IEnumerable files = dirInfo.GetFiles().Where(f => f.FullName != dllPath); + DirectoryInfo? dirInfo = new DirectoryInfo(dllPath).Parent; + IEnumerable? files = dirInfo?.GetFiles().Where(f => f.FullName != dllPath); + if (files is null) + { + return; + } + foreach (FileInfo file in files) { try @@ -626,8 +637,8 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder foreach (Type type in types) { - ConstructorInfo constructor = null; - Type parameterType = null; + ConstructorInfo? constructor = null; + Type? parameterType = null; foreach (ConstructorInfo ctor in type.GetConstructors()) { @@ -649,12 +660,12 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder throw new InvalidOperationException($"Type {type.FullName} is missing a public constructor with one argument of type, or implementing, IPropertySet."); } - PublishedModelAttribute attribute = type.GetCustomAttribute(false); + PublishedModelAttribute? attribute = type.GetCustomAttribute(false); var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias; if (modelInfos.TryGetValue(typeName, out var modelInfo)) { - throw new InvalidOperationException($"Both types {type.FullName} and {modelInfo.ModelType.FullName} want to be a model type for content type with alias \"{typeName}\"."); + throw new InvalidOperationException($"Both types {type.FullName} and {modelInfo.ModelType?.FullName} want to be a model type for content type with alias \"{typeName}\"."); } // TODO: use Core's ReflectionUtilities.EmitCtor !! @@ -800,8 +811,12 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder { if (disposing) { - _watcher.EnableRaisingEvents = false; - _watcher.Dispose(); + if (_watcher is not null) + { + _watcher.EnableRaisingEvents = false; + _watcher.Dispose(); + } + _locker.Dispose(); } @@ -817,20 +832,20 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder internal class Infos { - public Dictionary ModelTypeMap { get; set; } + public Dictionary? ModelTypeMap { get; set; } - public Dictionary ModelInfos { get; set; } + public Dictionary? ModelInfos { get; set; } } internal class ModelInfo { - public Type ParameterType { get; set; } + public Type? ParameterType { get; set; } - public Func Ctor { get; set; } + public Func? Ctor { get; set; } - public Type ModelType { get; set; } + public Type? ModelType { get; set; } - public Func ListCtor { get; set; } + public Func? ListCtor { get; set; } } } } diff --git a/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs b/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs index ea8408b212..10ee133684 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs @@ -141,8 +141,8 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder /// public void Handle(ModelBindingErrorNotification notification) { - ModelsBuilderAssemblyAttribute sourceAttr = notification.SourceType.Assembly.GetCustomAttribute(); - ModelsBuilderAssemblyAttribute modelAttr = notification.ModelType.Assembly.GetCustomAttribute(); + ModelsBuilderAssemblyAttribute? sourceAttr = notification.SourceType.Assembly.GetCustomAttribute(); + ModelsBuilderAssemblyAttribute? modelAttr = notification.ModelType.Assembly.GetCustomAttribute(); // if source or model is not a ModelsBuider type... if (sourceAttr == null || modelAttr == null) @@ -180,8 +180,8 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder { // both are pure - report, and if different versions, restart // if same version... makes no sense... and better not restart (loops?) - Version sourceVersion = notification.SourceType.Assembly.GetName().Version; - Version modelVersion = notification.ModelType.Assembly.GetName().Version; + Version? sourceVersion = notification.SourceType.Assembly.GetName().Version; + Version? modelVersion = notification.ModelType.Assembly.GetName().Version; notification.Message.Append(" Both view and content models are in memory generated, with "); notification.Message.Append(sourceVersion == modelVersion ? "same version. The application is in an unstable state and should be restarted." diff --git a/src/Umbraco.Web.Common/ModelsBuilder/RefreshingRazorViewEngine.cs b/src/Umbraco.Web.Common/ModelsBuilder/RefreshingRazorViewEngine.cs index 46dba59aba..aafdfa4bb5 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/RefreshingRazorViewEngine.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/RefreshingRazorViewEngine.cs @@ -95,7 +95,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder /// /// When the models change, re-construct the razor stack /// - private void InMemoryModelFactoryModelsChanged(object sender, EventArgs e) + private void InMemoryModelFactoryModelsChanged(object? sender, EventArgs e) { _locker.EnterWriteLock(); try @@ -121,7 +121,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder } } - public string GetAbsolutePath(string executingFilePath, string pagePath) + public string? GetAbsolutePath(string? executingFilePath, string? pagePath) { _locker.EnterReadLock(); try @@ -161,7 +161,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder } } - public ViewEngineResult GetView(string executingFilePath, string viewPath, bool isMainPage) + public ViewEngineResult GetView(string? executingFilePath, string viewPath, bool isMainPage) { _locker.EnterReadLock(); try diff --git a/src/Umbraco.Web.Common/ModelsBuilder/UmbracoAssemblyLoadContext.cs b/src/Umbraco.Web.Common/ModelsBuilder/UmbracoAssemblyLoadContext.cs index e374a7292f..75c08e8772 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/UmbracoAssemblyLoadContext.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/UmbracoAssemblyLoadContext.cs @@ -18,6 +18,6 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder } // we never load anything directly by assembly name. This method will never be called - protected override Assembly Load(AssemblyName assemblyName) => null; + protected override Assembly? Load(AssemblyName assemblyName) => null; } } diff --git a/src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs b/src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs index a744b98e70..2194572e77 100644 --- a/src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs +++ b/src/Umbraco.Web.Common/Mvc/HtmlStringUtilities.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Web.Common.Mvc return new HtmlString(value); } - public HtmlString StripHtmlTags(string html, params string[] tags) + public HtmlString StripHtmlTags(string html, params string[]? tags) { var doc = new HtmlDocument(); doc.LoadHtml("

" + html + "

"); @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Web.Common.Mvc //is element if (node.NodeType != HtmlNodeType.Element) continue; var filterAllTags = (tags == null || !tags.Any()); - if (filterAllTags || tags.Any(tag => string.Equals(tag, node.Name, StringComparison.CurrentCultureIgnoreCase))) + if (filterAllTags || (tags?.Any(tag => string.Equals(tag, node.Name, StringComparison.CurrentCultureIgnoreCase)) ?? false)) { targets.Add(node); } diff --git a/src/Umbraco.Web.Common/Profiler/InitializeWebProfiling.cs b/src/Umbraco.Web.Common/Profiler/InitializeWebProfiling.cs index 45901314a6..cdd6d0aee9 100644 --- a/src/Umbraco.Web.Common/Profiler/InitializeWebProfiling.cs +++ b/src/Umbraco.Web.Common/Profiler/InitializeWebProfiling.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Web.Common.Profiler public class InitializeWebProfiling : INotificationHandler { private readonly bool _profile; - private readonly WebProfiler _profiler; + private readonly WebProfiler? _profiler; /// /// Initializes a new instance of the class. @@ -48,7 +48,7 @@ namespace Umbraco.Cms.Web.Common.Profiler if (_profile && notification.RuntimeLevel == RuntimeLevel.Run) { // Stop the profiling of the booting process - _profiler.StopBoot(); + _profiler?.StopBoot(); } } diff --git a/src/Umbraco.Web.Common/Profiler/WebProfiler.cs b/src/Umbraco.Web.Common/Profiler/WebProfiler.cs index 688414b3de..fe1aa710d4 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfiler.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfiler.cs @@ -24,12 +24,12 @@ namespace Umbraco.Cms.Web.Common.Profiler { _ = x; }); - private MiniProfiler _startupProfiler; + private MiniProfiler? _startupProfiler; private int _first; - public IDisposable Step(string name) + public IDisposable? Step(string name) { return MiniProfiler.Current?.Step(name); } @@ -42,7 +42,7 @@ namespace Umbraco.Cms.Web.Common.Profiler public void StartBoot() => _startupProfiler = MiniProfiler.StartNew("Startup Profiler"); - public void StopBoot() => _startupProfiler.Stop(); + public void StopBoot() => _startupProfiler?.Stop(); public void Stop(bool discardResults = false) => MiniProfilerContext.Value?.Stop(discardResults); @@ -80,7 +80,10 @@ namespace Umbraco.Cms.Web.Common.Profiler var first = Interlocked.Exchange(ref _first, 1) == 0; if (first) { - AddSubProfiler(_startupProfiler); + if (_startupProfiler is not null) + { + AddSubProfiler(_startupProfiler); + } _startupProfiler = null; } @@ -110,10 +113,12 @@ namespace Umbraco.Cms.Web.Common.Profiler private void AddSubProfiler(MiniProfiler subProfiler) { var startupDuration = subProfiler.Root.DurationMilliseconds.GetValueOrDefault(); - MiniProfilerContext.Value.DurationMilliseconds += startupDuration; - MiniProfilerContext.Value.GetTimingHierarchy().First().DurationMilliseconds += startupDuration; - MiniProfilerContext.Value.Root.AddChild(subProfiler.Root); - + if (MiniProfilerContext.Value is not null) + { + MiniProfilerContext.Value.DurationMilliseconds += startupDuration; + MiniProfilerContext.Value.GetTimingHierarchy().First().DurationMilliseconds += startupDuration; + MiniProfilerContext.Value.Root.AddChild(subProfiler.Root); + } } private static bool ShouldProfile(HttpRequest request) diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs index 037e5e40ad..f061c58242 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Web.Common.Profiler var result = StackExchange.Profiling.Internal.Render.Includes( profiler, - path: context.Request.PathBase + path, + path: context is not null ? context.Request.PathBase + path : null, isAuthorized: true, requestIDs: new List { profiler.Id }, position: RenderPosition.Right, diff --git a/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs b/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs index 125a11ef1c..355c73c663 100644 --- a/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs +++ b/src/Umbraco.Web.Common/Routing/RoutableDocumentFilter.cs @@ -29,7 +29,7 @@ namespace Umbraco.Cms.Web.Common.Routing private readonly object _routeLocker = new object(); private object _initLocker = new object(); private bool _isInit = false; - private HashSet _reservedList; + private HashSet? _reservedList; /// /// Initializes a new instance of the class. @@ -134,7 +134,7 @@ namespace Umbraco.Cms.Web.Common.Routing } // return true if URL starts with an element of the reserved list - var isReserved = _reservedList.Any(x => absPath.InvariantStartsWith(x)); + var isReserved = _reservedList?.Any(x => absPath.InvariantStartsWith(x)) ?? false; if (isReserved) { @@ -170,7 +170,7 @@ namespace Umbraco.Cms.Web.Common.Routing // Borrowed and modified from https://stackoverflow.com/a/59550580 // Return a collection of Microsoft.AspNetCore.Http.Endpoint instances. - IEnumerable routeEndpoints = _endpointDataSource?.Endpoints + IEnumerable? routeEndpoints = _endpointDataSource?.Endpoints .OfType() .Where(x => { @@ -195,10 +195,10 @@ namespace Umbraco.Cms.Web.Common.Routing var routeValues = new RouteValueDictionary(); // To get the matchedEndpoint of the provide url - RouteEndpoint matchedEndpoint = routeEndpoints? + RouteEndpoint? matchedEndpoint = routeEndpoints? .Where(e => e.RoutePattern.RawText != null) .Where(e => new TemplateMatcher( - TemplateParser.Parse(e.RoutePattern.RawText), + TemplateParser.Parse(e.RoutePattern.RawText!), new RouteValueDictionary()) .TryMatch(absPath, routeValues)) .OrderBy(c => c.Order) diff --git a/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs b/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs index 6088f21931..d06f9bcd28 100644 --- a/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs +++ b/src/Umbraco.Web.Common/Routing/UmbracoRouteValues.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Web.Common.Routing public UmbracoRouteValues( IPublishedRequest publishedRequest, ControllerActionDescriptor controllerActionDescriptor, - string templateName = null) + string? templateName = null) { PublishedRequest = publishedRequest; ControllerActionDescriptor = controllerActionDescriptor; @@ -41,7 +41,7 @@ namespace Umbraco.Cms.Web.Common.Routing /// /// Gets the template name /// - public string TemplateName { get; } + public string? TemplateName { get; } /// /// Gets the controller type diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs index 198fe7a5d0..b1dc202a37 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeHelperAccessor.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Web.Common.RuntimeMinification var httpContext = _httpContextAccessor.HttpContext; if (httpContext == null) throw new InvalidOperationException($"Cannot get a {nameof(SmidgeHelper)} instance since there is no current http request"); - return httpContext.RequestServices.GetService(); + return httpContext.RequestServices.GetService()!; } } } diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs index 6e24c06b8e..992c676618 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs @@ -36,7 +36,7 @@ namespace Umbraco.Cms.Web.Common.RuntimeMinification private readonly Lazy _jsNonOptimizedPipeline; private readonly Lazy _cssOptimizedPipeline; private readonly Lazy _cssNonOptimizedPipeline; - private ICacheBuster _cacheBuster; + private ICacheBuster? _cacheBuster; private readonly Type _cacheBusterType; public SmidgeRuntimeMinifier( @@ -88,9 +88,9 @@ namespace Umbraco.Cms.Web.Common.RuntimeMinification public string CacheBuster => (_cacheBuster ??= _cacheBusterResolver.GetCacheBuster(_cacheBusterType)).GetValue(); // only issue with creating bundles like this is that we don't have full control over the bundle options, though that could - public void CreateCssBundle(string bundleName, BundlingOptions bundleOptions, params string[] filePaths) + public void CreateCssBundle(string bundleName, BundlingOptions bundleOptions, params string[]? filePaths) { - if (filePaths.Any(f => !f.StartsWith("/") && !f.StartsWith("~/"))) + if (filePaths?.Any(f => !f.StartsWith("/") && !f.StartsWith("~/")) ?? false) { throw new InvalidOperationException("All file paths must be absolute"); } @@ -110,9 +110,9 @@ namespace Umbraco.Cms.Web.Common.RuntimeMinification public async Task RenderCssHereAsync(string bundleName) => (await _smidge.SmidgeHelper.CssHereAsync(bundleName, _hostingEnvironment.IsDebugMode)).ToString(); - public void CreateJsBundle(string bundleName, BundlingOptions bundleOptions, params string[] filePaths) + public void CreateJsBundle(string bundleName, BundlingOptions bundleOptions, params string[]? filePaths) { - if (filePaths.Any(f => !f.StartsWith("/") && !f.StartsWith("~/"))) + if (filePaths?.Any(f => !f.StartsWith("/") && !f.StartsWith("~/")) ?? false) { throw new InvalidOperationException("All file paths must be absolute"); } diff --git a/src/Umbraco.Web.Common/RuntimeMinification/UmbracoSmidgeConfigCacheBuster.cs b/src/Umbraco.Web.Common/RuntimeMinification/UmbracoSmidgeConfigCacheBuster.cs index c323204148..b3d114e103 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/UmbracoSmidgeConfigCacheBuster.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/UmbracoSmidgeConfigCacheBuster.cs @@ -39,7 +39,7 @@ namespace Umbraco.Cms.Web.Common.RuntimeMinification private readonly IUmbracoVersion _umbracoVersion; private readonly IEntryAssemblyMetadata _entryAssemblyMetadata; - private string _cacheBusterValue; + private string? _cacheBusterValue; public UmbracoSmidgeConfigCacheBuster( IOptions runtimeMinificationSettings, diff --git a/src/Umbraco.Web.Common/Security/BackOfficeSecurityAccessor.cs b/src/Umbraco.Web.Common/Security/BackOfficeSecurityAccessor.cs index d98877e1c7..bcb74aa286 100644 --- a/src/Umbraco.Web.Common/Security/BackOfficeSecurityAccessor.cs +++ b/src/Umbraco.Web.Common/Security/BackOfficeSecurityAccessor.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Web.Common.Security /// /// Gets the current object. /// - public IBackOfficeSecurity BackOfficeSecurity + public IBackOfficeSecurity? BackOfficeSecurity => _httpContextAccessor.HttpContext?.RequestServices?.GetService(); } } diff --git a/src/Umbraco.Web.Common/Security/BackOfficeUserManager.cs b/src/Umbraco.Web.Common/Security/BackOfficeUserManager.cs index 505abdbe0e..aa3323e101 100644 --- a/src/Umbraco.Web.Common/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Web.Common/Security/BackOfficeUserManager.cs @@ -169,18 +169,18 @@ namespace Umbraco.Cms.Web.Common.Security return result; } - private string GetCurrentUserId(IPrincipal currentUser) + private string GetCurrentUserId(IPrincipal? currentUser) { - ClaimsIdentity umbIdentity = currentUser?.GetUmbracoIdentity(); + ClaimsIdentity? umbIdentity = currentUser?.GetUmbracoIdentity(); var currentUserId = umbIdentity?.GetUserId() ?? Core.Constants.Security.SuperUserIdAsString; return currentUserId; } - public void NotifyAccountLocked(IPrincipal currentUser, string userId) => Notify(currentUser, + public void NotifyAccountLocked(IPrincipal? currentUser, string userId) => Notify(currentUser, (currentUserId, ip) => new UserLockedNotification(ip, userId, currentUserId) ); - public void NotifyAccountUnlocked(IPrincipal currentUser, string userId) => Notify(currentUser, + public void NotifyAccountUnlocked(IPrincipal? currentUser, string userId) => Notify(currentUser, (currentUserId, ip) => new UserUnlockedNotification(ip, userId, currentUserId) ); @@ -192,7 +192,7 @@ namespace Umbraco.Cms.Web.Common.Security (currentUserId, ip) => new UserForgotPasswordChangedNotification(ip, userId, currentUserId) ); - public void NotifyLoginFailed(IPrincipal currentUser, string userId) => Notify(currentUser, + public void NotifyLoginFailed(IPrincipal? currentUser, string userId) => Notify(currentUser, (currentUserId, ip) => new UserLoginFailedNotification(ip, userId, currentUserId) ); @@ -213,19 +213,19 @@ namespace Umbraco.Cms.Web.Common.Security return new SignOutSuccessResult { SignOutRedirectUrl = notification.SignOutRedirectUrl }; } - public void NotifyPasswordChanged(IPrincipal currentUser, string userId) => Notify(currentUser, + public void NotifyPasswordChanged(IPrincipal? currentUser, string userId) => Notify(currentUser, (currentUserId, ip) => new UserPasswordChangedNotification(ip, userId, currentUserId) ); - public void NotifyPasswordReset(IPrincipal currentUser, string userId) => Notify(currentUser, + public void NotifyPasswordReset(IPrincipal? currentUser, string userId) => Notify(currentUser, (currentUserId, ip) => new UserPasswordResetNotification(ip, userId, currentUserId) ); - public void NotifyResetAccessFailedCount(IPrincipal currentUser, string userId) => Notify(currentUser, + public void NotifyResetAccessFailedCount(IPrincipal? currentUser, string userId) => Notify(currentUser, (currentUserId, ip) => new UserResetAccessFailedCountNotification(ip, userId, currentUserId) ); - private T Notify(IPrincipal currentUser, Func createNotification) where T : INotification + private T Notify(IPrincipal? currentUser, Func createNotification) where T : INotification { var currentUserId = GetCurrentUserId(currentUser); var ip = IpResolver.GetCurrentRequestIpAddress(); diff --git a/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs index 13ff104265..8630197650 100644 --- a/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs +++ b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Web.Common.Security private readonly IHttpContextAccessor _httpContextAccessor; private readonly object _currentUserLock = new object(); - private IUser _currentUser; + private IUser? _currentUser; public BackOfficeSecurity( IUserService userService, @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Web.Common.Security } /// - public IUser CurrentUser + public IUser? CurrentUser { get { @@ -55,15 +55,15 @@ namespace Umbraco.Cms.Web.Common.Security /// public Attempt GetUserId() { - ClaimsIdentity identity = _httpContextAccessor.HttpContext?.GetCurrentIdentity(); + ClaimsIdentity? identity = _httpContextAccessor.HttpContext?.GetCurrentIdentity(); return identity == null ? Attempt.Fail() : Attempt.Succeed(identity.GetId()); } /// public bool IsAuthenticated() { - HttpContext httpContext = _httpContextAccessor.HttpContext; - return httpContext?.User != null && httpContext.User.Identity.IsAuthenticated && httpContext.GetCurrentIdentity() != null; + HttpContext? httpContext = _httpContextAccessor.HttpContext; + return httpContext?.User != null && (httpContext.User.Identity?.IsAuthenticated ?? false) && httpContext.GetCurrentIdentity() != null; } /// diff --git a/src/Umbraco.Web.Common/Security/EncryptionHelper.cs b/src/Umbraco.Web.Common/Security/EncryptionHelper.cs index 48154d7c8f..8c9ebe2fff 100644 --- a/src/Umbraco.Web.Common/Security/EncryptionHelper.cs +++ b/src/Umbraco.Web.Common/Security/EncryptionHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net; using System.Web; @@ -30,7 +31,7 @@ namespace Umbraco.Cms.Web.Common.Security /// This is used in methods like BeginUmbracoForm and SurfaceAction to generate an encrypted string which gets submitted in a request for which /// Umbraco can decrypt during the routing process in order to delegate the request to a specific MVC Controller. /// - public static string CreateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string controllerName, string controllerAction, string area, object additionalRouteVals = null) + public static string CreateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string controllerName, string controllerAction, string area, object? additionalRouteVals = null) { if (dataProtectionProvider is null) { @@ -56,7 +57,7 @@ namespace Umbraco.Cms.Web.Common.Security var surfaceRouteParams = $"{ViewConstants.ReservedAdditionalKeys.Controller}={WebUtility.UrlEncode(controllerName)}&{ViewConstants.ReservedAdditionalKeys.Action}={WebUtility.UrlEncode(controllerAction)}&{ViewConstants.ReservedAdditionalKeys.Area}={area}"; // checking if the additional route values is already a dictionary and convert to querystring - string additionalRouteValsAsQuery; + string? additionalRouteValsAsQuery; if (additionalRouteVals != null) { if (additionalRouteVals is Dictionary additionalRouteValsAsDictionary) @@ -81,7 +82,7 @@ namespace Umbraco.Cms.Web.Common.Security return Encrypt(surfaceRouteParams, dataProtectionProvider); } - public static bool DecryptAndValidateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string encryptedString, out IDictionary parts) + public static bool DecryptAndValidateEncryptedRouteString(IDataProtectionProvider dataProtectionProvider, string encryptedString, [MaybeNullWhen(false)] out IDictionary parts) { if (dataProtectionProvider == null) { @@ -101,10 +102,13 @@ namespace Umbraco.Cms.Web.Common.Security } NameValueCollection parsedQueryString = HttpUtility.ParseQueryString(decryptedString); - parts = new Dictionary(); + parts = new Dictionary(); foreach (var key in parsedQueryString.AllKeys) { - parts[key] = parsedQueryString[key]; + if (key is not null) + { + parts[key] = parsedQueryString[key]; + } } // validate all required keys exist diff --git a/src/Umbraco.Web.Common/Security/IBackOfficeSignInManager.cs b/src/Umbraco.Web.Common/Security/IBackOfficeSignInManager.cs index 38ed6ba74a..0c7ff39c02 100644 --- a/src/Umbraco.Web.Common/Security/IBackOfficeSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/IBackOfficeSignInManager.cs @@ -12,14 +12,14 @@ namespace Umbraco.Cms.Web.BackOffice.Security /// public interface IBackOfficeSignInManager { - AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string userId = null); + AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string? userId = null); Task ExternalLoginSignInAsync(ExternalLoginInfo loginInfo, bool isPersistent, bool bypassTwoFactor = false); Task> GetExternalAuthenticationSchemesAsync(); - Task GetExternalLoginInfoAsync(string expectedXsrf = null); + Task GetExternalLoginInfoAsync(string? expectedXsrf = null); Task GetTwoFactorAuthenticationUserAsync(); Task PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure); Task SignOutAsync(); - Task SignInAsync(BackOfficeIdentityUser user, bool isPersistent, string authenticationMethod = null); + Task SignInAsync(BackOfficeIdentityUser user, bool isPersistent, string? authenticationMethod = null); Task CreateUserPrincipalAsync(BackOfficeIdentityUser user); Task TwoFactorSignInAsync(string provider, string code, bool isPersistent, bool rememberClient); Task UpdateExternalAuthenticationTokensAsync(ExternalLoginInfo externalLogin); diff --git a/src/Umbraco.Web.Common/Security/IMemberExternalLoginProviders.cs b/src/Umbraco.Web.Common/Security/IMemberExternalLoginProviders.cs index b3d6813c2f..50beb1f65a 100644 --- a/src/Umbraco.Web.Common/Security/IMemberExternalLoginProviders.cs +++ b/src/Umbraco.Web.Common/Security/IMemberExternalLoginProviders.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Web.Common.Security /// /// /// - Task GetAsync(string authenticationType); + Task GetAsync(string authenticationType); /// /// Get all registered diff --git a/src/Umbraco.Web.Common/Security/IMemberSignInManager.cs b/src/Umbraco.Web.Common/Security/IMemberSignInManager.cs index 4ba5caca9b..04d591866d 100644 --- a/src/Umbraco.Web.Common/Security/IMemberSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/IMemberSignInManager.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Web.Common.Security { // TODO: We could have a base interface for these to share with IBackOfficeSignInManager Task PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure); - Task SignInAsync(MemberIdentityUser user, bool isPersistent, string authenticationMethod = null); + Task SignInAsync(MemberIdentityUser user, bool isPersistent, string? authenticationMethod = null); Task SignOutAsync(); } } diff --git a/src/Umbraco.Web.Common/Security/IMemberSignInManagerExternalLogins.cs b/src/Umbraco.Web.Common/Security/IMemberSignInManagerExternalLogins.cs index eb6a66a000..20fe99b30a 100644 --- a/src/Umbraco.Web.Common/Security/IMemberSignInManagerExternalLogins.cs +++ b/src/Umbraco.Web.Common/Security/IMemberSignInManagerExternalLogins.cs @@ -9,8 +9,8 @@ namespace Umbraco.Cms.Web.Common.Security [Obsolete("This interface will be merged with IMemberSignInManager in Umbraco 10")] public interface IMemberSignInManagerExternalLogins : IMemberSignInManager { - AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string userId = null); - Task GetExternalLoginInfoAsync(string expectedXsrf = null); + AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string? userId = null); + Task GetExternalLoginInfoAsync(string? expectedXsrf = null); Task UpdateExternalAuthenticationTokensAsync(ExternalLoginInfo externalLogin); Task ExternalLoginSignInAsync(ExternalLoginInfo loginInfo, bool isPersistent, bool bypassTwoFactor = false); Task GetTwoFactorAuthenticationUserAsync(); diff --git a/src/Umbraco.Web.Common/Security/MemberCookieManager.cs b/src/Umbraco.Web.Common/Security/MemberCookieManager.cs index 9e176d15c1..bdc4306e55 100644 --- a/src/Umbraco.Web.Common/Security/MemberCookieManager.cs +++ b/src/Umbraco.Web.Common/Security/MemberCookieManager.cs @@ -54,7 +54,7 @@ namespace Umbraco.Cms.Web.Common.Security /// Explicitly implement this so that we filter the request /// /// - string ICookieManager.GetRequestCookie(HttpContext context, string key) + string? ICookieManager.GetRequestCookie(HttpContext context, string key) { var absPath = context.Request.Path; diff --git a/src/Umbraco.Web.Common/Security/MemberExternalLoginProvider.cs b/src/Umbraco.Web.Common/Security/MemberExternalLoginProvider.cs index 9681d47413..e146f7bc2c 100644 --- a/src/Umbraco.Web.Common/Security/MemberExternalLoginProvider.cs +++ b/src/Umbraco.Web.Common/Security/MemberExternalLoginProvider.cs @@ -28,8 +28,8 @@ namespace Umbraco.Cms.Web.Common.Security public MemberExternalLoginProviderOptions Options { get; } - public override bool Equals(object obj) => Equals(obj as MemberExternalLoginProvider); - public bool Equals(MemberExternalLoginProvider other) => other != null && AuthenticationType == other.AuthenticationType; + public override bool Equals(object? obj) => Equals(obj as MemberExternalLoginProvider); + public bool Equals(MemberExternalLoginProvider? other) => other != null && AuthenticationType == other.AuthenticationType; public override int GetHashCode() => HashCode.Combine(AuthenticationType); } diff --git a/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderOptions.cs b/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderOptions.cs index ea93a522da..3a98b701d7 100644 --- a/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderOptions.cs +++ b/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderOptions.cs @@ -6,9 +6,9 @@ namespace Umbraco.Cms.Web.Common.Security public class MemberExternalLoginProviderOptions { public MemberExternalLoginProviderOptions( - MemberExternalSignInAutoLinkOptions autoLinkOptions = null, + MemberExternalSignInAutoLinkOptions? autoLinkOptions = null, bool autoRedirectLoginToExternalProvider = false, - string customBackOfficeView = null) + string? customBackOfficeView = null) { AutoLinkOptions = autoLinkOptions ?? new MemberExternalSignInAutoLinkOptions(); } diff --git a/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderScheme.cs b/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderScheme.cs index 600405b638..423fa899e4 100644 --- a/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderScheme.cs +++ b/src/Umbraco.Web.Common/Security/MemberExternalLoginProviderScheme.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Web.Common.Security { public MemberExternalLoginProviderScheme( MemberExternalLoginProvider externalLoginProvider, - AuthenticationScheme authenticationScheme) + AuthenticationScheme? authenticationScheme) { ExternalLoginProvider = externalLoginProvider ?? throw new ArgumentNullException(nameof(externalLoginProvider)); AuthenticationScheme = authenticationScheme ?? throw new ArgumentNullException(nameof(authenticationScheme)); diff --git a/src/Umbraco.Web.Common/Security/MemberExternalLoginProviders.cs b/src/Umbraco.Web.Common/Security/MemberExternalLoginProviders.cs index 28102c434f..41b298d903 100644 --- a/src/Umbraco.Web.Common/Security/MemberExternalLoginProviders.cs +++ b/src/Umbraco.Web.Common/Security/MemberExternalLoginProviders.cs @@ -23,18 +23,18 @@ namespace Umbraco.Cms.Web.Common.Security } /// - public async Task GetAsync(string authenticationType) + public async Task GetAsync(string authenticationType) { var schemaName = authenticationType.EnsureStartsWith(Core.Constants.Security.MemberExternalAuthenticationTypePrefix); - if (!_externalLogins.TryGetValue(schemaName, out MemberExternalLoginProvider provider)) + if (!_externalLogins.TryGetValue(schemaName, out MemberExternalLoginProvider? provider)) { return null; } // get the associated scheme - AuthenticationScheme associatedScheme = await _authenticationSchemeProvider.GetSchemeAsync(provider.AuthenticationType); + AuthenticationScheme? associatedScheme = await _authenticationSchemeProvider.GetSchemeAsync(provider.AuthenticationType); if (associatedScheme == null) { @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Web.Common.Security foreach (MemberExternalLoginProvider login in _externalLogins.Values) { // get the associated scheme - AuthenticationScheme associatedScheme = await _authenticationSchemeProvider.GetSchemeAsync(login.AuthenticationType); + AuthenticationScheme? associatedScheme = await _authenticationSchemeProvider.GetSchemeAsync(login.AuthenticationType); providersWithSchemes.Add(new MemberExternalLoginProviderScheme(login, associatedScheme)); } diff --git a/src/Umbraco.Web.Common/Security/MemberExternalSignInAutoLinkOptions.cs b/src/Umbraco.Web.Common/Security/MemberExternalSignInAutoLinkOptions.cs index 42dcf6d56f..21ce550196 100644 --- a/src/Umbraco.Web.Common/Security/MemberExternalSignInAutoLinkOptions.cs +++ b/src/Umbraco.Web.Common/Security/MemberExternalSignInAutoLinkOptions.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Web.Common.Security /// public class MemberExternalSignInAutoLinkOptions { - private readonly string _defaultCulture; + private readonly string? _defaultCulture; /// /// Initializes a new instance of the class. @@ -22,8 +22,8 @@ namespace Umbraco.Cms.Web.Common.Security bool autoLinkExternalAccount = false, bool defaultIsApproved = true, string defaultMemberTypeAlias = Core.Constants.Conventions.MemberTypes.DefaultAlias, - string defaultCulture = null, - IEnumerable defaultMemberGroups = null) + string? defaultCulture = null, + IEnumerable? defaultMemberGroups = null) { AutoLinkExternalAccount = autoLinkExternalAccount; DefaultIsApproved = defaultIsApproved; @@ -36,14 +36,14 @@ namespace Umbraco.Cms.Web.Common.Security /// A callback executed during account auto-linking and before the user is persisted /// [IgnoreDataMember] - public Action OnAutoLinking { get; set; } + public Action? OnAutoLinking { get; set; } /// /// A callback executed during every time a user authenticates using an external login. /// returns a boolean indicating if sign in should continue or not. /// [IgnoreDataMember] - public Func OnExternalLogin { get; set; } + public Func? OnExternalLogin { get; set; } /// /// Gets a value indicating whether flag indicating if logging in with the external provider should auto-link/create a diff --git a/src/Umbraco.Web.Common/Security/MemberManager.cs b/src/Umbraco.Web.Common/Security/MemberManager.cs index dad9fddad2..f9f4f3d0bb 100644 --- a/src/Umbraco.Web.Common/Security/MemberManager.cs +++ b/src/Umbraco.Web.Common/Security/MemberManager.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Web.Common.Security private readonly IMemberUserStore _store; private readonly IPublicAccessService _publicAccessService; private readonly IHttpContextAccessor _httpContextAccessor; - private MemberIdentityUser _currentMember; + private MemberIdentityUser? _currentMember; public MemberManager( IIpResolver ipResolver, @@ -49,7 +49,7 @@ namespace Umbraco.Cms.Web.Common.Security public override bool SupportsUserTwoFactor => true; /// - public async Task IsMemberAuthorizedAsync(IEnumerable allowTypes = null, IEnumerable allowGroups = null, IEnumerable allowMembers = null) + public async Task IsMemberAuthorizedAsync(IEnumerable? allowTypes = null, IEnumerable? allowGroups = null, IEnumerable? allowMembers = null) { if (allowTypes == null) { @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Web.Common.Security } else { - MemberIdentityUser currentMember = await GetCurrentMemberAsync(); + MemberIdentityUser? currentMember = await GetCurrentMemberAsync(); // If a member could not be resolved from the provider, we are clearly not authorized and can break right here if (currentMember == null) @@ -91,7 +91,7 @@ namespace Umbraco.Cms.Web.Common.Security if (allowTypesList.Any(allowType => allowType != string.Empty)) { // Allow only if member's type is in list - allowAction = allowTypesList.Select(x => x.ToLowerInvariant()).Contains(currentMember.MemberTypeAlias.ToLowerInvariant()); + allowAction = allowTypesList.Select(x => x.ToLowerInvariant()).Contains(currentMember.MemberTypeAlias?.ToLowerInvariant()); } // If specific members defined, check member is of one of those @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Web.Common.Security /// public bool IsLoggedIn() { - HttpContext httpContext = _httpContextAccessor.HttpContext; + HttpContext? httpContext = _httpContextAccessor.HttpContext; return httpContext?.User.Identity?.IsAuthenticated ?? false; } @@ -169,7 +169,7 @@ namespace Umbraco.Cms.Web.Common.Security } /// - public async Task GetCurrentMemberAsync() + public async Task GetCurrentMemberAsync() { if (_currentMember == null) { @@ -177,7 +177,7 @@ namespace Umbraco.Cms.Web.Common.Security { return null; } - _currentMember = await GetUserAsync(_httpContextAccessor.HttpContext.User); + _currentMember = await GetUserAsync(_httpContextAccessor.HttpContext?.User); } return _currentMember; } @@ -190,7 +190,7 @@ namespace Umbraco.Cms.Web.Common.Security /// private async Task HasAccessAsync(string path) { - MemberIdentityUser currentMember = await GetCurrentMemberAsync(); + MemberIdentityUser? currentMember = await GetCurrentMemberAsync(); if (currentMember == null || !currentMember.IsApproved || currentMember.IsLockedOut) { return false; @@ -205,7 +205,7 @@ namespace Umbraco.Cms.Web.Common.Security private async Task> HasAccessAsync(IEnumerable paths) { var result = new Dictionary(); - MemberIdentityUser currentMember = await GetCurrentMemberAsync(); + MemberIdentityUser? currentMember = await GetCurrentMemberAsync(); if (currentMember == null || !currentMember.IsApproved || currentMember.IsLockedOut) { @@ -213,7 +213,7 @@ namespace Umbraco.Cms.Web.Common.Security } // ensure we only lookup user roles once - IList userRoles = null; + IList? userRoles = null; async Task> getUserRolesAsync() { if (userRoles != null) @@ -235,6 +235,6 @@ namespace Umbraco.Cms.Web.Common.Security return result; } - public IPublishedContent AsPublishedMember(MemberIdentityUser user) => _store.GetPublishedMember(user); + public IPublishedContent? AsPublishedMember(MemberIdentityUser user) => _store.GetPublishedMember(user); } } diff --git a/src/Umbraco.Web.Common/Security/MemberSignInManager.cs b/src/Umbraco.Web.Common/Security/MemberSignInManager.cs index e8bf1c2eb3..2710dc38c1 100644 --- a/src/Umbraco.Web.Common/Security/MemberSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/MemberSignInManager.cs @@ -70,7 +70,7 @@ namespace Umbraco.Cms.Web.Common.Security protected override string TwoFactorRememberMeAuthenticationType => IdentityConstants.TwoFactorRememberMeScheme; /// - public override async Task GetExternalLoginInfoAsync(string expectedXsrf = null) + public override async Task GetExternalLoginInfoAsync(string? expectedXsrf = null) { // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs#L422 // to replace the auth scheme @@ -111,7 +111,7 @@ namespace Umbraco.Cms.Web.Common.Security var providerDisplayName = (await GetExternalAuthenticationSchemesAsync()).FirstOrDefault(p => p.Name == provider)?.DisplayName ?? provider; return new ExternalLoginInfo(auth.Principal, provider, providerKey, providerDisplayName) { - AuthenticationTokens = auth.Properties.GetTokens(), + AuthenticationTokens = auth.Properties?.GetTokens(), AuthenticationProperties = auth.Properties }; } @@ -157,7 +157,7 @@ namespace Umbraco.Cms.Web.Common.Security /// /// /// - private async Task AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo, MemberExternalSignInAutoLinkOptions autoLinkOptions) + private async Task AutoLinkAndSignInExternalAccount(ExternalLoginInfo loginInfo, MemberExternalSignInAutoLinkOptions? autoLinkOptions) { // If there are no autolink options then the attempt is failed (user does not exist) if (autoLinkOptions == null || !autoLinkOptions.AutoLinkExternalAccount) @@ -295,7 +295,7 @@ namespace Umbraco.Cms.Web.Common.Security } /// - public override AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string userId = null) + public override AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string? userId = null) { // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs // to be able to use our own XsrfKey/LoginProviderKey because the default is private :/ @@ -354,7 +354,7 @@ namespace Umbraco.Cms.Web.Common.Security Logger.LogWarning("The AutoLinkOptions of the external authentication provider '{LoginProvider}' have refused the login based on the OnExternalLogin method. Affected user id: '{UserId}'", loginInfo.LoginProvider, user.Id); protected override async Task SignInOrTwoFactorAsync(MemberIdentityUser user, bool isPersistent, - string loginProvider = null, bool bypassTwoFactor = false) + string? loginProvider = null, bool bypassTwoFactor = false) { var result = await base.SignInOrTwoFactorAsync(user, isPersistent, loginProvider, bypassTwoFactor); diff --git a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs index cc07b6bd28..8e276b57a6 100644 --- a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs @@ -51,7 +51,7 @@ namespace Umbraco.Cms.Web.Common.Security } /// - public override async Task GetExternalLoginInfoAsync(string expectedXsrf = null) + public override async Task GetExternalLoginInfoAsync(string? expectedXsrf = null) { // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs#L422 // to replace the auth scheme @@ -91,7 +91,7 @@ namespace Umbraco.Cms.Web.Common.Security var providerDisplayName = (await GetExternalAuthenticationSchemesAsync()).FirstOrDefault(p => p.Name == provider)?.DisplayName ?? provider; return new ExternalLoginInfo(auth.Principal, provider, providerKey, providerDisplayName) { - AuthenticationTokens = auth.Properties.GetTokens(), + AuthenticationTokens = auth.Properties?.GetTokens(), AuthenticationProperties = auth.Properties }; } @@ -105,7 +105,7 @@ namespace Umbraco.Cms.Web.Common.Security var info = await RetrieveTwoFactorInfoAsync(); if (info == null) { - return null; + return null!; } return await UserManager.FindByIdAsync(info.UserId); } @@ -198,7 +198,7 @@ namespace Umbraco.Cms.Web.Common.Security } /// - public override async Task SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable additionalClaims) + public override async Task SignInWithClaimsAsync(TUser user, AuthenticationProperties? authenticationProperties, IEnumerable additionalClaims) { // override to replace IdentityConstants.ApplicationScheme with custom AuthenticationType // code taken from aspnetcore: https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs @@ -308,7 +308,7 @@ namespace Umbraco.Cms.Web.Common.Security /// /// /// - protected virtual async Task HandleSignIn(TUser user, string username, SignInResult result) + protected virtual async Task HandleSignIn(TUser? user, string? username, SignInResult result) { // TODO: Here I believe we can do all (or most) of the usermanager event raising so that it is not in the AuthenticationController @@ -320,7 +320,7 @@ namespace Umbraco.Cms.Web.Common.Security if (result.Succeeded) { //track the last login date - user.LastLoginDateUtc = DateTime.UtcNow; + user!.LastLoginDateUtc = DateTime.UtcNow; if (user.AccessFailedCount > 0) { //we have successfully logged in, reset the AccessFailedCount @@ -351,7 +351,7 @@ namespace Umbraco.Cms.Web.Common.Security } /// - protected override async Task SignInOrTwoFactorAsync(TUser user, bool isPersistent, string loginProvider = null, bool bypassTwoFactor = false) + protected override async Task SignInOrTwoFactorAsync(TUser user, bool isPersistent, string? loginProvider = null, bool bypassTwoFactor = false) { // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs // to replace custom auth types @@ -391,7 +391,7 @@ namespace Umbraco.Cms.Web.Common.Security // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs#L743 // to replace custom auth types - private ClaimsPrincipal StoreTwoFactorInfo(string userId, string loginProvider) + private ClaimsPrincipal StoreTwoFactorInfo(string userId, string? loginProvider) { var identity = new ClaimsIdentity(TwoFactorAuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, userId)); @@ -419,7 +419,7 @@ namespace Umbraco.Cms.Web.Common.Security // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs // copy is required in order to use a custom auth type - private async Task RetrieveTwoFactorInfoAsync() + private async Task RetrieveTwoFactorInfoAsync() { var result = await Context.AuthenticateAsync(TwoFactorAuthenticationType); if (result?.Principal != null) @@ -463,8 +463,8 @@ namespace Umbraco.Cms.Web.Common.Security // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs#L891 private class TwoFactorAuthenticationInfo { - public string UserId { get; set; } - public string LoginProvider { get; set; } + public string? UserId { get; set; } + public string? LoginProvider { get; set; } } } } diff --git a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs index 92ec2fa962..46d5856c9d 100644 --- a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs @@ -93,7 +93,7 @@ namespace Umbraco.Cms.Web.Common.Templates requestBuilder.SetCulture(defaultLanguage == null ? CultureInfo.CurrentUICulture.Name - : defaultLanguage.CultureInfo.Name); + : defaultLanguage.CultureInfo?.Name); } else { @@ -130,7 +130,7 @@ namespace Umbraco.Cms.Web.Common.Templates // First, save all of the items locally that we know are used in the chain of execution, we'll need to restore these // after this page has rendered. - SaveExistingItems(out IPublishedRequest oldPublishedRequest); + SaveExistingItems(out IPublishedRequest? oldPublishedRequest); IPublishedRequest contentRequest = requestBuilder.Build(); @@ -199,7 +199,7 @@ namespace Umbraco.Cms.Web.Common.Templates /// /// Save all items that we know are used for rendering execution to variables so we can restore after rendering /// - private void SaveExistingItems(out IPublishedRequest oldPublishedRequest) + private void SaveExistingItems(out IPublishedRequest? oldPublishedRequest) { var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); // Many objects require that these legacy items are in the http context items... before we render this template we need to first @@ -210,7 +210,7 @@ namespace Umbraco.Cms.Web.Common.Templates /// /// Restores all items back to their context's to continue normal page rendering execution /// - private void RestoreItems(IPublishedRequest oldPublishedRequest) + private void RestoreItems(IPublishedRequest? oldPublishedRequest) { var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); umbracoContext.PublishedRequest = oldPublishedRequest; diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs index cc56526d72..98f3db5483 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs @@ -20,12 +20,12 @@ namespace Umbraco.Cms.Web.Common.UmbracoContext private readonly ICookieManager _cookieManager; private readonly IHttpContextAccessor _httpContextAccessor; private readonly Lazy _publishedSnapshot; - private string _previewToken; + private string? _previewToken; private bool? _previewing; private readonly UmbracoRequestPaths _umbracoRequestPaths; - private Uri _requestUrl; - private Uri _originalRequestUrl; - private Uri _cleanedUmbracoUrl; + private Uri? _requestUrl; + private Uri? _originalRequestUrl; + private Uri? _cleanedUmbracoUrl; // initializes a new instance of the UmbracoContext class // internal for unit tests @@ -67,7 +67,7 @@ namespace Umbraco.Cms.Web.Common.UmbracoContext internal Guid UmbracoRequestId { get; } // lazily get/create a Uri for the current request - private Uri RequestUrl => _requestUrl ??= _httpContextAccessor.HttpContext is null + private Uri? RequestUrl => _requestUrl ??= _httpContextAccessor.HttpContext is null ? null : new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl()); @@ -94,16 +94,16 @@ namespace Umbraco.Cms.Web.Common.UmbracoContext public IPublishedMediaCache Media => PublishedSnapshot.Media; /// - public IDomainCache Domains => PublishedSnapshot.Domains; + public IDomainCache? Domains => PublishedSnapshot.Domains; /// - public IPublishedRequest PublishedRequest { get; set; } + public IPublishedRequest? PublishedRequest { get; set; } /// public bool IsDebug => // NOTE: the request can be null during app startup! _hostingEnvironment.IsDebugMode - && (string.IsNullOrEmpty(_httpContextAccessor.HttpContext.GetRequestValue("umbdebugshowtrace")) == false - || string.IsNullOrEmpty(_httpContextAccessor.HttpContext.GetRequestValue("umbdebug")) == false + && (string.IsNullOrEmpty(_httpContextAccessor.HttpContext?.GetRequestValue("umbdebugshowtrace")) == false + || string.IsNullOrEmpty(_httpContextAccessor.HttpContext?.GetRequestValue("umbdebug")) == false || string.IsNullOrEmpty(_cookieManager.GetCookieValue("UMB-DEBUG")) == false); /// @@ -121,7 +121,7 @@ namespace Umbraco.Cms.Web.Common.UmbracoContext private set => _previewing = value; } - internal string PreviewToken + internal string? PreviewToken { get { diff --git a/src/Umbraco.Web.Common/UmbracoHelper.cs b/src/Umbraco.Web.Common/UmbracoHelper.cs index 98f2d08fdd..c7e29a7302 100644 --- a/src/Umbraco.Web.Common/UmbracoHelper.cs +++ b/src/Umbraco.Web.Common/UmbracoHelper.cs @@ -24,8 +24,8 @@ namespace Umbraco.Cms.Web.Common private readonly IUmbracoComponentRenderer _componentRenderer; private readonly ICultureDictionaryFactory _cultureDictionaryFactory; - private IPublishedContent _currentPage; - private ICultureDictionary _cultureDictionary; + private IPublishedContent? _currentPage; + private ICultureDictionary? _cultureDictionary; #region Constructors @@ -50,7 +50,9 @@ namespace Umbraco.Cms.Web.Common /// Initializes a new empty instance of . /// /// For tests - nothing is initialized. +#pragma warning disable CS8618 internal UmbracoHelper() +#pragma warning restore CS8618 { } #endregion @@ -137,7 +139,7 @@ namespace Umbraco.Cms.Web.Common /// /// /// - public string GetDictionaryValue(string key) + public string? GetDictionaryValue(string key) { return CultureDictionary[key]; } @@ -174,12 +176,12 @@ namespace Umbraco.Cms.Web.Common /// /// The unique identifier, or the key, of the content item. /// The content, or null of the content item is not in the cache. - public IPublishedContent Content(object id) + public IPublishedContent? Content(object id) { return ContentForObject(id); } - private IPublishedContent ContentForObject(object id) => _publishedContentQuery.Content(id); + private IPublishedContent? ContentForObject(object id) => _publishedContentQuery.Content(id); public IPublishedContent ContentSingleAtXPath(string xpath, params XPathVariable[] vars) { @@ -191,7 +193,7 @@ namespace Umbraco.Cms.Web.Common /// /// The unique identifier of the content item. /// The content, or null of the content item is not in the cache. - public IPublishedContent Content(int id) => _publishedContentQuery.Content(id); + public IPublishedContent? Content(int id) => _publishedContentQuery.Content(id); /// /// Gets a content item from the cache. @@ -205,9 +207,9 @@ namespace Umbraco.Cms.Web.Common /// /// The unique identifier, or the key, of the content item. /// The content, or null of the content item is not in the cache. - public IPublishedContent Content(string id) => _publishedContentQuery.Content(id); + public IPublishedContent? Content(string id) => _publishedContentQuery.Content(id); - public IPublishedContent Content(Udi id) => _publishedContentQuery.Content(id); + public IPublishedContent? Content(Udi id) => _publishedContentQuery.Content(id); /// /// Gets content items from the cache. @@ -318,7 +320,7 @@ namespace Umbraco.Cms.Web.Common #endregion #region Media - public IPublishedContent Media(Udi id) => _publishedContentQuery.Media(id); + public IPublishedContent? Media(Udi id) => _publishedContentQuery.Media(id); public IPublishedContent Media(Guid id) => _publishedContentQuery.Media(id); @@ -332,16 +334,16 @@ namespace Umbraco.Cms.Web.Common /// this result in to this method. /// This method will throw an exception if the value is not of type int or string. /// - public IPublishedContent Media(object id) + public IPublishedContent? Media(object id) { return MediaForObject(id); } - private IPublishedContent MediaForObject(object id) => _publishedContentQuery.Media(id); + private IPublishedContent? MediaForObject(object id) => _publishedContentQuery.Media(id); - public IPublishedContent Media(int id) => _publishedContentQuery.Media(id); + public IPublishedContent? Media(int id) => _publishedContentQuery.Media(id); - public IPublishedContent Media(string id) => _publishedContentQuery.Media(id); + public IPublishedContent? Media(string id) => _publishedContentQuery.Media(id); /// /// Gets the medias corresponding to the identifiers. diff --git a/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs b/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs index 926e1e1d72..70f609d1c0 100644 --- a/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs +++ b/src/Umbraco.Web.Common/UmbracoHelperAccessor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -14,7 +15,7 @@ namespace Umbraco.Cms.Web.Common public UmbracoHelperAccessor(IHttpContextAccessor httpContextAccessor) => _httpContextAccessor = httpContextAccessor; - public bool TryGetUmbracoHelper(out UmbracoHelper umbracoHelper) + public bool TryGetUmbracoHelper([MaybeNullWhen(false)] out UmbracoHelper umbracoHelper) { umbracoHelper = _httpContextAccessor.HttpContext?.RequestServices.GetService(); return umbracoHelper is not null; diff --git a/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs b/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs index d9bed99861..7351a278fb 100644 --- a/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs +++ b/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs @@ -27,8 +27,8 @@ namespace Umbraco.Cms.Web.Common.Views public abstract class UmbracoViewPage : RazorPage { - private IUmbracoContext _umbracoContext; - private UmbracoHelper _helper; + private IUmbracoContext? _umbracoContext; + private UmbracoHelper? _helper; private IUmbracoContextAccessor UmbracoContextAccessor => Context.RequestServices.GetRequiredService(); @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Web.Common.Views return _helper; } - TModel model = ViewData.Model; + TModel? model = ViewData.Model; var content = model as IPublishedContent; if (content is null && model is IContentModel contentModel) { @@ -78,7 +78,7 @@ namespace Umbraco.Cms.Web.Common.Views /// /// Gets the /// - protected IUmbracoContext UmbracoContext + protected IUmbracoContext? UmbracoContext { get { @@ -86,6 +86,7 @@ namespace Umbraco.Cms.Web.Common.Views { return null; } + return umbracoContext; } } @@ -104,7 +105,7 @@ namespace Umbraco.Cms.Web.Common.Views } /// - public override void Write(object value) + public override void Write(object? value) { if (value is IHtmlEncodedString htmlEncodedString) { @@ -128,7 +129,7 @@ namespace Umbraco.Cms.Web.Common.Views // ASP.NET default value is text/html if (Context.Response?.ContentType?.InvariantContains("text/html") ?? false) { - if ((UmbracoContext.IsDebug || UmbracoContext.InPreviewMode) + if (((UmbracoContext?.IsDebug ?? false) || (UmbracoContext?.InPreviewMode ?? false)) && tagHelperOutput.TagName != null && tagHelperOutput.TagName.Equals("body", StringComparison.InvariantCultureIgnoreCase)) { @@ -142,7 +143,7 @@ namespace Umbraco.Cms.Web.Common.Views ContentSettings.PreviewBadge, IOHelper.ResolveUrl(GlobalSettings.UmbracoPath), Context.Request.GetEncodedUrl(), - UmbracoContext.PublishedRequest.PublishedContent.Id); + UmbracoContext.PublishedRequest?.PublishedContent?.Id); } else { @@ -163,7 +164,7 @@ namespace Umbraco.Cms.Web.Common.Views /// or . This will use the to bind the models /// to the correct output type. /// - protected ViewDataDictionary BindViewData(ContentModelBinder contentModelBinder, ViewDataDictionary viewData) + protected ViewDataDictionary BindViewData(ContentModelBinder contentModelBinder, ViewDataDictionary? viewData) { if (contentModelBinder is null) { @@ -187,8 +188,8 @@ namespace Umbraco.Cms.Web.Common.Views if (viewData.ModelMetadata.ModelType == typeof(ContentModel) && typeof(TModel) == typeof(IPublishedContent)) { - var contentModel = (ContentModel)viewData.Model; - viewData.Model = contentModel.Content; + var contentModel = (ContentModel?)viewData.Model; + viewData.Model = contentModel?.Content; return viewData; } @@ -202,7 +203,7 @@ namespace Umbraco.Cms.Web.Common.Views var bindingContext = new DefaultModelBindingContext(); contentModelBinder.BindModel(bindingContext, viewDataModel, typeof(TModel)); - viewData.Model = bindingContext.Result.Model; + viewData!.Model = bindingContext.Result.Model; // return the new view data return (ViewDataDictionary)viewData; @@ -211,7 +212,7 @@ namespace Umbraco.Cms.Web.Common.Views // viewData is the ViewDataDictionary (maybe ) that we have // modelType is the type of the model that we need to bind to // figure out whether viewData can accept modelType else replace it - private static ViewDataDictionary MapViewDataDictionary(ViewDataDictionary viewData, Type modelType) + private static ViewDataDictionary? MapViewDataDictionary(ViewDataDictionary viewData, Type modelType) { Type viewDataType = viewData.GetType(); @@ -239,19 +240,19 @@ namespace Umbraco.Cms.Web.Common.Views // if not possible or it is not generic then we need to create a new ViewDataDictionary Type nViewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType); var tViewData = new ViewDataDictionary(viewData) { Model = default(TModel) }; // temp view data to copy values - var nViewData = (ViewDataDictionary)Activator.CreateInstance(nViewDataType, tViewData); + var nViewData = (ViewDataDictionary?)Activator.CreateInstance(nViewDataType, tViewData); return nViewData; } /// /// Renders a section with default content if the section isn't defined /// - public HtmlString RenderSection(string name, HtmlString defaultContents) => RazorPageExtensions.RenderSection(this, name, defaultContents); + public HtmlString? RenderSection(string name, HtmlString defaultContents) => RazorPageExtensions.RenderSection(this, name, defaultContents); /// /// Renders a section with default content if the section isn't defined /// - public HtmlString RenderSection(string name, string defaultContents) => RazorPageExtensions.RenderSection(this, name, defaultContents); + public HtmlString? RenderSection(string name, string defaultContents) => RazorPageExtensions.RenderSection(this, name, defaultContents); } }