![]() |
General Programming »
Programming Tips »
General
Intermediate
License: The Code Project Open License (CPOL)
Object Oriented JavaScript Class Library in C#/.NET StyleBy EJocysJavaScript classes ported from .NET |
Javascript, CSS, HTML, .NET (.NET1.0, .NET1.1, .NET2.0, Mono, DotGNU, .NET3.0, .NET3.5), ASP, ASP.NET, Ajax
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
Welcome to Object Oriented JavaScript class library in C#/.NET style.
I like coding with JavaScript in object oriented style. But one day, I decided to bring my code into another level and make my JavaScript code to look like C# as much as possible. So I did the following:
C# (3.0) code to create HMAC-MD5 checksum:
// Create HMAC-MD5 Algorithm.
var hmac = new System.Security.Cryptography.HMACMD5();
// Convert string to array of bytes.
var key = System.Text.Encoding.UTF8.GetBytes("test key");
var data = System.Text.Encoding.UTF8.GetBytes("test data");
// Compute hash.
var hashBytes = hmac.ComputeHash(key, data);
// Convert to HEX string.
var hex = System.BitConverter.ToString(hashBytes);
// Convert to GUID so you can store it inside database.
var guid = new System.Guid(hashBytes);
HMAC-MD5 checksum code written with this JavaScript library:
Include JavaScripts:
// Create HMAC-MD5 Algorithm.
var hmac = new System.Security.Cryptography.HMACMD5();
// Convert string to array of bytes.
var key = System.Text.Encoding.UTF8.GetBytes("test key");
var data = System.Text.Encoding.UTF8.GetBytes("test data");
// Compute hash.
var hashBytes = hmac.ComputeHash(key, data);
// Convert to HEX string.
var hex = System.BitConverter.ToString(hashBytes);
// Convert to GUID so you can store it inside database.
var guid = new System.Guid(hashBytes);
As you can see, the code is 100% identical.
C# (3.0) code for AES-256 encryption:
// Turn input string into a byte array.
var input = System.Text.Encoding.Unicode.GetBytes("Plain Text");
// Create an instance of the Rijndael class.
var cipher = new System.Security.Cryptography.RijndaelManaged();
// Calculate salt to make it harder to guess key by using a dictionary attack.
var password = System.Text.Encoding.UTF8.GetBytes("password");
var hmac = new System.Security.Cryptography.HMACSHA1(password);
var salt = hmac.ComputeHash(password);
// Generate Secret Key from the password and salt.
// Note: Set number of iterations to 10 in order for JavaScript example to work faster.
var secretKey = new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt, 10);
// Create a encryptor from the existing SecretKey bytes by using
// 32 bytes (256 bits) for the secret key and
// 16 bytes (128 bits) for the initialization vector (IV).
var key = secretKey.GetBytes(32);
var iv = secretKey.GetBytes(16);
// Get cryptor as System.Security.Cryptography.ICryptoTransform class.
var cryptor = cipher.CreateEncryptor(key, iv);
// Create new Input.
var inputBuffer = new byte[input.Length];
// Copy data bytes to input buffer.
System.Buffer.BlockCopy(input, 0, inputBuffer, 0, inputBuffer.Length);
// Create a MemoryStream to hold the output bytes.
var stream = new System.IO.MemoryStream();
// Create a CryptoStream through which we are going to be processing our data.
var mode = System.Security.Cryptography.CryptoStreamMode.Write;
var cryptoStream = new System.Security.Cryptography.CryptoStream(stream, cryptor, mode);
// Start the crypting process.
cryptoStream.Write(inputBuffer, 0, inputBuffer.Length);
// Finish crypting.
cryptoStream.FlushFinalBlock();
// Convert data from a memoryStream into a byte array.
var outputBuffer = stream.ToArray();
// Close both streams.
stream.Close();
cryptoStream.Close();
// Convert encrypted data into a base64-encoded string.
var base64String = System.Convert.ToBase64String(outputBuffer);
// base64String = laFf3eKu9tzB2XksJjd8EVM3PA9O30wz0Y+X3nyelW4=
Same AES-256 encryption code written with this JavaScript library:
Include JavaScripts:
// Turn input string into a byte array.
var input = System.Text.Encoding.Unicode.GetBytes("Plain Text");
// Create an instance of the Rijndael class.
var cipher = new System.Security.Cryptography.RijndaelManaged();
// Calculate salt to make it harder to guess key by using a dictionary attack.
var password = System.Text.Encoding.UTF8.GetBytes("password");
var hmac = new System.Security.Cryptography.HMACSHA1(password);
var salt = hmac.ComputeHash(passwordBytes);
// Generate Secret Key from the password and salt.
// Note: Set number of iterations to 10 in order for JavaScript example to work faster.
var secretKey = new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt, 10);
// Create a encryptor from the existing SecretKey bytes by using
// 32 bytes (256 bits) for the secret key and
// 16 bytes (128 bits) for the initialization vector (IV).
var key = secretKey.GetBytes(32);
var iv = secretKey.GetBytes(16);
// Get cryptor as System.Security.Cryptography.ICryptoTransform class.
var cryptor = cipher.CreateEncryptor(key, iv);
// Create new Input.
var inputBuffer = new System.Byte(input.length);
// Copy data bytes to input buffer.
System.Buffer.BlockCopy(input, 0, inputBuffer, 0, inputBuffer.length);
// Create a MemoryStream to hold the output bytes.
var stream = new System.IO.MemoryStream();
// Create a CryptoStream through which we are going to be processing our data.
var mode = System.Security.Cryptography.CryptoStreamMode.Write;
var cryptoStream = new System.Security.Cryptography.CryptoStream(stream, cryptor, mode);
// Start the crypting process.
cryptoStream.Write(inputBuffer, 0, inputBuffer.length);
// Finish crypting.
cryptoStream.FlushFinalBlock();
// Convert data from a memoryStream into a byte array.
var outputBuffer = stream.ToArray();
// Close both streams.
stream.Close();
cryptoStream.Close();
// Convert encrypted data into a base64-encoded string.
var base64String = System.Convert.ToBase64String(outputBuffer);
// base64String = laFf3eKu9tzB2XksJjd8EVM3PA9O30wz0Y+X3nyelW4=
There is one difference. In JavaScript, I need to use "new System.Byte(length)" instead of simple "new byte[length]" with square brackets. Of course, I can create a class alias by doing "byte = System.Byte" inside JavaScript and make that difference smaller.
function firstButton_Click(){
Trace.Write("First Button Click");
}
function secondButton_Click(){
Trace.Write("Second Button Click");
}
function Window_Load(){
Trace.IsEnabled = true;
Trace.Write("Start Demo");
// Create toolbar.
var toolBar = new System.Web.UI.Interface.ToolBar("MyToolBar");
// Add toolbar to document.
document.body.appendChild(toolBar.Node);
// Create Bar.
var bar = new System.Web.UI.Interface.Bar("MainBar", document, "Bar Title");
toolBar.Add(bar);
// Create first button.
var firstButton = new System.Web.UI.Interface.Button("FirstButton", document);
firstButton.SetText("First");
firstButton.SetImage("Images/Icons/Options-16x16.png");
firstButton.SetTitle("First Button");
firstButton.customAction = firstButton_Click;
bar.Add(firstButton);
// Create second button.
var secondButton = new System.Web.UI.Interface.Button("SecondButton", document);
secondButton.SetText("Second");
secondButton.SetImage("Images/Icons/Trace.16x16.png");
secondButton.SetTitle("Second Button");
secondButton.customAction = secondButton_Click;
bar.Add(secondButton);
}
window.onload = Window_Load;
Will produce this interface on the web page:
Coding with JavaScript in C# .NET style provides these benefits:
JavaScript has a very limited number of types:
| JavaScript Object | typeof(Object) |
Object |
'object' |
Array |
'object' |
Function |
'function' |
String |
'string' |
Number |
'number' |
Boolean |
'boolean' |
null |
'object' |
undefined |
'undefined' |
But by combining the existing types, we can create JavaScript objects similar to C#. For example:
| C# Type | JavaScript Type |
public |
property declared with "this." prefix: this.Name = new String; |
private |
property declared with "var" prefix: var name = new String; |
class |
this.[ClassName] = function(){... without "return value;" at the end |
void |
function which has no "return value;" at the end |
short/Int16 |
whole Number from [-2^15, 2^15-1] range |
int/Int32 |
whole Number from [-2^31, 2^31-1] range |
long/Int64 |
whole Number from [-2^63, 2^63-1] range (Requires BigInteger class) |
byte |
whole Number from [0, 255] range: var b = 14; |
sbyte |
whole Number from [-128, 127] range: var sb = -14; |
bytes[] |
Array() filled with integers from [0-255] range. |
bit |
Number: 0 or 1 |
bit[] |
Array() filled with integers from [0-1] range. |
char |
String which contains a single character. Declared with single quotes: var c = 's' |
char[] |
Array() filled single characters: var chars = new Array(1); chars[0] = 's'; |
object |
parameter which was declared with "{ }": var o = {}; |
enum |
Object with "Enum" sufix and comma separated values: this.TriStateEnum = { Unknown: -2, False: 0, True: 1 } |
EventHandler |
function with parameters "sender" and "e": function(sender, e) or this.Click(sender, e) |
NUMBERS: All numbers in JavaScript are 64-bit (8 bytes) floating point numbers (double: 1-bit sign, 11-bits exponent, 52-bits mantissa). There is no Double, Single/Float, Boolean, Int16, UInt16, Int32 or UInt32. But you can use public static methods of System.BitConverter JavaScript class in order to treat the same JavaScript number as a different type:
// Convert number to [0x00, 0x00, 0xCC, 0xCC] array.
var bytes = System.BitConverter.GetBytes(-859045888, System.TypeCode.Int32);
// Convert bytes back to -859045888.
var n = System.BitConverter.ToInt32(bytes, 0);
System.BitConverter JavaScript class supports little-endian (default), big-endian byte orders and numeric arrays. System.BitConverter class is very useful in encoding/decoding/encryption/decryption classes. Please note that you need to specify number type when using GetBytes(value, typeCode) method by using System.TypeCode enumeration values (this enumeration is located inside System.js file).I've added System.BigInt class (same as .NET internal System.Security.Cryptography.BigInt class). It represents an arbitrarily large signed integer whose value in theory has no upper or lower bounds. It means you can add, subtract, multiply, divide numbers of Godzilla proportions in JavaScript which can be useful with client side encryption:
// Increase global System.BigInt size to 512 bytes.
// BigInt will act like System.Int4096 (default is System.Int1024).
System.BigInt.MaxBytes = 512;
// Create big integer from hexadecimal number.
var n1 = new System.BigInt("0x010203040506");
// Create big integer from decimal number.
var n2 = new System.BigInt("-280422911905295");
// Multiply them.
var n3 = System.BigInt.Multiply(n2, n1);
// Store result in various forms.
var h = n3.ToHex() // -0x01010C234779B3FAEED09F5A
var d = n3.ToDecimal() // -310751254825142252681076570
var bytes = n3.Elements // A6602F11054C86B8DCF3FEFEFFFFFF...
NOTE: You can use <param type="byte[]" name="data">...</param> inside JavaScript XML Comments in order to specify type of input data and <returns type="double">...</returns> - for output.
Files from this JavaScript library can be included on the client and server side, thanks to special header and footer:
<!--//--><%
//=============================================================================
// Jocys.com JavaScript.NET Classes (In C# Object Oriented Style)
// Created by Evaldas Jocys <evaldas@jocys.com>
//-----------------------------------------------------------------------------
// You can include this script on both sides - server and client:
// Server: <!-- #INCLUDE FILE="ScriptFile.js" -->
// Client: <script type="text/javascript" src="ScriptFile.js"></script>
//=============================================================================
JavaScript Code Here...
//==============================================================================
// END
//------------------------------------------------------------------------------
//%>
... and by avoiding Response.Write() or alert() use directly: for example: I can detect if the script is running on the server side or client side and show the message accordingly with this code:
this.IsServerSide = (typeof(Response) == "object");
// If we are on server side then...
if (this.IsServerSide){
// Write text to output.
Response.Write(text);
}else{
// Show popup message.
alert(text);
}
Visual Studio 2008 has built-in support for JavaScript IntelliSense. This means that if you open System.BitConverter.js file, place cursor at the end of file and type "System.BitConverter." then straight after the dot, VS 2008 will bring up a menu containing all available methods and properties of System.BitConverter class:
The good news here is that Microsoft is moving in the right direction. The bad news is that JavaScript IntelliSense works only with specific JavaScript coding style and sometimes needs workarounds. In other words, it works in mysterious ways or doesn't work at all :). Some extra upgrades are needed on my code I guess.
Extract source archive into webroot (/) folder of your website.
Inside the source code, you can find examples (Examples/) including password generator example. You can run it:
To make a suggestion or report bugs, please write to evaldas@jocys.com.
System.BigInt(.js file) class with examples:
System.Web.UI.HtmlControls.TextBox.CommandLine - Converts input to command line. Will be used later to create plain JavaScript console and in chat applications. System.TypeCode System.Collections.BitArray System.BitConverter (System.BitConverter.js) class was updated with methods: System.BitConverter.GetByte(value, typeCode) - get bytes from Double, Single, Boolean, Int16, UInt16, Int32, UInt32. You need to use values of System.TypeCode to specify how JavaScript must treat a number.byte[] back to numbers by using methods
System.BitConverter.ToDouble(bytes, startIndex) System.BitConverter.ToSingle(bytes, startIndex) System.BitConverter.ToBoolean(bytes, startIndex) System.BitConverter.ToInt16(bytes, startIndex) System.BitConverter.ToUInt16(bytes, startIndex) System.BitConverter.ToInt32(bytes, startIndex) System.BitConverter.ToUInt32(bytes, startIndex) Int64 and UInt64 types are not available yet because JavaScript 64-bit (8 bytes) float point numbers have only 52-bit mantissa which means that it is not possible to work with 64-bit whole numbers properly (possible by reusing BigInt class). System.Security.Cryptography.Rfc2898DeriveBytes System.Security.Cryptography.ICryptoTransform System.Security.Cryptography.RNGCryptoServiceProvider System.Security.Cryptography.CryptoStrea System.Security.Cryptography.RijndaelManaged System.Buffer.BlockCopy System.Array.Reverse System.Array.Clear System.Array.GetMultiDimensional System.Array.FillMultiDimensiona System.BitConverter static class was updated. System.IO.MemoryStream' class. I will use it later with symmetric encryption algorithms so encryption can be done between two web browser clients without any ActiveX. byte[] arrays filled with 0 numbers in JavaScript easier:var bytes = new System.Byte(10);byte[] bytes = new System.Byte[10];' or 'byte[] bytes = new byte[10];' in C#. You can define multi-dimensional arrays filled with zeroes too:var bytes = new System.Byte(16,16); bytes[4][5] = 10;
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 21 Jun 2009 Editor: Deeksha Shenoy |
Copyright 2007 by EJocys Everything else Copyright © CodeProject, 1999-2010 Web22 | Advertise on the Code Project |