Skip to content

Commit 44e61fd

Browse files
committed
Updates
1 parent c96c86a commit 44e61fd

File tree

2 files changed

+133
-10
lines changed

2 files changed

+133
-10
lines changed

aspnetcore/blazor/call-web-api.md

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,123 @@ Calls a todo list web API from a Blazor WebAssembly app:
9393

9494
:::moniker-end
9595

96+
## Client-side scenarios for calling external web APIs
97+
98+
Client-based components call external web APIs using <xref:System.Net.Http.HttpClient> instances, typically created with a preconfigured <xref:System.Net.Http.HttpClient> registered in the `Program` file:
99+
100+
```csharp
101+
builder.Services.AddScoped(sp =>
102+
new HttpClient
103+
{
104+
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
105+
});
106+
```
107+
108+
The following Razor component makes a request to a web API for GitHub branches similar to the *Basic Usage* example in the <xref:fundamentals/http-requests> article.
109+
110+
`CallWebAPI.razor`:
111+
112+
```razor
113+
@page "/call-web-api"
114+
@using System.Text.Json
115+
@using System.Text.Json.Serialization
116+
@inject HttpClient Client
117+
118+
<h1>Call web API from a Blazor WebAssembly Razor component</h1>
119+
120+
@if (getBranchesError || branches is null)
121+
{
122+
<p>Unable to get branches from GitHub. Please try again later.</p>
123+
}
124+
else
125+
{
126+
<ul>
127+
@foreach (var branch in branches)
128+
{
129+
<li>@branch.Name</li>
130+
}
131+
</ul>
132+
}
133+
134+
@code {
135+
private IEnumerable<GitHubBranch>? branches = [];
136+
private bool getBranchesError;
137+
private bool shouldRender;
138+
139+
protected override bool ShouldRender() => shouldRender;
140+
141+
protected override async Task OnInitializedAsync()
142+
{
143+
var request = new HttpRequestMessage(HttpMethod.Get,
144+
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
145+
request.Headers.Add("Accept", "application/vnd.github.v3+json");
146+
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
147+
148+
var response = await Client.SendAsync(request);
149+
150+
if (response.IsSuccessStatusCode)
151+
{
152+
using var responseStream = await response.Content.ReadAsStreamAsync();
153+
branches = await JsonSerializer.DeserializeAsync
154+
<IEnumerable<GitHubBranch>>(responseStream);
155+
}
156+
else
157+
{
158+
getBranchesError = true;
159+
}
160+
161+
shouldRender = true;
162+
}
163+
164+
public class GitHubBranch
165+
{
166+
[JsonPropertyName("name")]
167+
public string? Name { get; set; }
168+
}
169+
}
170+
```
171+
172+
In the preceding example for C# 12 or later, an empty array (`[]`) is created for the `branches` variable. For earlier versions of C# compiled with an SDK earlier than .NET 8, create an empty array (`Array.Empty<GitHubBranch>()`).
173+
174+
<!-- A version of the following content is also in the
175+
Security > WebAssembly > Overview article under
176+
the heading: "Web API requests" -->
177+
178+
To protect .NET/C# code and data, use [ASP.NET Core Data Protection](xref:security/data-protection/introduction) features with a server-side ASP.NET Core backend web API. The client-side Blazor WebAssembly app calls the server-side web API for secure app features and data processing. For more information, see <xref:blazor/call-web-api?pivots=webassembly> and the articles and examples in this documentation node.
179+
180+
Blazor WebAssembly apps are often prevented from making direct calls across origins to web APIs due to [Cross-Origin Request Sharing (CORS) security](xref:blazor/call-web-api#cross-origin-resource-sharing-cors). A typical exception looks like the following:
181+
182+
> :::no-loc text="Access to fetch at '{URL}' from origin 'https://localhost:{PORT}' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.":::
183+
184+
Even if you call <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserRequestMode%2A> with a <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestMode> field of `NoCors` (1) seeking to circumvent the preceding exception, the request often fails due to CORS restrictions on the web API's origin, such as a restriction that requires CORS or a restriction that prevents JavaScript [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch) requests from a browser. The only way for such calls to succeed is for the web API that you're calling to allow your origin to call its origin with the correct CORS configuration. Most external web APIs don't allow you to configure their CORS policies. To deal with this restriction, adopt either of the following strategies:
185+
186+
* Maintain your own server-side ASP.NET Core backend web API. The client-side Blazor WebAssembly app calls your server-side web API, and your web API makes the request from its server-based C# code (not a browser) to the external web API with the correct CORS headers, returning the result to your client-side Blazor WebAssembly app.
187+
188+
* Use a proxy service to proxy the request from the client-side Blazor WebAssembly app to the external web API. The proxy service uses a server-side app to make the request on the client's behalf and returns the result after the call succeeds. In the following example based on [CloudFlare's CORS PROXY](https://corsproxy.io/), the `{REQUEST URI}` placeholder is the request URI:
189+
190+
```razor
191+
@using System.Net
192+
@inject IHttpClientFactory ClientFactory
193+
194+
...
195+
196+
@code {
197+
public async Task CallApi()
198+
{
199+
var client = ClientFactory.CreateClient();
200+
201+
var urlEncodedRequestUri = WebUtility.UrlEncode("{REQUEST URI}");
202+
203+
var request = new HttpRequestMessage(HttpMethod.Get,
204+
$"https://corsproxy.io/?{urlEncodedRequestUri}");
205+
206+
var response = await client.SendAsync(request);
207+
208+
...
209+
}
210+
}
211+
```
212+
96213
## Server-side scenarios for calling external web APIs
97214

98215
Server-based components call external web APIs using <xref:System.Net.Http.HttpClient> instances, typically created using <xref:System.Net.Http.IHttpClientFactory>. For guidance that applies to server-side apps, see <xref:fundamentals/http-requests>.
@@ -115,7 +232,7 @@ The following Razor component makes a request to a web API for GitHub branches s
115232
@using System.Text.Json.Serialization
116233
@inject IHttpClientFactory ClientFactory
117234
118-
<h1>Call web API from a Blazor Server Razor component</h1>
235+
<h1>Call web API from a server-side Razor component</h1>
119236
120237
@if (getBranchesError || branches is null)
121238
{
@@ -171,7 +288,7 @@ else
171288
}
172289
```
173290

174-
In the preceding example for C# 12 or later, an empty array (`[]`) is created for the `branches` variable. For earlier versions of C#, create an empty array (`Array.Empty<GitHubBranch>()`).
291+
In the preceding example for C# 12 or later, an empty array (`[]`) is created for the `branches` variable. For earlier versions of C# compiled with an SDK earlier than .NET 8, create an empty array (`Array.Empty<GitHubBranch>()`).
175292

176293
For an additional working example, see the server-side file upload example that uploads files to a web API controller in the <xref:blazor/file-uploads#upload-files-to-a-server-with-server-side-rendering> article.
177294

aspnetcore/blazor/security/webassembly/index.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ For examples of the preceding approaches, see <xref:blazor/security/webassembly/
2929

3030
## Web API requests
3131

32+
<!-- A version of this content is also in the Call web API
33+
article under the heading:
34+
"Client-side scenarios for calling external web APIs" -->
35+
3236
To protect .NET/C# code and data, use [ASP.NET Core Data Protection](xref:security/data-protection/introduction) features with a server-side ASP.NET Core backend web API. The client-side Blazor WebAssembly app calls the server-side web API for secure app features and data processing. For more information, see <xref:blazor/call-web-api?pivots=webassembly> and the articles and examples in this documentation node.
3337

3438
Blazor WebAssembly apps are often prevented from making direct calls across origins to web APIs due to [Cross-Origin Request Sharing (CORS) security](xref:blazor/call-web-api#cross-origin-resource-sharing-cors). A typical exception looks like the following:
@@ -38,6 +42,7 @@ Blazor WebAssembly apps are often prevented from making direct calls across orig
3842
Even if you call <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserRequestMode%2A> with a <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestMode> field of `NoCors` (1) seeking to circumvent the preceding exception, the request often fails due to CORS restrictions on the web API's origin, such as a restriction that requires CORS or a restriction that prevents JavaScript [`fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch) requests from a browser. The only way for such calls to succeed is for the web API that you're calling to allow your origin to call its origin with the correct CORS configuration. Most external web APIs don't allow you to configure their CORS policies. To deal with this restriction, adopt either of the following strategies:
3943

4044
* Maintain your own server-side ASP.NET Core backend web API. The client-side Blazor WebAssembly app calls your server-side web API, and your web API makes the request from its server-based C# code (not a browser) to the external web API with the correct CORS headers, returning the result to your client-side Blazor WebAssembly app.
45+
4146
* Use a proxy service to proxy the request from the client-side Blazor WebAssembly app to the external web API. The proxy service uses a server-side app to make the request on the client's behalf and returns the result after the call succeeds. In the following example based on [CloudFlare's CORS PROXY](https://corsproxy.io/), the `{REQUEST URI}` placeholder is the request URI:
4247

4348
```razor
@@ -47,18 +52,19 @@ Even if you call <xref:Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssem
4752
...
4853
4954
@code {
50-
...
55+
public async Task CallApi()
56+
{
57+
var client = ClientFactory.CreateClient();
5158
52-
var client = ClientFactory.CreateClient();
59+
var urlEncodedRequestUri = WebUtility.UrlEncode("{REQUEST URI}");
5360
54-
var urlEncodedRequestUri = WebUtility.UrlEncode("{REQUEST URI}");
55-
56-
var request = new HttpRequestMessage(HttpMethod.Get,
57-
$"https://corsproxy.io/?{urlEncodedRequestUri}");
61+
var request = new HttpRequestMessage(HttpMethod.Get,
62+
$"https://corsproxy.io/?{urlEncodedRequestUri}");
5863
59-
var response = await client.SendAsync(request);
64+
var response = await client.SendAsync(request);
6065
61-
...
66+
...
67+
}
6268
}
6369
```
6470

0 commit comments

Comments
 (0)