-
Notifications
You must be signed in to change notification settings - Fork 340
WIP: Authorization Support (Using ASP.NET Core Native AuthN/AuthZ Integration) #377
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
Open
localden
wants to merge
155
commits into
main
Choose a base branch
from
localden/experimental
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 25 commits
Commits
Show all changes
155 commits
Select commit
Hold shift + click to select a range
0bd80e6
Experimental changes in a different direction
localden ac14bb2
Fix build issues
localden e8d9a23
Cleanup
localden 4b3f9f7
Cleanup
localden 8c790db
Tweaks to logic
localden b9ba2b9
Update Program.cs
localden 47f1937
Cleanup
localden 638bd35
Update HttpMcpServerBuilderExtensions.cs
localden d1f30f8
Tweaks to config
localden 3713da6
Server configuration
localden 9582111
Update based on feedback
localden 8b89c2d
Pop the browser open - implement that in the SDK
localden c67ef6c
Tweaks to handles
localden a439840
Mock handler
localden 932e678
Make sure I am not introducing unexpected changes
localden 2151d00
Rename projects
localden 3bfc258
Update sample project name and location
localden 70146dd
Make sure definitions are not changed
localden ec25187
Functionality consolidation
localden a3926ee
Fix name
localden 405db57
Organize things better
localden a0486d3
Cleanup
localden cc2f570
Update samples/ProtectedMCPServer/Program.cs
localden 4e0b508
Update samples/ProtectedMCPServer/Program.cs
localden 32f7b16
Update src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExten…
localden b5728d0
Update samples/AspNetCoreSseServer/Program.cs
localden 487bbd7
Update src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExten…
localden 22b7bcc
Update src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationExten…
localden a433f5a
Contextual rename
localden 31f8ce9
Added overload for custom scheme
localden 48bff9c
Introduce proper constants
localden 991b29b
Simplify the handling of the WWW-Authenticate implementaiton
localden 5c28b62
Update Program.cs
localden 1a1e48c
Remove no longer used entity
localden 008f521
Move to its own file.
localden 6e23f4a
Placeholder setup
localden ff8a2b7
Fix server devx
localden 03438d2
Defaults are applied here - no need to redeclare
localden a4f2495
Proper authorization configuration
localden 2cdee6e
Simplify defaults
localden e79dcb8
Update McpEndpointRouteBuilderExtensions.cs
localden 7903c75
Update Program.cs
localden fbb1817
Simplify tool configuration
localden 6aef68b
Update config
localden 1fd164c
Proper setup
localden 0badaf8
Update McpAuthenticationHandler.cs
localden 9209b61
Update samples
localden a90d01e
Consolidate some of the PKCE logic.
localden f3a3715
Consolidate some OAuth logic
localden e044475
Update McpAuthenticationHandler.cs
localden 8790a35
Clean up the helper
localden 4cff084
Minor changes to PRM doc logic
localden 6b768d8
Cleanup
localden e3c5c21
Remove unused namespaces
localden d77368d
Placeholder for events
localden 32f2265
Simplify policy setup
localden 67342cd
Policy setup
localden b37a7b9
Escaping
localden 583de65
Update server configuration
localden 5f15bce
Validation.
localden 7c33562
Delegate Base64 encoding to a more performant implementation
localden 8d4c0c4
Make sure we're consistent
localden 55bb471
Implement refresh token logic
localden debdb67
Stripping out the client implementation - this needs to be re-thought
localden 003f5a0
Standardize namespacing
localden ceee919
Updating the approach for client auth
localden 51bb38b
Cleanup for client logic
localden afd05af
Cleanup
localden a0fbec6
Simplify client logic
localden 4073efd
Complete PRM doc properties. Update for consistency
localden 2e06f59
Update for consistency
localden 2d7da73
Work on the basic OAuth implementation in sample
localden 10cf1f7
Token acquisition logic
localden 2f84981
Update token logic
localden 6768089
Significantly more basic provider implementation
localden cbb5c36
Working client-server interaction
localden 0aeec19
Cleanup
localden 531370a
Simplification
localden d511312
Cleanup for consistency
localden 1496b41
Update with better DevEx
localden 6b0b7ef
Cleanup
localden a9acba8
Delete AuthorizationServerUtils.cs
localden f8650f9
Cleanup
localden d4cc3ad
Multiple scheme support
localden 31f611a
Multi-scheme support
localden 3852be9
Cleaner implementation
localden 8f926ba
Redundant call
localden b501d23
Merge branch 'main' into localden/experimental
localden c92343c
Update src/ModelContextProtocol/Authentication/AuthorizationDelegatin…
localden c57b85c
Update src/ModelContextProtocol/Authentication/AuthorizationDelegatin…
localden bb25dbd
Update src/ModelContextProtocol/Authentication/AuthorizationDelegatin…
localden 291c7ec
Update src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenti…
localden d72221d
Update src/ModelContextProtocol.AspNetCore/Authentication/McpAuthoriz…
localden 2945083
Clean up scheme checks
localden 26f44de
Use ConfigureAwait
localden ca0cdf3
Fix LINQ issue. Simplify best scheme match check
localden 45c4b30
Proper array caching
localden 627e1e4
Update 401 handling logic. Remove pragma warning silencing.
localden 8903c42
Update based on feedback
localden a0275ea
Update the HttpClient configuration
localden 05e3550
Update for cleanup
localden e8f7012
Update McpAuthenticationHandler.cs
localden 94c39bc
No direct inclusion of HTTP client factory
localden 0504aee
Remove legacy packages
localden 7ac5c4a
Update signature and make test explicit
localden 7b6c9fd
URL check
localden c406230
Changes based on feedback
localden b8954b3
Update to use a HttpClientFactory
localden 0b030c2
Update McpAuthenticationHandler.cs
localden 7c6e406
Update based on feedback
localden 9420013
Update McpAuthenticationOptions.cs
localden 4fbf2e9
Update McpAuthenticationOptions.cs
localden 22962cf
Minor optimizations to the delegating handler
localden 5c94158
Update AuthorizationDelegatingHandler.cs
localden 0abea22
Update AuthorizationHelpers.cs
localden 58a7a3d
Update AuthorizationHelpers.cs
localden b3b8168
Update AuthorizationHelpers.cs
localden aad7ad5
Update AuthorizationHelpers.cs
localden 43eb6ff
Add record support for unauthorized result
localden 9a4cea0
Update BasicOAuthAuthorizationProvider.cs
localden b3766aa
Update ProtectedResourceMetadata.cs
localden bc1566e
Proper check for resource metadata
localden 0857b94
Update AuthorizationHelpers.cs
localden a40325d
.NET Standard 2.0 compatibility fix
localden a0cd4ad
Naming consistency
localden fe0d8ba
Update for consistency
localden 0ff4ac4
Update src/ModelContextProtocol/Authentication/AuthorizationDelegatin…
localden 3b46c8d
Update src/ModelContextProtocol/Protocol/Transport/SseClientTransport…
localden 8c6e1dc
Merge branch 'main' into localden/experimental
localden 3602c66
Merge branch 'main' into localden/experimental
localden 5980c9a
Update src/ModelContextProtocol/Authentication/AuthorizationDelegatin…
localden 34794dd
Update samples/ProtectedMCPServer/Program.cs
localden 614f8b3
Update McpAuthenticationOptions.cs
localden 6ed573d
Delete McpAuthorizationPolicyExtensions.cs
localden bd542e2
Update AuthorizationHelpers.cs
localden 325647b
Update AuthorizationHelpers.cs
localden 5435861
Merge branch 'main' of https://github.com/modelcontextprotocol/csharp…
localden e1ff4ca
Cleanup
localden f806625
Update with configuration for generic OAuth provider
localden 8fc0af1
Update GenericOAuthProvider.cs
localden 0af8a58
Merge branch 'main' of https://github.com/modelcontextprotocol/csharp…
localden c6b1e3a
Move auth stuff to Core.
localden d3591d6
Update AuthorizationHelpers.cs
localden 4d0a126
Update Program.cs
localden cbb504f
Shift listener implementation out of the SDK
localden b6ac759
Remove unused stuff
localden d81d30c
Update Directory.Packages.props
localden 6ccc1d1
Update Directory.Packages.props
localden 3df91d1
Merge branch 'main' into localden/experimental
localden 9f22fd3
Update src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenti…
localden e0c507c
Update Directory.Packages.props
localden 253f5d5
Update src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenti…
localden 2c88d7a
Update src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenti…
localden 6b3ec23
Update src/ModelContextProtocol.Core/Authentication/GenericOAuthProvi…
localden 39f0588
Update src/ModelContextProtocol.Core/Authentication/GenericOAuthProvi…
localden File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,4 +80,7 @@ docs/api | |
|
||
# Rider | ||
.idea/ | ||
.idea_modules/ | ||
.idea_modules/ | ||
|
||
# Misc project metadata | ||
.specs/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using ModelContextProtocol.Auth; | ||
using ModelContextProtocol.Client; | ||
using ModelContextProtocol.Protocol.Transport; | ||
|
||
namespace ProtectedMCPClient; | ||
|
||
class Program | ||
{ | ||
static async Task Main(string[] args) | ||
{ | ||
Console.WriteLine("MCP Secure Weather Client with OAuth Authentication"); | ||
Console.WriteLine("=================================================="); | ||
Console.WriteLine(); | ||
|
||
// Create the authorization config with HTTP listener | ||
var authConfig = new AuthorizationConfig | ||
{ | ||
ClientId = "04f79824-ab56-4511-a7cb-d7deaea92dc0", | ||
Scopes = ["User.Read"] | ||
}.UseHttpListener(hostname: "localhost", listenPort: 1170); | ||
|
||
// Create an HTTP client with OAuth handling | ||
var oauthHandler = new OAuthDelegatingHandler( | ||
redirectUri: authConfig.RedirectUri, | ||
clientId: authConfig.ClientId, | ||
clientName: authConfig.ClientName, | ||
scopes: authConfig.Scopes, | ||
authorizationHandler: authConfig.AuthorizationHandler) | ||
{ | ||
// The OAuth handler needs an inner handler | ||
InnerHandler = new HttpClientHandler() | ||
}; | ||
|
||
var httpClient = new HttpClient(oauthHandler); | ||
var serverUrl = "http://localhost:7071/sse"; // Default server URL | ||
|
||
// Allow the user to specify a different server URL | ||
Console.WriteLine($"Server URL (press Enter for default: {serverUrl}):"); | ||
var userInput = Console.ReadLine(); | ||
if (!string.IsNullOrWhiteSpace(userInput)) | ||
{ | ||
serverUrl = userInput; | ||
} | ||
|
||
Console.WriteLine(); | ||
Console.WriteLine($"Connecting to weather server at {serverUrl}..."); | ||
Console.WriteLine("When prompted for authorization, a browser window will open automatically."); | ||
Console.WriteLine("Complete the authentication in the browser, and this application will continue automatically."); | ||
Console.WriteLine(); | ||
|
||
try | ||
{ | ||
// Create SseClientTransportOptions with the server URL | ||
var transportOptions = new SseClientTransportOptions | ||
{ | ||
Endpoint = new Uri(serverUrl), | ||
Name = "Secure Weather Client" | ||
}; | ||
|
||
// Create SseClientTransport with our authenticated HTTP client | ||
var transport = new SseClientTransport(transportOptions, httpClient); | ||
|
||
// Create an MCP client using the factory method with our transport | ||
var client = await McpClientFactory.CreateAsync(transport); | ||
|
||
// Get the list of available tools | ||
var tools = await client.ListToolsAsync(); | ||
if (tools.Count == 0) | ||
{ | ||
Console.WriteLine("No tools available on the server."); | ||
return; | ||
} | ||
|
||
Console.WriteLine($"Found {tools.Count} tools on the server."); | ||
Console.WriteLine(); | ||
|
||
// Call the protected-data tool which requires authentication | ||
if (tools.Any(t => t.Name == "protected-data")) | ||
{ | ||
Console.WriteLine("Calling protected-data tool..."); | ||
var result = await client.CallToolAsync("protected-data"); | ||
Console.WriteLine("Result: " + result.Content[0].Text); | ||
Console.WriteLine(); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
Console.WriteLine($"Error: {ex.Message}"); | ||
if (ex.InnerException != null) | ||
{ | ||
Console.WriteLine($"Inner error: {ex.InnerException.Message}"); | ||
} | ||
} | ||
|
||
Console.WriteLine("Press any key to exit..."); | ||
Console.ReadKey(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.Extensions.Options; | ||
using ModelContextProtocol.AspNetCore.Auth; | ||
using ModelContextProtocol.Protocol.Types; | ||
using System.Security.Claims; | ||
using System.Text.Encodings.Web; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
// Configure MCP Server | ||
builder.Services.AddMcpServer(options => | ||
{ | ||
options.ServerInstructions = "This is an MCP server with OAuth authorization enabled."; | ||
|
||
// Configure regular server capabilities like tools, prompts, resources | ||
options.Capabilities = new() | ||
{ | ||
Tools = new() | ||
{ | ||
// Simple Echo tool | ||
CallToolHandler = (request, cancellationToken) => | ||
localden marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (request.Params?.Name == "echo") | ||
{ | ||
if (request.Params.Arguments?.TryGetValue("message", out var message) is not true) | ||
{ | ||
throw new Exception("It happens."); | ||
} | ||
|
||
return new ValueTask<CallToolResponse>(new CallToolResponse() | ||
{ | ||
Content = [new Content() { Text = $"Echo: {message}", Type = "text" }] | ||
}); | ||
} | ||
|
||
// Protected tool that requires authorization | ||
if (request.Params?.Name == "protected-data") | ||
{ | ||
// This tool will only be accessible to authenticated clients | ||
return new ValueTask<CallToolResponse>(new CallToolResponse() | ||
{ | ||
Content = [new Content() { Text = "This is protected data that only authorized clients can access" }] | ||
}); | ||
} | ||
|
||
throw new Exception("It happens."); | ||
}, | ||
|
||
ListToolsHandler = async (_, _) => new() | ||
{ | ||
Tools = | ||
[ | ||
new() | ||
{ | ||
Name = "echo", | ||
Description = "Echoes back the message you send" | ||
}, | ||
new() | ||
{ | ||
Name = "protected-data", | ||
Description = "Returns protected data that requires authorization" | ||
} | ||
] | ||
} | ||
} | ||
}; | ||
}) | ||
.WithHttpTransport() | ||
.WithAuthorization(metadata => | ||
{ | ||
metadata.AuthorizationServers.Add(new Uri("https://login.microsoftonline.com/a2213e1c-e51e-4304-9a0d-effe57f31655/v2.0")); | ||
metadata.BearerMethodsSupported.Add("header"); | ||
metadata.ScopesSupported.AddRange(["weather.read", "weather.write"]); | ||
|
||
// Add optional documentation | ||
metadata.ResourceDocumentation = new Uri("https://docs.example.com/api/weather"); | ||
localden marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
|
||
// Configure authentication using the built-in authentication system | ||
builder.Services.AddAuthentication(options => | ||
{ | ||
options.DefaultScheme = "Bearer"; | ||
options.DefaultChallengeScheme = "Bearer"; // Ensure challenges use Bearer scheme | ||
}) | ||
.AddScheme<AuthenticationSchemeOptions, SimpleAuthHandler>("Bearer", options => { }); | ||
localden marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Add authorization policy for MCP | ||
builder.Services.AddAuthorization(options => | ||
{ | ||
options.AddPolicy("McpAuth", policy => | ||
localden marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
policy.RequireAuthenticatedUser(); | ||
policy.RequireClaim("scope", "weather.read"); | ||
}); | ||
}); | ||
|
||
var app = builder.Build(); | ||
|
||
app.UseAuthentication(); | ||
app.UseMcpAuthenticationResponse(); | ||
app.UseAuthorization(); | ||
|
||
// Map MCP endpoints with authorization | ||
app.MapMcp(); | ||
|
||
Console.WriteLine("Starting MCP server with authorization at http://localhost:7071"); | ||
Console.WriteLine("PRM Document URL: http://localhost:7071/.well-known/oauth-protected-resource"); | ||
|
||
Console.WriteLine(); | ||
Console.WriteLine("Testing mode: Server will accept ANY non-empty token for authentication"); | ||
Console.WriteLine(); | ||
Console.WriteLine("To test the server:"); | ||
Console.WriteLine("1. Use an MCP client that supports authorization"); | ||
Console.WriteLine("2. The server will accept any non-empty token sent by the client"); | ||
Console.WriteLine("3. Tokens will be logged to the console for debugging"); | ||
Console.WriteLine(); | ||
Console.WriteLine("Press Ctrl+C to stop the server"); | ||
|
||
app.Run("http://localhost:7071/"); | ||
|
||
// Simple auth handler that accepts any non-empty token for testing | ||
// In a real app, you'd use a JWT handler or other proper authentication | ||
class SimpleAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions> | ||
{ | ||
public SimpleAuthHandler( | ||
IOptionsMonitor<AuthenticationSchemeOptions> options, | ||
ILoggerFactory logger, | ||
UrlEncoder encoder) | ||
: base(options, logger, encoder) | ||
{ | ||
} | ||
|
||
protected override Task<AuthenticateResult> HandleAuthenticateAsync() | ||
{ | ||
// Get the Authorization header | ||
if (!Request.Headers.TryGetValue("Authorization", out var authHeader)) | ||
{ | ||
return Task.FromResult(AuthenticateResult.Fail("Authorization header missing")); | ||
} | ||
|
||
// Parse the token | ||
var headerValue = authHeader.ToString(); | ||
if (!headerValue.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
return Task.FromResult(AuthenticateResult.Fail("Bearer token missing")); | ||
} | ||
|
||
var token = headerValue["Bearer ".Length..].Trim(); | ||
|
||
// Accept any non-empty token for testing purposes | ||
if (string.IsNullOrEmpty(token)) | ||
{ | ||
return Task.FromResult(AuthenticateResult.Fail("Token cannot be empty")); | ||
} | ||
|
||
// Log the received token for debugging | ||
Console.WriteLine($"Received and accepted token: {token}"); | ||
|
||
// Create a claims identity with required claims | ||
var claims = new[] | ||
{ | ||
new Claim(ClaimTypes.Name, "demo_user"), | ||
new Claim(ClaimTypes.NameIdentifier, "user123"), | ||
new Claim("scope", "weather.read") | ||
}; | ||
|
||
var identity = new ClaimsIdentity(claims, "Bearer"); | ||
var principal = new ClaimsPrincipal(identity); | ||
var ticket = new AuthenticationTicket(principal, "Bearer"); | ||
|
||
return Task.FromResult(AuthenticateResult.Success(ticket)); | ||
} | ||
|
||
protected override Task HandleChallengeAsync(AuthenticationProperties properties) | ||
{ | ||
// No need to manually set WWW-Authenticate header anymore - handled by middleware | ||
Response.StatusCode = 401; | ||
return Task.CompletedTask; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"profiles": { | ||
"ProtectedMCPServer": { | ||
"commandName": "Project", | ||
"launchBrowser": true, | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
}, | ||
"applicationUrl": "https://localhost:55598;http://localhost:55599" | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net9.0</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using System.Text.Json; | ||
|
||
namespace ModelContextProtocol; | ||
|
||
internal static class HttpClientExt | ||
{ | ||
public static async Task<JsonDocument> ReadJsonDocumentAsync(this HttpClient client, string requestUri) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Isn't this the same as https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/httpclient-extensions? |
||
{ | ||
using var response = await client.GetAsync(requestUri); | ||
response.EnsureSuccessStatusCode(); | ||
return await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync()); | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, what's this for? If it's some sort of dev tool, it might be better to call out what it is.