-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ClientModel: Add async and sync enumerable client results #43392
Changes from 2 commits
54f822b
d239e17
115295a
3b12f1f
dbf18ad
a798fd9
72951b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.ClientModel.Primitives; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace System.ClientModel; | ||
|
||
#pragma warning disable CS1591 // public XML comments | ||
public abstract class AsyncEnumerableResult<T> : ClientResult, IAsyncEnumerable<T>, IAsyncDisposable | ||
where T : IPersistableModel<T> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another question is whether or not we want to add this type constraint. The benefit is that it could simplify implementations by allowing them to use ModelReaderWriter to deserialize values coming across the wire, rather than requiring them to use other ways to pass in bespoke deserialization routines. A drawback is that it limits the use of the type to models that implement the interface -- if we wanted to enable scenarios like pages of primitives, that could be a problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we did not constrain There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The libraries haven't GA'ed yet, so we could still constrain it if we feel strongly about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, but not if we want Azure.Core Pageable<T> to be able to inherit from it. Alas! I will remove it. |
||
{ | ||
protected internal AsyncEnumerableResult(PipelineResponse response) : base(response) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can the response be updated/changed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it can. Is there a scenario where we would want that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The scenario is using this type to expose pageable REST APIs. In such scenarios there are multiple responses representing all items in the collection/pageable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you want to do that by changing the value returned from the response? Why not return a collection of PipelineResponses instead? (i.e. not inherit from ClientResult) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. I see that we already do that in Azure.Core Operation implementations such as KeyVaultBackupOperation and FuzzySearchBatchOperation. |
||
{ | ||
} | ||
|
||
public abstract IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default); | ||
|
||
protected abstract ValueTask DisposeAsyncCore(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FDGs say to make it virtual There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed per discussion about moving disposal of resources into the enumerator. |
||
|
||
protected abstract void Dispose(bool disposing); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this for? i.e. who call it? BTW, FDGs (that Jeremy wrote) say to implement both IAsyncDisposabel and IDisposable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed per discussion about moving disposal of resources into the enumerator. |
||
|
||
public async ValueTask DisposeAsync() | ||
{ | ||
await DisposeAsyncCore().ConfigureAwait(false); | ||
|
||
// Dispose of unmanaged resources. Note that DisposeAsyncCore disposes | ||
// of managed resources asychronously -- we pass false to Dispose so we | ||
// don't attempt to dispose of them synchronously as well. | ||
Dispose(disposing: false); | ||
jsquire marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
GC.SuppressFinalize(this); | ||
} | ||
} | ||
#pragma warning restore CS1591 // public XML comments |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.ClientModel.Primitives; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
|
||
namespace System.ClientModel; | ||
|
||
#pragma warning disable CS1591 // public XML comments | ||
public abstract class EnumerableClientResult<T> : ClientResult, IEnumerable<T>, IDisposable | ||
where T : IPersistableModel<T> | ||
{ | ||
protected internal EnumerableClientResult(PipelineResponse response) : base(response) | ||
{ | ||
} | ||
|
||
public abstract IEnumerator<T> GetEnumerator(); | ||
|
||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | ||
|
||
public void Dispose() | ||
{ | ||
Dispose(disposing: true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
protected abstract void Dispose(bool disposing); | ||
} | ||
#pragma warning restore CS1591 // public XML comments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The names don't seem symetrical. What about the following:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually not wild about
ClientResults
because I think it complicates what we're defining a "result" to be (although I am open to debate here).To take a concrete example, Pageable<T> is a collection of T's. Does the "result" mean the T or with the response? In a simple ClientResult<T> case there's a 1-1 relationship between them. But ClientResult itself just exposes GetRawResponse so it seems like result maps more closely to the response than the T. Given that, it feels strange to me to make the "result" plural when the T is the plural thing and there might only ever be one response.
Let me think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like 3.5.2 in the FDG recommends using
Collection
in the name of types that derive fromIEnumerable<T>
... what aboutClientResultCollection<T>
andAsyncClientResultCollection<T>
? Those are getting long, though, and don't really address my question about whether it is a collection of results, but I think I'm willing to drop argument since we defined ClientResult in the refdocs as "the result of a cloud service operation." A sequence of such results could easily be a result collection. Is it too long?