diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs index 490820a617a4..82068c89e2be 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs @@ -200,10 +200,8 @@ public virtual async Task> AddConfigurationSettin case 200: case 201: return await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false); - case 412: - throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); default: - throw new RequestFailedException(response); + throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); } } catch (Exception e) @@ -239,10 +237,8 @@ public virtual Response AddConfigurationSetting(Configurat case 200: case 201: return CreateResponse(response); - case 412: - throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); default: - throw new RequestFailedException(response); + throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); } } catch (Exception e) @@ -309,10 +305,9 @@ public virtual async Task> SetConfigurationSettin return response.Status switch { 200 => await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false), - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -352,10 +347,9 @@ public virtual Response SetConfigurationSetting(Configurat return response.Status switch { 200 => CreateResponse(response), - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -441,10 +435,9 @@ private async Task DeleteConfigurationSettingAsync(string key, string { 200 => response, 204 => response, - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response) + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -470,10 +463,9 @@ private Response DeleteConfigurationSetting(string key, string label, MatchCondi { 200 => response, 204 => response, - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response) + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -596,7 +588,7 @@ internal virtual async Task> GetConfigurationSett { 200 => await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false), 304 => CreateResourceModifiedResponse(response), - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()) }; } catch (Exception e) @@ -633,7 +625,7 @@ internal virtual Response GetConfigurationSetting(string k { 200 => CreateResponse(response), 304 => CreateResourceModifiedResponse(response), - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()) }; } catch (Exception e) @@ -1386,7 +1378,7 @@ private async ValueTask> SetReadOnlyAsync(string 200 => async ? await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false) : CreateResponse(response), - _ => throw new RequestFailedException(response) + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -1469,22 +1461,24 @@ private static RequestContext CreateRequestContext(ErrorOptions errorOptions, Ca private class ConfigurationRequestFailedDetailsParser : RequestFailedDetailsParser { + private const string TroubleshootingMessage = + "For troubleshooting information, see https://aka.ms/azsdk/net/appconfiguration/troubleshoot."; public override bool TryParse(Response response, out ResponseError error, out IDictionary data) { switch (response.Status) { case 409: - error = new ResponseError(null, "The setting is read only"); + error = new ResponseError(null, $"The setting is read only. {TroubleshootingMessage}"); data = null; return true; case 412: - error = new ResponseError(null, "Setting was already present."); + error = new ResponseError(null, $"Setting was already present. {TroubleshootingMessage}"); data = null; return true; default: - error = null; + error = new ResponseError(null, TroubleshootingMessage); data = null; - return false; + return true; } } } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs index 30e86abf2eba..59c01dd4ee35 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs @@ -29,6 +29,7 @@ public class ConfigurationMockTests : ClientTestBase private static readonly string s_credential = "b1d9b31"; private static readonly string s_secret = "aabbccdd"; private static readonly string s_connectionString = $"Endpoint={s_endpoint};Id={s_credential};Secret={s_secret}"; + private static readonly string s_troubleshootingLink = "https://aka.ms/azsdk/net/appconfiguration/troubleshoot"; private static readonly string s_version = new ConfigurationClientOptions().Version; private static readonly ConfigurationSetting s_testSetting = new ConfigurationSetting("test_key", "test_value") @@ -108,6 +109,27 @@ public void GetNotFound() Assert.AreEqual(404, exception.Status); } + // This test validates that the client throws an exception with the expected error message when it receives a + // non-success status code from the service. + [TestCase((int)HttpStatusCode.Unauthorized)] + [TestCase(403)] + [TestCase((int)HttpStatusCode.NotFound)] + public void GetUnsucessfulResponse(int statusCode) + { + var response = new MockResponse(statusCode); + var mockTransport = new MockTransport(response); + ConfigurationClient service = CreateTestService(mockTransport); + + RequestFailedException exception = Assert.ThrowsAsync(async () => + { + await service.GetConfigurationSettingAsync(key: s_testSetting.Key); + }); + + Assert.AreEqual(statusCode, exception.Status); + + Assert.True(exception?.Message.Contains(s_troubleshootingLink)); + } + [Test] public async Task GetIfChangedModified() {