| File: ServiceFakesHostExtensions.cs | Web Access |
| Project: src\src\Libraries\Microsoft.AspNetCore.Testing\Microsoft.AspNetCore.Testing.csproj (Microsoft.AspNetCore.Testing) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Microsoft.Shared.Diagnostics; namespace Microsoft.Extensions.Hosting; /// <summary> /// Extension methods supporting Kestrel server unit testing scenarios. /// </summary> public static class ServiceFakesHostExtensions { private static readonly Func<Uri, bool> _defaultAddressFilter = static _ => true; /// <summary> /// Creates an <see cref="HttpClient"/> to call the hosted application. /// </summary> /// <param name="host">An <see cref="IHost"/> instance.</param> /// <param name="handler">The inner <see cref="HttpClientHandler"/>.</param> /// <param name="addressFilter">Selects what address should be used. If null, takes the first available address.</param> /// <returns>An <see cref="HttpClient"/> configured to call the hosted application.</returns> [SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "not applicable")] [SuppressMessage("Reliability", "CA5399:HttpClient is created without enabling CheckCertificateRevocationList", Justification = "local calls")] public static HttpClient CreateClient(this IHost host, HttpMessageHandler? handler = null, Func<Uri, bool>? addressFilter = null) { _ = Throw.IfNull(host); addressFilter ??= _defaultAddressFilter; var uri = GetListenUris(host.Services.GetRequiredService<IServer>()).FirstOrDefault(addressFilter) ?? throw new InvalidOperationException("No suitable address found to call the server."); if (handler is null) { var certificate = host.Services.GetService<IOptions<FakeCertificateOptions>>()?.Value.Certificate; if (certificate is not null) { var httpHandler = new FakeCertificateHttpClientHandler(certificate); return new HttpClient(httpHandler) { BaseAddress = uri }; } return new HttpClient { BaseAddress = uri }; } return new HttpClient(handler) { BaseAddress = uri }; } /// <summary> /// Gets the first available URI the server listens to that passes the filter. /// </summary> /// <param name="host">An <see cref="IHost"/> instance.</param> /// <returns>A <see cref="Uri"/> instance.</returns> public static IEnumerable<Uri> GetListenUris(this IHost host) { return GetListenUris(Throw.IfNull(host).Services.GetRequiredService<IServer>()); } private static IEnumerable<Uri> GetListenUris(IServer server) { var feature = server.Features.Get<IServerAddressesFeature>(); // Stryker disable logical: we use the latter check to return static object instead of allocating a new one. if (feature is null || feature.Addresses.Count == 0) { return ArraySegment<Uri>.Empty; } return feature.Addresses .Select(x => new Uri(x.Replace("[::]", "localhost", StringComparison.OrdinalIgnoreCase))); } }