{"id":53077,"date":"2024-08-07T10:05:00","date_gmt":"2024-08-07T17:05:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=53077"},"modified":"2025-11-12T12:02:08","modified_gmt":"2025-11-12T20:02:08","slug":"adding-dotnet-aspire-to-your-existing-dotnet-apps","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/adding-dotnet-aspire-to-your-existing-dotnet-apps\/","title":{"rendered":"Adding Aspire to your existing .NET apps"},"content":{"rendered":"<p><a href=\"https:\/\/learn.microsoft.com\/dotnet\/aspire\">Aspire<\/a> is a new cloud-ready stack tailored for .NET, enabling developers to quickly and easily develop distributed applications. You&#8217;ve probably seen demos showing large .NET solutions with lots of fancy cloud dependencies and thought, well, maybe I&#8217;d use that someday if I&#8217;m starting on a giant enterprise Redis Kafka Postgres cloud-a-ganza, but it&#8217;s not really something I can use today.<\/p>\n<p>But Aspire is not just about cutting-edge technology and green-field apps; it&#8217;s also about making your current applications more straightforward. With Aspire, you can streamline the startup process, improve monitoring, and increase the reliability of your applications. Plus, you can use service discovery to enhance your apps, even if you&#8217;re not ready to use more complex features or services like Redis or containerized deployment.<\/p>\n<p>In this post, we&#8217;ll look at how easy it is to <strong>make your existing solutions better<\/strong> \u2013 just easier to maintain and add the kind of features you&#8217;re already working on. And, sure, it&#8217;s nice that you can more easily integrate more sophisticated cloud dependencies and features\u2026 but even if you never do it&#8217;s still a win.<\/p>\n<p><strong>TLDR<\/strong>: In under 5 minutes you can add Aspire to your existing apps and get a dashboard, health checks, and more&#8230; all without changing how your apps work, your CI\/CD pipeline, or deployment process.<\/p>\n<h2>What even is Aspire?<\/h2>\n<p>If you ask five people, you will most likely get five different answers. Honestly, it&#8217;s a little hard to describe, and attempts to do it briefly can turn into a bit of buzzword bingo. Really, it&#8217;s just a way to solve a problem: <strong>building distributed applications is hard<\/strong>. Even just running your app requires starting up one or more services and a front-end and making sure they can talk to each other can be frustrating. Wouldn&#8217;t it be nice if that was easier? That is what Aspire aims to do, be your building blocks for your distributed applications making them more observable, resilient, scalable, and manageable.<\/p>\n<p>Let&#8217;s take a look at how a lot of applications evolve over time. A lot start as a single monolithic proof of concept. You&#8217;ve got an app with a database.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/simple-app-diagram.webp\" alt=\"Diagram of a simple app with a Blazor front end connected to a data source\" \/><\/p>\n<p>Assuming your proof of concept is successful, just about every modern app evolves to include at least a front and back-end, in addition to the database.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/frontend-backend-database.svg\" alt=\"Diagram - frontend-backend-database\" \/><\/p>\n<p>And then, maybe, if our app&#8217;s usage and functionality keeps growing over time, the app will become really distributed, relying on a large set of distributed dependencies.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/distributed-app-diagram.svg\" alt=\"Diagram - distributed\" \/><\/p>\n<p>But here&#8217;s the important thing! Even in the really simple Proof Of Concept phase, and definitely in the Frontend-Backend-Database phase, we can benefit from Aspire! With just a few lines of code, and without messing with our CI or deployment, we can really simplify our day-to-day developer experience.<\/p>\n<h2>Step 1: Turn on .NET features we&#8217;ve been too busy to turn on with ServiceDefaults<\/h2>\n<p>The ASP.NET Core team has been lighting up features for cool features for things like tracing, health checks, and resiliency for years. I&#8217;ve done half a dozen conference talks on &#8220;The One Hour ASP.NET Makeover&#8221; where we just turn on and configure all these cool features that have been in the box for years. But here&#8217;s the thing&#8230; it takes an hour to do that talk, after reading the docs and practicing! What if I could just flip an &#8220;Enable Pro Mode&#8221; switch instead?<\/p>\n<p>That&#8217;s what Service Defaults does for you. You can just turn on Service Defaults and you&#8217;ve got smart logging, health checks, resiliency, etc. based on what the .NET team recommends for ASP.NET Core apps and services. If you want, you can easily edit the <code>Program.cs<\/code> file in the <em>ServiceDefaults<\/em> project, but you don&#8217;t have to. Just turn it on.<\/p>\n<h3>Adding a ServiceDefaults project<\/h3>\n<p>Let&#8217;s look at an example with a simple Frontend \u2013 Backend app. I&#8217;ll use Jeff Fritz&#8217;s new <em>MyWeatherHub<\/em> sample from the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/lets-learn-dotnet-aspire\/\">Let&#8217;s Learn Aspire<\/a> event series, starting with the <a href=\"https:\/\/github.com\/dotnet-presentations\/letslearn-dotnet-aspire\/tree\/main\/start-with-api\">start-with-api<\/a> code.<\/p>\n<p>Opening the solution, we&#8217;ll see that we&#8217;ve got two projects:<\/p>\n<ul>\n<li><strong>MyWeatherHub<\/strong> \u2013 Web front-end project which displays live weather data<\/li>\n<li><strong>API<\/strong> \u2013 Minimal API project which exposes live weather data from the US National Weather Service via a set of HTTP API endpoint<\/li>\n<\/ul>\n<p>Let&#8217;s add Service Defaults to this solution so we get health checks, logging, and other recommended features to both our front and back ends.<\/p>\n<p>In Visual Studio 2022 or Visual Studio Code with the C# Dev Kit installed, here&#8217;s all we need to do:<\/p>\n<ol>\n<li>Right-click on the solution and select <strong>Add<\/strong> &gt; <strong>New Project<\/strong>.<\/li>\n<li>Select the <em>.NET Aspire Service Defaults<\/em> project template.<\/li>\n<li>Name the project <em>ServiceDefaults<\/em> (any name would work if you&#8217;re feeling creative, but the instructions in this post assume you&#8217;re using <em>ServiceDefaults<\/em>).<\/li>\n<li>Click <strong>Next<\/strong> &gt; <strong>Create<\/strong>.<\/li>\n<\/ol>\n<p>Here&#8217;s how that looks in Visual Studio 2022:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/vs-add-servicedefaults.webp\" alt=\"Visual Studio dialog to add a service defaults project\" \/><\/p>\n<p>And in Visual Studio Code, it looks like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/vsc-add-servicedefaults.webp\" alt=\"Visual Studio Code dialog to add a service defaults project\" \/><\/p>\n<p>You can also add Service Defaults from the command line by using:<\/p>\n<pre><code class=\"language-console\">dotnet new aspire-servicedefaults -n ServiceDefaults<\/code><\/pre>\n<p>All the above options just drop a new project that knows the best settings for most ASP.NET Core distributed apps into your solution. However, none of your existing apps are using it yet. We&#8217;ll hook that up next.<\/p>\n<h3>Configure Service Defaults<\/h3>\n<p>Add a reference to the ServiceDefaults project in the Api and <em>MyWeatherHub<\/em> projects:<\/p>\n<ol>\n<li>\n<p>Right-click on the <em>Api<\/em> project and select <strong>Add<\/strong> &gt; <strong>Reference<\/strong>.<\/p>\n<\/li>\n<li>\n<p>Check the <em>ServiceDefaults<\/em> project and click OK.<\/p>\n<\/li>\n<li>\n<p>Right-click on the <em>MyWeatherHub<\/em> project and select <strong>Add<\/strong> &gt; <strong>Reference<\/strong>.<\/p>\n<\/li>\n<li>\n<p>Check the <em>ServiceDefaults<\/em> project and click OK.<\/p>\n<p><div class=\"alert alert-success\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Lightbulb\"><\/i><strong>Visual Studio 2022 tip<\/strong><\/p>\nIn Visual Studio 2022, you can drag and drop the project onto another project to add a reference.\n<\/div>\n<\/li>\n<li>\n<p>In both the Api and <em>MyWeatherHub<\/em> projects, update their <code>Program.cs<\/code> files, adding the following line immediately after their <code>var builder = WebApplication.CreateBuilder(args);<\/code> line:<\/p>\n<pre><code class=\"language-console\">builder.AddServiceDefaults();<\/code><\/pre>\n<\/li>\n<li>\n<p>In both the Api and <em>MyWeatherHub<\/em> projects, update their <code>Program.cs<\/code> files,adding the following line immediately after their <code>var app = builder.Build();<\/code> line:<\/p>\n<pre><code class=\"language-csharp\">app.MapDefaultEndpoints();<\/code><\/pre>\n<\/li>\n<\/ol>\n<h3>Run the application<\/h3>\n<p>To start with, we&#8217;re going to the application using a multiple-project launch configuration. This is <em>fine<\/em>, it&#8217;s how we&#8217;ve been doing things for years, but I have to admit I don&#8217;t really love it. Keep in mind that we&#8217;re going to make this easier in the next step. We&#8217;re doing this in two steps to make it clear what&#8217;s going on in Service Defaults and which parts are added by the AppHost.<\/p>\n<p>If you&#8217;re using Visual Studio 2022, right click on the <em>MyWeatherHub<\/em> solution and go to properties. Select the Api and <em>MyWeatherHub<\/em> as startup projects, select OK.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/vs-multiproject.webp\" alt=\"Visual Studio dialog to set multiple startup projects\" \/><\/p>\n<p>Now click <strong>Start<\/strong> to start and debug both projects.<\/p>\n<p>If you&#8217;re using Visual Studio Code, run the Api and <em>MyWeatherHub<\/em> projects using the Run and Debug panel. The sample project already includes a <a href=\"https:\/\/github.com\/dotnet-presentations\/letslearn-dotnet-aspire\/blob\/main\/start-with-api\/.vscode\/launch.json\">launch.json file<\/a> with the necessary configurations to run both.<\/p>\n<h3>Test the Service Defaults changes<\/h3>\n<ol>\n<li>\n<p>Test the application by navigating to the following URLs:<\/p>\n<ul>\n<li><a href=\"https:\/\/localhost:7032\/swagger\/index.html\">https:\/\/localhost:7032\/swagger\/index.html<\/a> &#8211; API<\/li>\n<li><a href=\"https:\/\/localhost:7274\/\">https:\/\/localhost:7274\/<\/a> &#8211; MyWeatherHub<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>You should see the Swagger UI for the API and the <em>MyWeatherHub<\/em> home page.<\/p>\n<\/li>\n<li>\n<p>You can also view the health checks for the API by navigating to <a href=\"https:\/\/localhost:7032\/health\">https:\/\/localhost:7032\/health<\/a>.<\/p>\n<\/li>\n<li>\n<p>You can also view the health checks for the <em>MyWeatherHub<\/em> by navigating to <a href=\"https:\/\/localhost:7274\/health\">https:\/\/localhost:7274\/health<\/a>.<\/p>\n<\/li>\n<li>\n<p>View the logs in the terminal to see the health checks and other telemetry data such as resiliency with Polly:<\/p>\n<pre><code class=\"language-console\">Polly: Information: Execution attempt. Source: '-standard\/\/Standard-Retry', Operation Key: '', Result: '200', Handled: 'False', Attempt: '0', Execution Time: '13.0649'<\/code><\/pre>\n<\/li>\n<li>\n<p>Click on 5 different cities and a &#8220;random&#8221; error will be thrown. You will see the Polly retry policy in action.<\/p>\n<pre><code class=\"language-console\">Polly: Warning: Execution attempt. Source: '-standard\/\/Standard-Retry', Operation Key: '', Result: '500', Handled: 'True', Attempt: '0', Execution Time: '9732.8258'\nPolly: Warning: Resilience event occurred. EventName: 'OnRetry', Source: '-standard\/\/Standard-Retry', Operation Key: '', Result: '500'\nSystem.Net.Http.HttpClient.NwsManager.ClientHandler: Information: Sending HTTP request GET http:\/\/localhost:5271\/forecast\/AKZ318<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>And that all works&#8230; the output for each application pops up in a separate console window, and we can see the health checks and logs in the terminal. So, it&#8217;s great that we&#8217;ve got all these features turned on, but it&#8217;s a bit of a pain to manage all these URLs, browser tabs, and console windows. You end up alt-tabbing between them all, and it&#8217;s a really disjointed experience.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/console-output.webp\" alt=\"Multiple console windows for the Api and MyWeatherHub projects\" \/><\/p>\n<p>Service Defaults works great on the individual project level, but it doesn&#8217;t help us manage multiple projects in a solution. That&#8217;s where the AppHost comes in.<\/p>\n<h2>Step 2. Simplify launch and add a fancy dashboard with AppHost<\/h2>\n<p>Okay, that was pretty cool! We added a project to our solution and two lines of code, and we got health checks, logging, resiliency, and more.<\/p>\n<p>But we can make that even better by adding an AppHost. That multiple-project configuration thing works, but it&#8217;s a bit annoying to set up and keep updated as we add other projects to the solution. Once we&#8217;re running we have to browse to a bunch of urls with different ports and manage each project separately. For instance, if we want to see logs or output, we have to check in each project&#8217;s console window. This gets even worse as we add more APIs and services to the solution \u2013 more URLs to manage, more console windows to check, etc. We&#8217;ve probably got some fancy dashboards and monitoring set up in production, but that doesn&#8217;t help me while I&#8217;m developing.<\/p>\n<p>The <em>AppHost<\/em> has a lot of great features, but two of my favorite are the solutions to the problems above: it simplifies project launch and it adds an amazing dashboard to monitor and manage my app in my development environment. The best way to understand what it&#8217;s doing it to just add it to our solution.<\/p>\n<h3>Adding an <em>AppHost<\/em> project<\/h3>\n<p>This is the standard &#8220;add project&#8221; steps we ran through before with ServiceDefaults, but this time we&#8217;re going to pick &#8220;.NET Aspire App Host&#8221; as the project template. In Visual Studio 2022 or Visual Studio Code with the C# DevKit installed:<\/p>\n<ol>\n<li>Right-click on the solution and select <strong>Add<\/strong> &gt; <strong>New Project<\/strong>.<\/li>\n<li>Select the <em>.NET Aspire App Host<\/em> project template.<\/li>\n<li>Name the project <em>AppHost<\/em> (again, any name would work).<\/li>\n<li>Click <strong>Next<\/strong> &gt; <strong>Create<\/strong>.<\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/vs-add-apphost.webp\" alt=\"Visual Studio dialog to add a app host project\" \/><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/vsc-add-apphost.webp\" alt=\"Visual Studio Code dialog to add a app host project\" \/><\/p>\n<p>And from the command-line, you can do that with:<\/p>\n<pre><code class=\"language-console\">dotnet new aspire-apphost -n AppHost<\/code><\/pre>\n<p>Just like when we added the Service Defaults, we need to add project references and a few lines of code to put the <em>AppHost<\/em> to work.<\/p>\n<h3>Add project references<\/h3>\n<p>Add a reference to the Api and <em>MyWeatherHub<\/em> projects in the new <em>AppHost<\/em> project:<\/p>\n<ol>\n<li>Right-click on the <em>AppHost<\/em> project and select Add &gt; Reference.<\/li>\n<li>Check the Api and <em>MyWeatherHub<\/em> projects and click OK.<\/li>\n<\/ol>\n<p>Note: Bonus points if you remembered the earlier tip that you can drag and drop the project onto another project to add a reference.<\/p>\n<p>When these references are added Source Generators automatically generate the necessary code to reference the projects in the App Host.<\/p>\n<h3>Orchestrate the Application<\/h3>\n<p>In the <em>AppHost<\/em> project, update the <code>Program.cs<\/code> file, adding the following line immediately after the var builder = DistributedApplication.CreateBuilder(args); line:<\/p>\n<pre><code class=\"language-csharp\"> var api = builder.AddProject&lt;Projects.Api&gt;(\"api\");\n var web = builder.AddProject&lt;Projects.MyWeatherHub&gt;(\"myweatherhub\");<\/code><\/pre>\n<p><strong>Run the application&#8230; the easy way!<\/strong><\/p>\n<p>Previously, we set up a multi-project launch profile. That still works, but from now on, you won&#8217;t have to bother with that. Instead, set the <em>AppHost<\/em> project as the startup project. It knows about all the other projects, and will launch them all automatically. That means that if you add an <em>AppHost<\/em> at the beginning (or use either the .NET Aspire Starter Application template or the .NET Aspire Application template), you never need to set up a multi-project launch profile again. And even better, if you add more services to your solution, the <em>AppHost<\/em> will automatically pick them up, too.<\/p>\n<p>In Visual Studio, you can set the <em>AppHost<\/em> project as the startup project in Visual Studio by right clicking on the <em>AppHost<\/em> and clicking Set Default Project and hitting Start.<\/p>\n<p>If you&#8217;re using Visual Studio Code, replace the contents of your launch.json file with the following and then hitting Run in the Run and Debug panel.<\/p>\n<pre><code class=\"language-json\"> {\n        \"version\": \"0.2.0\",\n        \"configurations\": [\n            {\n                \"name\": \"Run AppHost\",\n                \"type\": \"dotnet\",\n                \"request\": \"launch\",\n                \"projectPath\": \"${workspaceFolder}\\\\AppHost\\\\AppHost.csproj\"\n            }\n        ]\n    }<\/code><\/pre>\n<h3>Hey, we&#8217;ve got a dashboard!<\/h3>\n<p>Remember how we had to browse to a bunch of different URLs to see our app and its health checks? Now, the <em>AppHost<\/em> will automatically launch a dashboard with all our services and their dependencies. It rolls up all the health checks, traces, logs, and information like environment variables in one place. And, if we add more services to our solution, they&#8217;ll automatically show up in the dashboard. Let&#8217;s take a look.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/dashboard.webp\" alt=\".NET Aspire dashboard\" \/><\/p>\n<p>First, let&#8217;s take a look at the resources. This is a handy listing of all the resources in our solution. We can see the API and <em>MyWeatherHub<\/em> projects and watch their state as they start up. We also get clickable links to their endpoints, logs, and traces.<\/p>\n<p>The ServiceDefaults project we added earlier automatically configures tracing for all of our projects. We can see that in the Traces tab. This is a great way to understanding timing and dependencies in our app.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/dashboard-trace.webp\" alt=\".NET Aspire Dashboard showing trace view\" \/><\/p>\n<p>The <em>Metrics<\/em> tab shows us a lot of information about our app, including CPU and memory usage, and the number of requests and errors. Again, this is all automatically set up for us by the ServiceDefaults project and exposed in the <em>AppHost<\/em> dashboard.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/dashboard-metrics.webp\" alt=\".NET Aspire Dashboard showing metrics view\" \/><\/p>\n<p>The <em>Structured<\/em> tab shows us all the structured logs from our app. This is a great way to see errors and other important information in our app.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2025\/11\/dashboard-error.webp\" alt=\".NET Aspire Dashboard showing errors\" \/><\/p>\n<h2>Summary<\/h2>\n<p>The point is, .NET Aspire isn&#8217;t just for new apps or giant enterprise solutions. It&#8217;s for you, right now, to make your existing apps better. You can add it to your existing solutions and get a lot of benefits with just a few lines of code. And, if you&#8217;re not ready to use more advanced features like service discovery or containerized deployment, that&#8217;s okay. You can still benefit from the simplicity and reliability that .NET Aspire brings to your apps.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aspire can really simplify  local development for your existing apps, large or small. In this post, we&#8217;ll look at how easy it is to make your current solutions better with just a few lines of code.<\/p>\n","protected":false},"author":470,"featured_media":58833,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7509,7783,7689],"tags":[7768],"class_list":["post-53077","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-aspnetcore","category-aspire","category-cloud-native","tag-aspire"],"acf":[],"blog_post_summary":"<p>Aspire can really simplify  local development for your existing apps, large or small. In this post, we&#8217;ll look at how easy it is to make your current solutions better with just a few lines of code.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/53077","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\/470"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=53077"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/53077\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58833"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=53077"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=53077"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=53077"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}