---
title: "How to get ASP.NET Core's local server URLs"
excerpt: "Learn how to access the ASP.NET Core's local server URLs in Program.cs, in controllers using Dependency Injection, and in IHostedService or BackgroundService."
publishDate: "2022-01-25T00:00:00"
createDate: "2022-01-24T00:53:45.813"
updateDate: "2022-04-25T02:40:49.01"
category: "dotnet"
categoryName: ".NET"
tags: [".NET",".NET 6",".NET Core","ASP.NET","ASP.NET Core","C#"]
permalink: "/blog/dotnet/how-to-get-aspdotnet-core-server-urls"
canonical: "/blog/dotnet/how-to-get-aspdotnet-core-server-urls"
image: {"src":"/media/jzxlgtfn/blog-hero.png","focalPoint":{"left":0.5,"top":0.5},"crops":[{"alias":"Banner","width":1120,"height":400,"coordinates":null}]}
imageAlt: "How to get ASP.NET Core URLs"
imageBackgroundColor: "#fff"
thumbnailImage: {"src":"/media/dikleklg/dotnet-bot_builder.svg","focalPoint":{"left":0.5,"top":0.5},"crops":[{"alias":"thumbnail","width":250,"height":250,"coordinates":null}]}
thumbnailImageAlt: ".NET Bot"
metaTitle: "How to get ASP.NET Core's local server URLs"
metaDescription: "Learn how to access the ASP.NET Core's local server URLs in Program.cs, in controllers using Dependency Injection, and in IHostedService or BackgroundService."
ogTitle: "How to get ASP.NET Core's local server URLs"
ogDescription: "Learn how to access the ASP.NET Core's local server URLs in Program.cs, in controllers using Dependency Injection, and in IHostedService or BackgroundService."
ogImage: {"src":"/media/llcack2s/social.png","focalPoint":{"left":0.5,"top":0.5},"crops":[{"alias":"OpenGraph","width":1200,"height":630,"coordinates":null}]}
ogImageAlt: "How to get ASP.NET Core URLs"
relatedPostKeys: ["0da0d49da8fd41aaad1f4a7accdffe68","5c4e12e2de214755bf617878ecb92ed2","7f1121f7ac8c4d89870614ca9667740b"]
noIndex: false
noFollow: false
sitemapExclude: false
source: {"nodeId":1579,"contentKey":"29b547ac5a044a01972a0f963879e85f","sortOrder":120}
---


This doesn't seem to be a very common use case, but sometimes you need access to the ASP.NET Core server URLs in your `Program` class. In this case, <span style="text-decoration: underline;"><strong>server URLs does not mean the public URLs</strong></span> that your users see when your website is served on the internet. These URLs are the **local URLs** that you specify when you run your ASP.NET Core application.




<p class="panel panel--info">Check out this <a href="/blog/dotnet/how-to-get-the-full-public-url-of-aspdotnet-core" title="How to get the full public URL of ASPdotNET Core">blog post if you want to get the full public URL of your ASP.NET Core application</a>, or this <a href="/blog/dotnet/how-to-generate-absolute-urls-in-aspdotnet-core" title="How to generate absolute URLs in ASPdotNET Core">blog post if you want to generate absolute URLs for your ASP.NET Core application</a>.</p>

There are many ways to configure the URLs ASP.NET Core will try binding to. Here's a couple of ways:


-   You can programmatically configure the URLs using the <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.hostingabstractionswebhostbuilderextensions.useurls?view=aspnetcore-6.0">UseUrls method</a>.
-   You can use the `--urls` argument like this `dotnet run --urls "http://localhost:8080"`.
-   You can configure the URL with the `ASPNETCORE_URLS` environment variable.
-   Out of the box, the web templates will create a JSON file *Properties/launchSettings.json* which holds multiple profiles to run your application. In that JSON file, you can change the `applicationUrl` property to configure which URL ASP.NET Core will bind to. There are also other ways to set the URLs using JSON configuration.


You could try to programmatically check each one of these variations to see which URLs will be used, but there are multiple built-in APIs you can use to get these URLs.

## How to get ASP.NET Core server URLs in Program.cs with minimal APIs {#how-to-get-aspnet-core-server-urls-in-programcs-with-minimal-apis}




Here's how you could access the URLs in .NET 6's minimal API <em>Program.cs </em>file:




<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">var</span> builder = WebApplication.CreateBuilder(args);&#10;<span style="color:#7f0055; font-weight:bold; ">var</span> app = builder.Build();&#10;&#10;app.MapGet(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">/</span><span style="color:#2a00ff; ">"</span>, () =&gt; <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Hello World!</span><span style="color:#2a00ff; ">"</span>);&#10;&#10;Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Urls from Program.cs before app.StartAsync(): {string.Join(</span><span style="color:#2a00ff; ">"</span>, <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, app.Urls)}</span><span style="color:#2a00ff; ">"</span>);&#10;&#10;await app.StartAsync();&#10;&#10;Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Urls from Program.cs after app.StartAsync(): {string.Join(</span><span style="color:#2a00ff; ">"</span>, <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, app.Urls)}</span><span style="color:#2a00ff; ">"</span>);&#10;&#10;await app.WaitForShutdownAsync();&#10;</pre>

Here's what the output looks like:

<pre style="color:#000000;background:#ffffff;">Urls from Program.cs before app.StartAsync():&#10;info: Microsoft.Hosting.Lifetime[14]&#10;      Now listening on: <span style="color:#3f3fbf; ">https://localhost:7227</span>&#10;info: Microsoft.Hosting.Lifetime[14]&#10;      Now listening on: <span style="color:#3f3fbf; ">http://localhost:5227</span>&#10;info: Microsoft.Hosting.Lifetime[0]&#10;      Application started. Press Ctrl+C to shut down.&#10;Urls from Program.cs after app.StartAsync(): <span style="color:#3f3fbf; ">https://localhost:7227</span>, <span style="color:#3f3fbf; ">http://localhost:5227</span>&#10;</pre>

You can get the URLs via the `app.Urls` property, but only after the application has been started.<br>From the output, you can see that the URLs collection is empty before the app is started, but once the app is started, the URLs collection is populated.

## How to get ASP.NET Core server URLs using Dependency Injection {#how-to-get-aspnet-core-server-urls-using-dependency-injection}




You can also get the URLs in any class configured with dependency injection. Here's an example using a `Controller`:




<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Hosting.Server;&#10;<span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Hosting.Server.Features;&#10;<span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Mvc;&#10;&#10;<span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">class</span> HomeController : Controller&#10;{&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">readonly</span> IServer server;&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">public</span> HomeController(IServer server)&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.server = server;&#10;    }&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">public</span> IActionResult Index()&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">var</span> addresses = server.Features.Get&lt;IServerAddressesFeature&gt;().Addresses;&#10;        Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Addresses from HomeController.Index: {string.Join(</span><span style="color:#2a00ff; ">"</span>, <span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, addresses)}</span><span style="color:#2a00ff; ">"</span>);&#10;        <span style="color:#7f0055; font-weight:bold; ">return</span> View();&#10;    }&#10;}&#10;</pre>

You can have the `IServer` object injected through your constructor, and then get the `IServerAddressesFeature` feature.<br>This `IServerAddressesFeature` has an `Addresses` property which is a collection of the ASP.NET Core URLs. This is actually what `app.Urls` uses in the previous example.<br>Any time the `Index` action is called, the following line is written to the console:

<pre style="color:#000000;background:#ffffff;">Addresses from HomeController.Index: <span style="color:#3f3fbf; ">https://localhost:7187</span>, <span style="color:#3f3fbf; ">http://localhost:5187</span>&#10;</pre>



<p class="panel panel--warning">The <code>Addresses</code> collection will be empty if the server application hasn't started yet. You don't have to worry about that inside of a <code>Controller</code> because the controllers won't be invoked until the server has been started yet. But if you try to get address outside of Razor Pages, MVC controllers, or endpoints, you'll have to make sure the server has been started before getting the URLs.<br><br>So, what do you do if the server application hasn't started yet? Let's look at another example.</p>



## How to get ASP.NET Core server URLs in IHostedService or BackgroundService {#how-to-get-aspnet-core-server-urls-in-ihostedservice-or-backgroundservice}




In some cases, you need to access the ASP.NET Core URLs outside of the Razor Pages, Controllers, or endpoints. In this case, there's no certainty the web server has been started, and no certainty the addresses collection is populated.<br>Luckily, there's another built-in API that can help us, the `IHostApplicationLifetime`. Let's take a look at an `IHostedService` example:




<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Hosting.Server;&#10;<span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Hosting.Server.Features;&#10;&#10;<span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">class</span> MyHostedService : IHostedService&#10;{&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">readonly</span> IServer server;&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">readonly</span> IHostApplicationLifetime hostApplicationLifetime;&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">public</span> MyHostedService(IServer server, IHostApplicationLifetime hostApplicationLifetime)&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.server = server;&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.hostApplicationLifetime = hostApplicationLifetime;&#10;    }&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">public</span> Task StartAsync(CancellationToken cancellationToken)&#10;    {&#10;        Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Addresses before application has started: {GetAddresses()}</span><span style="color:#2a00ff; ">"</span>);&#10;&#10;        hostApplicationLifetime.ApplicationStarted.Register(&#10;                () =&gt; Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Addresses after application has started: {GetAddresses()}</span><span style="color:#2a00ff; ">"</span>));&#10;        &#10;        <span style="color:#7f0055; font-weight:bold; ">return</span> Task.CompletedTask;&#10;    }&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">string</span> GetAddresses()&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">var</span> addresses = server.Features.Get&lt;IServerAddressesFeature&gt;().Addresses;&#10;        <span style="color:#7f0055; font-weight:bold; ">return</span> <span style="color:#7f0055; font-weight:bold; ">string</span>.Join(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, </span><span style="color:#2a00ff; ">"</span>, addresses);&#10;    }&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">public</span> Task StopAsync(CancellationToken cancellationToken) =&gt; Task.CompletedTask;&#10;}&#10;</pre>




You can receive an instance of `IHostApplicationLifetime` through constructor dependency injection, and then use it in `StartAsync` to hook into its lifecycle events.<br>Oddly enough, the lifecycle events aren't C# events, but instead they are of type `CancellationToken`.<br>To run code once the application has started, you can pass in a lambda or delegate to `hostApplicationLifetime.ApplicationStarted.Register`.


The output looks like this:

<pre style="color:#000000;background:#ffffff;">Addresses before application has started:&#10;Addresses after application has started: <span style="color:#3f3fbf; ">https://localhost:7012</span>, <span style="color:#3f3fbf; ">http://localhost:5012</span>&#10;</pre>




You can also do this in the `ExecuteAsync` method if you use a `BackgroundService`:




<pre style="color:#000000;background:#ffffff;"><span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Hosting.Server;&#10;<span style="color:#7f0055; font-weight:bold; ">using</span> Microsoft.AspNetCore.Hosting.Server.Features;&#10;&#10;<span style="color:#7f0055; font-weight:bold; ">public</span> <span style="color:#7f0055; font-weight:bold; ">class</span> MyBackgroundService : BackgroundService&#10;{&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">readonly</span> IServer server;&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">readonly</span> IHostApplicationLifetime hostApplicationLifetime;&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">public</span> MyBackgroundService(IServer server, IHostApplicationLifetime hostApplicationLifetime)&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.server = server;&#10;        <span style="color:#7f0055; font-weight:bold; ">this</span>.hostApplicationLifetime = hostApplicationLifetime;&#10;    }&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">protected</span> <span style="color:#7f0055; font-weight:bold; ">override</span> async Task ExecuteAsync(CancellationToken stoppingToken)&#10;    {&#10;        Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Addresses before application has started: {GetAddresses()}</span><span style="color:#2a00ff; ">"</span>);&#10;&#10;        await WaitForApplicationStarted();&#10;        &#10;        Console.WriteLine($<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">Addresses after application has started: {GetAddresses()}</span><span style="color:#2a00ff; ">"</span>);&#10;    }&#10;&#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> <span style="color:#7f0055; font-weight:bold; ">string</span> GetAddresses()&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">var</span> addresses = server.Features.Get&lt;IServerAddressesFeature&gt;().Addresses;&#10;        <span style="color:#7f0055; font-weight:bold; ">return</span> <span style="color:#7f0055; font-weight:bold; ">string</span>.Join(<span style="color:#2a00ff; ">"</span><span style="color:#2a00ff; ">, </span><span style="color:#2a00ff; ">"</span>, addresses);&#10;    }   &#10;    &#10;    <span style="color:#7f0055; font-weight:bold; ">private</span> Task WaitForApplicationStarted()&#10;    {&#10;        <span style="color:#7f0055; font-weight:bold; ">var</span> completionSource = <span style="color:#7f0055; font-weight:bold; ">new</span> TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);&#10;        hostApplicationLifetime.ApplicationStarted.Register(() =&gt; completionSource.TrySetResult());&#10;        <span style="color:#7f0055; font-weight:bold; ">return</span> completionSource.Task;&#10;    }&#10;}&#10;</pre>

In `BackgroundService.ExecuteAsync` you can properly wait by awaiting a task. Unfortunately, in `IHostedService.StartAsync` you cannot do this because the application builder will wait for your hosted service to start, but your hosted service would wait for the application to start, in which case neither ever finish starting.


This is probably a less common use case, but being able to access the URLs can come in really useful. For example, you can use these [URLs to automatically start a ngrok tunnel and use the tunnel to respond to webhooks which I wrote about for the Twilio blog](https://www.twilio.com/blog/integrate-ngrok-into-aspdotnet-core-startup-and-automatically-update-your-webhook-urls)!





**I'm curious to know how you'll be using these URLs, let me know!**
