// Copyright © WireMock.Net
using System.Globalization;
using System.Net.Http.Headers;
using System.Text;
using Aspire.Hosting.ApplicationModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using RestEase;
using WireMock.Client;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting;
///
/// Some WireMock.Net extension methods for working with .
/// Based on https://github.com/dotnet/aspire/blob/main/src/Aspire.Hosting.Testing/DistributedApplicationHostingTestingExtensions.cs
///
public static class DistributedApplicationExtensions
{
///
/// Create a RestEase Admin client which can be used to call the admin REST endpoint.
///
/// The .
/// The resourceName of the resource.
/// The resourceName of the endpoint on the resource to communicate with.
/// A
public static IWireMockAdminApi CreateWireMockAdminClient(this DistributedApplication app, string resourceName, string? endpointName = default)
{
ThrowIfNotStarted(app);
var (resource, endpointUri) = GetResourceAndEndpointUri(app, resourceName);
var api = RestClient.For(endpointUri);
if (resource.Arguments.HasBasicAuthentication)
{
api.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{resource.Arguments.AdminUsername}:{resource.Arguments.AdminPassword}")));
}
return api;
}
private static (WireMockServerResource WireMockServerResource, string EndpointUri) GetResourceAndEndpointUri(IHost app, string resourceName, string? endpointName = default)
{
var wireMockServerResource = GetWireMockServerResource(app, resourceName);
EndpointReference? endpoint;
if (!string.IsNullOrEmpty(endpointName))
{
endpoint = GetEndpointOrDefault(wireMockServerResource, endpointName);
}
else
{
endpoint = GetEndpointOrDefault(wireMockServerResource, "http") ?? GetEndpointOrDefault(wireMockServerResource, "https");
}
if (endpoint is null)
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Endpoint '{0}' for resource '{1}' not found.", endpointName, resourceName), nameof(endpointName));
}
return (wireMockServerResource, endpoint.Url);
}
private static WireMockServerResource GetWireMockServerResource(IHost app, string resourceName)
{
var applicationModel = app.Services.GetRequiredService();
var resource = applicationModel.Resources
.OfType()
.SingleOrDefault(r => string.Equals(r.Name, resourceName, StringComparison.OrdinalIgnoreCase));
if (resource is null)
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "WireMockServerResource with name '{0}' not found.", resourceName), nameof(resourceName));
}
return resource;
}
private static EndpointReference? GetEndpointOrDefault(IResourceWithEndpoints wireMockServerResource, string endpointName)
{
var reference = wireMockServerResource.GetEndpoint(endpointName);
return reference.IsAllocated ? reference : null;
}
private static void ThrowIfNotStarted(IHost app)
{
var lifetime = app.Services.GetRequiredService();
if (!lifetime.ApplicationStarted.IsCancellationRequested)
{
throw new InvalidOperationException("The application must be started before resolving endpoints or connection strings");
}
}
}