Créer une application .NET locale combinant interface utilisateur (UI) et moteur IA vectoriel devient possible grâce à .NET 9, MAUI et Kestrel. Ce scénario vous permet de distribuer une app autonome, sans serveur externe, qui :
- héberge en local un moteur ASP.NET via Kestrel,
- utilise QDrant (en local ou Docker),
- interroge OpenAI pour calculer des embeddings,
- fournit une interface graphique multiplateforme.
🎯 Objectif de cet exemple
L'application doit permettre à l’utilisateur de :
- Entrer une requête textuelle ;
- Envoyer cette requête à une API locale qui interroge QDrant ;
- Obtenir une réponse affichée dans l’interface MAUI.
🧱 Étapes du projet
🔹 1. Créer un projet MAUI
dotnet new maui -n MauiSearchApp
🔹 2. Ajouter le projet ASP.NET Core
Ajoutez un projet classlib ou un projet aspnet (sans Program.cs) dans la solution :
dotnet new classlib -n LocalSearchApi
Dans LocalSearchApi, ajoutez :
- les contrôleurs,
- les dépendances à Qdrant.Client,
- la logique d’embedding.
Important : veillez à ne pas exécuter WebApplication.Run() directement ici.
🔹 3. Lancer Kestrel depuis MAUI
Dans MauiProgram.cs, modifiez comme suit :
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Démarrer l’API dans un thread séparé
Task.Run(() => StartApi());
return builder.Build();
}
private static void StartApi()
{
var builder = WebApplication.CreateBuilder();
builder.WebHost.UseUrls("http://localhost:5001");
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
app.MapControllers();
app.Run(); // blocant, donc lancé dans un thread dédié
}
}
🧠 Exemple d'API SemanticSearchController
Dans le projet LocalSearchApi (ou dans le même projet MAUI si besoin), ajoutez :
[ApiController]
[Route("search")]
public class SemanticSearchController : ControllerBase
{
[HttpPost]
public IActionResult Post([FromBody] SearchQuery query)
{
var fakeResults = new[]
{
new SearchResult { Text = "Résultat 1", Score = 0.91 },
new SearchResult { Text = "Résultat 2", Score = 0.84 }
};
return Ok(fakeResults); // à remplacer par appel QDrant
}
}
public class SearchQuery
{
public string Query { get; set; }
}
public class SearchResult
{
public string Text { get; set; }
public double Score { get; set; }
}
🖼️ Interface MAUI : MainPage.xaml
<VerticalStackLayout Padding="30" Spacing="20">
<Entry x:Name="QueryEntry" Placeholder="Entrez votre question"/>
<Button Text="Rechercher" Clicked="OnSearchClicked"/>
<CollectionView x:Name="ResultsView">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Text}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
Et le code-behind :
private async void OnSearchClicked(object sender, EventArgs e)
{
var query = QueryEntry.Text;
var http = new HttpClient();
var payload = JsonSerializer.Serialize(new { query });
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await http.PostAsync("http://localhost:5001/search", content);
var json = await response.Content.ReadAsStringAsync();
var results = JsonSerializer.Deserialize<List<SearchResult>>(json);
ResultsView.ItemsSource = results;
}
public class SearchResult
{
public string Text { get; set; }
public double Score { get; set; }
}
🧪 Lancer et tester
- Lancer QDrant (via Docker ou installation locale)
- Démarrer votre application MAUI
- Interroger une collection locale avec un moteur sémantique
- Visualiser les résultats instantanément dans l’UI
✅ Avantages de cette approche
- Zéro déploiement serveur
- Application locale et distribuable
- Idéale pour les outils internes, assistants documentaires, explorateurs IA
- Fonctionne sans Azure ni service cloud obligatoire
🧩 Pour aller plus loin
- Ajouter le support de Qdrant.Client
- Intégrer OpenAI pour le calcul des embeddings (cf. article précédent)
- Support multi-plateforme (Android : prévoir un port ou tunnel)
- Persistance des résultats
- Pagination / tri / feedback utilisateur
Dans quelques jours (1/5/26) je vous montrerai comment publier la même App MAUI hébergeant Kestrel sous la forme d'un exécutable autonome !
Stay Tuned !