Shared Client and Server configuration with custom ActionResult – Solving it in a DRY way

I’m developing a MVC application and there are some configurations I want to use both on client and server side but I don’t want to replicate them, I want it be DRY (Don’t Repeat Yourself). Having it gives me the hability of changing some value on both sides without deploying the application again.

I could have created my properties in my AppSettings section and then print the variables on a page, but the AppSettings would become huge and the page header a mess.

Here is the solution I end up with. I created a JSON file containing my propeties, like so:

common.json

{
	"highlightProductId": 5,
	"bannerEnabled": false,
	"passwordLength": 15,
	"adURL": "http://google.com/ad"
}

That allows me to use the Newtonsoft or any other JavaScript parser like the JavaScriptDeserializer from .Net and have that JSON as a class. You can also deserialize it as “dynamic” if you are using the Newtonsoft library.

Well, that solves the problem for the server side. The client side though would have to call jQuery.getJSON to be able to read that file but that slows the page loading down and doesn’t give the user a nice experience because the user has to wait until the ajax call gets finished, so it can continue processing the rest of the script.

What I did was to turn that JSON into a JS file. To do that, you just have to assign that JSON to a variable and then you can embed the result in the page as a JavaScript file!

var common = { };

That is a valid JS file!

Now let’s teach MVC how to do that. Create the file below:

namespace System.Web.Mvc
{
    using System;

    public class JsonToJavaScriptResult : ActionResult
    {
        public string Prefix { get; private set; }
        public string JsonFile { get; set; }

        public JsonToJavaScriptResult(string prefix, string jsonFile)
        {
            JsonFile = jsonFile;
            Prefix = prefix;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = "application/x-javascript";

            response.Write(Prefix);            
            response.WriteFile(JsonFile);
        }
    }
}

There we are creating a custom ActionResult that concatenates the prefix – which are the part that will hold our variable name – with the content of the file – our JSON – and writes it all to the page buffer.

Now let’s make our Controller that will use the newly created class.

    public class SharedController : Controller
    {        
        //
        // GET: /Shared/Script

        public JsonToJavaScriptResult Script()
        {
            const string fileName = "common.json"
            const string prefix = "var Shared = ";
            var jsonFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);

            return new JsonToJavaScriptResult(prefix, jsonFile);
        }
    }

The last step is just insert the script tag in your page that will embed our code.

<script src="@Url.Action("Script", "Shared")" type="application/x-javascript"></script>

and you can do something like that

<script type="text/javascript">
  alert(Shared.highlightProductId);
</script>

Any new ideas or improvements are welcome.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s