Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
4de315b
Implement LRO rehydration with static method
live1206 Mar 14, 2024
8c361fa
update test
live1206 Mar 14, 2024
516a77d
Add type constraint.
live1206 Mar 14, 2024
2f6bd66
update API
live1206 Mar 14, 2024
619c6ed
implement GetRehydrationToken
live1206 Mar 15, 2024
fb08623
cleanup
live1206 Mar 16, 2024
9f03f88
remove duplicates
live1206 Mar 16, 2024
ed0cf59
Merge branch 'main' into rehydration-static-method
live1206 Mar 16, 2024
e47d85e
address comments
live1206 Mar 20, 2024
e9e3c79
Make rawResponse non-nullable
live1206 Mar 21, 2024
70bc5c0
UpdaateStatus during LRO rehydration to get the latest state
live1206 Mar 21, 2024
c27d863
update for final get of delete LRO and add test for it
live1206 Mar 21, 2024
2843500
fix test
live1206 Mar 21, 2024
1231a36
update changelog and test
live1206 Mar 21, 2024
adc9277
cleanup
live1206 Mar 21, 2024
544068b
address comments
live1206 Mar 26, 2024
695bbed
Add async rehdyrate methods
live1206 Mar 26, 2024
3b040be
update
live1206 Mar 26, 2024
e86c766
fix for imcomplete nextRequesturi
live1206 Mar 26, 2024
6e2eb4a
remove unneeded test
live1206 Mar 26, 2024
71e65b8
Address comments
live1206 Mar 27, 2024
ebadd2c
make OpetaionId nullable
live1206 Mar 27, 2024
812b8ea
update tests
live1206 Mar 27, 2024
b4668a8
Add comments
live1206 Mar 27, 2024
cac95fc
update
live1206 Mar 27, 2024
f9f0ca8
cleanup
live1206 Mar 27, 2024
a501c92
Merge branch 'main' into rehydration-static-method
live1206 Mar 29, 2024
69a4c38
add parameter name for async while calling UpdateStateAsync
live1206 Mar 29, 2024
0887d04
remove apiversion for rehydration
live1206 Mar 29, 2024
9a06d85
Make operation id non-nullable and return NOT_SET instead of null
live1206 Apr 7, 2024
f19fe64
export API
live1206 Apr 7, 2024
1745223
cleanup
live1206 Apr 7, 2024
ecd5824
Merge branch 'main' into rehydration-static-method
live1206 Apr 7, 2024
5545d54
update description
live1206 Apr 8, 2024
b3daf2e
avoid cast
live1206 Apr 10, 2024
edf14b5
Merge branch 'rehydration-static-method' of https://github.com/live12…
live1206 Apr 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions sdk/core/Azure.Core.TestFramework/src/MockJsonModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.ClientModel.Primitives;
using System.IO;
using System.Text.Json;
using Azure.Core.Serialization;

namespace Azure.Core.TestFramework
{
public class MockJsonModel : IJsonModel<MockJsonModel>
{
internal MockJsonModel()
{
}

public int IntValue { get; set; }

public string StringValue { get; set; }

public byte[] Utf8BytesValue { get; }

public MockJsonModel(int intValue, string stringValue)
{
IntValue = intValue;
StringValue = stringValue;

dynamic json = BinaryData.FromString("{}").ToDynamicFromJson(JsonPropertyNames.CamelCase);
json.IntValue = IntValue;
json.StringValue = StringValue;

MemoryStream stream = new();
using Utf8JsonWriter writer = new Utf8JsonWriter(stream);

writer.WriteStartObject();
writer.WriteNumber("IntValue", IntValue);
writer.WriteString("StringValue", StringValue);
writer.WriteEndObject();

writer.Flush();
Utf8BytesValue = stream.ToArray();
}

MockJsonModel IPersistableModel<MockJsonModel>.Create(BinaryData data, ModelReaderWriterOptions options)
{
dynamic json = data.ToDynamicFromJson(JsonPropertyNames.CamelCase);
return new MockJsonModel(json.IntValue, json.StringValue);
}

MockJsonModel IJsonModel<MockJsonModel>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
{
using JsonDocument doc = JsonDocument.ParseValue(ref reader);
int intValue = doc.RootElement.GetProperty("IntValue").GetInt32();
string stringValue = doc.RootElement.GetProperty("StringValue").GetString()!;
return new MockJsonModel(intValue, stringValue);
}

string IPersistableModel<MockJsonModel>.GetFormatFromOptions(ModelReaderWriterOptions options)
=> "J";

BinaryData IPersistableModel<MockJsonModel>.Write(ModelReaderWriterOptions options)
{
return BinaryData.FromBytes(Utf8BytesValue);
}

void IJsonModel<MockJsonModel>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
{
writer.WriteStartObject();
writer.WriteNumber("IntValue", IntValue);
writer.WriteString("StringValue", StringValue);
writer.WriteEndObject();
}
}
}
2 changes: 2 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net461.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ protected Operation() { }
public override int GetHashCode() { throw null; }
public abstract Azure.Response GetRawResponse();
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
public static Azure.Operation<T> Rehydrate<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public override string? ToString() { throw null; }
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
Expand Down
2 changes: 2 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net472.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ protected Operation() { }
public override int GetHashCode() { throw null; }
public abstract Azure.Response GetRawResponse();
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
public static Azure.Operation<T> Rehydrate<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public override string? ToString() { throw null; }
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
Expand Down
2 changes: 2 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net6.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ protected Operation() { }
public override int GetHashCode() { throw null; }
public abstract Azure.Response GetRawResponse();
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
public static Azure.Operation<T> Rehydrate<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public override string? ToString() { throw null; }
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
Expand Down
2 changes: 2 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ protected Operation() { }
public override int GetHashCode() { throw null; }
public abstract Azure.Response GetRawResponse();
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
public static Azure.Operation<T> Rehydrate<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken? rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public override string? ToString() { throw null; }
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
Expand Down
3 changes: 3 additions & 0 deletions sdk/core/Azure.Core/src/Azure.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@
<Compile Include="Shared\FixedDelayWithNoJitterStrategy.cs" />
<Compile Include="Shared\HashCodeBuilder.cs" />
<Compile Include="Shared\HttpMessageSanitizer.cs" />
<Compile Include="Shared\IOperationSource.cs" />
<Compile Include="Shared\InitializationConstructorAttribute.cs" />
<Compile Include="Shared\Multipart\MemoryResponse.cs" />
<Compile Include="Shared\NextLinkOperationImplementation.cs" />
<Compile Include="Shared\NullableAttributes.cs" />
<Compile Include="Shared\OperationInternalBase.cs" />
<Compile Include="Shared\TrimmingAttribute.cs" />
<Compile Include="Shared\VoidValue.cs" />
<Compile Include="Shared\OperationFinalStateVia.cs" />
<Compile Include="Shared\OperationInternal.cs" />
<Compile Include="Shared\OperationInternalOfT.cs" />
<Compile Include="Shared\SequentialDelayStrategy.cs" />
Expand Down
22 changes: 22 additions & 0 deletions sdk/core/Azure.Core/src/Internal/GenericOperationSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.ClientModel.Primitives;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;

namespace Azure.Core
{
internal class GenericOperationSource<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T> : IOperationSource<T> where T : IPersistableModel<T>
{
T IOperationSource<T>.CreateResult(Response response, CancellationToken cancellationToken)
=> CreateResult(response);

ValueTask<T> IOperationSource<T>.CreateResultAsync(Response response, CancellationToken cancellationToken)
=> new ValueTask<T>(CreateResult(response));

private T CreateResult(Response response)
=> (T)ModelReaderWriter.Read(response.Content, typeof(T))!;
}
}
46 changes: 46 additions & 0 deletions sdk/core/Azure.Core/src/Internal/RehydrationOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#nullable disable

using System;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Pipeline;

namespace Azure.Core
{
internal class RehydrationOperation : Operation
{
private readonly NextLinkOperationImplementation _nextLinkOperation;
private readonly OperationInternal _operation;

public RehydrationOperation(HttpPipeline pipeline, RehydrationToken? rehydrationToken, ClientOptions options = null)
{
AssertNotNull(pipeline, nameof(pipeline));
AssertNotNull(rehydrationToken, nameof(rehydrationToken));
_nextLinkOperation = (NextLinkOperationImplementation)NextLinkOperationImplementation.Create(pipeline, rehydrationToken);
_operation = new OperationInternal(_nextLinkOperation, new ClientDiagnostics(options ?? ClientOptions.Default), null, requestMethod: _nextLinkOperation.RequestMethod);
}

public override string Id => _nextLinkOperation?.OperationId ?? null;

public override RehydrationToken? GetRehydrationToken() => _nextLinkOperation?.GetRehydrationToken();

public override bool HasCompleted => _operation.HasCompleted;

public override Response GetRawResponse() => _operation.RawResponse;

public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operation.UpdateStatus(cancellationToken);

public override ValueTask<Response> UpdateStatusAsync(CancellationToken cancellationToken = default) => _operation.UpdateStatusAsync(cancellationToken);

private static void AssertNotNull<T>(T value, string name)
{
if (value is null)
{
throw new ArgumentNullException(name);
}
}
}
}
56 changes: 56 additions & 0 deletions sdk/core/Azure.Core/src/Internal/RehydrationOperationOfT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#nullable disable

using System;
using System.ClientModel.Primitives;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core.Pipeline;

namespace Azure.Core
{
#pragma warning disable SA1649 // File name should match first type name
internal class RehydrationOperation<T> : Operation<T> where T : IPersistableModel<T>
#pragma warning restore SA1649 // File name should match first type name
{
private readonly OperationInternal<T> _operation;
private readonly NextLinkOperationImplementation _nextLinkOperation;

public RehydrationOperation(HttpPipeline pipeline, RehydrationToken? rehydrationToken, ClientOptions options = null)
{
if (pipeline is null)
{
throw new ArgumentNullException(nameof(pipeline));
}

if (rehydrationToken is null)
{
throw new ArgumentNullException(nameof(rehydrationToken));
}

IOperationSource<T> source = new GenericOperationSource<T>();
_nextLinkOperation = (NextLinkOperationImplementation)NextLinkOperationImplementation.Create(pipeline, rehydrationToken);
var operation = NextLinkOperationImplementation.Create(source, _nextLinkOperation);
var clientDiagnostics = new ClientDiagnostics(options ?? ClientOptions.Default);
_operation = new OperationInternal<T>(operation, clientDiagnostics, null);
}

public override T Value => _operation.Value;

public override bool HasValue => _operation.HasValue;

public override string Id => _nextLinkOperation.OperationId ?? null;

public override RehydrationToken? GetRehydrationToken() => _nextLinkOperation?.GetRehydrationToken();

public override bool HasCompleted => _operation.HasCompleted;

public override Response GetRawResponse() => _operation.RawResponse;

public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operation.UpdateStatus(cancellationToken);

public override ValueTask<Response> UpdateStatusAsync(CancellationToken cancellationToken = default) => _operation.UpdateStatusAsync(cancellationToken);
}
}
22 changes: 22 additions & 0 deletions sdk/core/Azure.Core/src/Operation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
// Licensed under the MIT License.

using System;
using System.ClientModel.Primitives;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
using Azure.Core.Pipeline;

namespace Azure
{
Expand All @@ -16,6 +18,26 @@ namespace Azure
public abstract class Operation
#pragma warning restore AZC0012 // Avoid single word type names
{
/// <summary>
/// Rehydrates an operation from a <see cref="RehydrationToken"/>.
/// </summary>
/// <param name="pipeline">The Http pipeline.</param>
/// <param name="rehydrationToken">The rehydration token.</param>
/// <param name="options">The client options.</param>
/// <returns>The long-running operation.</returns>
public static Operation<T> Rehydrate<T>(HttpPipeline pipeline, RehydrationToken? rehydrationToken, ClientOptions? options = null) where T : IPersistableModel<T>
=> new RehydrationOperation<T>(pipeline, rehydrationToken, options);

/// <summary>
/// Rehydrates an operation from a <see cref="RehydrationToken"/>.
/// </summary>
/// <param name="pipeline">The Http pipeline.</param>
/// <param name="rehydrationToken">The rehydration token.</param>
/// <param name="options">The client options.</param>
/// <returns>The long-running operation.</returns>
public static Operation Rehydrate(HttpPipeline pipeline, RehydrationToken? rehydrationToken, ClientOptions? options = null)
=> new RehydrationOperation(pipeline, rehydrationToken, options);

/// <summary>
/// Get a token that can be used to rehydrate the operation.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/Azure.Core/src/RehydrationToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public readonly partial struct RehydrationToken
public string? Id { get; }

// Version for this contract itself since we might change the members in the future.
internal string Version { get; } = "1.0.0";
internal string Version { get; } = NextLinkOperationImplementation.RehydartionTokenVersion;

// The below members are used to re-construct <cref="NextLinkOperationImplemenation">.
// Value of <cref="NextLinkOperationImplemenration.HeaderSrouce">.
Expand Down
Loading