v14: Add async methods to Deploy interfaces (#16055)

* Add async method to IContextCache

* Add async methods to IImageSourceParser and ILocalLinkParser

* Add async methods to IDataTypeConfigurationConnector, IServiceConnector and IValueConnector

* Obsolete non-aysnc methods

* Add cancellation tokens to new async methods

* Add ConfigureAwait(false) to awaits
This commit is contained in:
Ronald Barendse
2024-04-15 18:04:47 +02:00
committed by GitHub
parent 5ddf7a1be7
commit 2d850bf8f1
9 changed files with 324 additions and 22 deletions

View File

@@ -24,6 +24,35 @@ public interface IContextCache
/// </returns>
T? GetOrCreate<T>(string key, Func<T?> factory);
/// <summary>
/// Gets an item from the context cache or creates and stores it using the specified <paramref name="key" />.
/// </summary>
/// <typeparam name="T">The type of the cached item.</typeparam>
/// <param name="key">The key of the cached item.</param>
/// <param name="factory">The factory method to create the item (if it doesn't exist yet).</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the item.
/// </returns>
async Task<T?> GetOrCreateAsync<T>(string key, Func<Task<T?>> factory)
{
// TODO: Remove default implementation in v15
bool shouldCreate = false;
T? value = GetOrCreate<T>(key, () =>
{
shouldCreate = true;
return default;
});
if (shouldCreate)
{
// Only invoke and await if we need to create the value
value = await factory().ConfigureAwait(false);
Create(key, value);
}
return value;
}
/// <summary>
/// Clears all cached items on this context.
/// </summary>

View File

@@ -3,11 +3,11 @@ using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Deploy;
/// <summary>
/// Defines methods that can convert data type configuration to / from an environment-agnostic string.
/// Defines methods that can convert data type configuration to and from an environment-agnostic string.
/// </summary>
/// <remarks>
/// Configuration may contain values such as content identifiers, that would be local
/// to one environment, and need to be converted in order to be deployed.
/// Configuration may contain values such as content identifiers, that would be local to one environment, and need to be converted in order to be deployed.
/// It can also contain references to other deployable artifacts, that need to be tracked as dependencies.
/// </remarks>
public interface IDataTypeConfigurationConnector
{
@@ -28,8 +28,24 @@ public interface IDataTypeConfigurationConnector
/// <returns>
/// The artifact configuration value.
/// </returns>
[Obsolete("Use ToArtifactAsync() instead. This method will be removed in a future version.")]
string? ToArtifact(IDataType dataType, ICollection<ArtifactDependency> dependencies, IContextCache contextCache);
/// <summary>
/// Gets the artifact configuration value corresponding to a data type configuration and gather dependencies.
/// </summary>
/// <param name="dataType">The data type.</param>
/// <param name="dependencies">The dependencies.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the artifact configuration value.
/// </returns>
Task<string?> ToArtifactAsync(IDataType dataType, ICollection<ArtifactDependency> dependencies, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(ToArtifact(dataType, dependencies, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Gets the data type configuration corresponding to an artifact configuration value.
/// </summary>
@@ -39,5 +55,21 @@ public interface IDataTypeConfigurationConnector
/// <returns>
/// The data type configuration.
/// </returns>
[Obsolete("Use FromArtifactAsync() instead. This method will be removed in a future version.")]
IDictionary<string, object> FromArtifact(IDataType dataType, string? configuration, IContextCache contextCache);
/// <summary>
/// Gets the data type configuration corresponding to an artifact configuration value.
/// </summary>
/// <param name="dataType">The data type.</param>
/// <param name="configuration">The artifact configuration value.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the data type configuration.
/// </returns>
Task<IDictionary<string, object>> FromArtifactAsync(IDataType dataType, string? configuration, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(FromArtifact(dataType, configuration, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@@ -17,6 +17,7 @@ public interface IFileSource
/// <para>Returns null if no content could be read.</para>
/// <para>The caller should ensure that the stream is properly closed/disposed.</para>
/// </remarks>
[Obsolete("Use GetFileStreamAsync() instead. This method will be removed in a future version.")]
Stream GetFileStream(StringUdi udi);
/// <summary>
@@ -43,6 +44,7 @@ public interface IFileSource
/// <remarks>
/// Returns null if no content could be read.
/// </remarks>
[Obsolete("Use GetFileContentAsync() instead. This method will be removed in a future version.")]
string GetFileContent(StringUdi udi);
/// <summary>
@@ -65,6 +67,7 @@ public interface IFileSource
/// <returns>
/// The length of the file, or -1 if the file does not exist.
/// </returns>
[Obsolete("Use GetFileLengthAsync() instead. This method will be removed in a future version.")]
long GetFileLength(StringUdi udi);
/// <summary>
@@ -83,6 +86,7 @@ public interface IFileSource
/// <param name="udis">The UDIs of the files to get.</param>
/// <param name="continueOnFileNotFound">A flag indicating whether to continue if a file isn't found or to stop and throw a FileNotFoundException.</param>
/// <param name="fileTypes">A collection of file types which can store the files.</param>
[Obsolete("Use GetFilesAsync() instead. This method will be removed in a future version.")]
void GetFiles(IEnumerable<StringUdi> udis, bool continueOnFileNotFound, IFileTypeCollection fileTypes);
/// <summary>

View File

@@ -20,6 +20,7 @@ public interface IFileType
/// <returns>
/// The stream.
/// </returns>
[Obsolete("Use GetStreamAsync() instead. This method will be removed in a future version.")]
Stream GetStream(StringUdi udi);
/// <summary>
@@ -55,6 +56,7 @@ public interface IFileType
/// </summary>
/// <param name="udi">The UDI.</param>
/// <param name="stream">The stream.</param>
[Obsolete("Use SetStreamAsync() instead. This method will be removed in a future version.")]
void SetStream(StringUdi udi, Stream stream);
/// <summary>

View File

@@ -17,8 +17,27 @@ public interface IImageSourceParser
/// <remarks>
/// Turns src="/media/..." into src="umb://media/..." and adds the corresponding udi to the dependencies.
/// </remarks>
[Obsolete("Use ToArtifactAsync() instead. This method will be removed in a future version.")]
string ToArtifact(string value, ICollection<Udi> dependencies, IContextCache contextCache);
/// <summary>
/// Parses an Umbraco property value and produces an artifact property value.
/// </summary>
/// <param name="value">The property value.</param>
/// <param name="dependencies">A list of dependencies.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the parsed value.
/// </returns>
/// <remarks>
/// Turns src="/media/..." into src="umb://media/..." and adds the corresponding udi to the dependencies.
/// </remarks>
Task<string> ToArtifactAsync(string value, ICollection<Udi> dependencies, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(ToArtifact(value, dependencies, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Parses an artifact property value and produces an Umbraco property value.
/// </summary>
@@ -30,5 +49,23 @@ public interface IImageSourceParser
/// <remarks>
/// Turns umb://media/... into /media/....
/// </remarks>
[Obsolete("Use FromArtifactAsync() instead. This method will be removed in a future version.")]
string FromArtifact(string value, IContextCache contextCache);
/// <summary>
/// Parses an artifact property value and produces an Umbraco property value.
/// </summary>
/// <param name="value">The artifact property value.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the parsed value.
/// </returns>
/// <remarks>
/// Turns umb://media/... into /media/....
/// </remarks>
Task<string> FromArtifactAsync(string value, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(FromArtifact(value, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@@ -15,11 +15,29 @@ public interface ILocalLinkParser
/// The parsed value.
/// </returns>
/// <remarks>
/// Turns {{localLink:1234}} into {{localLink:umb://{type}/{id}}} and adds the corresponding udi to the
/// dependencies.
/// Turns {{localLink:1234}} into {{localLink:umb://{type}/{id}}} and adds the corresponding udi to the dependencies.
/// </remarks>
[Obsolete("Use ToArtifactAsync() instead. This method will be removed in a future version.")]
string ToArtifact(string value, ICollection<Udi> dependencies, IContextCache contextCache);
/// <summary>
/// Parses an Umbraco property value and produces an artifact property value.
/// </summary>
/// <param name="value">The property value.</param>
/// <param name="dependencies">A list of dependencies.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the parsed value.
/// </returns>
/// <remarks>
/// Turns {{localLink:1234}} into {{localLink:umb://{type}/{id}}} and adds the corresponding udi to the dependencies.
/// </remarks>
Task<string> ToArtifactAsync(string value, ICollection<Udi> dependencies, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(ToArtifact(value, dependencies, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Parses an artifact property value and produces an Umbraco property value.
/// </summary>
@@ -31,5 +49,23 @@ public interface ILocalLinkParser
/// <remarks>
/// Turns {{localLink:umb://{type}/{id}}} into {{localLink:1234}}.
/// </remarks>
[Obsolete("Use FromArtifactAsync() instead. This method will be removed in a future version.")]
string FromArtifact(string value, IContextCache contextCache);
/// <summary>
/// Parses an artifact property value and produces an Umbraco property value.
/// </summary>
/// <param name="value">The artifact property value.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the parsed value.
/// </returns>
/// <remarks>
/// Turns {{localLink:umb://{type}/{id}}} into {{localLink:1234}}.
/// </remarks>
Task<string> FromArtifactAsync(string value, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(FromArtifact(value, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using Umbraco.Cms.Core.Composing;
namespace Umbraco.Cms.Core.Deploy;
@@ -13,10 +14,25 @@ public interface IServiceConnector : IDiscoverable
/// <param name="udi">The entity identifier of the artifact.</param>
/// <param name="contextCache">The context cache.</param>
/// <returns>
/// The corresponding artifact, or null.
/// The corresponding artifact or <c>null</c>.
/// </returns>
[Obsolete("Use GetArtifactAsync() instead. This method will be removed in a future version.")]
IArtifact? GetArtifact(Udi udi, IContextCache contextCache);
/// <summary>
/// Gets an artifact.
/// </summary>
/// <param name="udi">The entity identifier of the artifact.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the corresponding artifact or <c>null</c>.
/// </returns>
Task<IArtifact?> GetArtifactAsync(Udi udi, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(GetArtifact(udi, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Gets an artifact.
/// </summary>
@@ -25,46 +41,132 @@ public interface IServiceConnector : IDiscoverable
/// <returns>
/// The corresponding artifact.
/// </returns>
[Obsolete("Use GetArtifactAsync() instead. This method will be removed in a future version.")]
IArtifact GetArtifact(object entity, IContextCache contextCache);
/// <summary>
/// Gets an artifact.
/// </summary>
/// <param name="entity">The entity.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the corresponding artifact.
/// </returns>
Task<IArtifact> GetArtifactAsync(object entity, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(GetArtifact(entity, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Initializes processing for an artifact.
/// </summary>
/// <param name="art">The artifact.</param>
/// <param name="context">The deploy context.</param>
/// <returns>
/// The mapped artifact.
/// The state of an artifact being deployed.
/// </returns>
[Obsolete("Use ProcessInitAsync() instead. This method will be removed in a future version.")]
ArtifactDeployState ProcessInit(IArtifact art, IDeployContext context);
/// <summary>
/// Initializes processing for an artifact.
/// </summary>
/// <param name="artifact">The artifact.</param>
/// <param name="context">The deploy context.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the state of an artifact being deployed.
/// </returns>
Task<ArtifactDeployState> ProcessInitAsync(IArtifact artifact, IDeployContext context, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(ProcessInit(artifact, context)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Processes an artifact.
/// </summary>
/// <param name="dart">The mapped artifact.</param>
/// <param name="dart">The state of the artifact being deployed.</param>
/// <param name="context">The deploy context.</param>
/// <param name="pass">The processing pass number.</param>
[Obsolete("Use ProcessAsync() instead. This method will be removed in a future version.")]
void Process(ArtifactDeployState dart, IDeployContext context, int pass);
/// <summary>
/// Explodes a range into UDIs.
/// Processes an artifact.
/// </summary>
/// <param name="range">The range.</param>
/// <param name="udis">The list of UDIs where to add the new UDIs.</param>
/// <remarks>
/// Also, it's cool to have a method named Explode. Kaboom!
/// </remarks>
/// <param name="state">The state of the artifact being deployed.</param>
/// <param name="context">The deploy context.</param>
/// <param name="pass">The processing pass number.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation.
/// </returns>
Task ProcessAsync(ArtifactDeployState state, IDeployContext context, int pass, CancellationToken cancellationToken = default)
{
// TODO: Remove default implementation in v15
#pragma warning disable CS0618 // Type or member is obsolete
Process(state, context, pass);
#pragma warning restore CS0618 // Type or member is obsolete
return Task.CompletedTask;
}
/// <summary>
/// Explodes/expands an UDI range into UDIs.
/// </summary>
/// <param name="range">The UDI range.</param>
/// <param name="udis">The list of UDIs where to add the exploded/expanded UDIs.</param>
[Obsolete("Use ExpandRangeAsync() instead. This method will be removed in a future version.")]
void Explode(UdiRange range, List<Udi> udis);
/// <summary>
/// Gets a named range for a specified udi and selector.
/// Expands an UDI range into UDIs.
/// </summary>
/// <param name="udi">The udi.</param>
/// <param name="range">The UDI range.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// Returns an <see cref="IAsyncEnumerable{Udi}" /> which when enumerated will asynchronously expand the UDI range into UDIs.
/// </returns>
async IAsyncEnumerable<Udi> ExpandRangeAsync(UdiRange range, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
// TODO: Remove default implementation in v15
var udis = new List<Udi>();
#pragma warning disable CS0618 // Type or member is obsolete
Explode(range, udis);
#pragma warning restore CS0618 // Type or member is obsolete
foreach (Udi udi in udis)
{
yield return await ValueTask.FromResult(udi);
}
}
/// <summary>
/// Gets a named range for a specified UDI and selector.
/// </summary>
/// <param name="udi">The UDI.</param>
/// <param name="selector">The selector.</param>
/// <returns>
/// The named range for the specified udi and selector.
/// The named range for the specified UDI and selector.
/// </returns>
[Obsolete("Use GetRangeAsync() instead. This method will be removed in a future version.")]
NamedUdiRange GetRange(Udi udi, string selector);
/// <summary>
/// Gets a named range for a specified UDI and selector.
/// </summary>
/// <param name="udi">The UDI.</param>
/// <param name="selector">The selector.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the named range for the specified UDI and selector.
/// </returns>
Task<NamedUdiRange> GetRangeAsync(Udi udi, string selector, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(GetRange(udi, selector)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Gets a named range for specified entity type, identifier and selector.
/// </summary>
@@ -80,22 +182,44 @@ public interface IServiceConnector : IDiscoverable
/// At the moment our UI has a hard time returning proper UDIs, mainly because Core's tree do
/// not manage GUIDs but only integers... so we have to provide a way to support it. The string id here
/// can be either a real string (for string UDIs) or an "integer as a string", using the value "-1" to
/// indicate the "root" i.e. an open udi.
/// indicate the "root" i.e. an open UDI.
/// </para>
/// </remarks>
[Obsolete("Use GetRangeAsync() instead. This method will be removed in a future version.")]
NamedUdiRange GetRange(string entityType, string sid, string selector);
/// <summary>
/// Gets a named range for specified entity type, identifier and selector.
/// </summary>
/// <param name="entityType">The entity type.</param>
/// <param name="sid">The identifier.</param>
/// <param name="selector">The selector.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the named range for the specified entity type, identifier and selector.
/// </returns>
/// <remarks>
/// <para>This is temporary. At least we thought it would be, in sept. 2016. What day is it now?</para>
/// <para>
/// At the moment our UI has a hard time returning proper UDIs, mainly because Core's tree do
/// not manage GUIDs but only integers... so we have to provide a way to support it. The string id here
/// can be either a real string (for string UDIs) or an "integer as a string", using the value "-1" to
/// indicate the "root" i.e. an open UDI.
/// </para>
/// </remarks>
Task<NamedUdiRange> GetRangeAsync(string entityType, string sid, string selector, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(GetRange(entityType, sid, selector)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Compares two artifacts.
/// </summary>
/// <param name="art1">The first artifact.</param>
/// <param name="art2">The second artifact.</param>
/// <param name="differences">A collection of differences to append to, if not null.</param>
/// <param name="differences">A collection of differences to append to, if not <c>null</c>.</param>
/// <returns>
/// A boolean value indicating whether the artifacts are identical.
/// </returns>
/// <remarks>
/// ServiceConnectorBase{TArtifact} provides a very basic default implementation.
/// </remarks>
bool Compare(IArtifact? art1, IArtifact? art2, ICollection<Difference>? differences = null);
}

View File

@@ -30,8 +30,25 @@ public interface IValueConnector
/// <returns>
/// The deploy property value.
/// </returns>
[Obsolete("Use ToArtifactAsync() instead. This method will be removed in a future version.")]
string? ToArtifact(object? value, IPropertyType propertyType, ICollection<ArtifactDependency> dependencies, IContextCache contextCache);
/// <summary>
/// Gets the deploy property value corresponding to a content property value, and gather dependencies.
/// </summary>
/// <param name="value">The content property value.</param>
/// <param name="propertyType">The value property type</param>
/// <param name="dependencies">The content dependencies.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the deploy property value.
/// </returns>
Task<string?> ToArtifactAsync(object? value, IPropertyType propertyType, ICollection<ArtifactDependency> dependencies, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(ToArtifact(value, propertyType, dependencies, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
/// <summary>
/// Gets the content property value corresponding to a deploy property value.
/// </summary>
@@ -42,5 +59,22 @@ public interface IValueConnector
/// <returns>
/// The content property value.
/// </returns>
[Obsolete("Use FromArtifactAsync() instead. This method will be removed in a future version.")]
object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache);
/// <summary>
/// Gets the content property value corresponding to a deploy property value.
/// </summary>
/// <param name="value">The deploy property value.</param>
/// <param name="propertyType">The value property type</param>
/// <param name="currentValue">The current content property value.</param>
/// <param name="contextCache">The context cache.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>
/// A task that represents the asynchronous operation. The task result contains the content property value.
/// </returns>
Task<object?> FromArtifactAsync(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache, CancellationToken cancellationToken = default)
#pragma warning disable CS0618 // Type or member is obsolete
=> Task.FromResult(FromArtifact(value, propertyType, currentValue, contextCache)); // TODO: Remove default implementation in v15
#pragma warning restore CS0618 // Type or member is obsolete
}

View File

@@ -28,6 +28,10 @@ public sealed class PassThroughCache : IContextCache
public T? GetOrCreate<T>(string key, Func<T?> factory)
=> factory();
/// <inheritdoc />
public async Task<T?> GetOrCreateAsync<T>(string key, Func<Task<T?>> factory)
=> await factory().ConfigureAwait(false);
/// <inheritdoc />
public void Clear()
{ }