7

I have a Web application in .net Core 2.1 using signalR. I need to pass HubUrl into custom javascript file. Is that possible in .net Core?

Sample of js code:

const connection = new signalR.HubConnectionBuilder()
.withUrl('http://localhost:5000/hub') //Here I need to read appSettings.json to get value from there
.configureLogging(signalR.LogLevel.Information)
.build();
k1dl3r
  • 103
  • 1
  • 2
  • 11
  • If your javascript inside view and you are using some kind of view engine like razor. You can check that post for solution https://stackoverflow.com/questions/48979294/how-to-read-appsettings-json-in-my-layout-chtml. – maximelian1986 Sep 27 '18 at 07:31
  • @maximelian1986 The problem is that I just only reffer this Js file in my view like that ` ` – k1dl3r Sep 27 '18 at 07:45

5 Answers5

10

appsettings.json located on server. So you need to add end-point to controller that returns needed value.

Controller:

public class MyController:Controller{
    private readonly IConfiguration configuration;

    public MyController(IConfiguration configuration){
         this.configuration = configuration;
    }

    [HTTPGet]
    public ActionResult GetConfigurationValue(string sectionName, string paramName){
        var parameterValue= configuration[$"{sectionName}:{paramName}"];
        return Json(new { parameter= parameterValue});
    }
}

Client side:

$.ajax({
    type:"GET",
    url: "/MyController/GetConfigurationValue"
    data:{
        sectionName = "MySection",
        paramName = "MyParameter"
    }
}).done(
    function(parameterValue){
        //do what you need
});

In appsettings.json:

{
    "MySection":{
        "MyParameter":"value that I want to get"
    }
}
maximelian1986
  • 2,308
  • 1
  • 18
  • 32
  • 1
    Work like a charm. Thanks a lot. – k1dl3r Sep 27 '18 at 09:29
  • 6
    Note that this implementation is really dangerous as it allows anyone to read **any** configuration value, including secrets like a connection string or other internal values. If you want to have an endpoint to return configuration values you should either restrict this to very few explicit values and/or have a very strong input validation to prevent people from accessing critical information. – poke Sep 27 '18 at 10:04
  • This hits controller every time you read the setting value. Try to pull all config values as a list. Make sure your secret is managed. – Kurkula Mar 07 '19 at 06:43
  • @Kurkula, no this implementation only runs once. It makes the AJAX call to the controller, then executes a function when the AJAX call is complete that would, presumably, do something with the value of `parameterValue`. However, I do agree with you that the controller would be better implemented to pull all needed configuration values as a list, so that the controller is only hit once for each page view. In its current form, the AJAX call is not reusable when you need multiple configuration values, but that was not part of the OP's question. – Blair Allen Sep 12 '19 at 14:42
6

In appsettings.json

"ApiUrls": {
    "commonUrl": "https://localhost:44348/api/"    
  }

In _Layout.cshtml

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

<script>      
        const commonUrl = @Json.Serialize(@Configuration.GetSection("ApiUrls").GetSection("commonUrl").Value)
</script>

now this will be like a global variable accessible to all js files

tejas n
  • 638
  • 1
  • 8
  • 14
3

A very safe yet flexible way to do this is to expose the URL inside a <script> block in a view. That way, you are not exposing application configuration (which access you will have to protect very well) but instead just explicitly expose a single secure value.

It also has the added benefit that you do not need to make a request to an endpoint (which address you actually also need to know in your script) but have the value instantly there when you need it.

To do that, you can simply render a <script> tag that defines the value globally. For example, you could have the following in your layout:

<script>
window._signalRAddress = @Json.Serialize(ViewData["SignalRAddress"]);
</script>
<script src="~/your-custom-script.js"></script>

And then you just use window._signalRAddress inside of your script.

poke
  • 369,085
  • 72
  • 557
  • 602
  • 1
    I believe this is a better solution . – itminus Sep 28 '18 at 01:10
  • I use this method in several of my web applications. However, I recently hit a snag with using Content Security Policy (CSP) to effectively whitelist the scripts that can be executed by the browser. With a CSP script policy in place, I would need to add `'unsafe-inline'` as an exception, effectively allowing _any_ inline script to be executed, including something that may be injected maliciously. (Hence why the policy is named "unsafe"). Just something to be wary of if you start adopting CSP! – Blair Allen Sep 12 '19 at 14:36
  • @BlairAllen That does apply to any kind of inline script though. Alternatively, you could also have a controller action that returns a dynamically rendered JavaScript file for example. – poke Sep 12 '19 at 23:45
1

In an SPA with webpack, you can just import the appsettings.json and make it available via a convenience class that you import;

e.g.

appsettings.js:

appsettingsjson = process.env.NODE_ENV === 'development'
    ? require('./appsettings.Development.json')
    : require('./appsettings.json');

class AppConfig {

    constructor() {
    }

    static Settings() {
        return appsettingsjson;
    }
}

module.exports = AppConfig;

Then wherever you need it, just import and use. e.g.:

const AppConfig = require("./appsettings");
console.log(AppConfig.Settings().YourSection.YourParameter)
Mark Z.
  • 2,127
  • 16
  • 33
0

respecting "Maxemelian"'s answer, extending answer by adding validation cases to check

  1. If section name is null
  2. Ignoring secret
private readonly IConfiguration configuration;

public MyController(IConfiguration configuration){
     this.configuration = configuration;
}

[HttpGet("[action]")]
public ActionResult GetConfigurationValue(string sectionName, string paramName)
{
    if (paramName.ToLower().Contains("secret")) {
        return null;
    }

    var parameterValue = (!string.IsNullOrEmpty(sectionName)) ? config[$"{sectionName}:{paramName}"] : config[$"{paramName}"];
    return Json(new { parameter = parameterValue });
}
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
Kurkula
  • 6,386
  • 27
  • 127
  • 202
  • I would recommend that your controller deny (return `null`) all parameter names **except** for the ones that you whitelist. With your current implementation, if you add `secret2` to your config but forget to update this controller code, you will expose that new secret value accidentally. – Blair Allen Sep 12 '19 at 14:33