Skip to content

Commit 44d1f56

Browse files
authored
Implement LRO rehydration with static method (#42686)
1 parent e2cd909 commit 44d1f56

23 files changed

+730
-101
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.ClientModel.Primitives;
6+
using System.IO;
7+
using System.Text.Json;
8+
using Azure.Core.Serialization;
9+
10+
namespace Azure.Core.TestFramework
11+
{
12+
public class MockJsonModel : IJsonModel<MockJsonModel>
13+
{
14+
internal MockJsonModel()
15+
{
16+
}
17+
18+
public int IntValue { get; set; }
19+
20+
public string StringValue { get; set; }
21+
22+
public byte[] Utf8BytesValue { get; }
23+
24+
public MockJsonModel(int intValue, string stringValue)
25+
{
26+
IntValue = intValue;
27+
StringValue = stringValue;
28+
29+
dynamic json = BinaryData.FromString("{}").ToDynamicFromJson(JsonPropertyNames.CamelCase);
30+
json.IntValue = IntValue;
31+
json.StringValue = StringValue;
32+
33+
MemoryStream stream = new();
34+
using Utf8JsonWriter writer = new Utf8JsonWriter(stream);
35+
36+
writer.WriteStartObject();
37+
writer.WriteNumber("IntValue", IntValue);
38+
writer.WriteString("StringValue", StringValue);
39+
writer.WriteEndObject();
40+
41+
writer.Flush();
42+
Utf8BytesValue = stream.ToArray();
43+
}
44+
45+
MockJsonModel IPersistableModel<MockJsonModel>.Create(BinaryData data, ModelReaderWriterOptions options)
46+
{
47+
dynamic json = data.ToDynamicFromJson(JsonPropertyNames.CamelCase);
48+
return new MockJsonModel(json.IntValue, json.StringValue);
49+
}
50+
51+
MockJsonModel IJsonModel<MockJsonModel>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
52+
{
53+
using JsonDocument doc = JsonDocument.ParseValue(ref reader);
54+
int intValue = doc.RootElement.GetProperty("IntValue").GetInt32();
55+
string stringValue = doc.RootElement.GetProperty("StringValue").GetString()!;
56+
return new MockJsonModel(intValue, stringValue);
57+
}
58+
59+
string IPersistableModel<MockJsonModel>.GetFormatFromOptions(ModelReaderWriterOptions options)
60+
=> "J";
61+
62+
BinaryData IPersistableModel<MockJsonModel>.Write(ModelReaderWriterOptions options)
63+
{
64+
return BinaryData.FromBytes(Utf8BytesValue);
65+
}
66+
67+
void IJsonModel<MockJsonModel>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
68+
{
69+
writer.WriteStartObject();
70+
writer.WriteNumber("IntValue", IntValue);
71+
writer.WriteString("StringValue", StringValue);
72+
writer.WriteEndObject();
73+
}
74+
}
75+
}

sdk/core/Azure.Core/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Features Added
66

7+
- Add `Operation.Rehydrate` and `Operation.Rehydrate<T>` static methods to rehydrate a long-running operation.
8+
79
### Breaking Changes
810

911
### Bugs Fixed

sdk/core/Azure.Core/api/Azure.Core.net461.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ protected Operation() { }
138138
public override int GetHashCode() { throw null; }
139139
public abstract Azure.Response GetRawResponse();
140140
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
141+
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
142+
public static System.Threading.Tasks.Task<Azure.Operation> RehydrateAsync(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
143+
public static System.Threading.Tasks.Task<Azure.Operation<T>> RehydrateAsync<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
144+
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; }
141145
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
142146
public override string? ToString() { throw null; }
143147
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -530,7 +534,7 @@ public static partial class MultipartResponse
530534
{
531535
private readonly object _dummy;
532536
private readonly int _dummyPrimitive;
533-
public string? Id { get { throw null; } }
537+
public string Id { get { throw null; } }
534538
Azure.Core.RehydrationToken System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
535539
void System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { }
536540
object System.ClientModel.Primitives.IJsonModel<object>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }

sdk/core/Azure.Core/api/Azure.Core.net472.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ protected Operation() { }
138138
public override int GetHashCode() { throw null; }
139139
public abstract Azure.Response GetRawResponse();
140140
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
141+
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
142+
public static System.Threading.Tasks.Task<Azure.Operation> RehydrateAsync(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
143+
public static System.Threading.Tasks.Task<Azure.Operation<T>> RehydrateAsync<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
144+
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; }
141145
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
142146
public override string? ToString() { throw null; }
143147
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -530,7 +534,7 @@ public static partial class MultipartResponse
530534
{
531535
private readonly object _dummy;
532536
private readonly int _dummyPrimitive;
533-
public string? Id { get { throw null; } }
537+
public string Id { get { throw null; } }
534538
Azure.Core.RehydrationToken System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
535539
void System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { }
536540
object System.ClientModel.Primitives.IJsonModel<object>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }

sdk/core/Azure.Core/api/Azure.Core.net6.0.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ protected Operation() { }
138138
public override int GetHashCode() { throw null; }
139139
public abstract Azure.Response GetRawResponse();
140140
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
141+
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
142+
public static System.Threading.Tasks.Task<Azure.Operation> RehydrateAsync(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
143+
public static System.Threading.Tasks.Task<Azure.Operation<T>> RehydrateAsync<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
144+
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; }
141145
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
142146
public override string? ToString() { throw null; }
143147
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -530,7 +534,7 @@ public static partial class MultipartResponse
530534
{
531535
private readonly object _dummy;
532536
private readonly int _dummyPrimitive;
533-
public string? Id { get { throw null; } }
537+
public string Id { get { throw null; } }
534538
Azure.Core.RehydrationToken System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
535539
void System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { }
536540
object System.ClientModel.Primitives.IJsonModel<object>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }

sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ protected Operation() { }
138138
public override int GetHashCode() { throw null; }
139139
public abstract Azure.Response GetRawResponse();
140140
public virtual Azure.Core.RehydrationToken? GetRehydrationToken() { throw null; }
141+
public static Azure.Operation Rehydrate(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
142+
public static System.Threading.Tasks.Task<Azure.Operation> RehydrateAsync(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) { throw null; }
143+
public static System.Threading.Tasks.Task<Azure.Operation<T>> RehydrateAsync<T>(Azure.Core.Pipeline.HttpPipeline pipeline, Azure.Core.RehydrationToken rehydrationToken, Azure.Core.ClientOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel<T> { throw null; }
144+
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; }
141145
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
142146
public override string? ToString() { throw null; }
143147
public abstract Azure.Response UpdateStatus(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
@@ -530,7 +534,7 @@ public static partial class MultipartResponse
530534
{
531535
private readonly object _dummy;
532536
private readonly int _dummyPrimitive;
533-
public string? Id { get { throw null; } }
537+
public string Id { get { throw null; } }
534538
Azure.Core.RehydrationToken System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
535539
void System.ClientModel.Primitives.IJsonModel<Azure.Core.RehydrationToken>.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { }
536540
object System.ClientModel.Primitives.IJsonModel<object>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }

sdk/core/Azure.Core/src/Azure.Core.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,15 @@
6060
<Compile Include="Shared\FixedDelayWithNoJitterStrategy.cs" />
6161
<Compile Include="Shared\HashCodeBuilder.cs" />
6262
<Compile Include="Shared\HttpMessageSanitizer.cs" />
63+
<Compile Include="Shared\IOperationSource.cs" />
6364
<Compile Include="Shared\InitializationConstructorAttribute.cs" />
6465
<Compile Include="Shared\Multipart\MemoryResponse.cs" />
66+
<Compile Include="Shared\NextLinkOperationImplementation.cs" />
6567
<Compile Include="Shared\NullableAttributes.cs" />
6668
<Compile Include="Shared\OperationInternalBase.cs" />
6769
<Compile Include="Shared\TrimmingAttribute.cs" />
6870
<Compile Include="Shared\VoidValue.cs" />
71+
<Compile Include="Shared\OperationFinalStateVia.cs" />
6972
<Compile Include="Shared\OperationInternal.cs" />
7073
<Compile Include="Shared\OperationInternalOfT.cs" />
7174
<Compile Include="Shared\SequentialDelayStrategy.cs" />
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.ClientModel.Primitives;
5+
using System.Diagnostics.CodeAnalysis;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace Azure.Core
10+
{
11+
internal class GenericOperationSource<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T> : IOperationSource<T> where T : IPersistableModel<T>
12+
{
13+
T IOperationSource<T>.CreateResult(Response response, CancellationToken cancellationToken)
14+
=> CreateResult(response);
15+
16+
ValueTask<T> IOperationSource<T>.CreateResultAsync(Response response, CancellationToken cancellationToken)
17+
=> new ValueTask<T>(CreateResult(response));
18+
19+
private T CreateResult(Response response)
20+
=> ModelReaderWriter.Read<T>(response.Content)!;
21+
}
22+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Azure.Core.Pipeline;
7+
8+
namespace Azure.Core
9+
{
10+
internal class RehydrationOperation : Operation
11+
{
12+
private readonly NextLinkOperationImplementation _nextLinkOperation;
13+
private readonly OperationInternal _operation;
14+
15+
public RehydrationOperation(NextLinkOperationImplementation nextLinkOperation, OperationState operationState, ClientOptions? options = null)
16+
{
17+
_nextLinkOperation = nextLinkOperation;
18+
_operation = operationState.HasCompleted
19+
? _operation = new OperationInternal(operationState)
20+
: new OperationInternal(_nextLinkOperation, new ClientDiagnostics(options ?? ClientOptions.Default), operationState.RawResponse);
21+
}
22+
23+
public override string Id => _nextLinkOperation.OperationId;
24+
25+
public override RehydrationToken? GetRehydrationToken() => _nextLinkOperation.GetRehydrationToken();
26+
27+
public override bool HasCompleted => _operation.HasCompleted;
28+
29+
public override Response GetRawResponse() => _operation.RawResponse;
30+
31+
public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operation.UpdateStatus(cancellationToken);
32+
33+
public override ValueTask<Response> UpdateStatusAsync(CancellationToken cancellationToken = default) => _operation.UpdateStatusAsync(cancellationToken);
34+
}
35+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.ClientModel.Primitives;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Azure.Core.Pipeline;
8+
9+
namespace Azure.Core
10+
{
11+
#pragma warning disable SA1649 // File name should match first type name
12+
internal class RehydrationOperation<T> : Operation<T> where T : IPersistableModel<T>
13+
#pragma warning restore SA1649 // File name should match first type name
14+
{
15+
private readonly OperationInternal<T> _operation;
16+
private readonly NextLinkOperationImplementation _nextLinkOperation;
17+
18+
public RehydrationOperation(NextLinkOperationImplementation nextLinkOperation, OperationState<T> operationState, IOperation<T> operation, ClientOptions? options = null)
19+
{
20+
_nextLinkOperation = nextLinkOperation;
21+
_operation = operationState.HasCompleted
22+
? new OperationInternal<T>(operationState)
23+
: new OperationInternal<T>(operation, new ClientDiagnostics(options ?? ClientOptions.Default), operationState.RawResponse);
24+
}
25+
26+
public override T Value => _operation.Value;
27+
28+
public override bool HasValue => _operation.HasValue;
29+
30+
public override string Id => _nextLinkOperation.OperationId;
31+
32+
public override RehydrationToken? GetRehydrationToken() => _nextLinkOperation.GetRehydrationToken();
33+
34+
public override bool HasCompleted => _operation.HasCompleted;
35+
36+
public override Response GetRawResponse() => _operation.RawResponse;
37+
38+
public override Response UpdateStatus(CancellationToken cancellationToken = default) => _operation.UpdateStatus(cancellationToken);
39+
40+
public override ValueTask<Response> UpdateStatusAsync(CancellationToken cancellationToken = default) => _operation.UpdateStatusAsync(cancellationToken);
41+
}
42+
}

0 commit comments

Comments
 (0)