Open kazo0 opened 1 month ago
Notes from @nickrandolph
The trick with integrating Kiota so that it can take advantage of auth is to make sure the HttpClient is generated by the service container
auth registers additional http handlers that are used to set cookie or http header with the current access token
auth also handles the token refresh in the case of authorization challenges
all of which is transparent if you get the HttpClient from the service container
@Kunal22shah we would need to register the HttpClient through the Http Extensions like we do in Refit with the AddClientWithEndpoint
extension method here: https://github.com/unoplatform/uno.extensions/blob/f677bd295bc6d689e675b854f33a8ccee8e733ec/src/Uno.Extensions.Http.Refit/ServiceCollectionExtensions.cs#L59-L77
So we'd need to use the registered HttpClient from that extension method and pass that one along to the HttpClientRequestAdapter I believe.
Same for the IAuthenticationProvider stuff, this is a bit confusing as both the Auth extensions from Uno and the Kiota packages define a IAuthenticationProvider interface.
We need to dig deeper and brainstorm exactly what will be the implementation of AddKiotaClient
. It's within that extension method that we should be registering the client with the requestadapter and all of that.
@kazo0 we could register the HttpClient
through the Http Extensions similar to how it's done for Refit. This will allow us touse the existing AddClientWithEndpoint
pattern something like:
public static IServiceCollection AddKiotaClient<TClient>(
this IServiceCollection services,
HostBuilderContext context,
EndpointOptions? options = null,
string? name = null,
Func<IHttpClientBuilder, EndpointOptions?, IHttpClientBuilder>? configure = null
)
where TClient : class
{
return services.AddKiotaClientWithEndpoint<TClient, EndpointOptions>(context, options, name, configure);
}
and then do something like this for AddClientWithEndpoint : (not sure if we want a custom auth handler for kiota?)
services.AddClientWithEndpoint<TClient, TEndpoint>(...)
.ConfigurePrimaryHttpMessageHandler(() =>
{
var serviceProvider = s.BuildServiceProvider();
var authProvider = serviceProvider.GetRequiredService<IAuthenticationProvider>();
return new AuthenticationHandler(authProvider); // Custom Auth Handler?
})
.ConfigureHttpClient(client =>
{
if (options?.Url != null)
{
client.BaseAddress = new Uri(options.Url);
}
}),
configure: configure
)
.AddSingleton<IRequestAdapter, HttpClientRequestAdapter>(sp =>
{
var authProvider = sp.GetRequiredService<IAuthenticationProvider>();
var parseNodeFactory = new Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory();
var serializationWriterFactory = new Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory();
var httpClient = sp.GetRequiredService<HttpClient>();
return new HttpClientRequestAdapter(authProvider, parseNodeFactory, serializationWriterFactory, httpClient);
})
.AddSingleton<TClient>(sp =>
{
var requestAdapter = sp.GetRequiredService<IRequestAdapter>();
return (TClient)Activator.CreateInstance(typeof(TClient), requestAdapter)!;
});
i had a similar approach in chefs : https://github.com/unoplatform/uno.chefs/blob/fe5971f955bbc92847655a688b3b2d6ccf3e21e5/src/Chefs/App.xaml.cs#L83-L100
@kazo0 we could register the
HttpClient
through the Http Extensions similar to how it's done for Refit. This will allow us touse the existingAddClientWithEndpoint
pattern something like:public static IServiceCollection AddKiotaClient<TClient>( this IServiceCollection services, HostBuilderContext context, EndpointOptions? options = null, string? name = null, Func<IHttpClientBuilder, EndpointOptions?, IHttpClientBuilder>? configure = null ) where TClient : class { return services.AddKiotaClientWithEndpoint<TClient, EndpointOptions>(context, options, name, configure); }
and then do something like this for AddClientWithEndpoint : (not sure if we want a custom auth handler for kiota?)
services.AddClientWithEndpoint<TClient, TEndpoint>(...) .ConfigurePrimaryHttpMessageHandler(() => { var serviceProvider = s.BuildServiceProvider(); var authProvider = serviceProvider.GetRequiredService<IAuthenticationProvider>(); return new AuthenticationHandler(authProvider); // Custom Auth Handler? }) .ConfigureHttpClient(client => { if (options?.Url != null) { client.BaseAddress = new Uri(options.Url); } }), configure: configure ) .AddSingleton<IRequestAdapter, HttpClientRequestAdapter>(sp => { var authProvider = sp.GetRequiredService<IAuthenticationProvider>(); var parseNodeFactory = new Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory(); var serializationWriterFactory = new Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory(); var httpClient = sp.GetRequiredService<HttpClient>(); return new HttpClientRequestAdapter(authProvider, parseNodeFactory, serializationWriterFactory, httpClient); }) .AddSingleton<TClient>(sp => { var requestAdapter = sp.GetRequiredService<IRequestAdapter>(); return (TClient)Activator.CreateInstance(typeof(TClient), requestAdapter)!; });
i had a similar approach in chefs : https://github.com/unoplatform/uno.chefs/blob/fe5971f955bbc92847655a688b3b2d6ccf3e21e5/src/Chefs/App.xaml.cs#L83-L100
I don't recall how much implementation there was in the refit support but it looks like there's quite a bit here that I would have assumed is not required (eg configurehttpclient) if we're picking up the HttpClient from extensions but perhaps this is required for Kiota, which I'm not that familiar with.
We should be able to do something like this:
Where we can add handlers to the IHttpClientBuilder
@nickrandolph @kazo0 i made changes to add the kiota handler as a part of the same draft PR so its easier to follow
https://github.com/unoplatform/uno.extensions/pull/2509
From what I see as part of the Refit implementation, the Refit extensions are responsible for the HttpClient creation, or at least responsible for providing the IHttpClientBuilder
here
Below is a working example of how we could provide the IHttpClientBuilder from the Kiota extensions, through the AddHttpClient
call from the example below:
https://github.com/microsoft/kiota/issues/3816#issuecomment-1962445644
so i followed their approach mentioned here : https://github.com/unoplatform/uno.extensions/pull/2509
AddKiotaClient
and AddKiotaClientWithEndpoint
: registering the Kiota client in the dependency injection container. Including setting up the base URL, attaching Kiota handlers, and configuring the HttpClientRequestAdapter
with the necessary components (IAuthenticationProvider, JsonParseNodeFactory, and JsonSerializationWriterFactory).AddKiotaHandlers
- dynamically registers Kiota handlers in the DI container. following this https://learn.microsoft.com/en-us/openapi/kiota/tutorials/dotnet-dependency-injection#create-extension-methods AttachKiotaHandlers
- attaches the previously registered Kiota handlers to the IHttpClientBuilder.
Description
Creating a new project for Kiota under Http and Serialization for Kiota. Issue : https://github.com/unoplatform/uno.extensions/issues/2459, Draft : https://github.com/unoplatform/uno.extensions/pull/2509
ServiceCollectionExtensions
for Kiota: will facilitate the registration of Kiota clients, similar to how Refit is handled in Uno.Extensions.Usage
appsettings.json
, similar to existing Http extensions.Implement a
KiotaSerializerAdapter
to manage the serialization and deserialization of Kiota-generated modelsUse
HttpClientRequestAdapter
: It will include support for IRequestAdapter and IAuthenticationProvider to handle requests and authentication