Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Microsoft. Identity.Web bietet drei Ansätze zum Aufrufen eigener geschützter APIs: IDownstreamApi, IAuthorizationHeaderProvider und MicrosoftIdentityMessageHandler.
Auswählen eines Ansatzes
Wenn Sie benutzerdefinierte REST-APIs aufrufen, haben Sie je nach Ihren Anforderungen drei Hauptoptionen:
| Vorgehensweise | Kompliziertheit | Flexibilität | Anwendungsfall |
|---|---|---|---|
| IDownstreamApi | Niedrig | Mittelstufe | Standard-REST-APIs mit Konfiguration |
| MicrosoftIdentityMessageHandler | Mittelstufe | Hoch | HttpClient mit DI und zusammensetzbarer Pipeline |
| IAuthorizationHeaderProvider | Hoch | Sehr hoch | Vollständige Kontrolle über HTTP-Anforderungen |
Verwenden von IDownstreamApi für Standardszenarien
IDownstreamApi bietet einen einfachen, konfigurationsgesteuerten Ansatz zum Aufrufen von REST-APIs mit automatischer Tokenerfassung.
Installiere das Paket
Fügen Sie dem Projekt das DownstreamApi NuGet-Paket hinzu.
dotnet add package Microsoft.Identity.Web.DownstreamApi
Konfigurieren der API-Einstellungen
Definieren Sie Ihre API in appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-client-id",
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret": "your-client-secret"
}
]
},
"DownstreamApis": {
"MyApi": {
"BaseUrl": "https://api.example.com",
"Scopes": ["api://my-api-client-id/read", "api://my-api-client-id/write"],
"RelativePath": "api/v1",
"RequestAppToken": false
},
"PartnerApi": {
"BaseUrl": "https://partner.example.com",
"Scopes": ["api://partner-api-id/.default"],
"RequestAppToken": true
}
}
}
Einrichten von ASP.NET Core
Registrieren Sie Authentifizierungs- und downstream-API-Dienste in Ihrer Program.cs Datei.
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add authentication
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
// Register downstream APIs
builder.Services.AddDownstreamApis(
builder.Configuration.GetSection("DownstreamApis"));
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Ausführen grundlegender API-Vorgänge
Der folgende Controller veranschaulicht GET-, POST-, PUT- und DELETE-Vorgänge für eine konfigurierte downstream-API.
using Microsoft.Identity.Abstractions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[Authorize]
public class ProductsController : Controller
{
private readonly IDownstreamApi _api;
public ProductsController(IDownstreamApi api)
{
_api = api;
}
// GET request
public async Task<IActionResult> Index()
{
var products = await _api.GetForUserAsync<List<Product>>(
"MyApi",
"products");
return View(products);
}
// Call downstream API with GET request with query parameters
public async Task<IActionResult> Details(int id)
{
var product = await _api.GetForUserAsync<Product>(
"MyApi",
$"products/{id}");
return View(product);
}
// Call downstream API with POST request
[HttpPost]
public async Task<IActionResult> Create([FromBody] Product product)
{
var created = await _api.PostForUserAsync<Product, Product>(
"MyApi",
"products",
product);
return CreatedAtAction(nameof(Details), new { id = created.Id }, created);
}
// Call downstream API with PUT request
[HttpPut("{id}")]
public async Task<IActionResult> Update(int id, [FromBody] Product product)
{
var updated = await _api.PutForUserAsync<Product, Product>(
"MyApi",
$"products/{id}",
product);
return Ok(updated);
}
// Call downstream API with DELETE request
[HttpDelete("{id}")]
public async Task<IActionResult> Delete(int id)
{
await _api.DeleteForUserAsync<Product>(
"MyApi",
$"products/{id}");
return NoContent();
}
}
Konfigurieren erweiterter IDownstreamApi-Optionen
Verwenden Sie diese Optionen, um Anforderungsheader anzupassen, konfiguration außer Kraft zu setzen, Abfrageparameter hinzuzufügen und Antwortheader zu lesen.
Hinzufügen von benutzerdefinierten Kopfzeilen und Optionen
Im folgenden Beispiel werden der ausgehenden Anforderung benutzerdefinierte HTTP-Header hinzugefügt.
public async Task<IActionResult> GetDataWithHeaders()
{
var options = new DownstreamApiOptions
{
CustomizeHttpRequestMessage = message =>
{
message.Headers.Add("X-Custom-Header", "MyValue");
message.Headers.Add("X-Request-Id", Guid.NewGuid().ToString());
message.Headers.Add("X-Correlation-Id", HttpContext.TraceIdentifier);
}
};
var data = await _api.CallApiForUserAsync<MyData>(
"MyApi",
options,
content: null);
return Ok(data);
}
Außerkraftsetzen der Konfiguration pro Anfrage
Im folgenden Beispiel werden die Basis-URL, Bereiche und Tokentyp für eine einzelne Anforderung überschrieben.
public async Task<IActionResult> CallDifferentEndpoint()
{
var options = new DownstreamApiOptions
{
BaseUrl = "https://alternative-api.example.com",
RelativePath = "v2/data",
Scopes = new[] { "api://alternative/.default" },
RequestAppToken = true
};
var data = await _api.CallApiForAppAsync<MyData>(
"MyApi",
options);
return Ok(data);
}
Hinzufügen von Abfrageparametern
Im folgenden Beispiel wird eine Suchanforderung mit Abfrageparametern im relativen Pfad erstellt.
public async Task<IActionResult> Search(string query, int page, int pageSize)
{
var options = new DownstreamApiOptions
{
RelativePath = $"search?q={Uri.EscapeDataString(query)}&page={page}&pageSize={pageSize}"
};
var results = await _api.GetForUserAsync<SearchResults>(
"MyApi",
options);
return Ok(results);
}
Sie können auch das Optionen.ExtraQueryParameters-Wörterbuch verwenden.
Behandeln von Antwortheadern
Im folgenden Beispiel werden Informationen zum Zinslimit aus Antwortheadern gelesen.
public async Task<IActionResult> GetWithHeaders()
{
var response = await _api.CallApiAsync<MyData>(
"MyApi",
options =>
{
options.RelativePath = "data";
});
// Access response headers
if (response.Headers.TryGetValues("X-RateLimit-Remaining", out var values))
{
var remaining = values.FirstOrDefault();
_logger.LogInformation("Rate limit remaining: {Remaining}", remaining);
}
return Ok(response.Content);
}
Erwerben von Nur-App-Token mit IDownstreamApi
Wird GetForAppAsync verwendet, um eine API mit Anwendungsberechtigungen anstelle delegierter Benutzerberechtigungen aufzurufen.
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
private readonly IDownstreamApi _api;
public DataController(IDownstreamApi api)
{
_api = api;
}
[HttpGet("batch")]
public async Task<ActionResult> GetBatchData()
{
// Call with application permissions
var data = await _api.GetForAppAsync<BatchData>(
"MyApi",
"batch/process");
return Ok(data);
}
}
Verwenden der MicrosoftIdentityMessageHandler für die HttpClient-Integration
MicrosoftIdentityMessageHandler fügt ihrer HttpClient-Pipeline automatisch Microsoft Entra Authentifizierung hinzu.
Ermitteln, wann MicrosoftIdentityMessageHandler verwendet werden soll
- Sie benötigen eine differenzierte Kontrolle über HTTP-Anforderungen
- Sie möchten mehrere Nachrichtenhandler verfassen
- Sie integrieren Code, der auf dem vorhandenen HttpClient basiert.
- Sie benötigen Zugriff auf unformatierte HttpResponseMessage
Konfigurieren von Überladungen des MicrosoftIdentityMessageHandlers
MicrosoftIdentityMessageHandler ist ein DelegatingHandler, das Authentifizierung zu HttpClient-Anforderungen hinzufügt. Verwenden Sie diesen Handler, wenn Sie vollständige HttpClient-Funktionen mit automatischer Tokenerfassung benötigen.
Die AddMicrosoftIdentityMessageHandler Erweiterungsmethoden bieten eine flexible Möglichkeit zum Konfigurieren von HttpClient mit automatischer Microsoft Entra ID-Authentifizierung:
- Parameterlos: Für flexibilität bei der Konfiguration pro Anforderung
- Optionsinstanz: Für vorkonfigurierte Optionsobjekte
- Aktionsdelegat: Für die Inlinekonfiguration (am häufigsten)
- IConfiguration: Zur Konfiguration von appsettings.json
Wählen Sie die Überladung aus, die am besten zu Ihrem Szenario passt, und genießen Sie die automatische Authentifizierung für Ihre downstream-API-Aufrufe.
Verwenden der parameterlosen Überladung für die Konfiguration pro Anforderung
Konfigurieren Sie Authentifizierungsoptionen auf Anforderungsbasis mit dieser Überladung.
services.AddHttpClient("FlexibleClient")
.AddMicrosoftIdentityMessageHandler();
// Later, in a service:
var request = new HttpRequestMessage(HttpMethod.Get, "/api/data")
.WithAuthenticationOptions(options =>
{
options.Scopes.Add("https://api.example.com/.default");
});
var response = await httpClient.SendAsync(request);
Übergeben Sie eine vorkonfigurierte Optionsinstanz.
Verwenden Sie diese Überladung, wenn Sie über ein vordefiniertes Optionsobjekt verfügen.
var options = new MicrosoftIdentityMessageHandlerOptions
{
Scopes = { "https://graph.microsoft.com/.default" }
};
options.WithAgentIdentity("agent-application-id");
services.AddHttpClient("GraphClient", client =>
{
client.BaseAddress = new Uri("https://graph.microsoft.com");
})
.AddMicrosoftIdentityMessageHandler(options);
Konfigurieren von Inline mit einem Aktionsdelegat
Verwenden Sie diese Überladung für die Inlinekonfiguration, eines der am häufigsten verwendeten Szenarien.
services.AddHttpClient("MyApiClient", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api.example.com/.default");
options.RequestAppToken = true;
});
Konfiguration aus appsettings.json laden
Verwenden Sie diese Überladung, um Einstellungen direkt aus Ihrer Konfigurationsdatei zu binden.
appsettings.json:
{
"DownstreamApi": {
"Scopes": ["https://api.example.com/.default"]
},
"GraphApi": {
"Scopes": ["https://graph.microsoft.com/.default", "User.Read"]
}
}
Program.cs:
services.AddHttpClient("DownstreamApiClient", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
configuration.GetSection("DownstreamApi"),
"DownstreamApi");
services.AddHttpClient("GraphClient", client =>
{
client.BaseAddress = new Uri("https://graph.microsoft.com");
})
.AddMicrosoftIdentityMessageHandler(
configuration.GetSection("GraphApi"),
"GraphApi");
Überprüfen von Konfigurationsbeispielen
Diese Beispiele veranschaulichen allgemeine Konfigurationsmuster für den Nachrichtenhandler.
Erstellen eines einfachen Web-API-Clients
Im folgenden Beispiel wird ein Wetter-API-Client registriert und verwendet.
// Configure in Program.cs
services.AddHttpClient("WeatherApiClient", client =>
{
client.BaseAddress = new Uri("https://api.weather.com");
})
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api.weather.com/.default");
});
// Use in a controller or service
public class WeatherService
{
private readonly HttpClient _httpClient;
public WeatherService(IHttpClientFactory factory)
{
_httpClient = factory.CreateClient("WeatherApiClient");
}
public async Task<WeatherForecast> GetForecastAsync(string city)
{
var response = await _httpClient.GetAsync($"/forecast/{city}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<WeatherForecast>();
}
}
Konfigurieren mehrerer API-Clients
Im folgenden Beispiel werden zwei separate API-Clients mit unterschiedlichen Bereichen und Tokentypen registriert.
// Configure multiple clients in Program.cs
services.AddHttpClient("ApiClient1")
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api1.example.com/.default");
});
services.AddHttpClient("ApiClient2")
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api2.example.com/.default");
options.RequestAppToken = true;
});
// Use in a service
public class MultiApiService
{
private readonly HttpClient _client1;
private readonly HttpClient _client2;
public MultiApiService(IHttpClientFactory factory)
{
_client1 = factory.CreateClient("ApiClient1");
_client2 = factory.CreateClient("ApiClient2");
}
public async Task<string> GetFromBothApisAsync()
{
var data1 = await _client1.GetStringAsync("/data");
var data2 = await _client2.GetStringAsync("/data");
return $"{data1} | {data2}";
}
}
Laden komplexer Optionen aus appsettings.json
Im folgenden Beispiel werden mehrere API-Konfigurationen aus einem freigegebenen Konfigurationsabschnitt gebunden.
appsettings.json:
{
"DownstreamApis": {
"CustomerApi": {
"Scopes": ["api://customer-api/.default"]
},
"OrderApi": {
"Scopes": ["api://order-api/.default"]
},
"InventoryApi": {
"Scopes": ["api://inventory-api/.default"]
}
}
}
Program.cs:
var downstreamApis = configuration.GetSection("DownstreamApis");
services.AddHttpClient("CustomerApiClient", client =>
{
client.BaseAddress = new Uri("https://customer-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
downstreamApis.GetSection("CustomerApi"),
"CustomerApi");
services.AddHttpClient("OrderApiClient", client =>
{
client.BaseAddress = new Uri("https://order-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
downstreamApis.GetSection("OrderApi"),
"OrderApi");
services.AddHttpClient("InventoryApiClient", client =>
{
client.BaseAddress = new Uri("https://inventory-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
downstreamApis.GetSection("InventoryApi"),
"InventoryApi");
Überschreiben von Optionen pro Anfrage
Sie können Standardoptionen auf Anforderungsbasis überschreiben, indem Sie die WithAuthenticationOptions Erweiterungsmethode verwenden.
// Configure client with default options
services.AddHttpClient("ApiClient")
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api.example.com/.default");
});
// Override for specific requests
public class MyService
{
private readonly HttpClient _httpClient;
public MyService(IHttpClientFactory factory)
{
_httpClient = factory.CreateClient("ApiClient");
}
public async Task<string> GetSensitiveDataAsync()
{
// Override scopes for this specific request
var request = new HttpRequestMessage(HttpMethod.Get, "/api/sensitive")
.WithAuthenticationOptions(options =>
{
options.Scopes.Clear();
options.Scopes.Add("https://api.example.com/sensitive.read");
options.RequestAppToken = true;
});
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
Implementieren erweiterter Szenarien
In den folgenden Abschnitten werden die Agentidentität, die Handlerkomposition und die automatische Abfragebehandlung behandelt.
Konfigurieren der Agentidentität
Verwenden Sie die Agentidentität, wenn Ihre Anwendung im Namen einer anderen Anwendung handeln muss:
services.AddHttpClient("AgentClient")
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://graph.microsoft.com/.default");
options.WithAgentIdentity("agent-application-id");
options.RequestAppToken = true;
});
Verfassen mit anderen Handlern
Verketten Sie mehrere Handler in der Pipeline, um Protokollierung, Wiederholungen oder andere übergreifende Anliegen hinzuzufügen.
services.AddHttpClient("ApiClient")
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api.example.com/.default");
})
.AddHttpMessageHandler<LoggingHandler>()
.AddHttpMessageHandler<RetryHandler>();
WWW-Authenticate-Anforderungen behandeln
Der Handler verarbeitet automatisch WWW-Authenticate Herausforderungen für Szenarien mit bedingtem Zugriff.
// No additional code needed - automatic handling
services.AddHttpClient("ProtectedApiClient")
.AddMicrosoftIdentityMessageHandler(options =>
{
options.Scopes.Add("https://api.example.com/.default");
});
// The handler will automatically:
// 1. Detect 401 responses with WWW-Authenticate challenges
// 2. Extract required claims from the challenge
// 3. Acquire a new token with the additional claims
// 4. Retry the request with the new token
Fehler behandeln
Im folgenden Beispiel werden Authentifizierungs- und HTTP-Fehler getrennt erfasst, wenn eine API über den Nachrichtenhandler aufgerufen wird.
public class MyService
{
private readonly HttpClient _httpClient;
private readonly ILogger<MyService> _logger;
public MyService(IHttpClientFactory factory, ILogger<MyService> logger)
{
_httpClient = factory.CreateClient("ApiClient");
_logger = logger;
}
public async Task<string> GetDataWithErrorHandlingAsync()
{
try
{
var response = await _httpClient.GetAsync("/api/data");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (MicrosoftIdentityAuthenticationException authEx)
{
_logger.LogError(authEx, "Authentication failed: {Message}", authEx.Message);
throw;
}
catch (HttpRequestException httpEx)
{
_logger.LogError(httpEx, "HTTP request failed: {Message}", httpEx.Message);
throw;
}
}
}
Verwenden von IAuthorizationHeaderProvider für maximale Kontrolle
IAuthorizationHeaderProvider ermöglicht Ihnen direkten Zugriff auf Autorisierungsheader, um die vollständige Kontrolle über HTTP-Anforderungen zu erhalten.
Ermitteln, wann IAuthorizationHeaderProvider verwendet werden soll
- Sie benötigen vollständige Kontrolle über die HTTP-Anforderungserstellung.
- Sie integrieren nicht standardisierte HTTP-APIs
- Sie müssen HttpClient ohne DI verwenden
- Sie erstellen benutzerdefinierte HTTP-Abstraktionen
Ausführen grundlegender Vorgänge
Der folgende Controller ruft einen Autorisierungsheader ab und fügt ihn an eine manuelle HTTP-Anforderung an.
using Microsoft.Identity.Abstractions;
[Authorize]
public class CustomApiController : Controller
{
private readonly IAuthorizationHeaderProvider _headerProvider;
private readonly ILogger<CustomApiController> _logger;
public CustomApiController(
IAuthorizationHeaderProvider headerProvider,
ILogger<CustomApiController> logger)
{
_headerProvider = headerProvider;
_logger = logger;
}
public async Task<IActionResult> GetData()
{
// Get authorization header (includes "Bearer " prefix)
var authHeader = await _headerProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "api://my-api/read" });
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", authHeader);
client.DefaultRequestHeaders.Add("X-Custom-Header", "MyValue");
var response = await client.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return Content(content, "application/json");
}
}
Nur-App-Token erwerben
Verwenden Sie CreateAuthorizationHeaderForAppAsync, um ein App-only-Token für Hintergrund- oder Daemon-Szenarien abzurufen.
public async Task<IActionResult> GetBackgroundData()
{
// Get app-only authorization header
var authHeader = await _headerProvider.CreateAuthorizationHeaderForAppAsync(
scopes: new[] { "api://my-api/.default" });
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", authHeader);
var response = await client.GetAsync("https://api.example.com/background");
var data = await response.Content.ReadFromJsonAsync<BackgroundData>();
return Ok(data);
}
Integration in benutzerdefinierte HTTP-Bibliotheken
Im folgenden Beispiel wird IAuthorizationHeaderProvider mit einer HTTP-Bibliothek eines Drittanbieters verwendet.
public async Task<IActionResult> CallWithRestSharp()
{
var authHeader = await _headerProvider.CreateAuthorizationHeaderForUserAsync(
scopes: new[] { "api://my-api/read" });
// Example with RestSharp
var client = new RestClient("https://api.example.com");
var request = new RestRequest("data", Method.Get);
request.AddHeader("Authorization", authHeader);
var response = await client.ExecuteAsync<MyData>(request);
return Ok(response.Data);
}
Konfigurieren der erweiterten Optionen
Im folgenden Beispiel wird ein AuthorizationHeaderProviderOptions Objekt mit expliziten Bereichen und Tokenakquisitionseinstellungen erstellt.
public async Task<IActionResult> GetDataWithOptions()
{
var options = new AuthorizationHeaderProviderOptions
{
Scopes = new[] { "api://my-api/read" },
RequestAppToken = false,
AcquireTokenOptions = new AcquireTokenOptions
{
AuthenticationOptionsName = JwtBearerDefaults.AuthenticationScheme,
ForceRefresh = false,
Claims = null
}
};
var authHeader = await _headerProvider.CreateAuthorizationHeaderAsync(options);
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", authHeader);
var response = await client.GetAsync("https://api.example.com/data");
var data = await response.Content.ReadFromJsonAsync<MyData>();
return Ok(data);
}
Vergleichen von Ansätzen
Verwenden Sie die folgenden Kriterien, um den besten Ansatz für Ihr Szenario auszuwählen.
IDownstreamApi verwenden, wenn:
Aufrufen standardmäßiger REST-APIs
Möchten Sie einen konfigurationsgesteuerten Ansatz
Automatische Serialisierung/Deserialisierung erforderlich
Möchten Sie minimalen Code?
Folgen Sie den Microsoft.Identity.Web-Mustern
Example:
var product = await _api.GetForUserAsync<Product>("MyApi", "products/123");
Verwenden Sie MicrosoftIdentityMessageHandler, wenn:
Benötigen Sie vollständige HttpClient-Funktionen
Möchten Sie mehrere Handler erstellen
Verwenden von HttpClientFactory-Mustern
Zugriff auf HttpResponseMessage erforderlich
Integration mit vorhandenem HttpClient-Code
Example:
var response = await _httpClient.GetAsync("api/products/123");
var product = await response.Content.ReadFromJsonAsync<Product>();
Verwenden Sie IAuthorizationHeaderProvider in folgenden Fällen:
Vollständige Kontrolle über HTTP-Anforderungen benötigen
Verwenden von benutzerdefinierten HTTP-Bibliotheken
Erstellen benutzerdefinierter Abstraktionen
HttpClientFactory kann nicht verwendet werden
Manuelles Erstellen von Anforderungen
Example:
var authHeader = await _headerProvider.CreateAuthorizationHeaderForUserAsync(scopes);
client.DefaultRequestHeaders.Add("Authorization", authHeader);
Fehler behandeln
In den folgenden Abschnitten werden Fehlerbehandlungsmuster für jeden Ansatz angezeigt.
Behandeln von IDownstreamApi-Fehlern
Im folgenden Beispiel werden Anforderungen an die Zustimmung, HTTP-Statusfehler und allgemeine Ausnahmen erfasst.
try
{
var data = await _api.GetForUserAsync<MyData>("MyApi", "data");
}
catch (MicrosoftIdentityWebChallengeUserException ex)
{
// User needs to consent
_logger.LogWarning(ex, "Consent required for scopes: {Scopes}", string.Join(", ", ex.Scopes));
throw; // Let ASP.NET Core handle consent flow
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return NotFound("Resource not found");
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
return Unauthorized("API returned 401");
}
catch (Exception ex)
{
_logger.LogError(ex, "API call failed");
return StatusCode(500, "An error occurred");
}
Fehler bei MicrosoftIdentityMessageHandler beheben
Im folgenden Beispiel wird der Antwortstatuscode überprüft und detaillierte Fehlerinformationen protokolliert.
try
{
var response = await _httpClient.GetAsync("api/data");
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
_logger.LogError("API returned {StatusCode}: {Error}", response.StatusCode, error);
return StatusCode((int)response.StatusCode, error);
}
var data = await response.Content.ReadFromJsonAsync<MyData>();
return Ok(data);
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "HTTP request failed");
return StatusCode(500, "Failed to call API");
}
Bewährte Methoden befolgen
Wenden Sie diese Muster an, um zuverlässige, wartungsfähige API-Integrationen zu erstellen.
1. Konfigurieren von Timeoutwerten
Legen Sie explizite Timeouts fest, um zu verhindern, dass Anfragen unbegrenzt hängen bleiben.
builder.Services.AddDownstreamApi("MyApi", options =>
{
options.BaseUrl = "https://api.example.com";
options.HttpClientName = "MyApi";
});
builder.Services.AddHttpClient("MyApi", client =>
{
client.Timeout = TimeSpan.FromSeconds(30);
});
2. Verwenden von typierten Clients
Umschließen Sie IDownstreamApi mit einer typisierten Clientschnittstelle, um die Testbarkeit und Kapselung zu verbessern.
public interface IProductApiClient
{
Task<List<Product>> GetProductsAsync();
Task<Product> GetProductAsync(int id);
Task<Product> CreateProductAsync(Product product);
}
public class ProductApiClient : IProductApiClient
{
private readonly IDownstreamApi _api;
public ProductApiClient(IDownstreamApi api)
{
_api = api;
}
public Task<List<Product>> GetProductsAsync() =>
_api.GetForUserAsync<List<Product>>("MyApi", "products");
public Task<Product> GetProductAsync(int id) =>
_api.GetForUserAsync<Product>("MyApi", $"products/{id}");
public Task<Product> CreateProductAsync(Product product) =>
_api.PostForUserAsync<Product, Product>("MyApi", "products", product);
}
// Register
builder.Services.AddScoped<IProductApiClient, ProductApiClient>();
3. Protokollieren von Anforderungsdetails
Verfolgen Sie die Dauer und Ergebnisse des API-Aufrufs, um Leistungsengpässe zu identifizieren.
public async Task<IActionResult> GetDataWithLogging()
{
_logger.LogInformation("Calling MyApi for data");
var stopwatch = Stopwatch.StartNew();
try
{
var data = await _api.GetForUserAsync<MyData>("MyApi", "data");
stopwatch.Stop();
_logger.LogInformation("API call succeeded in {ElapsedMs}ms", stopwatch.ElapsedMilliseconds);
return Ok(data);
}
catch (Exception ex)
{
stopwatch.Stop();
_logger.LogError(ex, "API call failed after {ElapsedMs}ms", stopwatch.ElapsedMilliseconds);
throw;
}
}
Implementieren der OWIN-Unterstützung
Verwenden Sie die OWIN-Integration, wenn Ihre Anwendung anstelle von ASP.NET Core auf der klassischen ASP.NET-Pipeline ausgeführt wird.
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Owin;
public class Startup
{
public void Configuration(IAppBuilder app)
{
OwinTokenAcquirerFactory factory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
app.AddMicrosoftIdentityWebApp(factory);
factory.Services
.AddDownstreamApis(factory.Configuration.GetSection("DownstreamAPI"))
.AddInMemoryTokenCaches();
factory.Build();
}
}
Durchsuchen verwandter Inhalte
Nächste Schritte: Überprüfen Sie die Hauptdokumentation für die Entscheidungsstruktur und den Vergleich aller Ansätze.