File: ResourceBuilderExtensions.cs
Web Access
Project: src\playground\Stress\Stress.AppHost\Stress.AppHost.csproj (Stress.AppHost)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Extensions.DependencyInjection;
 
internal static class ResourceBuilderExtensions
{
    /// <summary>
    /// Adds a command to the resource that sends an HTTP request to the specified path.
    /// </summary>
    public static IResourceBuilder<TResource> WithHttpsCommand<TResource>(this IResourceBuilder<TResource> builder,
        string path,
        string displayName,
        HttpMethod? method = default,
        string? endpointName = default,
        string? iconName = default)
        where TResource : IResourceWithEndpoints
        => WithHttpCommandImpl(builder, path, displayName, endpointName ?? "https", method, "https", iconName);
 
    /// <summary>
    /// Adds a command to the resource that sends an HTTP request to the specified path.
    /// </summary>
    public static IResourceBuilder<TResource> WithHttpCommand<TResource>(this IResourceBuilder<TResource> builder,
        string path,
        string displayName,
        HttpMethod? method = default,
        string? endpointName = default,
        string? iconName = default)
        where TResource : IResourceWithEndpoints
        => WithHttpCommandImpl(builder, path, displayName, endpointName ?? "http", method, "http", iconName);
 
    private static IResourceBuilder<TResource> WithHttpCommandImpl<TResource>(this IResourceBuilder<TResource> builder,
        string path,
        string displayName,
        string endpointName,
        HttpMethod? method,
        string expectedScheme,
        string? iconName = default)
        where TResource : IResourceWithEndpoints
    {
        method ??= HttpMethod.Post;
 
        var endpoints = builder.Resource.GetEndpoints();
        var endpoint = endpoints.FirstOrDefault(e => string.Equals(e.EndpointName, endpointName, StringComparison.OrdinalIgnoreCase))
            ?? throw new DistributedApplicationException($"Could not create HTTP command for resource '{builder.Resource.Name}' as no endpoint named '{endpointName}' was found.");
 
        var commandType = $"http-{method.Method.ToLowerInvariant()}-{path.ToLowerInvariant()}-request";
 
        builder.WithCommand(commandType, displayName, async context =>
        {
            if (!endpoint.IsAllocated)
            {
                return new ExecuteCommandResult { Success = false, ErrorMessage = "Endpoints are not yet allocated." };
            }
 
            if (!string.Equals(endpoint.Scheme, expectedScheme, StringComparison.OrdinalIgnoreCase))
            {
                return new ExecuteCommandResult { Success = false, ErrorMessage = $"The endpoint named '{endpointName}' on resource '{builder.Resource.Name}' does not have the expected scheme of '{expectedScheme}'." };
            }
 
            var uri = new UriBuilder(endpoint.Url) { Path = path }.Uri;
            var httpClient = context.ServiceProvider.GetRequiredService<IHttpClientFactory>().CreateClient();
            var request = new HttpRequestMessage(method, uri);
            try
            {
                var response = await httpClient.SendAsync(request, context.CancellationToken);
                response.EnsureSuccessStatusCode();
            }
            catch (Exception ex)
            {
                return new ExecuteCommandResult { Success = false, ErrorMessage = ex.Message };
            }
            return new ExecuteCommandResult { Success = true };
        },
        iconName: iconName,
        iconVariant: IconVariant.Regular);
 
        return builder;
    }
}