Skip to content
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

IDownstreamApi overloads that take JsonTypeInfo<T> as a parameter to enable source generated Json deserialization for NativeAOT #131

Merged
merged 16 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</PropertyGroup>

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net462</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net462;net8.0</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../build/MSAL.snk</AssemblyOriginatorKeyFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
168 changes: 168 additions & 0 deletions src/Microsoft.Identity.Abstractions/CompatibilitySuppressions.xml

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
// Licensed under the MIT License.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Abstractions;

#if NET8_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
#endif

namespace Microsoft.Identity.Abstractions
{
/// <summary>
Expand All @@ -24,9 +28,20 @@ namespace Microsoft.Identity.Abstractions
public partial interface IDownstreamApi
{
<#
foreach(string framework in new string[]{ "all", "net8" } )
{

if (framework == "net8")
{
#>

#if NET8_0_OR_GREATER
<#
}

foreach(string httpMethod in new string[]{ "Get", "Post", "Put", "Patch", "Delete"} )
{
if (httpMethod == "Patch")
if (httpMethod == "Patch" && framework != "net8")
dualtagh marked this conversation as resolved.
Show resolved Hide resolved
{
#>

Expand Down Expand Up @@ -63,6 +78,12 @@ namespace Microsoft.Identity.Abstractions
<# } #>
<# if (hasOutput){ #>
/// <typeparam name="TOutput">Generic output type.</typeparam>
<# } #>
<# if (hasInput && framework == "net8"){ #>
/// <param name="inputJsonTypeInfo">JSON serialization metadata for TInput</param>
<# } #>
<# if (hasOutput && framework == "net8"){ #>
/// <param name="outputJsonTypeInfo">JSON serialization metadata for TOutput</param>
<# } #>
dualtagh marked this conversation as resolved.
Show resolved Hide resolved
/// <param name="serviceName">Name of the service describing the downstream API. There can
/// be several configuration named sections mapped to a <see cref="DownstreamApiOptions"/>,
Expand Down Expand Up @@ -93,13 +114,21 @@ namespace Microsoft.Identity.Abstractions
/// });
/// </code>
/// </example>
<# if (framework != "net8"){ #>
#if NET6_0_OR_GREATER
[RequiresUnreferencedCode("This method's implementations also use generic types and are not trim-friendly.")]
#endif
<# } #>
public <#= returnType #> <#= httpMethod #>For<#= token #>Async<#= template #>(
string? serviceName,
<# if (hasInput){ #>
TInput input,
<# } #>
<# if (hasInput && framework == "net8"){ #>
JsonTypeInfo<TInput> inputJsonTypeInfo,
<# } #>
<# if (hasOutput && framework == "net8"){ #>
JsonTypeInfo<TOutput> outputJsonTypeInfo,
<# } #>
Action<DownstreamApiOptionsReadOnlyHttpMethod>? downstreamApiOptionsOverride = null,
<# if (!hasApp){ #>
Expand All @@ -111,14 +140,18 @@ namespace Microsoft.Identity.Abstractions
}
#>
<#
if (httpMethod == "Patch")
if (httpMethod == "Patch" && framework != "net8")
{
#>

#endif // NETSTANDARD2_1_OR_GREATER
<#
}
}
}
}
if (framework == "net8") {#>
#endif // NET8_0_OR_GREATER
<#}
}
#>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
// Licensed under the MIT License.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;

#if NET8_0_OR_GREATER
using System.Text.Json.Serialization.Metadata;
using System.Diagnostics.CodeAnalysis;
#endif

namespace Microsoft.Identity.Abstractions
{
/// <summary>
Expand Down Expand Up @@ -236,5 +240,136 @@ Task<HttpResponseMessage> CallApiForAppAsync(
Action<DownstreamApiOptions>? downstreamApiOptionsOverride = null,
dualtagh marked this conversation as resolved.
Show resolved Hide resolved
CancellationToken cancellationToken = default)
where TOutput : class;

#if NET8_0_OR_GREATER
dualtagh marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Calls a downstream API consuming JSON with some data and returns data.
/// </summary>
/// <typeparam name="TInput">Input type.</typeparam>
/// <typeparam name="TOutput">Output type.</typeparam>
/// <param name="serviceName">Name of the service describing the downstream API. There can
/// be several configuration named sections mapped to a <see cref="DownstreamApiOptions"/>,
/// each for one downstream API. You can pass-in null, but in that case <paramref name="downstreamApiOptionsOverride"/>
/// needs to be set.</param>
/// <param name="input">Input parameter to the downstream web API.</param>
/// <param name="inputJsonTypeInfo">JSON serialization metadata for TInput</param>
/// <param name="outputJsonTypeInfo">JSON serialization metadata for TOutput</param>
/// <param name="downstreamApiOptionsOverride">Overrides the options proposed in the configuration described
/// by <paramref name="serviceName"/>.</param>
/// <param name="user">[Optional] Claims representing a user. This is useful in platforms like Blazor
/// or Azure Signal R, where the HttpContext is not available. In other platforms, the library
/// will find the user from the HttpContext.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The value returned by the downstream web API.</returns>
/// <example>
/// A list method that returns an IEnumerable&lt;MyItem&gt;&gt;.
/// <code>
/// public Task&lt;IEnumerable&lt;MyItem&gt;&gt; GetAsync()
/// {
/// return _downstreamWebApi.CallWebApiForUserAsync&lt;object, IEnumerable&lt;MyItem&gt;&gt;(
/// ServiceName,
/// null,
/// options =>
/// {
/// options.RelativePath = $"api/todolist";
/// });
/// }
/// </code>
///
/// Example of editing.
/// <code>
/// public Task&lt;MyItem&gt; EditAsync(MyItem myItem)
/// {
/// return _downstreamWebApi.CallWebApiForUserAsync&lt;MyItem, MyItem&gt;(
/// ServiceName,
/// nyItem,
/// options =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to update this code snippet (which goes in the reference documentation). See the Examples paragraph of https://learn.microsoft.com/en-us/dotnet/api/microsoft.identity.abstractions.idownstreamapi.callapiforuserasync?view=msal-model-dotnet-latest for instance

/// {
/// options.HttpMethod = HttpMethod.Patch;
/// options.RelativePath = $"api/todolist/{myItem.Id}";
/// });
/// }
/// </code>
/// </example>
public Task<TOutput?> CallApiForUserAsync<TInput, TOutput>(
eerhardt marked this conversation as resolved.
Show resolved Hide resolved
string? serviceName,
TInput input,
JsonTypeInfo<TInput> inputJsonTypeInfo,
JsonTypeInfo<TOutput> outputJsonTypeInfo,
Action<DownstreamApiOptions>? downstreamApiOptionsOverride = null,
ClaimsPrincipal? user = default,
CancellationToken cancellationToken = default)
where TOutput : class;

/// <summary>
/// Call a web API endpoint with an HttpGet, and return strongly typed data.
/// </summary>
/// <typeparam name="TOutput">Output type.</typeparam>
/// <param name="serviceName">Name of the service describing the downstream API. There can
/// be several configuration named sections mapped to a <see cref="DownstreamApiOptions"/>,
/// each for one downstream API. You can pass-in null, but in that case <paramref name="downstreamApiOptionsOverride"/>
/// needs to be set.</param>
/// <param name="outputJsonTypeInfo">JSON serialization metadata for TOutput</param>
/// <param name="downstreamApiOptionsOverride">Overrides the options proposed in the configuration described
/// by <paramref name="serviceName"/>.</param>
/// <param name="user">[Optional] Claims representing a user. This is useful in platforms like Blazor
/// or Azure Signal R, where the HttpContext is not available. In other platforms, the library
/// will find the user from the HttpContext.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The value returned by the downstream web API.</returns>
public Task<TOutput?> CallApiForUserAsync<TOutput>(
string serviceName,
JsonTypeInfo<TOutput> outputJsonTypeInfo,
Action<DownstreamApiOptions>? downstreamApiOptionsOverride = null,
ClaimsPrincipal? user = default,
CancellationToken cancellationToken = default)
where TOutput : class;

/// <summary>
/// Calls a downstream API consuming JSON with some data and returns data.
/// </summary>
/// <typeparam name="TInput">Input type.</typeparam>
/// <typeparam name="TOutput">Output type.</typeparam>
/// <param name="serviceName">Name of the service describing the downstream API. There can
/// be several configuration named sections mapped to a <see cref="DownstreamApiOptions"/>,
/// each for one downstream API. You can pass-in null, but in that case <paramref name="downstreamApiOptionsOverride"/>
/// needs to be set.</param>
/// <param name="input">Input parameter to the downstream web API.</param>
/// <param name="inputJsonTypeInfo">JSON serialization metadata for TInput</param>
/// <param name="outputJsonTypeInfo">JSON serialization metadata for TOutput</param>
/// <param name="downstreamApiOptionsOverride">Overrides the options proposed in the configuration described
/// by <paramref name="serviceName"/>.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The value returned by the downstream web API.</returns>
public Task<TOutput?> CallApiForAppAsync<TInput, TOutput>(
string? serviceName,
TInput input,
JsonTypeInfo<TInput> inputJsonTypeInfo,
JsonTypeInfo<TOutput> outputJsonTypeInfo,
Action<DownstreamApiOptions>? downstreamApiOptionsOverride = null,
CancellationToken cancellationToken = default)
where TOutput : class;

/// <summary>
/// Call a web API endpoint with an HttpGet, and return strongly typed data.
/// </summary>
/// <typeparam name="TOutput">Output type.</typeparam>
/// <param name="serviceName">Name of the service describing the downstream API. There can
/// be several configuration named sections mapped to a <see cref="DownstreamApiOptions"/>,
/// each for one downstream API. You can pass-in null, but in that case <paramref name="downstreamApiOptionsOverride"/>
/// needs to be set.</param>
/// <param name="outputJsonTypeInfo">JSON serialization metadata for TOutput</param>
/// <param name="downstreamApiOptionsOverride">Overrides the options proposed in the configuration described
/// by <paramref name="serviceName"/>.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>The value returned by the downstream web API.</returns>
public Task<TOutput?> CallApiForAppAsync<TOutput>(
string serviceName,
JsonTypeInfo<TOutput> outputJsonTypeInfo,
Action<DownstreamApiOptions>? downstreamApiOptionsOverride = null,
CancellationToken cancellationToken = default)
where TOutput : class;
#endif
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@
<DependentUpon>IDownstreamApi.HttpMethods.tt</DependentUpon>
</Compile>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Microsoft.Identity.Abstractions.DownstreamApi.Tests
{
internal class CustomDownstreamApi : IDownstreamApi
internal partial class CustomDownstreamApi : IDownstreamApi
{
public CustomDownstreamApi()
{
Expand Down
Loading
Loading