Closed borissedov closed 1 year ago
This already works Today the configure method is just a helper you can just do it all on your own with AddHttpClient
. Further the ConfigureHttpClient
has another overload.
// In program.cs
builder.Services.AddShopifyAdminGraphQLClient()
.ConfigureHttpClient((serviceProvider, client, clientBuilder) =>
{
using var scope = serviceProvider.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<WorkContext>();
var currentStore = context.GetCurrentStoreAsync().Result;
client.BaseAddress = new Uri($"https://{currentStore.Shop}/admin/api/2023-07/graphql.json");
client.DefaultRequestHeaders.Add("X-Shopify-Access-Token", currentStore.AccessToken);
clientBuilder.AddHttpMessageHandler<ShopifyGraphQLClientHandler>();
});
Is that what you were looking for?
@michaelstaib Thanks for pointing that out.
I am currently utilizing the second overload, but it's proving to be a bit problematic. By creating a service scope, I'm encountering situations where some service members are being modified during the request execution. This alteration results in inconsistent data across different scopes, which obviously isn't ideal. It's a delicate balance, and I'm trying to find the sweet spot to ensure reliable behavior without adding unnecessary complexity.
If you have any further insights or suggestions on how to effectively tackle this, I'd greatly appreciate it!
Sorry for closing accidentally.
I did try out the approach to use the generated client name with the standard AddHttpClient method:
serviceCollection.AddTransient<ShopifyGraphQLClientHandler>();
serviceCollection.AddHttpClient(ShopifyAdminGraphQLClient.ClientName)
.AddHttpMessageHandler<ShopifyGraphQLClientHandler>();
However, I ran into issues where the custom message handler wasn't being invoked as expected, and in some instances, the client wasn't able to properly resolve dependencies.
To explore potential workarounds, I attempted a more embedded approach:
public static IClientBuilder<ShopifyAdminGraphQLClientStoreAccessor> AddCustomShopifyAdminGraphQLClient(this IServiceCollection services, ExecutionStrategy strategy = ExecutionStrategy.NetworkOnly)
{
// Call the original method
var clientBuilder = services.AddShopifyAdminGraphQLClient(strategy);
// Assuming you have a method to get the internal service collection from the clientBuilder
var internalServiceCollection = clientBuilder.ClientServices;
// Now add your custom configurations to the internal service collection
internalServiceCollection.AddTransient<ShopifyGraphQLClientHandler>();
internalServiceCollection.AddHttpClient(ShopifyAdminGraphQLClient.ClientName)
.AddHttpMessageHandler<ShopifyGraphQLClientHandler>();
internalServiceCollection.BuildServiceProvider();
return clientBuilder;
}
However that leads to entire failure of the services registration flow inside the client service provider and it falls with the error:
System.InvalidOperationException: No service for type '[System.Net](http://system.net/).Http.IHttpClientFactory' has been registered.
This is not really an issue of strawberry shake as it has more todo with how you register the services.
why do internalServiceCollection.BuildServiceProvider();
and do nothing with it.
If you have questions stick to slack or GitHub discussions as this is geared toward enhancements and bugs.
internalServiceCollection.AddTransient
I would not use the client services to be honest as the HttpClient always sits on the outer scope. With version 14 we will switch to the new keyed services.
I was finally able to achieve the desired behaviour with the following code:
//ShopifyGraphQLClientHandler.cs
public class ShopifyGraphQLClientHandler : DelegatingHandler
{
private void ConfigureShopifyStoreRequest(HttpRequestMessage request)
{
var currentStore = new
{
Shop = "quickstart-my.myshopify.com",
AccessToken = "my-access-token"
};
request.RequestUri = new Uri($"https://{currentStore.Shop}/admin/api/2023-07/graphql.json");
request.Headers.Add("X-Shopify-Access-Token", currentStore.AccessToken);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
ConfigureShopifyStoreRequest(request);
return await base.SendAsync(request, cancellationToken);
}
protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
{
ConfigureShopifyStoreRequest(request);
return base.Send(request, cancellationToken);
}
}
//Program.cs
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<ShopifyGraphQLClientHandler>();
serviceCollection.AddShopifyAdminGraphQLClient().ConfigureHttpClient(
client =>
client.BaseAddress = new Uri("https://www.microsoft.com"), // This is just a random URL which will be overwritten by the handler
builder =>
builder.AddHttpMessageHandler<ShopifyGraphQLClientHandler>());
IServiceProvider services = serviceCollection.BuildServiceProvider();
My mistake was to not set the BaseAddress in the ConfigureHttpClient so the HttpMessageHandler has never been invoked because of request validation error.
Product
Strawberry Shake
Is your feature request related to a problem?
Hello StrawberryShake maintainers and community,
While integrating StrawberryShake into an ASP.NET Core project, I encountered a limitation in the current client configuration system. Specifically, I found it challenging to adjust the client's behavior based on the authenticated user's information. This adjustment often involves setting a specific URL and authentication headers.
Currently, StrawberryShake offers the ConfigureHttpClient mechanism. While this provides a level of configuration, it's cumbersome in scenarios where the HttpClient requires more dynamic behavior based on runtime data or other services.
Current Scenario:
The solution you'd like
I propose adding support for HttpMessageHandler in StrawberryShake's client configuration. This would offer developers a straightforward way to inject services and adjust the client's behavior dynamically.
Benefits:
I believe this enhancement will make StrawberryShake more flexible and even more powerful in various scenarios. Looking forward to your thoughts on this proposal.
Thank you for your hard work on StrawberryShake, and I appreciate your consideration of this request.