{"id":56973,"date":"2025-06-03T10:15:00","date_gmt":"2025-06-03T17:15:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=56973"},"modified":"2025-06-30T16:53:01","modified_gmt":"2025-06-30T23:53:01","slug":"using-ai-foundry-with-dotnet-maui","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/using-ai-foundry-with-dotnet-maui\/","title":{"rendered":"Using AI Foundry with .NET MAUI"},"content":{"rendered":"<p>What&#8217;s better than a &#8220;to do&#8221; app? A &#8220;to do&#8221; app that helps you do more with the power of AI! Using Microsoft.Extensions.AI, you can easily bring the smarts of any model you find in AI Foundry directly into your mobile and desktop .NET MAUI applications. To demonstrate this, I&#8217;ll show you how to take the first step towards making our .NET MAUI sample content application <em>intelligent<\/em>. When the user creates a new project in the app, we&#8217;ll have AI generate a good set of tasks to get them going.<\/p>\n<p><div style=\"width: 640px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-56973-1\" width=\"640\" height=\"360\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/05\/maui-telepathy-ai-foundry.mp4?_=1\" \/><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/05\/maui-telepathy-ai-foundry.mp4\">https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/05\/maui-telepathy-ai-foundry.mp4<\/a><\/video><\/div><\/p>\n<h2>Getting Started<\/h2>\n<p>To quickly get started you&#8217;ll need an Azure service account where you can configure your AI Foundry model agent, and an app in which to consume and use that service.<\/p>\n<p>Let&#8217;s start at AI Foundry.<\/p>\n<h3>AI Foundry<\/h3>\n<p>Login at <a href=\"http:\/\/ai.azure.com\">ai.azure.com<\/a> and click <strong>Create an agent<\/strong>. Give the project a name, and create it with the defaults. Opening the project details you&#8217;ll see various endpoints you can now use to call the agent.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/06\/foundry_create_project.png\" alt=\"create a new project\" \/><\/p>\n<p>By default, you&#8217;ll get the gpt-4o model, which you can see when you select <strong>My Assets &gt; Models + endpoints<\/strong> from the menu. Later, you should browse the Model catalog to choose something more aligned with your goals, but for now we&#8217;ll stick with the default.<\/p>\n<p>Make note of your primary endpoint and your API key as you&#8217;ll need those next.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/06\/foundry_endpoints_key.png\" alt=\"endpoints and key\" \/><\/p>\n<h3>.NET MAUI<\/h3>\n<p>In .NET 9 we introduced a new &#8220;to do&#8221; app template option that brings a bunch of the most popular libraries for building modern applications like the new open source <a href=\"https:\/\/www.syncfusion.com\/net-maui-toolkit\">Syncfusion Toolkit for .NET MAUI<\/a>, <a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/maui\/\">.NET MAUI Community Toolkit<\/a>, and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/mvvm\/\">MVVM Toolkit<\/a>. To get started with this template, select the checkbox in Visual Studio (or choose the option in Visual Studio Code) for &#8220;sample content&#8221;. You can also include this option on the command line.<\/p>\n<pre><code class=\"language-console\">dotnet new maui -n Telepathy --sc<\/code><\/pre>\n<p>After you hit F5 to make sure everything restores and runs, go ahead and add the latest version of the Microsoft.Extensions.AI NuGet package using your favorite NuGet package manager, or again the handy command line.<\/p>\n<pre><code class=\"language-console\">dotnet add package Microsoft.Extensions.AI<\/code><\/pre>\n<p>Before you start writing code, you are going to need that endpoint and API key in the app. You absolutely do not want to add them to your source code where anyone can get at them even when distributing through public app stores. In most cases you would have a web service where you authenticate the user and then handle the calls securely behind that in the cloud. For this quick sample, let&#8217;s use environment variables which work easily for desktop.<\/p>\n<p><div class=\"alert alert-warning\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Warning\"><\/i><strong>Warning<\/strong><\/p>Never include API keys or sensitive credentials directly in your source code. For production applications, use secure authentication services and key management systems.<\/div><\/p>\n<h4>Create the Chat Client<\/h4>\n<p>Using Microsoft.Extensions.AI you can create a new <code>IChatClient<\/code> instance from which to send prompts to the AI Foundry endpoint, and receive back a strongly typed response. The same works with OpenAI, Ollama, and even ONNX for local and embedded models. Open the <code>MauiProgram<\/code> file and instantiate a new client that you can add to the services collection.<\/p>\n<pre><code class=\"language-csharp\">public static class MauiProgram\r\n{\r\n    public static MauiApp CreateMauiApp()\r\n    {\r\n        var builder = MauiApp.CreateBuilder().UseMauiApp&lt;App&gt;();\r\n\r\n        var endpoint = Environment.GetEnvironmentVariable(\"AI_Foundry_Endpoint\");\r\n        var apiKey = Environment.GetEnvironmentVariable(\"AI_Foundry_ApiKey\");\r\n        var foundryClient = new AzureOpenAIClient(new Uri(endpoint),new System.ClientModel.ApiKeyCredential(apiKey));\r\n        var chatClient = foundryClient.GetChatClient(\"gpt-4o\").AsIChatClient();\r\n\r\n        builder.Services.AddChatClient(chatClient);\r\n\r\n        return builder.Build();\r\n    }\r\n}<\/code><\/pre>\n<h4>Send the prompt, receive the smarts<\/h4>\n<p>Now open the <code>ProjectDetailPage<\/code> and <code>ProjectDetailPageModel<\/code> where you will use the chat client. When the user is done creating a title for the project you&#8217;ll listen to the <code>Unfocus<\/code> event of the <code>Entry<\/code> control to signal to the view model that it can retrieve tasks based on that title.<\/p>\n<p>In the <code>ProjectDetailPage<\/code> subscribe to the <code>Entry.Unfocus<\/code> using a convenient event to command behavior from the .NET Community Toolkit for .NET MAUI.<\/p>\n<pre><code class=\"language-xml\">&lt;Entry \r\n    Text=\"{Binding Name}\"&gt;\r\n    &lt;Entry.Behaviors&gt;\r\n        &lt;toolkit:EventToCommandBehavior EventName=\"Unfocused\" Command=\"{Binding NameUnfocusedCommand}\"\/&gt;\r\n    &lt;\/Entry.Behaviors&gt;\r\n&lt;\/Entry&gt;<\/code><\/pre>\n<p>The binding context for this page is <code>ProjectDetailPageModel<\/code>, so add a command there to implement <code>NameUnfocusedCommand<\/code>. For this you&#8217;ll use the <code>RelayCommand<\/code> from the .NET Community MVVM Toolkit.<\/p>\n<pre><code class=\"language-csharp\">[RelayCommand]\r\nasync Task NameUnfocused()\r\n{\r\n    \/\/ Only trigger if new project and no tasks\r\n    if (_project != null &amp;&amp; _project.IsNullOrNew() &amp;&amp; !string.IsNullOrWhiteSpace(Name) &amp;&amp; (Tasks == null || Tasks.Count == 0))\r\n    {\r\n        await GetRecommendationsAsync(Name);\r\n    }\r\n}<\/code><\/pre>\n<p>And now you are finally ready to make the magic call to AI Foundry from <code>GetRecommendationsAsync<\/code>. The <code>chatClient<\/code> comes from the services container via constructor injection, and you can provide the object type you want returned (<code>RecommendationResponse<\/code>) when calling <code>GetResponseAsync<\/code>.<\/p>\n<pre><code class=\"language-csharp\">partial class ProjectDetailPageModel : ObservableObject\r\n{\r\n    IChatClient _chatClient;\r\n\r\n    public ProjectDetailPageModel(IChatClient chatClient)\r\n    {\r\n        _chatClient = chatClient;\r\n    }\r\n\r\n    private async Task GetRecommendationsAsync(string projectName)\r\n    {\r\n        try\r\n        {\r\n            var categoryTitles = Categories?.Select(c =&gt; c.Title).ToList() ?? new List&lt;string&gt;();\r\n\r\n            var prompt = $\"Given a project named '{projectName}', and these categories: {string.Join(\", \", categoryTitles)}, pick the best matching category and suggest 3-7 tasks for this project.\";\r\n\r\n            var response = await _chatClient.GetResponseAsync&lt;RecommendationResponse&gt;(prompt);\r\n\r\n        if (response?.Result != null)\r\n            {\r\n                var rec = response.Result;\r\n\r\n                var recommendedTasks = new List&lt;ProjectTask&gt;();\r\n                foreach (var t in rec.Tasks)\r\n                {\r\n                    recommendedTasks.Add(new ProjectTask { Title = t, IsRecommendation = true });\r\n                }\r\n                RecommendedTasks = recommendedTasks;\r\n            }\r\n        }\r\n        catch (InvalidOperationException ex)\r\n        {\r\n            _errorHandler.HandleError(new Exception(\"Chat client is not initialized. Please add your OpenAI API key in settings.\", ex));\r\n        }\r\n        catch (Exception ex)\r\n        {\r\n            _errorHandler.HandleError(ex);\r\n        }\r\n        finally\r\n        {\r\n            IsBusy = false;\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<p>Back in the <code>ProjectDetailPage<\/code> you&#8217;ll then want to render the <code>RecommendedTasks<\/code> for the user to accept or reject.<\/p>\n<p>To see a completed sample with even more AI features, check out the <a href=\"https:\/\/github.com\/davidortinau\/telepathy\">Telepathy<\/a> sample and our breakout session from Microsoft Build 2025, <a href=\"https:\/\/www.youtube.com\/watch?v=tFOFU7LDQlA\">AI infused mobile and desktop app development with .NET MAUI<\/a>.<\/p>\n<p><iframe width=\"800\" height=\"450\" src=\"https:\/\/www.youtube.com\/embed\/tFOFU7LDQlA?si=LUXp0WMSvPH4lD9s\" allowfullscreen><\/iframe><\/p>\n<h2>Resources<\/h2>\n<ul>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/ai\/\">Microsoft.Extensions.AI Documentation<\/a><\/li>\n<li><a href=\"https:\/\/ai.azure.com\">Azure AI Foundry<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/maui\/\">.NET MAUI Documentation<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/davidortinau\/telepathy\">Telepathy Sample Application<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/\">.NET Community Toolkit<\/a><\/li>\n<li><a href=\"https:\/\/www.syncfusion.com\/net-maui-toolkit\">Syncfusion Toolkit for .NET MAUI<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/maui\/\">.NET MAUI Community Toolkit<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/mvvm\/\">MVVM Toolkit<\/a><\/li>\n<\/ul>\n<h2>Summary<\/h2>\n<p>In this article, I&#8217;ve demonstrated how to integrate AI Foundry with your .NET MAUI applications using Microsoft.Extensions.AI. By following these steps, you can enhance your mobile and desktop applications with intelligent features powered by large language models. Start experimenting with AI in your .NET MAUI apps today!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using AI Foundry with .NET MAUI brings the power of LLMs to mobile and desktop applications.<\/p>\n","protected":false},"author":553,"featured_media":56974,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7233,7781,756],"tags":[4,568,7870],"class_list":["post-56973","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-maui","category-ai","category-csharp","tag-net","tag-ai","tag-meai"],"acf":[],"blog_post_summary":"<p>Using AI Foundry with .NET MAUI brings the power of LLMs to mobile and desktop applications.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56973","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/553"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=56973"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/56973\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/56974"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=56973"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=56973"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=56973"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}