Search code examples
javascriptc#asp.netknockout.jsknockout-mvc

howto retrieve asp.net appSettings key from front-end .js file using knockout.js


I have an asp.net backend application and i am using web.config and other files to store configuration keys.

I have a front-end built with javascript files using knockout.js.

We would like to know how can we retrieve key value from web.config in backend and read this value in front-end using javascript and knockout.js.

Is there a simple way to do this ???, Views are javascript files and not asp.net web pages


Solution

    • You can render values directly to JavaScript <script> in your view/HTML/page files.
      • And then any JavaScript (with or without Knockout, jQuery, React, Redux, AngularJS, Angular2+, whatever) can access those values immediately.
    • IMPORTANT: Be sure to correctly JS-encode (not HTML-encode!) C#/.NET String values when rendering them as JavaScript string literals! ...otherwise backslashes and quotes will be rendered literally which will break your rendered <script> element and likely introduce significant XSS vulnerabilities.
      • In ASP.NET 4.x, use HttpUtility.JavaScriptStringEncode to ensure C#/.NET string values are correctly and safely encoded to JavaScript strings.

      • In ASP.NET Core you can continue to use HttpUtility.JavaScriptStringEncode (in the now almost empty System.Web.dll System.Web.HttpUtility.dll in .NET Core 2.x or later) however now the preferred API in .NET is System.Text.Encodings.Web.JavaScriptEncoder's Encode method (tip: use JavaScriptEncoder.Default.Encode).

      • Note that HttpUtility.JavaScriptStringEncode can optionally add delimiting quotes for you, but System.Text.Encodings.Web.JavaScriptEncoder never renders outer quotes.

    For Razor .cshtml in ASP.NET MVC and ASP.NET 4.x WebPages:

    (I assume your <head> is in _Layout.cshtml)

    @using System.Configuration
    @using System.Web.Configuration
    
    <html>
    <head>
        <script>
    
    var myAppSetting = '@( HttpUtility.JavaScriptStringEncode( WebConfigurationManager.AppSettings["myAppSetting"], addDoubleQuotes: false ) )';
    
        </script>
    </head>
    <body>
    </body>
    

    For ASP.NET WebForms .aspx/.ascx/.master and/or ASP.NET MVC 1.x and 2.x using the WebForms ASPX View Engine:

    • (I assume your <head> is in Layout.master)
    • Use <%= instead of <%: to render directly, btw, as we don't want to HTML-encode this JavaScript string literal.
    <%@ Import Namespace="System.Configuration" %>
    <%@ Import Namespace="System.Web.Configuration" %>
    <html>
    <head>
        <script>
    
    var myAppSetting = '<%= HttpUtility.JavaScriptStringEncode( WebConfigurationManager.AppSettings["myAppSetting"], addDoubleQuotes: false ) %>';
    
        </script>
    </head>
    <body>
    </body>
    

    For ASP.NET Core MVC's Razor .cshtml views:

    • Use @inject IConfiguration to get immediate access to .NET Core's appSettings.
    • You can use either HttpUtility.JavaScriptStringEncode(...) or System.Text.Encodings.Web.JavaScriptEncoder.Default.Encode(...) in ASP.NET Core (including .NET 6).
      • Don't forget outer-quotes!
    • Use Html.Raw() to render the JS literal string. Do not use the normal Razor "write" syntax (i.e. @( value ) or @value) because it will HTML-encode your JavaScript, which you don't want.
    • Like so:
    @using System.Text.Encodings.Web
    @inject IConfiguration Config
    
    <html>
    <head>
        <script>
    
    var myAppSetting = '@Html.Raw( JavaScriptEncoder.Default.Encode( this.Config.GetValue<String>("appSettings:myAppSetting") )';
    
        </script>
    </head>
    <body>
    </body>
    

    Note that if you want null values from your appSettings.json to appear as JavaScript null literals then you need to do that manually - you can use a @functions method to handle this, like so:

    @using System.Text.Encodings.Web
    @using Microsoft.AspNetCore.Html
    @inject IConfiguration Config
    @functions{
        
        public HtmlString GetAppSettingJSString( String name )
        {
            if( name is null ) throw new ArgumentNullException(nameof(name));
    
            String? appSettingValue = this.Config.GetValue<String?>( "appSettings:" + name );
            return ToJSStringLiteral( appSettingValue );
        }
    
        private static readonly HtmlString _nullLiteral = new HtmlString( "null" );
    
        public static HtmlString ToJSStringLiteral( String? value )
        {
            if( value is null ) return _nullLiteral;
            
            String jsStringLiteralChars = JavaScriptEncoder.Default.Encode( value );
            return new HtmlString( '"' + jsStringLiteralChars + '"' );
        }
    }
    
    <html>
    <head>
        <script>
    var myAppSetting = @Html.Raw( this.GetAppSettingJSString( "myAppSetting" ) );
        </script>
    </head>
    <body>
    </body>
    

    So now the <script> above will be rendered as either this:

    <script>
    var myAppSetting = "foobarbaz";
    </script>
    

    ...or this:

    <script>
    var myAppSetting = null;
    </script>
    

    Any script (except ES Modules, I think?) can access myAppSetting via the implicit global (aka window) object, as all top-level var declarations become global properties.

    So like so:

    <script>
    document.addEventListener( 'DOMContentLoaded', function() {
    
        alert( "myAppSetting: \"" + window.myAppSetting + "\"" );
    
    } );
    </script>