36

I'd like to use string constants on both sides, in C# on server and in Javascript on client. I encapsulate my constants in C# class

namespace MyModel
{
        public static class Constants
        {
            public const string T_URL = "url";
            public const string T_TEXT = "text";
     . . .
        }
}

I found a way to use these constants in Javascript using Razor syntax, but it looks weird to me:

@using MyModel
        <script type="text/javascript">

            var T_URL = '@Constants.T_URL';  
            var T_TEXT = '@Constants.T_TEXT';
     . . .
            var selValue = $('select#idTagType').val();
            if (selValue == T_TEXT) { ... 

Is there any more "elegant" way of sharing constants between C# and Javascript? (Or at least more automatic, so I do not have to make changes in two files)

VikVik
  • 1,045
  • 2
  • 11
  • 15
  • 1
    This is the best way I've found. Are you wanting something that will scrape your .cs files for `public const string` and automatically recreate those values as `var` in the javascript for you? I can't imagine that would be inherently useful all the time. – jcolebrand Jun 02 '11 at 16:03
  • An addendum to my last comment. I failed to notice these were constants. That, on the other hand, is useful. – jcolebrand Jun 02 '11 at 16:58

5 Answers5

81

The way you are using it is dangerous. Imagine some of your constants contained a quote, or even worse some other dangerous characters => that would break your javascripts.

I would recommend you writing a controller action which will serve all constants as javascript:

public ActionResult Constants()
{
    var constants = typeof(Constants)
        .GetFields()
        .ToDictionary(x => x.Name, x => x.GetValue(null));
    var json = new JavaScriptSerializer().Serialize(constants);
    return JavaScript("var constants = " + json + ";");
}

and then in your layout reference this script:

<script type="text/javascript" src="@Url.Action("Constants")"></script>

Now whenever you need a constant in your scripts simply use it by name:

<script type="text/javascript">
    alert(constants.T_URL);
</script>
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • The javascript file get cached on the client side? – Patrick Dec 30 '12 at 19:17
  • 1
    For every JS file I have to do this? And if I want to separate Constants for each JS/View ? – Patrick Mar 05 '13 at 11:54
  • @Patrick, since the js is cached on the client why care? Simply put your constants in a single script. – Darin Dimitrov Mar 05 '13 at 12:12
  • And can I have a resource based constant for Multi-Language front-end like this: public static string centerButtonTitle = HeelpResources.MapCenterButtonTitle; ? centerButtonTitle is the label of a google map that is put by javascript. – Patrick Mar 07 '13 at 16:11
  • Ok thanks, I thought that has it's in the server-side, the dynamic resource language was not able to refresh the value of the constant to present in the client side – Patrick Mar 07 '13 at 16:34
  • Great solution but be careful that you don't go creating a javascript file that contains constants not intended for general consumption. – atreeon Apr 18 '13 at 17:49
  • 1
    nice trick! does this work with MVC's minification? Since this is not a js file that we can specify within a bundle, and the constants from this may be getting used in js files that are specified within a bundle, will there be a variable name mismatch? – Saharsh Sep 10 '15 at 21:36
5

You can use an HTML helper to output the script necessary, and use reflection to grab the fields and their values so it will automatically update.

    public static HtmlString GetConstants(this HtmlHelper helper)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        sb.AppendLine("<script type=\"text/javascript\">");

        foreach (var prop in typeof(Constants).GetFields())
        {
            sb.AppendLine(string.Format("    var {0} = '{1}'", prop.Name, prop.GetValue(null).ToString()));
        }

        sb.AppendLine("</script>");
        return new HtmlString(sb.ToString());
    }
Jay
  • 6,224
  • 4
  • 20
  • 23
2

My version to create a namespaced javascript object from my C# constants that is immutable:

public static HtmlString GetConstants<T>()
        {
            StringBuilder jsConstant = new StringBuilder();
                jsConstant.Append("myApp." + typeof(T).Name + " = Object.freeze({");
            foreach(var item in typeof(T).GetFields())
            {
                jsConstant.Append(string.Format("{0}:'{1}'",item.Name,item.GetValue(null).ToString()) + ",");
            }
            jsConstant.Remove(jsConstant.Length - 1, 1);
            jsConstant.Append("})");
            return new HtmlString(jsConstant.ToString());
        }

Used like this in Razor:

@(HtmlHelpers.GetConstants<MyApp.Infrastructure.ApplicationConstants.SomeConstants>())
bigbadmad
  • 51
  • 4
2

Rather then storing your constant data in a C# class, store it in a static config/constants file.

// Constants.json
{
    "T_URL": "url",
    "T_TEXT": "text"
}

// Constants.cs

// load the json from a file stream into a constants object

// Constants.js

window.Constants = $.getJSON(url);

Simply store it as some file format (json, xml, cvs, whatever) then load it up from both the client & server.

This means your either creating a class in the C# on the fly at runtime using black magic reflection or just have a hashtable / dictionary containing your constants under keys.

jQuery.getJSON, JsonReaderWriterFactor

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • 1
    close but not close enough. He needs something to use reflection (more or less) on the server to generate things for the client. – jcolebrand Jun 02 '11 at 16:57
  • @jcolebrand where the constants are is arbitary if there in a class or in a file. I prefer to keep them in a file. – Raynos Jun 02 '11 at 17:21
  • but you would still have to duplicate effort to keep .cs, .json, .js in sync. – jcolebrand Jun 02 '11 at 17:42
  • @jcolebrand the `.cs` & `.js` are static write once files. The `.json` is dynamic – Raynos Jun 02 '11 at 17:44
  • Could you elaborate on the black magic please? That's exactly what I'm trying to do. – Shagglez Dec 04 '12 at 18:19
  • @Shagglez what ever your doing it's a bad idea. – Raynos Dec 05 '12 at 02:06
  • @Raynos I am trying to set up a unified format for constants that could be used across several languages to store error codes. Ideally I'd like to have them strongly typed for C#, would would mean parsing the file (JSON probably) and creating a DLL that could be used in my application. Is that a bad idea? What's an alternative? – Shagglez Dec 05 '12 at 10:10
1

Another option is to add the constant as a data- value to the button/link calling the JavaScript code.

Your view:

<button data-url="@T_URL" ...>

Your script:

$('button').click(function(event) {
    var url = $(this).data('url');
    ...
Jonathan E. Landrum
  • 2,748
  • 4
  • 30
  • 46