Introduction
When it comes to writing the HTML/JavaScript client for your (“your” here means you own the code or have direct access to the assemblies) web service there is one thing that bothers everyone - translating classes from .NET to JavaScript. The problem is that whenever your service contract changes you need to reflect this change in your client application. Yes, most of the time this is not the case when the service is already in production but when the client and the service are both being written at the same time I think you would agree that continuous changes in service contract are a common thing.
Another big issue - even if current service contract (read API version) is “frozen” and is not going to change in future you still have to manually translate all your .NET classes to the JavaScript. It is OK if you have a handful of classes, but can you imagine (or even recall) the pain of translating couple of dozens of C# classes to the JavaScript?
That’s it, that is why I’ve decided to share my approach to this issue of translating the .NET classes to JavaScript.
The Problem
Lets imagine the situation where we have two teams that are working on two projects - the server side and the client side. The server side is represented by ASP.NET WebAPI service and the client side is an HTML/JavaScript application. As the server project progresses client team notices that it continuously have to make little adjustments “here and there” to keep up to date with the WebAPI changes in its DTO classes. So the problem is to automate this tedious for both teams process.
As of writing this post I’ve found that there is a question on StackOverflow showing an interest to this topic - How to reuse existing C# class definitions in TypeScript projects.
The Solution
As always there are two ways of solving the problem - use existing solution or write a new one.
There are at least two tools are available - TypeLite and T4TS. Everything is good with these tools but when it came to customization it turned out that you need to decorate the classes with some fancy attributes or code transformation functions. This means that you should mix in the requirements like module/property naming convention to the classes that are not even aware of existence of some client project that indirectly depends on them.
You can call me a purist but hey, why would I need to keep the metadata required for one project in another? And why should I complicate things and instruct the team working with a server side of how to decorate the classes with attributes that are needed by other team? Simple things should be simple. I just want my C# classes/structs/enums to be transformed to the TypeScript interfaces/classes/enums.
From my experience when it comes to codegeneration most of the time you will not find the “ready for use” solution that will 100% satisfy you. Best case is that you’ll find something that is simple and easy to change.
So I’ve chosen the second path - hack my own solution. For DTOs I’ve decided to write a code generator based on T4 Text Templates and reflection. And since I have a TypeScript based project my code generation templates are producing TypeScript code. Why TypeScript? For me, the main reason is compile time errors. I like that I can have classes and interfaces which usage will be checked by compiler at development time and I will see the mistakes before I run the app. Also it is worth to mention that TypeScript supports almost all features of the the ECMAScript 6 which is also good because investing time in TypeScript now I will be up to date with the latest standard available.
I also strongly believe that it is critically important to run code generation on every build and have no auto-generated things committed in a source control. This approach minimizes the probability of mistakes made by engineers (yes, I’ve had experience when warnings like // This code was auto-generated
were ignored).
Code
Since I’m going to generate classes I have to describe the metadata I need. This would be the name of the interface/enum and a list of its members:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
MetadataHelper
class is the heart of solution - it will extract the data needed for codegeneration using reflection:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
To be able to parameterize and run codegeneration on every build I’m using preprocessed T4 templates (for more information on topic please refer to the Oleg Sych’s Understanding T4: Preprocessed Text Templates blog post). Preprocessed template generates a partial class that I’ll be able to extend with metadata I need:
1 2 3 4 5 6 7 |
|
And the actual template. It also contains a helper method that translates .NET types to the corresponding TypeScript type names.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
|
And the usage is very simple. I’ve created a console application which could be launched for example on CI server during the build.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Conclusion
As you can see with a very little effort I’ve got a working and open to any customizations codegenerator. As always the code from this post is available on Github. Feel free to clone and adjust to your needs.
Keep the code simple!