Skip to content

Commit

Permalink
Move RequestOptions and related types to Azure.Core (#24945)
Browse files Browse the repository at this point in the history
* Move RequestContext and related to Azure.Core

* Update sdk/core/Azure.Core/src/ErrorOptions.cs

Co-authored-by: tg-msft <tg-msft@users.noreply.github.com>

* remove PerCallPolicy and Apply method

* update Core API listing

* remove Apply() method

Co-authored-by: tg-msft <tg-msft@users.noreply.github.com>
  • Loading branch information
annelo-msft and tg-msft authored Oct 27, 2021
1 parent e2c8130 commit c622678
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,20 @@ public PetStoreClient(Uri endpoint, TokenCredential credential, PetStoreClientOp

/// <summary> Get a pet by its Id. </summary>
/// <param name="id"> Id of pet to return. </param>
/// <param name="options"> The request options. </param>
/// <param name="context"> The request options. </param>
#pragma warning disable AZC0002
public virtual async Task<Response> GetPetAsync(string id, RequestOptions options = null)
public virtual async Task<Response> GetPetAsync(string id, RequestContext context = null)
#pragma warning restore AZC0002
{
using HttpMessage message = CreateGetPetRequest(id, options);
RequestOptions.Apply(options, message);
using HttpMessage message = CreateGetPetRequest(id, context);
using var scope = _clientDiagnostics.CreateScope("PetStoreClient.GetPet");
scope.Start();
try
{
await Pipeline.SendAsync(message, options?.CancellationToken ?? default).ConfigureAwait(false);
var statusOption = options?.StatusOption ?? ResponseStatusOption.Default;
await Pipeline.SendAsync(message, context?.CancellationToken ?? default).ConfigureAwait(false);
var errorOptions = context?.ErrorOptions ?? ErrorOptions.Default;

if (statusOption == ResponseStatusOption.NoThrow)
if (errorOptions == ErrorOptions.NoThrow)
{
return message.Response;
}
Expand All @@ -107,19 +106,18 @@ public virtual async Task<Response> GetPetAsync(string id, RequestOptions option
/// <param name="id"> Id of pet to return. </param>
/// <param name="options"> The request options. </param>
#pragma warning disable AZC0002
public virtual Response GetPet(string id, RequestOptions options = null)
public virtual Response GetPet(string id, RequestContext context = null)
#pragma warning restore AZC0002
{
using HttpMessage message = CreateGetPetRequest(id, options);
RequestOptions.Apply(options, message);
using HttpMessage message = CreateGetPetRequest(id, context);
using var scope = _clientDiagnostics.CreateScope("PetStoreClient.GetPet");
scope.Start();
try
{
Pipeline.Send(message, options?.CancellationToken ?? default);
var statusOption = options?.StatusOption ?? ResponseStatusOption.Default;
Pipeline.Send(message, context?.CancellationToken ?? default);
var errorOptions = context?.ErrorOptions ?? ErrorOptions.Default;

if (statusOption == ResponseStatusOption.NoThrow)
if (errorOptions == ErrorOptions.NoThrow)
{
return message.Response;
}
Expand All @@ -146,7 +144,7 @@ public virtual Response GetPet(string id, RequestOptions options = null)
/// <summary> Create Request for <see cref="GetPet"/> and <see cref="GetPetAsync"/> operations. </summary>
/// <param name="id"> Id of pet to return. </param>
/// <param name="options"> The request options. </param>
private HttpMessage CreateGetPetRequest(string id, RequestOptions options = null)
private HttpMessage CreateGetPetRequest(string id, RequestContext context = null)
{
var message = Pipeline.CreateMessage();
var request = message.Request;
Expand Down
20 changes: 10 additions & 10 deletions sdk/core/Azure.Core.Experimental/tests/LowLevelClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public async Task CanGetResponseFromLlcGetMethodAsync()
var mockTransport = new MockTransport(mockResponse);
PetStoreClient client = CreateClient(mockTransport);

Response response = await client.GetPetAsync("snoopy", new RequestOptions());
Response response = await client.GetPetAsync("snoopy", new RequestContext());
var doc = JsonDocument.Parse(response.Content.ToMemory());

Assert.AreEqual(200, response.Status);
Expand Down Expand Up @@ -75,7 +75,7 @@ public async Task ModelCastThrowsOnErrorCodeAsync()
var mockTransport = new MockTransport(mockResponse);
PetStoreClient client = CreateClient(mockTransport);

Response response = await client.GetPetAsync("pet1", ResponseStatusOption.NoThrow);
Response response = await client.GetPetAsync("pet1", ErrorOptions.NoThrow);

Assert.Throws<RequestFailedException>(() => { Pet pet = response; });
}
Expand Down Expand Up @@ -140,7 +140,7 @@ public async Task GetRequestFailedException_StatusOptionNoThrow()
{
// NOTE: is it weird that we're saying NoThrow here and it throws?
// This looks confusing to me as someone reading this code.
Pet pet = await client.GetPetAsync("pet1", ResponseStatusOption.NoThrow);
Pet pet = await client.GetPetAsync("pet1", ErrorOptions.NoThrow);
}
catch (RequestFailedException e)
{
Expand All @@ -158,15 +158,15 @@ public void CanSuppressExceptions()
var mockTransport = new MockTransport(mockResponse);
PetStoreClient client = CreateClient(mockTransport);

RequestOptions options = new RequestOptions()
RequestContext context = new RequestContext()
{
StatusOption = ResponseStatusOption.NoThrow
ErrorOptions = ErrorOptions.NoThrow
};

Response response = default;
Assert.DoesNotThrowAsync(async () =>
{
response = await client.GetPetAsync("snoopy", options);
response = await client.GetPetAsync("snoopy", context);
});

Assert.AreEqual(404, response.Status);
Expand All @@ -183,9 +183,9 @@ public async Task ThrowOnErrorDoesntThrowOnSuccess()
var mockTransport = new MockTransport(mockResponse);
PetStoreClient client = CreateClient(mockTransport);

Response response = await client.GetPetAsync("snoopy", new RequestOptions()
Response response = await client.GetPetAsync("snoopy", new RequestContext()
{
StatusOption = ResponseStatusOption.Default
ErrorOptions = ErrorOptions.Default
});
var doc = JsonDocument.Parse(response.Content.ToMemory());

Expand All @@ -204,9 +204,9 @@ public void ThrowOnErrorThrowsOnError()

Assert.ThrowsAsync<RequestFailedException>(async () =>
{
await client.GetPetAsync("snoopy", new RequestOptions()
await client.GetPetAsync("snoopy", new RequestContext()
{
StatusOption = ResponseStatusOption.Default
ErrorOptions = ErrorOptions.Default
});
});
}
Expand Down
12 changes: 0 additions & 12 deletions sdk/core/Azure.Core.Experimental/tests/RequestOptionsTest.cs

This file was deleted.

13 changes: 13 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net461.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public AzureSasCredential(string signature) { }
public string Signature { get { throw null; } }
public void Update(string signature) { }
}
[System.FlagsAttribute]
public enum ErrorOptions
{
Default = 0,
NoThrow = 1,
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ETag : System.IEquatable<Azure.ETag>
{
Expand Down Expand Up @@ -179,6 +185,13 @@ public RequestConditions() { }
public System.DateTimeOffset? IfModifiedSince { get { throw null; } set { } }
public System.DateTimeOffset? IfUnmodifiedSince { get { throw null; } set { } }
}
public partial class RequestContext
{
public RequestContext() { }
public System.Threading.CancellationToken CancellationToken { get { throw null; } set { } }
public Azure.ErrorOptions ErrorOptions { get { throw null; } set { } }
public static implicit operator Azure.RequestContext (Azure.ErrorOptions options) { throw null; }
}
public partial class RequestFailedException : System.Exception, System.Runtime.Serialization.ISerializable
{
public RequestFailedException(int status, string message) { }
Expand Down
13 changes: 13 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.net5.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public AzureSasCredential(string signature) { }
public string Signature { get { throw null; } }
public void Update(string signature) { }
}
[System.FlagsAttribute]
public enum ErrorOptions
{
Default = 0,
NoThrow = 1,
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ETag : System.IEquatable<Azure.ETag>
{
Expand Down Expand Up @@ -179,6 +185,13 @@ public RequestConditions() { }
public System.DateTimeOffset? IfModifiedSince { get { throw null; } set { } }
public System.DateTimeOffset? IfUnmodifiedSince { get { throw null; } set { } }
}
public partial class RequestContext
{
public RequestContext() { }
public System.Threading.CancellationToken CancellationToken { get { throw null; } set { } }
public Azure.ErrorOptions ErrorOptions { get { throw null; } set { } }
public static implicit operator Azure.RequestContext (Azure.ErrorOptions options) { throw null; }
}
public partial class RequestFailedException : System.Exception, System.Runtime.Serialization.ISerializable
{
public RequestFailedException(int status, string message) { }
Expand Down
13 changes: 13 additions & 0 deletions sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public AzureSasCredential(string signature) { }
public string Signature { get { throw null; } }
public void Update(string signature) { }
}
[System.FlagsAttribute]
public enum ErrorOptions
{
Default = 0,
NoThrow = 1,
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ETag : System.IEquatable<Azure.ETag>
{
Expand Down Expand Up @@ -179,6 +185,13 @@ public RequestConditions() { }
public System.DateTimeOffset? IfModifiedSince { get { throw null; } set { } }
public System.DateTimeOffset? IfUnmodifiedSince { get { throw null; } set { } }
}
public partial class RequestContext
{
public RequestContext() { }
public System.Threading.CancellationToken CancellationToken { get { throw null; } set { } }
public Azure.ErrorOptions ErrorOptions { get { throw null; } set { } }
public static implicit operator Azure.RequestContext (Azure.ErrorOptions options) { throw null; }
}
public partial class RequestFailedException : System.Exception, System.Runtime.Serialization.ISerializable
{
public RequestFailedException(int status, string message) { }
Expand Down
13 changes: 13 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 @@ -42,6 +42,12 @@ public AzureSasCredential(string signature) { }
public string Signature { get { throw null; } }
public void Update(string signature) { }
}
[System.FlagsAttribute]
public enum ErrorOptions
{
Default = 0,
NoThrow = 1,
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct ETag : System.IEquatable<Azure.ETag>
{
Expand Down Expand Up @@ -179,6 +185,13 @@ public RequestConditions() { }
public System.DateTimeOffset? IfModifiedSince { get { throw null; } set { } }
public System.DateTimeOffset? IfUnmodifiedSince { get { throw null; } set { } }
}
public partial class RequestContext
{
public RequestContext() { }
public System.Threading.CancellationToken CancellationToken { get { throw null; } set { } }
public Azure.ErrorOptions ErrorOptions { get { throw null; } set { } }
public static implicit operator Azure.RequestContext (Azure.ErrorOptions options) { throw null; }
}
public partial class RequestFailedException : System.Exception, System.Runtime.Serialization.ISerializable
{
public RequestFailedException(int status, string message) { }
Expand Down
25 changes: 25 additions & 0 deletions sdk/core/Azure.Core/src/ErrorOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;

namespace Azure
{
/// <summary>
/// ErrorOptions controls the behavior of an operation when an unexpected response status code is received.
/// </summary>
[Flags]
public enum ErrorOptions
{
/// <summary>
/// Indicates that an operation should throw an exception when the response indicates a failure.
/// </summary>
Default = 0,

/// <summary>
/// Indicates that an operation should not throw an exception when the response indicates a failure.
/// Callers should check the Response.IsError property instead of catching exceptions.
/// </summary>
NoThrow = 1,
}
}
39 changes: 39 additions & 0 deletions sdk/core/Azure.Core/src/RequestContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

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

namespace Azure
{
/// <summary>
/// Options which can be used to control the behavior of a request sent by a client.
/// </summary>
public class RequestContext
{
/// <summary>
/// Initializes a new instance of the <see cref="RequestContext"/> class.
/// </summary>
public RequestContext()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="RequestContext"/> class using the given <see cref="ErrorOptions"/>.
/// </summary>
/// <param name="options"></param>
public static implicit operator RequestContext(ErrorOptions options) => new RequestContext { ErrorOptions = options };

/// <summary>
/// The token to check for cancellation.
/// </summary>
public CancellationToken CancellationToken { get; set; } = CancellationToken.None;

/// <summary>
/// Controls under what conditions the operation raises an exception if the underlying response indicates a failure.
/// </summary>
public ErrorOptions ErrorOptions { get; set; } = ErrorOptions.Default;
}
}
6 changes: 3 additions & 3 deletions sdk/core/Azure.Core/tests/HttpPipelineMessageTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void DisposeNoopsForNullResponse()
var requestMock = new Mock<Request>();
HttpMessage message = new HttpMessage(requestMock.Object, new ResponseClassifier());
message.Dispose();
requestMock.Verify(r=>r.Dispose(), Times.Once);
requestMock.Verify(r => r.Dispose(), Times.Once);
}

[Test]
Expand All @@ -29,8 +29,8 @@ public void DisposingMessageDisposesTheRequestAndResponse()
HttpMessage message = new HttpMessage(requestMock.Object, new ResponseClassifier());
message.Response = responseMock.Object;
message.Dispose();
requestMock.Verify(r=>r.Dispose(), Times.Once);
responseMock.Verify(r=>r.Dispose(), Times.Once);
requestMock.Verify(r => r.Dispose(), Times.Once);
responseMock.Verify(r => r.Dispose(), Times.Once);
}

[Test]
Expand Down
31 changes: 31 additions & 0 deletions sdk/core/Azure.Core/tests/RequestContextTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;

namespace Azure.Core.Tests
{
public class RequestContextTests
{
[Test]
public void CanCastFromErrorOptions()
{
RequestContext context = ErrorOptions.Default;

Assert.IsTrue(context.ErrorOptions == ErrorOptions.Default);
}

[Test]
public void CanSetErrorOptions()
{
RequestContext context = new RequestContext { ErrorOptions = ErrorOptions.NoThrow };

Assert.IsTrue(context.ErrorOptions == ErrorOptions.NoThrow);
}
}
}

0 comments on commit c622678

Please sign in to comment.