diff --git a/sdk/core/Azure.Core/src/Internal/ResponseDebugView.cs b/sdk/core/Azure.Core/src/Internal/ResponseDebugView.cs new file mode 100644 index 000000000000..da31b80a1ea3 --- /dev/null +++ b/sdk/core/Azure.Core/src/Internal/ResponseDebugView.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Diagnostics; + +namespace Azure +{ + internal class ResponseDebugView + { + private readonly Response _response; + + public ResponseDebugView(Response response) + { + _response = response; + } + + public Response GetRawResponse => _response.GetRawResponse(); + + public T Value => _response.Value; + } +} diff --git a/sdk/core/Azure.Core/src/Response.cs b/sdk/core/Azure.Core/src/Response.cs index 5d535c512fad..fe7a5798544d 100644 --- a/sdk/core/Azure.Core/src/Response.cs +++ b/sdk/core/Azure.Core/src/Response.cs @@ -35,5 +35,10 @@ public static Response FromValue(T value, Response response) { return new ValueResponse(response, value); } + + public override string ToString() + { + return $"Status: {Status}, ReasonPhrase: {ReasonPhrase}"; + } } } diff --git a/sdk/core/Azure.Core/src/Response{T}.cs b/sdk/core/Azure.Core/src/Response{T}.cs index a37c3a967d22..4ebe53eb1841 100644 --- a/sdk/core/Azure.Core/src/Response{T}.cs +++ b/sdk/core/Azure.Core/src/Response{T}.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.ComponentModel; +using System.Diagnostics; namespace Azure { @@ -9,6 +10,7 @@ namespace Azure /// Represents a result of Azure operation. /// /// The type of returned value. + [DebuggerTypeProxy(typeof(ResponseDebugView<>))] public abstract class Response { /// @@ -37,7 +39,9 @@ public abstract class Response public override int GetHashCode() => base.GetHashCode(); /// - [EditorBrowsable(EditorBrowsableState.Never)] - public override string ToString() => base.ToString(); + public override string ToString() + { + return $"Status: {GetRawResponse().Status}, Value: {Value}"; + } } } diff --git a/sdk/core/Azure.Core/src/Shared/NoBodyResponse{T}.cs b/sdk/core/Azure.Core/src/Shared/NoBodyResponse{T}.cs index 4959cdbdcf61..85ba5aa2f303 100644 --- a/sdk/core/Azure.Core/src/Shared/NoBodyResponse{T}.cs +++ b/sdk/core/Azure.Core/src/Shared/NoBodyResponse{T}.cs @@ -24,6 +24,11 @@ public override T Value public override Response GetRawResponse() => _response; + public override string ToString() + { + return $"Status: {GetRawResponse().Status}, Service returned no content"; + } + #pragma warning disable CA1064 // Exceptions should be public private class ResponseBodyNotFoundException : Exception #pragma warning restore CA1064 // Exceptions should be public diff --git a/sdk/core/Azure.Core/tests/ResponseTests.cs b/sdk/core/Azure.Core/tests/ResponseTests.cs index 61ecac1a3301..38eb58d37070 100644 --- a/sdk/core/Azure.Core/tests/ResponseTests.cs +++ b/sdk/core/Azure.Core/tests/ResponseTests.cs @@ -28,6 +28,22 @@ public void ValueObtainedFromCast() Assert.AreEqual("test_name", value.Name); } + [Test] + public void ToStringsFormatsStatusAndValue() + { + var response = Response.FromValue(new TestPayload("test_name"), response: new MockResponse(200)); + + Assert.AreEqual("Status: 200, Value: Name: test_name", response.ToString()); + } + + [Test] + public void ToStringsFormatsStatusAndResponsePhrase() + { + var response = new MockResponse(200, "Phrase"); + + Assert.AreEqual("Status: 200, ReasonPhrase: Phrase", response.ToString()); + } + [Test] public void ValueThrowsIfUnspecified() { @@ -63,6 +79,15 @@ public void ValueThrowsFromCastIfUnspecified() Assert.True(throws); } + [Test] + public void ToStringsFormatsStatusAndMessageForNoBodyResponse() + { + var response = new NoBodyResponse(new MockResponse(200)); + + Assert.AreEqual("Status: 200, Service returned no content", response.ToString()); + } + + internal class TestPayload { public string Name { get; } @@ -71,6 +96,11 @@ public TestPayload(string name) { Name = name; } + + public override string ToString() + { + return $"Name: {Name}"; + } } } diff --git a/sdk/core/Azure.Core/tests/TestFramework/MockResponse.cs b/sdk/core/Azure.Core/tests/TestFramework/MockResponse.cs index cc30ad2df51f..8e190463ad6f 100644 --- a/sdk/core/Azure.Core/tests/TestFramework/MockResponse.cs +++ b/sdk/core/Azure.Core/tests/TestFramework/MockResponse.cs @@ -29,8 +29,6 @@ public MockResponse(int status, string reasonPhrase = null) public bool IsDisposed { get; private set; } - public override string ToString() => $"{Status}"; - public void SetContent(byte[] content) { ContentStream = new MemoryStream(content); diff --git a/sdk/storage/Azure.Storage.Blobs.Batching/src/DelayedResponse.cs b/sdk/storage/Azure.Storage.Blobs.Batching/src/DelayedResponse.cs index 1b7bafbf6ec8..ec6370a8beb0 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batching/src/DelayedResponse.cs +++ b/sdk/storage/Azure.Storage.Blobs.Batching/src/DelayedResponse.cs @@ -77,6 +77,11 @@ public void SetLiveResponse(Response live, bool throwOnFailure) } } + public override string ToString() + { + return _live == null ? "Status: NotSent, the batch has not been submitted yet" : base.ToString(); + } + // We directly forward the entire Response interface to LiveResponse #region forward Response members to Live /// diff --git a/sdk/storage/Azure.Storage.Blobs.Batching/tests/DelayedResponseTests.cs b/sdk/storage/Azure.Storage.Blobs.Batching/tests/DelayedResponseTests.cs new file mode 100644 index 000000000000..397bf9dbd935 --- /dev/null +++ b/sdk/storage/Azure.Storage.Blobs.Batching/tests/DelayedResponseTests.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; +using Azure.Core.Testing; +using Azure.Storage.Blobs.Specialized; +using NUnit.Framework; + +namespace Azure.Storage.Blobs.Test +{ + public class DelayedResponseTests + { + [Test] + public void DelayedResponseToStringDoesntThrow() + { + DelayedResponse delayedResponse = new DelayedResponse(new HttpMessage(new MockRequest(), new ResponseClassifier())); + Assert.AreEqual("Status: NotSent, the batch has not been submitted yet", delayedResponse.ToString()); + } + + [Test] + public void CompletedDelayedResponseToStringCallsBase() + { + DelayedResponse delayedResponse = new DelayedResponse(new HttpMessage(new MockRequest(), new ResponseClassifier())); + delayedResponse.SetLiveResponse(new MockResponse(200, "Yay"), false); + Assert.AreEqual("Status: 200, ReasonPhrase: Yay", delayedResponse.ToString()); + } + } +}