Convert C# Classes to Javascript Objects With sharp2Js

By | November 28, 2015

Convert C# Classes to Javascript Objects
I’ve been working on a VERY large Angular Single Page Application for the last 1.5 years. This application deals with data models that can be large and somewhat complex at times. Generally, this means maintaining two sets of DTOs. One set created in C#, and another set created in JS to consume data received from the application-tier.

Now, you could skip the client-side DTOs and just work directly with the javascript objects returned from the service. In small applications this is fine, and probably standard practice. If you only have to remember or manage a handful of properties, a formal client-side data model can be overkill. But….what if you are working with larger models with lots of hierarchy and properties?

Why not use a client-side data model and get the benefits of code completion and unambiguous interpretation of the model? Usually, because you just don’t have the time. That and stubbing out data contracts isn’t exactly the most exciting work.

Enter sharp2Js.

sharp2Js is an open-source library I created to automatically convert C# DTO/data model classes to javascript objects with ease.
Primary benefits include:

  • Code completion when working with your model (if your code editor supports it)
  • Running a one-step T4 template keep you in sync with your model classes
  • Built-in utility functions
  • Not having to type it out yourself. Because life is too short to spend it duplicating your DTOs

Links/Install:
Nuget – sharp2Js
GitHub – sharp2Js

Convert C# Classes to Javascript Example:

Start with these classes that need to be converted:

public class AddressInformation
{
    public string Name { get; set; }
    public string Address { get; set; }
    public int ZipCode { get; set; }
    public OwnerInformation Owner { get; set; }
    public List<Feature> Features { get; set; }
    public List<string> Tags { get; set; }
}

public class OwnerInformation
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

public class Feature
{
    public string Name { get; set; }
    public double Value { get; set; }
}

And this configuration for sharp2Js:

var options = new Castle.Sharp2Js.JsGeneratorOptions() {
  CamelCase = false,
  OutputNamespace = "models",
  IncludeMergeFunction = true,
  ClassNameConstantsToRemove = new List<string>() { "Dto" },
  RespectDataMemberAttribute = true,
  RespectDefaultValueAttribute = true,
  TreatEnumsAsStrings = false,
  CustomFunctionProcessors =
          new List<
                Action<
                  StringBuilder, 
                  IEnumerable<Castle.Sharp2Js.PropertyBag>, 
                  Castle.Sharp2Js.JsGeneratorOptions>>()
          {
              (builder, bags, arg3) =>
              {
                  builder.AppendLine("\tthis.helloWorld = function () {");
                  builder.AppendLine("\t\tconsole.log('hello');");
                  builder.AppendLine("\t}");
              }
         }
  };

var str = Castle.Sharp2Js.JsGenerator.
    Generate(new [] { 
        typeof(Castle.Sharp2Js.SampleData.AddressInformation) }, options);

Outputs:

models.AddressInformation = function (cons, overrideObj) {
    if (!overrideObj) { overrideObj = { }; }
    if (!cons) { cons = { }; }
    var i, length;

    this.Name = cons.Name;
    this.Address = cons.Address;
    this.ZipCode = cons.ZipCode;
    if (!overrideObj.OwnerInformation) {
        this.Owner = new models.OwnerInformation(cons.Owner);
    } else {
        this.Owner = new overrideObj.OwnerInformation(cons.Owner, overrideObj);
    }
    this.Features = new Array(cons.Features == null ? 0 : cons.Features.length );
    if(cons.Features != null) {
        for (i = 0, length = cons.Features.length; i < length; i++) {
            if (!overrideObj.Feature) {
                this.Features[i] = new models.Feature(cons.Features[i]);
            } else {
                this.Features[i] = new overrideObj.Feature(cons.Features[i], overrideObj);
            }
        }
    }
    this.Tags = new Array(cons.Tags == null ? 0 : cons.Tags.length );
    if(cons.Tags != null) {
        for (i = 0, length = cons.Tags.length; i < length; i++) {
            this.Tags[i] = cons.Tags[i];
        }
    }
}


models.OwnerInformation = function (cons) {
    if (!cons) { cons = { }; }

    this.FirstName = cons.FirstName;
    this.LastName = cons.LastName;
    this.Age = cons.Age;
}


models.Feature = function (cons) {
    if (!cons) { cons = { }; }

    this.Name = cons.Name;
    this.Value = cons.Value;
}

Comments, concerns, questions welcome. Hopefully it helps someone out!

Leave a Reply

Your email address will not be published. Required fields are marked *