From 8ac4caec847394d1b771720c5612a45a7c8ad4d6 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Sun, 11 Aug 2024 14:14:02 +0300 Subject: [PATCH 1/7] Use ExtraQP to inject telemetry SDK ID --- .../DownstreamApi.cs | 49 ++++++++++++++----- ...icrosoft.Identity.Web.DownstreamApi.csproj | 3 ++ .../Constants.cs | 1 - .../IdHelper.cs | 9 +++- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs index b0dccca0e..fd5f59816 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs +++ b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; @@ -167,8 +168,8 @@ public Task CallApiForAppAsync( HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, false, null, user, cancellationToken).ConfigureAwait(false); return await DeserializeOutputAsync(response, effectiveOptions).ConfigureAwait(false); - } - + } + #if NET8_0_OR_GREATER /// public async Task CallApiForUserAsync( @@ -267,7 +268,7 @@ public Task CallApiForAppAsync( /// /// Named configuration. /// Delegate to override the configuration. - internal /* for tests */ DownstreamApiOptions MergeOptions( + private /* for tests */ DownstreamApiOptions MergeOptions( string? optionsInstanceName, Action? calledApiOptionsOverride) { @@ -293,7 +294,7 @@ public Task CallApiForAppAsync( /// Named configuration. /// Delegate to override the configuration. /// Http method overriding the configuration options. - internal /* for tests */ DownstreamApiOptions MergeOptions( + private DownstreamApiOptions MergeOptions( string? optionsInstanceName, Action? calledApiOptionsOverride, HttpMethod httpMethod) { @@ -311,8 +312,8 @@ public Task CallApiForAppAsync( DownstreamApiOptionsReadOnlyHttpMethod clonedOptions = new DownstreamApiOptionsReadOnlyHttpMethod(options, httpMethod.ToString()); calledApiOptionsOverride?.Invoke(clonedOptions); return clonedOptions; - } - + } + internal static HttpContent? SerializeInput(TInput input, DownstreamApiOptions effectiveOptions) { return SerializeInputImpl(input, effectiveOptions, null); @@ -350,7 +351,7 @@ public Task CallApiForAppAsync( } internal static async Task DeserializeOutputAsync(HttpResponseMessage response, DownstreamApiOptions effectiveOptions) - where TOutput : class + where TOutput : class { try { @@ -398,8 +399,8 @@ public Task CallApiForAppAsync( } return stringContent as TOutput; } - } - + } + private static async Task DeserializeOutputImplAsync(HttpResponseMessage response, DownstreamApiOptions effectiveOptions, JsonTypeInfo outputJsonTypeInfo) where TOutput : class { @@ -451,7 +452,7 @@ public Task CallApiForAppAsync( } } - internal async Task CallApiInternalAsync( + private async Task CallApiInternalAsync( string? serviceName, DownstreamApiOptions effectiveOptions, bool appToken, @@ -461,6 +462,7 @@ internal async Task CallApiInternalAsync( { // Downstream API URI string apiUrl = effectiveOptions.GetApiUrl(); + AddCallerSDKTelemetry(effectiveOptions); // Create an HTTP request message using HttpRequestMessage httpRequestMessage = new( @@ -517,7 +519,7 @@ internal async Task UpdateRequestAsync( effectiveOptions.Scopes, effectiveOptions, user, - cancellationToken).ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); httpRequestMessage.Headers.Add(Authorization, authorizationHeader); } @@ -532,5 +534,30 @@ internal async Task UpdateRequestAsync( // Opportunity to change the request message effectiveOptions.CustomizeHttpRequestMessage?.Invoke(httpRequestMessage); } + + + private static readonly Dictionary s_callerSDKDetails = new() + { + { "caller-sdk-id", "1" }, // 1 = Downstream API SDK ID + { "caller-sdk-ver", IdHelper.GetIdWebVersion() } + }; + + private static void AddCallerSDKTelemetry(DownstreamApiOptions effectiveOptions) + { + if (effectiveOptions.AcquireTokenOptions.ExtraQueryParameters == null) + { + effectiveOptions.AcquireTokenOptions.ExtraQueryParameters = s_callerSDKDetails; + } + else + { + if (!effectiveOptions.AcquireTokenOptions.ExtraQueryParameters.ContainsKey("caller-sdk-id")) + { + effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-id"] = + s_callerSDKDetails["caller-sdk-id"]; + effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-ver"] = + s_callerSDKDetails["caller-sdk-ver"]; + } + } + } } } diff --git a/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj b/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj index ce13a395f..992ce8ba8 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj +++ b/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj @@ -7,6 +7,9 @@ true README.md + + + True diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/Constants.cs b/src/Microsoft.Identity.Web.TokenAcquisition/Constants.cs index 9734ee86a..2b4b08399 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/Constants.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/Constants.cs @@ -144,7 +144,6 @@ public static class Constants // Telemetry headers internal const string TelemetryHeaderKey = "x-client-brkrver"; - internal const string IDWebSku = "IDWeb."; // Authorize for scopes attributes internal const string XReturnUrl = "x-ReturnUrl"; diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs b/src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs index b8601e59e..9275c58c9 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs @@ -10,6 +10,8 @@ namespace Microsoft.Identity.Web { internal static class IdHelper { + private const string IDWebSku = "IDWeb."; + private static readonly Lazy s_idWebVersion = new Lazy( () => { @@ -34,9 +36,14 @@ internal static class IdHelper return version[1]; }); + public static string GetIdWebVersion() + { + return s_idWebVersion.Value; + } + public static string CreateTelemetryInfo() { - return string.Format(CultureInfo.InvariantCulture, Constants.IDWebSku + s_idWebVersion.Value); + return string.Format(CultureInfo.InvariantCulture, IDWebSku + s_idWebVersion.Value); } } } From d885dc6cc259e2f028088142152e8a9141a21649 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Sun, 11 Aug 2024 14:16:52 +0300 Subject: [PATCH 2/7] 2 --- .../DownstreamApi.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs index fd5f59816..dd716dde4 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs +++ b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs @@ -550,13 +550,10 @@ private static void AddCallerSDKTelemetry(DownstreamApiOptions effectiveOptions) } else { - if (!effectiveOptions.AcquireTokenOptions.ExtraQueryParameters.ContainsKey("caller-sdk-id")) - { - effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-id"] = - s_callerSDKDetails["caller-sdk-id"]; - effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-ver"] = - s_callerSDKDetails["caller-sdk-ver"]; - } + effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-id"] = + s_callerSDKDetails["caller-sdk-id"]; + effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-ver"] = + s_callerSDKDetails["caller-sdk-ver"]; } } } From 8706512988d6ffc4874dc17fee73ae866b14d24b Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 13 Aug 2024 10:58:54 +0300 Subject: [PATCH 3/7] Address PR and add UT --- .../IdHelper.cs | 6 +-- .../DownstreamApi.cs | 29 +++++++------- ...icrosoft.Identity.Web.DownstreamApi.csproj | 3 -- .../AppBuilderExtension.cs | 1 + .../MsalAspNetCoreHttpClientFactory.cs | 1 + ...tyWebAppAuthenticationBuilderExtensions.cs | 1 + .../DownstreamApiTests.cs | 40 ++++++++++++++++++- 7 files changed, 60 insertions(+), 21 deletions(-) rename src/{Microsoft.Identity.Web.TokenAcquisition => Microsoft.Identity.Web.Diagnostics}/IdHelper.cs (94%) diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs b/src/Microsoft.Identity.Web.Diagnostics/IdHelper.cs similarity index 94% rename from src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs rename to src/Microsoft.Identity.Web.Diagnostics/IdHelper.cs index 9275c58c9..dd5591cbc 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/IdHelper.cs +++ b/src/Microsoft.Identity.Web.Diagnostics/IdHelper.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Text.RegularExpressions; -namespace Microsoft.Identity.Web +namespace Microsoft.Identity.Web.Diagnostics { internal static class IdHelper { @@ -37,13 +37,13 @@ internal static class IdHelper }); public static string GetIdWebVersion() - { + { return s_idWebVersion.Value; } public static string CreateTelemetryInfo() { - return string.Format(CultureInfo.InvariantCulture, IDWebSku + s_idWebVersion.Value); + return string.Format(CultureInfo.InvariantCulture, IDWebSku + GetIdWebVersion()); } } } diff --git a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs index dd716dde4..c8f80eee8 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs +++ b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs @@ -17,6 +17,7 @@ using Microsoft.Extensions.Options; using Microsoft.Identity.Abstractions; using Microsoft.Identity.Client; +using Microsoft.Identity.Web.Diagnostics; namespace Microsoft.Identity.Web { @@ -168,8 +169,8 @@ public Task CallApiForAppAsync( HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, false, null, user, cancellationToken).ConfigureAwait(false); return await DeserializeOutputAsync(response, effectiveOptions).ConfigureAwait(false); - } - + } + #if NET8_0_OR_GREATER /// public async Task CallApiForUserAsync( @@ -312,8 +313,8 @@ private DownstreamApiOptions MergeOptions( DownstreamApiOptionsReadOnlyHttpMethod clonedOptions = new DownstreamApiOptionsReadOnlyHttpMethod(options, httpMethod.ToString()); calledApiOptionsOverride?.Invoke(clonedOptions); return clonedOptions; - } - + } + internal static HttpContent? SerializeInput(TInput input, DownstreamApiOptions effectiveOptions) { return SerializeInputImpl(input, effectiveOptions, null); @@ -351,8 +352,8 @@ private DownstreamApiOptions MergeOptions( } internal static async Task DeserializeOutputAsync(HttpResponseMessage response, DownstreamApiOptions effectiveOptions) - where TOutput : class - { + where TOutput : class + { try { response.EnsureSuccessStatusCode(); @@ -462,7 +463,6 @@ private async Task CallApiInternalAsync( { // Downstream API URI string apiUrl = effectiveOptions.GetApiUrl(); - AddCallerSDKTelemetry(effectiveOptions); // Create an HTTP request message using HttpRequestMessage httpRequestMessage = new( @@ -496,7 +496,7 @@ private async Task CallApiInternalAsync( return downstreamApiResult; } - internal async Task UpdateRequestAsync( + internal /* internal for test */ async Task UpdateRequestAsync( HttpRequestMessage httpRequestMessage, HttpContent? content, DownstreamApiOptions effectiveOptions, @@ -504,6 +504,8 @@ internal async Task UpdateRequestAsync( ClaimsPrincipal? user, CancellationToken cancellationToken) { + AddCallerSDKTelemetry(effectiveOptions); + if (content != null) { httpRequestMessage.Content = content; @@ -519,7 +521,7 @@ internal async Task UpdateRequestAsync( effectiveOptions.Scopes, effectiveOptions, user, - cancellationToken).ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); httpRequestMessage.Headers.Add(Authorization, authorizationHeader); } @@ -535,8 +537,7 @@ internal async Task UpdateRequestAsync( effectiveOptions.CustomizeHttpRequestMessage?.Invoke(httpRequestMessage); } - - private static readonly Dictionary s_callerSDKDetails = new() + internal /* for test */ static Dictionary CallerSDKDetails { get; } = new() { { "caller-sdk-id", "1" }, // 1 = Downstream API SDK ID { "caller-sdk-ver", IdHelper.GetIdWebVersion() } @@ -546,14 +547,14 @@ private static void AddCallerSDKTelemetry(DownstreamApiOptions effectiveOptions) { if (effectiveOptions.AcquireTokenOptions.ExtraQueryParameters == null) { - effectiveOptions.AcquireTokenOptions.ExtraQueryParameters = s_callerSDKDetails; + effectiveOptions.AcquireTokenOptions.ExtraQueryParameters = CallerSDKDetails; } else { effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-id"] = - s_callerSDKDetails["caller-sdk-id"]; + CallerSDKDetails["caller-sdk-id"]; effectiveOptions.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-ver"] = - s_callerSDKDetails["caller-sdk-ver"]; + CallerSDKDetails["caller-sdk-ver"]; } } } diff --git a/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj b/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj index 992ce8ba8..ce13a395f 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj +++ b/src/Microsoft.Identity.Web.DownstreamApi/Microsoft.Identity.Web.DownstreamApi.csproj @@ -7,9 +7,6 @@ true README.md - - - True diff --git a/src/Microsoft.Identity.Web.OWIN/AppBuilderExtension.cs b/src/Microsoft.Identity.Web.OWIN/AppBuilderExtension.cs index 55083dbc6..01de5fc9c 100644 --- a/src/Microsoft.Identity.Web.OWIN/AppBuilderExtension.cs +++ b/src/Microsoft.Identity.Web.OWIN/AppBuilderExtension.cs @@ -17,6 +17,7 @@ using Microsoft.Owin.Security.Jwt; using Microsoft.Owin.Security.OAuth; using Microsoft.Owin.Security.OpenIdConnect; +using Microsoft.Identity.Web.Diagnostics; using Owin; namespace Microsoft.Identity.Web diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/MsalAspNetCoreHttpClientFactory.cs b/src/Microsoft.Identity.Web.TokenAcquisition/MsalAspNetCoreHttpClientFactory.cs index 481016003..1537edfb0 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/MsalAspNetCoreHttpClientFactory.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/MsalAspNetCoreHttpClientFactory.cs @@ -3,6 +3,7 @@ using System.Net.Http; using Microsoft.Identity.Client; +using Microsoft.Identity.Web.Diagnostics; namespace Microsoft.Identity.Web { diff --git a/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs b/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs index 1e731d0c0..3d51521b0 100644 --- a/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs +++ b/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs @@ -16,6 +16,7 @@ using Microsoft.IdentityModel.Protocols.OpenIdConnect; using System.Linq; using System.Diagnostics.CodeAnalysis; +using Microsoft.Identity.Web.Diagnostics; namespace Microsoft.Identity.Web { diff --git a/tests/Microsoft.Identity.Web.Test/DownstreamWebApiSupport/DownstreamApiTests.cs b/tests/Microsoft.Identity.Web.Test/DownstreamWebApiSupport/DownstreamApiTests.cs index 052a96e42..1e0bce09a 100644 --- a/tests/Microsoft.Identity.Web.Test/DownstreamWebApiSupport/DownstreamApiTests.cs +++ b/tests/Microsoft.Identity.Web.Test/DownstreamWebApiSupport/DownstreamApiTests.cs @@ -49,14 +49,51 @@ public async Task UpdateRequestAsync_WithContent_AddsContentToRequestAsync() // Arrange var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); var content = new StringContent("test content"); + var options = new DownstreamApiOptions(); // Act - await _input.UpdateRequestAsync(httpRequestMessage, content, new DownstreamApiOptions(), false, null, CancellationToken.None); + await _input.UpdateRequestAsync(httpRequestMessage, content, options, false, null, CancellationToken.None); // Assert Assert.Equal(content, httpRequestMessage.Content); Assert.Equal("application/json", httpRequestMessage.Headers.Accept.Single().MediaType); Assert.Equal("text/plain", httpRequestMessage.Content?.Headers.ContentType?.MediaType); + Assert.Equal(options.AcquireTokenOptions.ExtraQueryParameters, DownstreamApi.CallerSDKDetails); + } + + + [Fact] + public async Task UpdateRequestAsync_AddsToExtraQP() + { + // Arrange + var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); + var content = new StringContent("test content"); + var options = new DownstreamApiOptions() { + AcquireTokenOptions = new AcquireTokenOptions() { + ExtraQueryParameters = new Dictionary() + { + { "n1", "v1" }, + { "n2", "v2" }, + { "caller-sdk-id", "bogus" } // value will be overwritten by the SDK + } + } }; + + // Act + await _input.UpdateRequestAsync(httpRequestMessage, content, options, false, null, CancellationToken.None); + + // Assert + Assert.Equal(content, httpRequestMessage.Content); + Assert.Equal("application/json", httpRequestMessage.Headers.Accept.Single().MediaType); + Assert.Equal("text/plain", httpRequestMessage.Content?.Headers.ContentType?.MediaType); + Assert.Equal("v1", options.AcquireTokenOptions.ExtraQueryParameters["n1"]); + Assert.Equal("v2", options.AcquireTokenOptions.ExtraQueryParameters["n2"]); + Assert.Equal( + DownstreamApi.CallerSDKDetails["caller-sdk-id"], + options.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-id"] ); + Assert.Equal( + DownstreamApi.CallerSDKDetails["caller-sdk-ver"], + options.AcquireTokenOptions.ExtraQueryParameters["caller-sdk-ver"]); + } [Theory] @@ -83,6 +120,7 @@ public async Task UpdateRequestAsync_WithScopes_AddsAuthorizationHeaderToRequest Assert.Equal("ey", httpRequestMessage.Headers.Authorization?.Parameter); Assert.Equal("Bearer", httpRequestMessage.Headers.Authorization?.Scheme); Assert.Equal("application/json", httpRequestMessage.Headers.Accept.Single().MediaType); + Assert.Equal(options.AcquireTokenOptions.ExtraQueryParameters, DownstreamApi.CallerSDKDetails); } [Fact] From 33448dbf33d47b5188d8736259c7996f5c1e302f Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Wed, 14 Aug 2024 09:17:40 +0300 Subject: [PATCH 4/7] 3 --- .../DownstreamApi.cs | 614 +++++++++--------- 1 file changed, 307 insertions(+), 307 deletions(-) diff --git a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs index c8f80eee8..31c02af2d 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs +++ b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs @@ -1,176 +1,176 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Runtime.CompilerServices; -using System.Security.Claims; -using System.Text; -using System.Text.Json; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Runtime.CompilerServices; +using System.Security.Claims; +using System.Text; +using System.Text.Json; using System.Text.Json.Serialization.Metadata; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Identity.Abstractions; -using Microsoft.Identity.Client; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Identity.Abstractions; +using Microsoft.Identity.Client; using Microsoft.Identity.Web.Diagnostics; - -namespace Microsoft.Identity.Web -{ - /// - internal partial class DownstreamApi : IDownstreamApi - { - private readonly IAuthorizationHeaderProvider _authorizationHeaderProvider; - private readonly IHttpClientFactory _httpClientFactory; - private readonly IOptionsMonitor _namedDownstreamApiOptions; - private const string Authorization = "Authorization"; - protected readonly ILogger _logger; - - /// - /// Constructor. - /// - /// Authorization header provider. - /// Named options provider. - /// HTTP client factory. - /// Logger. - public DownstreamApi( - IAuthorizationHeaderProvider authorizationHeaderProvider, - IOptionsMonitor namedDownstreamApiOptions, - IHttpClientFactory httpClientFactory, - ILogger logger) - { - _authorizationHeaderProvider = authorizationHeaderProvider; - _namedDownstreamApiOptions = namedDownstreamApiOptions; - _httpClientFactory = httpClientFactory; - _logger = logger; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Task CallApiAsync( - string? serviceName, - Action? downstreamApiOptionsOverride = null, - ClaimsPrincipal? user = null, - HttpContent? content = null, - CancellationToken cancellationToken = default) - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - return CallApiInternalAsync(serviceName, effectiveOptions, effectiveOptions.RequestAppToken, content, - user, cancellationToken); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Task CallApiAsync( - DownstreamApiOptions downstreamApiOptions, - ClaimsPrincipal? user = null, - HttpContent? content = null, - CancellationToken cancellationToken = default) - { - return CallApiInternalAsync(null, downstreamApiOptions, downstreamApiOptions.RequestAppToken, content, - user, cancellationToken); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Task CallApiForUserAsync( - string? serviceName, - Action? downstreamApiOptionsOverride = null, - ClaimsPrincipal? user = null, - HttpContent? content = null, - CancellationToken cancellationToken = default) - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - return CallApiInternalAsync(serviceName, effectiveOptions, false, content, user, cancellationToken); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Task CallApiForAppAsync( - string? serviceName, - Action? downstreamApiOptionsOverride = null, - HttpContent? content = null, - CancellationToken cancellationToken = default) - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - return CallApiInternalAsync(serviceName, effectiveOptions, true, content, null, cancellationToken); - } - - /// - public async Task CallApiForUserAsync( - string? serviceName, - TInput input, - Action? downstreamApiOptionsOverride = null, - ClaimsPrincipal? user = null, - CancellationToken cancellationToken = default) where TOutput : class - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - HttpContent? effectiveInput = SerializeInput(input, effectiveOptions); - - HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, false, - effectiveInput, user, cancellationToken).ConfigureAwait(false); - - // Only dispose the HttpContent if was created here, not provided by the caller. - if (input is not HttpContent) - { - effectiveInput?.Dispose(); - } - + +namespace Microsoft.Identity.Web +{ + /// + internal partial class DownstreamApi : IDownstreamApi + { + private readonly IAuthorizationHeaderProvider _authorizationHeaderProvider; + private readonly IHttpClientFactory _httpClientFactory; + private readonly IOptionsMonitor _namedDownstreamApiOptions; + private const string Authorization = "Authorization"; + protected readonly ILogger _logger; + + /// + /// Constructor. + /// + /// Authorization header provider. + /// Named options provider. + /// HTTP client factory. + /// Logger. + public DownstreamApi( + IAuthorizationHeaderProvider authorizationHeaderProvider, + IOptionsMonitor namedDownstreamApiOptions, + IHttpClientFactory httpClientFactory, + ILogger logger) + { + _authorizationHeaderProvider = authorizationHeaderProvider; + _namedDownstreamApiOptions = namedDownstreamApiOptions; + _httpClientFactory = httpClientFactory; + _logger = logger; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task CallApiAsync( + string? serviceName, + Action? downstreamApiOptionsOverride = null, + ClaimsPrincipal? user = null, + HttpContent? content = null, + CancellationToken cancellationToken = default) + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + return CallApiInternalAsync(serviceName, effectiveOptions, effectiveOptions.RequestAppToken, content, + user, cancellationToken); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task CallApiAsync( + DownstreamApiOptions downstreamApiOptions, + ClaimsPrincipal? user = null, + HttpContent? content = null, + CancellationToken cancellationToken = default) + { + return CallApiInternalAsync(null, downstreamApiOptions, downstreamApiOptions.RequestAppToken, content, + user, cancellationToken); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task CallApiForUserAsync( + string? serviceName, + Action? downstreamApiOptionsOverride = null, + ClaimsPrincipal? user = null, + HttpContent? content = null, + CancellationToken cancellationToken = default) + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + return CallApiInternalAsync(serviceName, effectiveOptions, false, content, user, cancellationToken); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task CallApiForAppAsync( + string? serviceName, + Action? downstreamApiOptionsOverride = null, + HttpContent? content = null, + CancellationToken cancellationToken = default) + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + return CallApiInternalAsync(serviceName, effectiveOptions, true, content, null, cancellationToken); + } + + /// + public async Task CallApiForUserAsync( + string? serviceName, + TInput input, + Action? downstreamApiOptionsOverride = null, + ClaimsPrincipal? user = null, + CancellationToken cancellationToken = default) where TOutput : class + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + HttpContent? effectiveInput = SerializeInput(input, effectiveOptions); + + HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, false, + effectiveInput, user, cancellationToken).ConfigureAwait(false); + + // Only dispose the HttpContent if was created here, not provided by the caller. + if (input is not HttpContent) + { + effectiveInput?.Dispose(); + } + return await DeserializeOutputAsync(response, effectiveOptions).ConfigureAwait(false); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public async Task CallApiForAppAsync( - string? serviceName, - TInput input, - Action? downstreamApiOptionsOverride = null, - CancellationToken cancellationToken = default) where TOutput : class - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - HttpContent? effectiveInput = SerializeInput(input, effectiveOptions); - HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, true, - effectiveInput, null, cancellationToken).ConfigureAwait(false); - - // Only dispose the HttpContent if was created here, not provided by the caller. - if (input is not HttpContent) - { - effectiveInput?.Dispose(); - } - + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public async Task CallApiForAppAsync( + string? serviceName, + TInput input, + Action? downstreamApiOptionsOverride = null, + CancellationToken cancellationToken = default) where TOutput : class + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + HttpContent? effectiveInput = SerializeInput(input, effectiveOptions); + HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, true, + effectiveInput, null, cancellationToken).ConfigureAwait(false); + + // Only dispose the HttpContent if was created here, not provided by the caller. + if (input is not HttpContent) + { + effectiveInput?.Dispose(); + } + return await DeserializeOutputAsync(response, effectiveOptions).ConfigureAwait(false); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public async Task CallApiForAppAsync(string serviceName, - Action? downstreamApiOptionsOverride = null, - CancellationToken cancellationToken = default) where TOutput : class - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, true, - null, null, cancellationToken).ConfigureAwait(false); - + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public async Task CallApiForAppAsync(string serviceName, + Action? downstreamApiOptionsOverride = null, + CancellationToken cancellationToken = default) where TOutput : class + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, true, + null, null, cancellationToken).ConfigureAwait(false); + return await DeserializeOutputAsync(response, effectiveOptions).ConfigureAwait(false); - } - - /// - public async Task CallApiForUserAsync( - string? serviceName, - Action? downstreamApiOptionsOverride = null, - ClaimsPrincipal? user = null, - CancellationToken cancellationToken = default) where TOutput : class - { - DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); - HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, false, - null, user, cancellationToken).ConfigureAwait(false); + } + + /// + public async Task CallApiForUserAsync( + string? serviceName, + Action? downstreamApiOptionsOverride = null, + ClaimsPrincipal? user = null, + CancellationToken cancellationToken = default) where TOutput : class + { + DownstreamApiOptions effectiveOptions = MergeOptions(serviceName, downstreamApiOptionsOverride); + HttpResponseMessage response = await CallApiInternalAsync(serviceName, effectiveOptions, false, + null, user, cancellationToken).ConfigureAwait(false); return await DeserializeOutputAsync(response, effectiveOptions).ConfigureAwait(false); - } - + } + #if NET8_0_OR_GREATER /// public async Task CallApiForUserAsync( @@ -264,59 +264,59 @@ public Task CallApiForAppAsync( } #endif - /// - /// Merge the options from configuration and override from caller. - /// - /// Named configuration. - /// Delegate to override the configuration. - private /* for tests */ DownstreamApiOptions MergeOptions( - string? optionsInstanceName, - Action? calledApiOptionsOverride) - { - // Gets the options from configuration (or default value) - DownstreamApiOptions options; - if (optionsInstanceName != null) - { - options = _namedDownstreamApiOptions.Get(optionsInstanceName); - } - else - { - options = _namedDownstreamApiOptions.CurrentValue; - } - - DownstreamApiOptions clonedOptions = new DownstreamApiOptions(options); - calledApiOptionsOverride?.Invoke(clonedOptions); - return clonedOptions; - } - - /// - /// Merge the options from configuration and override from caller. - /// - /// Named configuration. - /// Delegate to override the configuration. - /// Http method overriding the configuration options. - private DownstreamApiOptions MergeOptions( - string? optionsInstanceName, - Action? calledApiOptionsOverride, HttpMethod httpMethod) - { - // Gets the options from configuration (or default value) - DownstreamApiOptions options; - if (optionsInstanceName != null) - { - options = _namedDownstreamApiOptions.Get(optionsInstanceName); - } - else - { - options = _namedDownstreamApiOptions.CurrentValue; - } - - DownstreamApiOptionsReadOnlyHttpMethod clonedOptions = new DownstreamApiOptionsReadOnlyHttpMethod(options, httpMethod.ToString()); - calledApiOptionsOverride?.Invoke(clonedOptions); - return clonedOptions; - } - - internal static HttpContent? SerializeInput(TInput input, DownstreamApiOptions effectiveOptions) - { + /// + /// Merge the options from configuration and override from caller. + /// + /// Named configuration. + /// Delegate to override the configuration. + internal /* for tests */ DownstreamApiOptions MergeOptions( + string? optionsInstanceName, + Action? calledApiOptionsOverride) + { + // Gets the options from configuration (or default value) + DownstreamApiOptions options; + if (optionsInstanceName != null) + { + options = _namedDownstreamApiOptions.Get(optionsInstanceName); + } + else + { + options = _namedDownstreamApiOptions.CurrentValue; + } + + DownstreamApiOptions clonedOptions = new DownstreamApiOptions(options); + calledApiOptionsOverride?.Invoke(clonedOptions); + return clonedOptions; + } + + /// + /// Merge the options from configuration and override from caller. + /// + /// Named configuration. + /// Delegate to override the configuration. + /// Http method overriding the configuration options. + internal /* for tests */ DownstreamApiOptions MergeOptions( + string? optionsInstanceName, + Action? calledApiOptionsOverride, HttpMethod httpMethod) + { + // Gets the options from configuration (or default value) + DownstreamApiOptions options; + if (optionsInstanceName != null) + { + options = _namedDownstreamApiOptions.Get(optionsInstanceName); + } + else + { + options = _namedDownstreamApiOptions.CurrentValue; + } + + DownstreamApiOptionsReadOnlyHttpMethod clonedOptions = new DownstreamApiOptionsReadOnlyHttpMethod(options, httpMethod.ToString()); + calledApiOptionsOverride?.Invoke(clonedOptions); + return clonedOptions; + } + + internal static HttpContent? SerializeInput(TInput input, DownstreamApiOptions effectiveOptions) + { return SerializeInputImpl(input, effectiveOptions, null); } @@ -325,11 +325,11 @@ private DownstreamApiOptions MergeOptions( HttpContent? httpContent; if (effectiveOptions.Serializer != null) - { + { httpContent = effectiveOptions.Serializer(input); - } - else - { + } + else + { // if the input is already an HttpContent, it's used as is, and should already contain a ContentType. httpContent = input switch { @@ -347,13 +347,13 @@ private DownstreamApiOptions MergeOptions( Encoding.UTF8, "application/json"), }; - } - return httpContent; - } - + } + return httpContent; + } + internal static async Task DeserializeOutputAsync(HttpResponseMessage response, DownstreamApiOptions effectiveOptions) - where TOutput : class - { + where TOutput : class + { try { response.EnsureSuccessStatusCode(); @@ -405,75 +405,75 @@ private DownstreamApiOptions MergeOptions( private static async Task DeserializeOutputImplAsync(HttpResponseMessage response, DownstreamApiOptions effectiveOptions, JsonTypeInfo outputJsonTypeInfo) where TOutput : class { - try - { - response.EnsureSuccessStatusCode(); - } - catch - { - string error = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - -#if NET5_0_OR_GREATER - throw new HttpRequestException($"{(int)response.StatusCode} {response.StatusCode} {error}", null, response.StatusCode); -#else - throw new HttpRequestException($"{(int)response.StatusCode} {response.StatusCode} {error}"); -#endif - } - - HttpContent content = response.Content; - - if (content == null) - { - return default; - } - - string? mediaType = content.Headers.ContentType?.MediaType; - - if (effectiveOptions.Deserializer != null) - { - return effectiveOptions.Deserializer(content) as TOutput; - } + try + { + response.EnsureSuccessStatusCode(); + } + catch + { + string error = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + +#if NET5_0_OR_GREATER + throw new HttpRequestException($"{(int)response.StatusCode} {response.StatusCode} {error}", null, response.StatusCode); +#else + throw new HttpRequestException($"{(int)response.StatusCode} {response.StatusCode} {error}"); +#endif + } + + HttpContent content = response.Content; + + if (content == null) + { + return default; + } + + string? mediaType = content.Headers.ContentType?.MediaType; + + if (effectiveOptions.Deserializer != null) + { + return effectiveOptions.Deserializer(content) as TOutput; + } else if (typeof(TOutput).IsAssignableFrom(typeof(HttpContent))) { return content as TOutput; - } - else - { - string stringContent = await content.ReadAsStringAsync(); - if (mediaType == "application/json") - { + } + else + { + string stringContent = await content.ReadAsStringAsync(); + if (mediaType == "application/json") + { return JsonSerializer.Deserialize(stringContent, outputJsonTypeInfo); } - if (mediaType != null && !mediaType.StartsWith("text/", StringComparison.OrdinalIgnoreCase)) - { - // Handle other content types here - throw new NotSupportedException("Content type not supported. Provide your own deserializer. "); - } - return stringContent as TOutput; - } - } - - private async Task CallApiInternalAsync( - string? serviceName, - DownstreamApiOptions effectiveOptions, - bool appToken, - HttpContent? content = null, - ClaimsPrincipal? user = null, - CancellationToken cancellationToken = default) - { - // Downstream API URI - string apiUrl = effectiveOptions.GetApiUrl(); - + if (mediaType != null && !mediaType.StartsWith("text/", StringComparison.OrdinalIgnoreCase)) + { + // Handle other content types here + throw new NotSupportedException("Content type not supported. Provide your own deserializer. "); + } + return stringContent as TOutput; + } + } + + internal /* for tests */ async Task CallApiInternalAsync( + string? serviceName, + DownstreamApiOptions effectiveOptions, + bool appToken, + HttpContent? content = null, + ClaimsPrincipal? user = null, + CancellationToken cancellationToken = default) + { + // Downstream API URI + string apiUrl = effectiveOptions.GetApiUrl(); + // Create an HTTP request message using HttpRequestMessage httpRequestMessage = new( - new HttpMethod(effectiveOptions.HttpMethod), - apiUrl); - - await UpdateRequestAsync(httpRequestMessage, content, effectiveOptions, appToken, user, cancellationToken); - + new HttpMethod(effectiveOptions.HttpMethod), + apiUrl); + + await UpdateRequestAsync(httpRequestMessage, content, effectiveOptions, appToken, user, cancellationToken); + using HttpClient client = string.IsNullOrEmpty(serviceName) ? _httpClientFactory.CreateClient() : _httpClientFactory.CreateClient(serviceName); - - // Send the HTTP message + + // Send the HTTP message var downstreamApiResult = await client.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false); // Retry only if the resource sent 401 Unauthorized with WWW-Authenticate header and claims @@ -495,7 +495,7 @@ private async Task CallApiInternalAsync( return downstreamApiResult; } - + internal /* internal for test */ async Task UpdateRequestAsync( HttpRequestMessage httpRequestMessage, HttpContent? content, @@ -513,29 +513,29 @@ private async Task CallApiInternalAsync( effectiveOptions.RequestAppToken = appToken; - // Obtention of the authorization header (except when calling an anonymous endpoint - // which is done by not specifying any scopes - if (effectiveOptions.Scopes != null && effectiveOptions.Scopes.Any()) - { + // Obtention of the authorization header (except when calling an anonymous endpoint + // which is done by not specifying any scopes + if (effectiveOptions.Scopes != null && effectiveOptions.Scopes.Any()) + { string authorizationHeader = await _authorizationHeaderProvider.CreateAuthorizationHeaderAsync( effectiveOptions.Scopes, effectiveOptions, user, - cancellationToken).ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); httpRequestMessage.Headers.Add(Authorization, authorizationHeader); - } - else - { - Logger.UnauthenticatedApiCall(_logger, null); - } - if (!string.IsNullOrEmpty(effectiveOptions.AcceptHeader)) + } + else + { + Logger.UnauthenticatedApiCall(_logger, null); + } + if (!string.IsNullOrEmpty(effectiveOptions.AcceptHeader)) { httpRequestMessage.Headers.Accept.ParseAdd(effectiveOptions.AcceptHeader); - } - // Opportunity to change the request message + } + // Opportunity to change the request message effectiveOptions.CustomizeHttpRequestMessage?.Invoke(httpRequestMessage); - } + } internal /* for test */ static Dictionary CallerSDKDetails { get; } = new() { @@ -557,5 +557,5 @@ private static void AddCallerSDKTelemetry(DownstreamApiOptions effectiveOptions) CallerSDKDetails["caller-sdk-ver"]; } } - } -} + } +} From 47d71ec1eb8f057166b8d2febcbbd47e95d5e484 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 29 Oct 2024 17:50:41 +0000 Subject: [PATCH 5/7] Update internal api --- .../PublicAPI/net6.0/InternalAPI.Unshipped.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net6.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net6.0/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net6.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net6.0/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file From 7193bddc22599798f09c941483acb78efd988a3a Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 29 Oct 2024 18:13:00 +0000 Subject: [PATCH 6/7] api --- .../PublicAPI/net462/InternalAPI.Unshipped.txt | 3 +++ .../PublicAPI/net472/InternalAPI.Unshipped.txt | 3 +++ .../PublicAPI/net7.0/InternalAPI.Unshipped.txt | 3 +++ .../PublicAPI/net8.0/InternalAPI.Unshipped.txt | 3 +++ .../PublicAPI/net9.0/InternalAPI.Unshipped.txt | 3 +++ .../PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt | 3 +++ 6 files changed, 18 insertions(+) diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net462/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net462/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net462/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net462/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net472/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net472/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net472/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net472/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net7.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net7.0/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net7.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net7.0/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net8.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net8.0/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net8.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net8.0/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net9.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net9.0/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net9.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/net9.0/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt index e69de29bb..8aef75df7 100644 --- a/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.Diagnostics/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt @@ -0,0 +1,3 @@ +Microsoft.Identity.Web.Diagnostics.IdHelper +static Microsoft.Identity.Web.Diagnostics.IdHelper.CreateTelemetryInfo() -> string! +static Microsoft.Identity.Web.Diagnostics.IdHelper.GetIdWebVersion() -> string! \ No newline at end of file From 32674df4c225b8498515ed103ea0475564b43a38 Mon Sep 17 00:00:00 2001 From: Bogdan Gavril Date: Tue, 29 Oct 2024 21:06:32 +0000 Subject: [PATCH 7/7] fix --- .../PublicAPI/net462/InternalAPI.Unshipped.txt | 2 +- .../PublicAPI/net472/InternalAPI.Unshipped.txt | 1 + .../PublicAPI/net6.0/InternalAPI.Unshipped.txt | 1 + .../PublicAPI/net7.0/InternalAPI.Unshipped.txt | 1 + .../PublicAPI/net8.0/InternalAPI.Unshipped.txt | 1 + .../PublicAPI/net9.0/InternalAPI.Unshipped.txt | 1 + .../PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net462/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net462/InternalAPI.Unshipped.txt index 1ffcfc6b9..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net462/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net462/InternalAPI.Unshipped.txt @@ -1 +1 @@ -bn +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net472/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net472/InternalAPI.Unshipped.txt index e69de29bb..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net472/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net472/InternalAPI.Unshipped.txt @@ -0,0 +1 @@ +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net6.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net6.0/InternalAPI.Unshipped.txt index e69de29bb..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net6.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net6.0/InternalAPI.Unshipped.txt @@ -0,0 +1 @@ +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net7.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net7.0/InternalAPI.Unshipped.txt index e69de29bb..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net7.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net7.0/InternalAPI.Unshipped.txt @@ -0,0 +1 @@ +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net8.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net8.0/InternalAPI.Unshipped.txt index e69de29bb..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net8.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net8.0/InternalAPI.Unshipped.txt @@ -0,0 +1 @@ +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net9.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net9.0/InternalAPI.Unshipped.txt index e69de29bb..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net9.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/net9.0/InternalAPI.Unshipped.txt @@ -0,0 +1 @@ +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file diff --git a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt index e69de29bb..066b4e1dc 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt +++ b/src/Microsoft.Identity.Web.DownstreamApi/PublicAPI/netstandard2.0/InternalAPI.Unshipped.txt @@ -0,0 +1 @@ +static Microsoft.Identity.Web.DownstreamApi.CallerSDKDetails.get -> System.Collections.Generic.Dictionary! \ No newline at end of file