17

I am currently creating an Asp.NET Core 3.1 API Application. In it, I have a launchSettings.json that looks like the following:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:61392",
      "sslPort": 44308
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "weatherforecast",
      "environmentVariables": {
        "Key": "Value",
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Application.API": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "weatherforecast",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    }
  }
}

In particular, I am interested in obtaining the applicationUrl values defined in this file. Unfortunately, I do not see any obvious way to access them outside of loading the file directly via JSON serialization and probing the values there.

As such, I am looking for a more elegant solution. Is there a way to access these values from within the Startup.Configure and/or Startup.ConfigureServices methods?

I am thinking of something like:

public void Configure(IApplicationBuilder builder)
{
    var url = builder.ApplicationServices.GetRequiredService<IServerHostingEnvironment>().ApplicationUrl
}

For reference, I did see this question, but it seems that this requires an HTTP request. In my case, I am still configuring the server before a request has been made.

For further reference and context: I am building a .NET GitHub App application, and am making the corresponding equivalent of the Smee.io client, whose Javascript code can be found here.

The client takes a source (via Server-sent events) and sends it to a target. I got the source figured out and configured, but am ironically having trouble accessing and establishing the target URL (the applicationUrl seen above) in an obvious and configured fashion.

Finally, I realize I could hardcode the value in appSettings.json, but that would then mean I would be maintaining the same value in two places -- one in appSettings.json and one in the already-existing launchSettings.json. I would rather keep it to one place to reduce maintenance burden, if possible.

Mike-E
  • 2,477
  • 3
  • 22
  • 34
  • 2
    Based on my understanding, you cannot. I assume VS only reads launchSettings.json to learn which URL to use and then launch the web browser. Your web app, however, is launched separately upon IIS Express, using the config file under `.vs` folder, so all it can see are those settings from there. There is a mechanism to sync `launchSettings.json` and IIS Express config file (starting in a certain version of VS), but that's also transparent to your web app. – Lex Li Dec 18 '19 at 23:56
  • Thank you for your insight, @LexLi. The ideal is to accommodate for both local development (IIS) and production. It seems that such a basic and fundamental property of the web hosting environment would be accessible and readily available during initialization, but for some reason, it appears to be most elusive. The `IHttpContextAccessor` is the closest approximation, but it is `null` during `Startup.Configure`. – Mike-E Dec 19 '19 at 07:41
  • Did you find a solution or did LexLi's comment turn out to be the final word, so to speak? – ruffin Jun 08 '21 at 15:02
  • 2
    @ruffin I ended up biting the bullet here and duplicating my connection strings/addresses throughout my solution. Such as it is. Nice to see others feeling the same way and wanting a better solution, however. – Mike-E Jun 10 '21 at 05:42

5 Answers5

10

I was actually looking for something similar myself recently.

It turns out you can determine what URL's were passed to the application by Visual Studio during a debugging session (from applicationUrl within launchSettings.json) By looking at the environmental variables.

Although bearing in mind this is probably only useful for debugging within VStudio IDE which uses the launchSettings.json file

var urls = Environment.GetEnvironmentVariable("ASPNETCORE_URLS").Split(";");
garlicbread
  • 321
  • 3
  • 6
3

Have not tested it but I use this pattern to access appsettings.json.

In startup.cs add launchsettings.json to the configuration builder:

public Startup(IConfiguration configuration)
{
    var builder = new ConfigurationBuilder().AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "Properties", "launchSettings.json"));
    Configuration = builder.Build();
}

public IConfiguration Configuration { get; }

Add it as a service:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton <IConfiguration> (Configuration);
}

    

Inject it in controller and get key value:

public class SomeController: ControllerBase 
{  
    private IConfiguration _iconfiguration;  
    public SomeController(IConfiguration iconfiguration) 
    {  
        _iconfiguration = iconfiguration;  
    }

    void SomeMethod()
    {
        string appUrl = _iConfiguration.GetValue<string>("applicationUrl","someDefaultValue")
    }
}
desertnaut
  • 57,590
  • 26
  • 140
  • 166
Zonorai
  • 91
  • 4
  • 1
    Thank you for your answer. If I understand correctly this is relying on the `appSettings.json` file which is not preferred. The information is in the `launchSettings.json` (or *somewhere* in memory as it is used somewhere by the IIS server), and that is what I am wanting to access it. – Mike-E Dec 18 '19 at 20:32
  • No, look in the first code block. `var builder = new ConfigurationBuilder().AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "Properties", "launchSettings.json"));` –  Dec 18 '19 at 21:28
  • 1
    OK got it... I am with you now. This seems to be a fallback strategy if another does not present itself. As previously stated, I am aware I can simply deserialize the value from a configuration file and poking around the `IConfiguration` API is a flavor of this. What I am looking for is this value as utilized and exposed by core framework code. Something like `IApplicationBuilder.ApplicationServices.GetRequiredService().ApplicationUrl`. You would think that this value would be readily available in `IWebHostEnvironment`, but alas. – Mike-E Dec 18 '19 at 21:44
  • I understand now I thought you just wanted a cleaner way than literally reading all the text from the file and getting the value that way, if I stumble upon something I'll let you know! – Zonorai Dec 19 '19 at 08:30
2

I know, one year has passed, but this solution may be useful for somebody:

var configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json")
                .AddEnvironmentVariables()
                .Build();
var appUrl = configuration["ASPNETCORE_URLS"].Split(";").First();
Alex White
  • 155
  • 1
  • 1
  • 10
0

In your Startup constructor, you can get an IConfiguration from dependency injection. With this, you can access properties inside your appsettings.json by using the configuration like so:

var appUrl = _configuration["profiles:applicationUrl"];

If you will be accessing many properties inside your appsettings.json you can use the IConfiguration.Bind() method to bind all properties within your configuration json to a class instance. For instance, you would have:

public class Config
{
   public Profile Profiles { get; set; }
}
public class Profile
{
   public string ApplicationUrl { get; set; }
}

Then in ConfigureServices:

var config = new Config();
_configuration.Bind(config);

Then if you register config into the serviceprovider you can access your configuration anywhere through DI:

services.AddSingleton(config);

EDIT

To add json files other than the default appsettings.json, call ConfigureAppConfiguration() on the IWebHostBuilder after CreateDefaultBuilder in Program.cs documented below.

Link to File Configuration Docs

In the callback parameter you can add as many json,xml,ini files into the configuration you want, then use my answer above to get any values from all files. Note that if two of the same key is present, the last value for that key will be used.

aweyeahdawg
  • 886
  • 9
  • 19
  • 2
    Thank you for your answer. If I understand correctly, this would mean using `appsettings.json` which as I mentioned in the question is not ideal, as I then have to then manage the same data in two locations. Please let me know if I have misunderstood something here. – Mike-E Dec 18 '19 at 20:30
  • You could do what @zonorai mentioned and add the launchSettings.json as a json file in configuration then just access that value from that part of the configuration. I added an edit to explain this a little more. – aweyeahdawg Dec 18 '19 at 21:34
  • Indeed, that seems to be the frontrunner if another answer is not presented. I would prefer something that doesn't use `IConfiguration` and exposes the property as defined and utilized within the framework and, more specifically, the hosting (IIS) server. – Mike-E Dec 18 '19 at 21:35
  • You might want to look into environment variables then, and access that from all your apps. – aweyeahdawg Dec 18 '19 at 21:52
-1
            Url = new Uri($"{Environment.GetEnvironmentVariable("ASPNETCORE_URLS").Split(";").First()}/mini-profiler/results-index")
ertugrulakdag
  • 67
  • 1
  • 3
  • 1
    Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. **Would you kindly [edit] your answer to include additional details for the benefit of the community?** – Jeremy Caney Jul 07 '23 at 00:10