Thursday, May 14, 2009

techNote_Append Registry Via Visual Studio Setup Project


How can I append a directory to the PATH environment variable when creating a Visual Studio Setup project.


Objective: To be able to APPEND Path Environment Variable by changing Windows Registry setting,  using a MSI Windows Installer created by a Visual Studio Setup project.

End Product: An exe and a msi file to install a program and also change registry setting automatically. When the program is uninstalled (via Add or Remove programs) then the registry setting will be changed to the pre-installation state.

Reference: This article is based on the article and code found below, but with necessary modifications.
http://askville.amazon.com/append-directory-PATH-environment-variable-Visual-Studio-Deployment-installation-Project/AnswerViewer.do?requestId=4628663

The code presented in askville, assumes that the path to be added is only the path where the programs are installed. For example if pre-install path = "c:\temp", and the program is to be installed in "c:\programs", then the final path would be "c:\temp;c:\programs".

With the modifications I made to the code, it allows the user to setup multiple additional paths, not only where the program is installed. The scenario is like this:
Preinstall path variable: c:\temp
Additional paths: c:\dirA;c:\dirB
Installation path: c:\programs
Intended final path: c:\temp;c:\dirA;c:\dirB;c:\programs
After uninstall path: c:\temp

Basically, the idea is to create a custom action class and then configure the Setup project.
Here are the detailed steps of how to construct the Visual Studio setup project.

1. Copy the code below and put into an empty C# class and called in Installer1.cs. Need to change the Namespace in the code to tailor to the namespace of your project.

Basically, the C# code override the Install, Uninstall, and Rollback methods of the standard Installer class.

2. The C# class file in step 1 need to be put into a C# project. It could be a new project or it could one of your working project to be included in the Setup Project.

3. Create the Visual Studio Setup Project. Add the C# project in step 2 to the setup. This is done in the normal way by right clicking the setup project in Solution Explorer. Click Add -> Project Output. Then select that C# project and select Primary Output, then click OK.

4. Right click on your Setup project, select View|Custom Actions, and then right-click on Install, Rollback, and Uninstall to add the assembly containing the custom action class to each one.

5. Finally add any additional directories to the user path via the Registry by the following:
i) Assume that the new variable to be appended to the User Path is called "MySetup". This name "MySetup"
is hard coded to the function GetAddedPath, which can be changed as desired.
ii) Right click on the setup project, choose View -> Registry.
iii) In the Registry editor, go to HKEY_CURRENT_USER and add new Key "Environment" if it is not there already.
iv) Click on the new "Environment" entry and ADD -> New -> Environment String Value.
v) on the right hand pane, name the new variable as "MySetup".
vi) Click on the entry "MySetup" and in its property box, write the value of any subdirectories you wish to
include in the user path.
---------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using Microsoft.Win32;

namespace YOUR_OWN_NAMESPACE
{
    /// <summary>
    /// A Custom Action class that provides action to append registry for MS Setup project.
    /// </summary>
    [RunInstaller(true)]
    public partial class Installer1 : Installer
    {
        public Installer1()
        {
            InitializeComponent();
        }

        public override void Install(System.Collections.IDictionary stateSaver)
        {
            base.Install(stateSaver);
            string curPath = GetUserPath();
            stateSaver.Add("previousPath", curPath);
            string newPath;
            if (curPath.Length == 0 ) {
                newPath = AddPath(GetAddedPath() , MyPath());
            }else{
                newPath = AddPath(curPath, GetAddedPath()+";"+MyPath());
            }
           
            if (curPath != newPath)
            {
                stateSaver.Add("changedPath", true);
                SetPath(newPath);
            }
            else
                stateSaver.Add("changedPath", false);
        }

        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            base.Uninstall(savedState);
            if ((bool)savedState["changedPath"])
            {
                SetPath(RemovePath(GetUserPath(), MyPath()));
                SetPath(RemovePath(GetUserPath(), GetAddedPath()));
            }
        }

        public override void Rollback(System.Collections.IDictionary savedState)
        {
            base.Rollback(savedState);
            if ((bool)savedState["changedPath"])
                SetPath((string)savedState["previousPath"]);
        }

        internal static string MyPath()
        {
            string myFile = System.Reflection.Assembly.GetExecutingAssembly().Location;
            string myPath = System.IO.Path.GetDirectoryName(myFile);
            return myPath;
        }

        private static RegistryKey GetPathRegKey(bool writable)
        {
            // for the user-specific path...
            return Registry.CurrentUser.OpenSubKey("Environment", writable);

            // for the system-wide path...
            //return Registry.LocalMachine.OpenSubKey(
            //    @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", writable);
        }

        private static void SetPath(string value)
        {
            using (RegistryKey reg = GetPathRegKey(true))
            {
                reg.SetValue("Path", value, RegistryValueKind.ExpandString);
            }
        }

        internal static string GetUserPath()
        {
            using (RegistryKey reg = GetPathRegKey(false))
            {
                return (string)reg.GetValue("Path", "", RegistryValueOptions.DoNotExpandEnvironmentNames);
            }
        }
        internal static string GetAddedPath()
        {
            using (RegistryKey reg = GetPathRegKey(false))
            {
                return (string)reg.GetValue("MySetup", "", RegistryValueOptions.DoNotExpandEnvironmentNames);
            }
        }


        private static string AddPath(string list, string item)
        {
            List<string> paths = new List<string>(list.Split(';'));

            foreach (string path in paths)
                if (string.Compare(path, item, true) == 0)
                {
                    // already present
                    return list;
                }

            paths.Add(item);
            return string.Join(";", paths.ToArray());
        }

        private static string RemovePath(string list, string item)
        {
            List<string> paths = new List<string>(list.Split(';'));

            for (int i = 0; i < paths.Count; i++)
                if (string.Compare(paths[i], item, true) == 0)
                {
                    paths.RemoveAt(i);
                    return string.Join(";", paths.ToArray());
                }

            // not present
            return list;
        }

    }
}


Sunday, May 10, 2009

Notes C Sharp - C#

NotesCSharp
============

C# Architecture
New Syntax
Compiling C# code
Reference vs Value Type
Namespace
.Net C# data type
Escape Sequence
Basic Programming constructs
Constructors
Accessor
Events
Delegates
OpenDialog
Environment Variables
Strings
fileIOPermission
FileIO Classes
DataAccess with ADO.NET
ADO.Net - ExecuteNonQuery
Arrays
Type Conversion
Unsafe
Console I/O
Special Folder Path
How to: Convert Between Hexadecimal Strings and Numeric Types (C# Programming Guide)
C# calling Fortran function in DLL
Destructors, Finalize and IDisposable
Reading XML structure with XMLDocument and XPathNavigator
Boxing and Unboxing
Dispose, Finalize, Finally, Close
How to: Create and use a Toggle Button as a Web User Control
XML Serialization
Assemblies
CLS Compliant Requirements
Global Assembly Cache (GAC)
Public Key Cryptography
Versioning shared assemblies and .Net Framework Runtime
.Net Remoting
Presentation - Business - Data Layered applications
Marshalling
Var - Type Inference - C# 3.0
Extension Methods - C# 3.0
Lambda Expressions - C# 3.0
Object and Collection Initializers - C# 3.0
Anonymous Types / Class - C# 3.0
LINQ - C# 3.0
Auto-Implemented Properties - C# 3.0


C# Architecture
==================
       The BASE CLASS LIBRARY
DataAccess, GUI, Security, XML/SOAP, Threading, File I/O, Debugging, (et.al.)

       The COMMON LANGUAGE RUNTIME
Common Type System,        Common Language Specification

CLR contains two core entities:
- runtime execution engine mscoreee.dll
- base class library mscorlib.dll

.net binaries = .net Assemblies
- Assemblies contain: metadata, MSIL (intermediate language)

New Syntax
==========
Properties
- for get and set methods
-

Indexers
- a way to treat an object as an array.

Attributes
- provide directive like statements for the code
- similar to using #DEF in C++  unix code


Compiling C# code
===================
Source Code -> compile
   |
   V
Assembly  (contains MSIL, manifest, other resources require by assembly)
   |
   V
Exe or DLL -> Run -> loaded into Managed Environment -> compile using JIT compiler to...
   |
   V
Machine code


To Compile with command line:
csc /target:exe TestApp.cs
csc /r:System.Windows.Forms.dll /target:exe TestApp.cs



MSIL = MS Intermediate Language
- like Java ByteCode
- can be examined using MSIL Dissembler


Reference vs Value Type
========================
Value Type: All predefined types (eg int), structs, enumerations
Reference Type: object, string, all classes




Namespace
=========
Typical structure:
   using System;
   using ....
   namespace myName{
      class blah......


   }

- Namespace correspond to project name - like Java package?
- Most code are put inside namespace
- Many files may define namespaces with the same name.
- Using keyword makes the things in that namespace available

Sample .Net namespaces:
System
System.Collections
System.Datat
System.Data.Common
System.Data.OleDb
System.SqlClient
System.Diagnostics
System.Drawing
System.Drawing.Drawing2D
System.Drawing.Printing
System.IO
System.Net
System.Reflection
System.Reflection.Emit
System.Runtime.InteropServices
System.Runtime.Remoting
System.Security
System.Threading
System.Web
System.Windows.Forms
System.Xml


ILDasm.exe can be used to view the contents of Assembly as follows:
- to view namespace tree -> File -> Dump Tree View
- to view ILD            -> File -> Dump
- to view metadata       -> Ctrl+M


Class Viewer Web Application
-> http://localhost/ClassViewer/Default.aspx

WinCV
-> WinCV.exe

.Net C# data type
==================
Note C# does not have native data type, but its data type are actually .Net data types which
can be used by C#, VB and VC++ etc. i.e. All data types are actually classes.

int32 ii=3;
ii.ToString();    // valid because int32 is really System.Int32

          CLR Type        Bytes         Append
bool    System.Boolean     true/false
sbyte   System.SByte      1
byte    System.Byte       1
short   System.Int16      2
ushort  System.Uint16     2
int     System.Int32      4               1
uint    System.Uint32     4               1U
long    System.Int64      8               1L
ulong   System.Uint64     8               1UL
char    System.Char       2
string  System.String    
decimal System.Decimal    12              1.0M
float   System.Single                      1.0F
double  System.Double                     1.0

Some useful classes:
string
DateTime
Array


Escape Sequence
=================
\'  single quote
\"  double quote
\\  backslash
\0  null
\a  Alert
\b  backspace
\f  formfeed
\n  newline
\r  carriage return
\t  tab
\v  vertical tab




Basic Programming constructs
===============================
Conditional structures:
  ==, != <, >, <=, >=, &&, ||,

if()
{
}
else if()
{
}
else
{
}

switch(number)   // number must be int, bool, char, string, enumeration
{
   case1:
      break;
   case2:
      break;
   default:
      break;
}

for (int i=0; i<10; i++){ ....}

string[] sArr = {"1", "2", "3"};
foreach(string elem in sArr) { ......... }

while(..) {....}

do {.......} while(....);

break - to exit any loop.

Accessibility Keywords for variables, methods, properties, events
   public - access by any class
   private - access only by the class it is defined
   internal - access by any class within the assembly
   protected - access by this class or any of its children
   protected internal - access by any code in the same assembly and in derived classes

C# Code Components:
- class
- constructor - don't use "void" keyword
- property / accessor - (see Accessor)
- method
- event - needs delegates (see Events)


Constructors
=============
Constructors for derived classes automatically calls its parent constructors first, all the way up until
the System.Object class. Then the base constructors get executed first, followed by the children constructors.

Consider the example:
abstract class GenericCustomer{
   private string name;
   public GenericCustomer(string name){
       this.name = name;
   }

class SpecCustomer{
   private string referer
   public SpecCustomer(string name, string referer) : base(name) {
       this.referer = referer;
   }
   public SpecCustomer(string name) : this(name, "blah") {     }

If the class is called with a single argument, eg new SpecCustomer(my_name)
then it calls its overloaded constructor "THIS" using two arguments,
which in turns calls the base constructor of GenericCustomer.




Accessor
=========
1. Declaration / Definition
public class Product{
   private decimal price;

   public decimal Price{
      get{ return price; }
 set( price = value; }
   } // end accessor
} // end class

2. Usage
Product prod = new Product();
prod.Price = 49.99M;     // M makes it decimal type.

Events
=======
public class Product{
   private string name;
   public delegate void NameChangedEventHandler();     // delegate type
   public event NameChangedEventHandler NameChanged;   // an event - also a delegate variable
   public string Name{
      get{ return name; }
 set{ name = value;
      if (NameChanged != null) {                  // check if event is nulled
     NameChanged();
  }
  } // end set
    }   // end Name
} // end class

Event handler ChangedDetected() defined in another class.
public void ChangeDetected(){  .... blah ....}

//Using the event:
Product prod = new Product();

//Connect the event to the handler via delegates - like registering???
prod.NameChanged += new NameChangedEventHandler(ChangeDetected);

//Event will occur here
prod.Name = "blah";




Delegates
==========
- are like pointer to functions.
Example:
  private delegate string StringFunction(string in);    // 1. a delegate type
  private string Translate(string word) {...};          // 2. actual method or procedure
  StringFunction funcRef;                               // 3. a delegate variable or instance of type StringFunction
  funcRef = Translate;                                  // 4. use delegate to point to real function.
  funcRef("blah");                                      // 5. using the actual function via delegate.

Multicast Delegates - can point to a list of methods (order of execution not guaranteed)
- Must return void to be consistent across methods.
  eg. delegate void DoubleOp(double value);
- Instantiating the delegate:
  eg. DoubleOp oper = new DoubleOp(Maths.Mutilpy);
      oper += new DoubleOp(Maths.Square);



OpenDialog
===========
FileIOPermissions may restrict OpenFileDialog from opening properly if the exe is located on a network share drive.
But the application should run properly when copied to a local drive.

Environment Variables
=========================
In C#, environment variables can be obtained programmatically from System.Environment....

The Environment.SpecialFolder enumeration is:

ApplicationData The directory that serves as a common repository for application-specific data for the current roaming user.  A roaming user works on more than one computer on a network. A roaming user's profile is kept on a server on the network and is loaded onto a system when the user logs on.

CommonApplicationData The directory that serves as a common repository for application-specific data that is used by all users.
CommonProgramFiles The directory for components that are shared across applications.
Cookies The directory that serves as a common repository for Internet cookies.
Desktop The logical Desktop rather than the physical file system location.
DesktopDirectory The directory used to physically store file objects on the desktop.  Do not confuse this directory with the desktop folder itself, which is a virtual folder.

Favorites The directory that serves as a common repository for the user's favorite items.
History The directory that serves as a common repository for Internet history items.
InternetCache The directory that serves as a common repository for temporary Internet files.
LocalApplicationData The directory that serves as a common repository for application-specific data that is used by the current, non-roaming user.
MyComputer The "My Computer" folder.
MyMusic The "My Music" folder.
MyPictures The "My Pictures" folder.
Personal The directory that serves as a common repository for documents.
ProgramFiles The program files directory.
Programs The directory that contains the user's program groups.
Recent The directory that contains the user's most recently used documents.
SendTo The directory that contains the Send To menu items.
StartMenu The directory that contains the Start menu items.
Startup The directory that corresponds to the user's Startup program group.
The system starts these programs whenever a user logs on or starts Windows NT or later, or starts Windows 98.
System The System directory.
Templates The directory that serves as a common repository for document templates.


Strings
========
"string" is a native data type which is based on the .Net object "String"

Concatenation can be done with "+"

Verbatim character is "@", for example
   new DirectoryInfo(@"C:\");



fileIOPermission
==================
http://www.csharphelp.com/archives/archive203.html
http://www.bluevisionsoftware.com/WebSite/TipsAndTricksDetails.aspx?Name=PermissionRequests

c# fileIOPermission

FileIO Classes
=================
for general IO:
    Object -> Stream -> FileStream, MemoryStream, BufferedStream

for text data IO:
    Object -> TextReader -> StreamReader, StringReader
           -> TextWriter -> StreamWriter, StringWriter

Example: reading from text file
            // create reader and open file
            TextReader tr = new StreamReader("hello.txt");
// Reading a line
            String shello = tr.ReadLine();
// Close file
            tr.Close();

Example: writing from text file
            TextWriter tw = new StreamWriter(this.fileOut);
            tw.WriteLine(DateTime.Now);
            tw.Close();

Read all lines from a file and then join into one long string.
string[] readText = File.ReadAllLines("CQCratings.xml");  
sxml = String.Join("", readText);

Example: writing Object to Binary file
Note that someObject must belong to a class which is declared [Serializable()]
using (FileStream fs = new FileStream("eldListTest.dat", FileMode.OpenOrCreate,
FileAccess.Write, FileShare.None))
            {
                IFormatter binF = new BinaryFormatter();
                binF.Serialize(fs, someObject);
            }
           
Example: reading Object from Binary file
Note that someObject must belong to a class which is declared [Serializable()]
            using (FileStream fs = new FileStream("eldListTest.dat", FileMode.Open,
FileAccess.Read, FileShare.None))
            {
                IFormatter binF = new BinaryFormatter();
                someObject = (<Class type of Object>)binF.Deserialize(fs);
            }
                   
DataAccess with ADO.NET
========================
Ref: Chap 13 - Data Access with ADO.NET
Namespaces for ADO:
- System.Data
- System.Data.Common
- System.Data.OleDb
- System.Data.SqlClient
- System.Data.SqlTypes


Data structure Hierarchy:
1. DataTableCollection
   - DataTable
     - DataColumnCollection
       - DataColumn
     - DataRowCollection
       - DataRow
2. DataSet
   - DataRelationCollection
   - DataTableCollection
   - PropertyCollection


DataColumn.ColumnMapping has values of MappingType.
... where MappingType = {Attribute | Element | Hidden | TableElement | Text}
    for XML, use Attribute or Element

Adding Row Data:
   DataRow dr;
   dr = myDataTable.NewRow();
   // Method 1
   dr["ID"]=12
   dr["NAME"]="name12"
   // Method 2
   object [] myVals = new object[2];  // correspond to 2 columns
   myVals[0] = 12;
   myVals[1] = "name12";
   dr.ItemArray = myVals;
   // End
   myDataTable.Rows.Add(dr);

Filtering:
myTable.Select("SelString");    ... where SelString are like SQL statements, eg "ID > '1030'"

Connecting to Database
- connect to MSAccess
OleDbConnection cn = new OleDbConnection();
cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + // Which provider
@"Data Source=D:\DATA\UsercheeOnD\myVSprojects\CsharpLearn\source\Chapter 13\Access DB\\Cars.mdb;";  
cn.Open();
- connect to MS  
OleDbConnection cn = new OleDbConnection();
cn.ConnectionString = "Provider=SQLOLEDB.1;" + // Which provider
   "Integrated security=SSPI;" +
"Persist Security Info=False;" +
"Initial Catalog=Cars;" +                 // Name of database
"Data Source=BIGMANU;";                   // Name of machine
cn.Open();

SqlDataAdapter (System.Data.SqlClient):
- provides a local copy of the database(as in DataSet) of the real database - ie. Disconnected Data Set.
- Fill command copies the actual DB into the local DataSet.
- Update command copies the local DataSet into the actual DB.
- has properties: Select, Insert, Delete, Update

SqlCommand
- allows the creation of commands the interact directly with the DB, instead of using DataAdapters.

      Example - calling Select operation
// Connection
string sConn = @"Data Source=DBserver;Initial Catalog=DBname;Integrated Security=True";
SqlConnection aSQLconn = new SqlConnection( sConn )
aSQLconn.Open();

// SQL commands and data adapter
SqlCommand selectCmd = new SqlCommand("Select * from tables", aSQLconn);
SqlDataAdapter da = new SqlDataAdapter(selectCmd);

// Filling Data set
DataSet ds = new DataSet();
da.Fill(ds)
aSQLconn.Close();


ADO.Net - ExecuteNonQuery
==========================
An alternative to perform SQL operations (Select, Insert, Update, Delete) without using DataSets is to use
ExecuteNonQuery, ExecuteReader, ExecuteScalar.

ExecuteNonQuery()
- Executes a Transact-SQL statement against the connection and returns the number of rows affected.
- querying the structure of a database, creating database objects such as tables, change the data in a database without using DATASET
- executes the UPDATE, INSERT, DELETE statements.
- Example:
The following example creates a SqlCommand and then executes it using ExecuteNonQuery. The example is passed a string that is a Transact-SQL statement (such as UPDATE, INSERT, or DELETE) and a string to use to connect to the data source.

private static void CreateCommand(string queryString,    string connectionString){
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(queryString, connection);
        command.Connection.Open();
        command.ExecuteNonQuery();
    }
}

ExecuteReader()
- Sends the CommandText to the Connection and builds a SqlDataReader.
- returns a SqlDataReader
- can be used with Stored Procedure.
- When the CommandType property is set to StoredProcedure, the CommandText property should be set to the name of the stored procedure. The command executes this stored procedure when you call ExecuteReader.
- Example:
private static void CreateCommand(string queryString, string connectionString){
    using (SqlConnection connection = new SqlConnection(connectionString))    {
        connection.Open();
        SqlCommand command = new SqlCommand(queryString, connection);
        SqlDataReader reader = command.ExecuteReader();
        while (reader.Read())
        {
            Console.WriteLine(String.Format("{0}", reader[0]));
        }
    }
}

ExecuteScalar()
- Executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
- Use the ExecuteScalar method to retrieve a single value (for example, an aggregate value) from a database. This requires less code than using the ExecuteReader method, and then performing the operations that you need to generate the single value using the data returned by a SqlDataReader.
- Example:
 cmd.CommandText = "SELECT COUNT(*) FROM dbo.region";
 Int32 count = (Int32) cmd.ExecuteScalar();







Arrays
=======

   Examples of array creation:
string[] stringArray = new string[4];
int[,]   intArray    = new int[2,4];
string[] stringArray = {"1", "2", "3", "4"};
int[] intArray       = {{1,2}, {3,4}, {5,6}, {7,8}};      // no comma in int[] - as copied from book.

for dynamic arrays, use the class:
ArrayList dynamicList = new ArrayList();
dynamicList.Add("one");
string item = Convert.ToString(dynamicList(0));

Type Conversion
=================
long i64;
int  i32;

i64 = i32;       auto conversion for small to big
i32 = (int)i64;  explicit conversion
Convert.ToInt32(...)   if argument is null, returns 0.
Int32.Parse(...)       if argument is null, returns null exception.

Unsafe
=======
Anything to do with C# pointers need to be marked as unsafe.
1. methods
   unsafe int getNum(){...}
2. class
   unsafe class Myclass{.....}
3. Class members
   class MyClass{ unsafe int *pX; }
4. execution code
   void myMethod(){
      unsafe{ ...... }
   }
5. Must tell compiler to compile unsafe code using the option:
   /unsafe or -unsafe
   (check properties on VS.Net)

Console I/O
============
Example:   Console.WriteLine(" {0,9:C2} blah {1,9:C2} ", i, j};
The 0 and 1 in the {} represent first and second argument i, j
The 9 represents length of output.
The C2 represents Currency format with 2 decimal place.

C      interprets the value in terms of the local currency,
F      indicates a fixed-point format,
E      indicates an exponential (scientific) format,
G      leaves it to the system to pick the most compact form

Special Folder Path
======================
Environment.SpecialFolder Enumeration:
Desktop
DesktopDirectory
Favorites
History
InternetCache
LocalApplicationData
MyComputer
MyDocuments
MyMusic
MyPictures
Personal
ProgramFiles
Programs
Recent
SendTo
StartMenu
Startup
System
Templates

How to: Convert Between Hexadecimal Strings and Numeric Types (C# Programming Guide)
=======================================================================================

These examples show you how to perform the following tasks:

Obtain the hexadecimal value of each character in a string.

Obtain the char that corresponds to each value in a hexadecimal string.

Convert a hexadecimal string to an int.

Convert a hexadecimal string to a float.

Convert a byte array to a hexadecimal string.

 Example
This example outputs the hexadecimal value of each character in a string. First it parses the string to an array of characters. Then it calls ToInt32(Char) on each character to obtain its numeric value. Finally, it formats the number as its hexadecimal representation in a string.

C#
string input = "Hello World!";
char[] values = input.ToCharArray();
foreach (char letter in values)
{
    // Get the integral value of the character.
    int value = Convert.ToInt32(letter);
    // Convert the decimal value to a hexadecimal value in string form.
    string hexOutput = String.Format("{0:X}", value);
    Console.WriteLine("Hexadecimal value of {0} is {1}", letter, hexOutput);
}
/* Output:
   Hexadecimal value of H is 48
    Hexadecimal value of e is 65
    Hexadecimal value of l is 6C
    Hexadecimal value of l is 6C
    Hexadecimal value of o is 6F
    Hexadecimal value of   is 20
    Hexadecimal value of W is 57
    Hexadecimal value of o is 6F
    Hexadecimal value of r is 72
    Hexadecimal value of l is 6C
    Hexadecimal value of d is 64
    Hexadecimal value of ! is 21
 */


This example parses a string of hexadecimal values and outputs the character corresponding to each hexadecimal value. First it calls the Split(array<Char>[]()[]) method to obtain each hexadecimal value as an individual string in an array. Then it calls ToInt32(String, Int32) to convert the hexadecimal value to a decimal value represented as an int. It shows two different ways to obtain the character corresponding to that character code. The first technique uses ConvertFromUtf32(Int32), which returns the character corresponding to the integer argument as a string. The second technique explicitly casts the int to a char.

C#
string hexValues = "48 65 6C 6C 6F 20 57 6F 72 6C 64 21";
string[] hexValuesSplit = hexValues.Split(' ');
foreach (String hex in hexValuesSplit)
{
    // Convert the number expressed in base-16 to an integer.
    int value = Convert.ToInt32(hex, 16);
    // Get the character corresponding to the integral value.
    string stringValue = Char.ConvertFromUtf32(value);
    char charValue = (char)value;
    Console.WriteLine("hexadecimal value = {0}, int value = {1}, char value = {2} or {3}",
                        hex, value, stringValue, charValue);
}
/* Output:
    hexadecimal value = 48, int value = 72, char value = H or H
    hexadecimal value = 65, int value = 101, char value = e or e
    hexadecimal value = 6C, int value = 108, char value = l or l
    hexadecimal value = 6C, int value = 108, char value = l or l
    hexadecimal value = 6F, int value = 111, char value = o or o
    hexadecimal value = 20, int value = 32, char value =   or
    hexadecimal value = 57, int value = 87, char value = W or W
    hexadecimal value = 6F, int value = 111, char value = o or o
    hexadecimal value = 72, int value = 114, char value = r or r
    hexadecimal value = 6C, int value = 108, char value = l or l
    hexadecimal value = 64, int value = 100, char value = d or d
    hexadecimal value = 21, int value = 33, char value = ! or !
*/


This example shows another way to convert a hexadecimal string to an integer, by calling the Parse(String, NumberStyles) method.

C#
string hexString = "8E2";
int num = Int32.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
Console.WriteLine(num);
//Output: 2274


The following example shows how to convert a hexadecimal string to a float by using the System..::.BitConverter class and the Int32..::.Parse method.

C#
string hexString = "43480170";
uint num = uint.Parse(hexString, System.Globalization.NumberStyles.AllowHexSpecifier);

byte[] floatVals = BitConverter.GetBytes(num);
float f = BitConverter.ToSingle(floatVals, 0);
Console.WriteLine("float convert = {0}", f);

// Output: 200.0056          


The following example shows how to convert a byte array to a hexadecimal string by using the System..::.BitConverter class.

C#
byte[] vals = { 0x01, 0xAA, 0xB1, 0xDC, 0x10, 0xDD };

string str = BitConverter.ToString(vals);
Console.WriteLine(str);

str = BitConverter.ToString(vals).Replace("-", "");
Console.WriteLine(str);

/*Output:
  01-AA-B1-DC-10-DD
  01AAB1DC10DD
 */


C# calling Fortran function in DLL
=====================================
1. Write the Fortran function in a module and compile to save as DLL.
Example: The module below is compiled into the CallbackF90.dll
module mod1
    contains
    subroutine Sample_dll(nSize, nOut)
    !DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS:'_Sample_dll'  :: Sample_dll
    !DEC$ ATTRIBUTES REFERENCE :: nSize, nOut
        implicit none
        INTEGER(4), INTENT(IN) :: nSize    
        INTEGER(4), INTENT(OUT) :: nOut
        call Sample(nSize, nOut)
    end subroutine Sample_dll
    subroutine Sample(nSize, nOut)
        implicit none
        INTEGER(4), INTENT(IN) :: nSize    
        INTEGER(4), INTENT(OUT) :: nOut
        nOut = 2* nSize
    end subroutine Sample
end module mod1

Note the following:
i) The name of the function to be exported becomes Sample_dll.
ii) All variables are exported as REFERENCE


2. Copy the CallbackF90.dll into the C# project's bin/Debug or bin/Release directory.

3. In the C# code example:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace CallbackCS
{
    class Program
    {
        [DllImport("CallbackF90.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern void Sample_dll([In, Out] ref int nSize, [In, Out] ref int nOut);

        static void Main(string[] args)
        {
            Console.WriteLine("Start");
           
            int iOut;
            int iIn;
            iIn = 3;
            iOut = 0;
            Sample_dll(ref iIn, ref iOut);
            Console.WriteLine("{0,5:D} and {1,5:D}", iIn, iOut);

            Console.WriteLine("End");
            Console.ReadLine();
        }
    }
}

Note the following:
i) Use of System.Runtime.InteropServices is needed.
ii) The Fortran DLL function interface is revealed via the DLLIMPORT statement, and the use of
"public static extern void" for Fortran's subroutine.
iii) Note the use of "ref" in the interface.
iv) Note the use of [In, Out]
v) Call the function using the name Sample_dll.


Destructors, Finalize and IDisposable
==========================
There are two main ways to clean up the managed heap.
1. Using Destructors / Finalize
Example:
   class MyClass{
      ~MyClass() { //implementation }
   }
The destructor above has the same function as below.
Example:
   protected override void Finalize(){
      try {  // implementation  }
 finally{ base.Finalize(); }
   }

   The above method is not guaranteed when it will happen. It depends on when the garbage collector will kick in and
   is non-deterministic.

2. A better, more deterministic way is to implement the IDisposable interface.
Example:
   class MyClass : IDisposable {
      public void Dispose() { // implementation }
   }
 
 Two ways to use this are:
 a) MyClass mc = null;
    try{
mc =  new MyClass();
    }
finally{
    if (mc != null) {mc.Dispose();}
    }
b) the above is the same as:
    using(MyClass mc =  new MyClass())
{  do stuff   }


Reading XML structure with XMLDocument and XPathNavigator
===========================================================
C# allows the user to read an xml file and navigate through the nodes using the
combination of XMLDocument and XPathNavigator.

To explain via the example below:
----------------------------------------------
            // sFile is the name of the file to read
Program aprog = new Program();
            XmlDocument doc = new XmlDocument();
            FileStream fs = new FileStream(aprog.sFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);

            doc.Load(fs) ; // or doc.Load(aprog.sFile);

// Method 1
XmlNodeList xmlnode = doc.GetElementsByTagName("system.web");
            XmlNode aNode;
            for (int ii = 0; ii < xmlnode.Count; ii++) {
                aNode = xmlnode[ii];
                //Console.WriteLine(aNode.InnerXml);
            }
           
// Method 2
            XPathNavigator xpath = doc.CreateNavigator();
            XPathNodeIterator xpIter = xpath.SelectDescendants("add", "", false);  //appSettings
            while (xpIter.MoveNext()) {
                Console.WriteLine("name: " + xpIter.Current.Name);
                Console.WriteLine("value: " + xpIter.Current.Value);
                Console.WriteLine("attribute-key: " + xpIter.Current.GetAttribute("key", "") );
                Console.WriteLine("attribute-value: " + xpIter.Current.GetAttribute("value", ""));
            }
----------------------------------------------
Note that method 1 which uses the GetElementsByTagName returns a list of XmlNode, but the contents
of this node is a text, rather than a sub-node structure.

XPathNavigator (Method 2) is more versatile as it allows us to choose and keep the node structure.

Looking at Method 2 in detail:
1. Load the xml file into the XmlDocument, eg:
            doc.Load(fs) ;

2. Create the XPathNavigator from the XmlDocument
            XPathNavigator xpath = doc.CreateNavigator();

3. Use a variety of methods from XPathNavigator to drill down on a specified node. The example
here uses the SelectDescendants method to look for the node called "add"
            XPathNodeIterator xpIter = xpath.SelectDescendants("add", "", false);  //appSettings

4. WARNING: To navigate through the XPathNodeIterator list, we must MOVE once before actually getting
the First node of the structure. This is best done in the while loop below.
while (xpIter.MoveNext()) {
                Console.WriteLine("name: " + xpIter.Current.Name);
                ....
}

The example xml to read from may look like this:
-----------------------------------
<?xml version="1.0"?>

<configuration>
  <appSettings>
    <add key="environ_name_text" value="Debug"/>
    <add key="vers_id_text" value="0.0.1.0"/>
  </appSettings>
-----------------------------------

5. In the example above, the "add" node has NO value, but it has 2 attributes, viz "key" and "value".


C# How to - Create and use a Toggle Button as a Web User Control
==============================================================
Part 1: Creating the Toggle Button as Web User Control.
1. Create the control by going to your Project and Add New Item -> Web User Control. (This needs to be
   a web project). Give the name WUC_ToggleButton.ascx to this control.
2. By now these files are created:
   WUC_ToggleButton.ascx  -> HTML kind of page
   WUC_ToggleButton.ascx.cs   -> where you add code
   WUC_ToggleButton.ascx.designer.cs  -> auto-generated - DO NOT touch this.
3. Double click on the WUC_ToggleButton.ascx file from Solution Explorer, then choose the Design tab.
   Open up Toolbox from View menu, and drag the Button from Toolbox, onto the design are of WUC_ToggleButton.ascx.
4. Go back to the Design view of WUC_ToggleButton.ascx and right click on the button. In the Properties panel,
   rename the button to btnToggle01.
5. Double click on th btnToggle01 and the following code will be added to the source file  WUC_ToggleButton.ascx.cs:
        protected void btnToggle01_Click(object sender, EventArgs e)
        {

        }
 6. Add the following sections of code to the WUC_ToggleButton.ascx.cs class:
********************************************************
        public event EventHandler eventToggle_On;
        public event EventHandler eventToggle_Off;

        // Toggle State
        public enum ToggleButtonState
        {
            On = 0,
            Off = 1,
        }
        public ToggleButtonState toggleState
        {
            get
            {
                if (ViewState["toggleState"] == null)
                    ViewState["toggleState"] = ToggleButtonState.On;
                return (ToggleButtonState)ViewState["toggleState"];
            }
            set { ViewState["toggleState"] = value; }
        }


        // Toggle parameters: Allow user to specify on, off labels as parameters via html link in Designer
        public string onText;
        public string offText;

        public string OnText
        {
            get { return onText; }
            set { onText = value; }
        }
        public string OffText
        {
            get { return offText; }
            set { offText = value; }
        }
********************************************************
There are 3 main sections above:
a) The Toggle State code enable us to design how the toggle operation should be carried out.
b) The Toggle Parameters enable allow the designer to specify text to describe the toggle states via the
HTML-like aspx design page (more details later). So the user of this WUC can specify "on/off", "show/hide"
to represent the states.
c) The EventHandler allow the WUC to pass control back to the main caller routine to execute specific code.

7. Add the code logic for the Click event for toggle button in WUC_ToggleButton.ascx.cs :
***********************      
        protected void btnToggle01_Click(object sender, EventArgs e)
        {
            if (this.toggleState == ToggleButtonState.On)
            {
                toggleState = ToggleButtonState.Off;
                btnToggle01.Text = this.OffText;
                if (eventToggle_On != null)
                {
                    eventToggle_On(this, new EventArgs());
                }
            }
            else
            {
                toggleState = ToggleButtonState.On;
                btnToggle01.Text = this.OnText;
                if (eventToggle_Off != null)
                {
                    eventToggle_Off(this, new EventArgs());
                }
            }
        }
***********************
Note that the Toggle action need only the switch of toggleState. The 2 extra features of this
Toggle button are:
1) Changing text on the button, as done using btnToggle01.Text
2) Passing the event via eventToggle_On/Off back to the caller, which must have registered the events.


8. If you look at the Source of WUC_ToggleButton.ascx, you will find these lines:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WUC_ToggleButton.ascx.cs" Inherits="WebMenu.WUC_ToggleButton" %>
 <asp:Button ID="btnToggle01" runat="server" OnClick="btnToggle01_Click" Text="Button" />
       
Part 2: Using the Toggle Button Web User Control
1. Open the *.aspx file, example default.aspx, and go to Design view.
2. Drag and drop the WUC_ToggleButton.ascx from the Solution Explorer unto the design view.
3. Open up the default.aspx Source view and confirm the following lines are added automatically:
***********
<%@ Register Src="WUC_ToggleButton.ascx" TagName="WUC_ToggleButton" TagPrefix="uc1" %>
<uc1:WUC_ToggleButton ID="WUC_ToggleButtonA" runat="server" toggleState="On" OnText="Show" OffText="Hide" />      
***********
4. In the Source view for Design.aspx, add the toggleState, OnText, OffText attributes as follows:
<uc1:WUC_ToggleButton ID="WUC_ToggleButtonA" runat="server" toggleState="On" OnText="Show" OffText="Hide" />      
toggleState - specifies the initial state of the button
OnText - lets the user define the text shown on button when state is On
OffText - lets the user define the text shown on button when state is Off.
5. The Toggle button also allow the caller page to specify what operations to perform by using event
handlers. To initialize the event handlers, in the Page_Load method of the caller default.aspx,
            WUC_ToggleButtonA.eventToggle_On +=new EventHandler(WUC_ToggleButtonA_eventToggle_On);
            WUC_ToggleButtonA.eventToggle_Off +=new EventHandler(WUC_ToggleButtonA_eventToggle_Off);
This adds two event handlers to the Toggle Button. The caller default.aspx can now define the methods below
to perform the desired operations:
private void WUC_ToggleButtonA_eventToggle_On(object sender, EventArgs ev)
private void WUC_ToggleButtonA_eventToggle_Off(object sender, EventArgs ev)

Part 3: Pass Data or information via Events from Toggle Button WUC back to the caller
1. Derive an EventArgs class to pass the desired information, eg:
   public class myEventArgs : EventArgs{
      public string message;
      public myEventArgs(string msg){ message = msg; }
   }
2. To use this new Event class, create a new delegate class to represent the new Event signature:
        public delegate void myEventHandler(object sender, myEventArgs e);
3. Use the new EventHandler in the WUC_ToggleButton.ascx.cs, instead of
        public event EventHandler eventToggle_On;  
   we now have
        public event myEventHandler eventToggle_On;
4. The code for raising the events needs to submit the required two pieces of information as event parameters.
In part 1, step 7, in the btnToggle01_Click method, instead of:
                if (eventToggle_On != null)
                {
                    eventToggle_On(this, new EventArgs());
                }
we have the following:
                if (eventToggle_On != null)
                {
myEventArgs eventInfo = new myEventArgs("some message");
                    eventToggle_On(this, eventInfo);
                }
5. In the caller code default.aspx.cs (part 2, step 5), the user defined method:
private void WUC_ToggleButtonA_eventToggle_On(object sender, EventArgs ev)
can be changed to
private void WUC_ToggleButtonA_eventToggle_On(object sender, myEventArgs ev)
Note that ev now has the message "some message" which can be accessed via:
    ev.message.

Boxing and Unboxing
====================
Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap. Unboxing extracts the value type from the object. In the following example, the integer variable i is boxed and assigned to object o.

int i = 123;      // a value type
object o = i;     // boxing
int j = (int)o;  // unboxing

In relation to simple assignments, boxing and unboxing are computationally expensive processes. When a value type is boxed, a new object must be allocated and constructed. To a lesser degree, the cast required for unboxing is also expensive computationally.


Dispose, Finalize, Finally, Close
===================================
Ref: http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae

Dispose
- for unmanaged objects
- executes when user calls it - hence we know exactly when it gets executed.
- need to implement the IDisposable interface.


Finalize
- to be performed by GC at underterministic time.
- are Destructors in C# and .Net.
- is called when a reference object is garbage collected.
- the base class Object has Finalize method which does nothing. Usually we override the
  base method with our own Finalize.
- Implementation of finalize
   class MyClass {
     ~MyClass() { .... }
   }
   the compiler will see the above as:
   protected override void Finalize(){
      try{
.....
 } finally{
    base.Finalize();
 }
   }
- CLR uses single thread for Finalize method. If there are many finalize (ie. destructors)
  being used, then performance is impacted.

Dispose and Finalise pattern. This is used together for the benefits of both. The IDisposable
interface is implemented for users to call the Dispose, BUT, also imlements a destructor (Finalize)
 as a safety mechanism in case Dispose() is not called. The design pattern is:

public class ComplexCleanupBase : IDisposable{
    // some fields that require cleanup
    private bool disposed = false; // to detect redundant calls
    public ComplexCleanupBase()   {
        // allocate resources
    }
    protected virtual void Dispose(bool disposing)    {
        if (!disposed)        {
            if (disposing)            {
                // dispose-only, i.e. non-finalizable logic
// clean up managed objects by calling their Dispose methods()
            }
            // shared cleanup logic
// cleanup unmanaged objecs
            disposed = true;
        }
    }
    ~ComplexCleanupBase()    {
        Dispose(false);
    }
    public void Dispose()    {
        Dispose(true);
        GC.SuppressFinalize(this);  // tells the GC that it does not have to garbage collect here.
    }
}

Finally - part of the try, catch, finally block
- recommend to call Dispose methods in finally blocks
- File and Database handlers can call Close() in the finally block.


XML Serialization
===================
0. Prerequisites:
using System.Xml.Serialization;  // Does XML serializing for a class.


1. Define the classes to serialize. The HomeAddress class does not get serialize into a node by itself. But it serves to be
a component of Client class which is a root node.
[Serializable]     // need this attribute for BINARY serialization
public class HomeAddress {
/// Default constructor for this class (required for serialization).
public HomeAddress() { }

// this field should be serialized as an XML attribute instead of an element
[XmlAttribute]
public string Address = null;
}

    [XmlRootAttribute("Client", Namespace = "", IsNullable = false)]
    public class Client    {
        public Client()        /// Default constructor for this class (required for serialization).        {        }

        // Set this 'DateTimeValue' field to be an attribute of the root node.
        [XmlAttributeAttribute(DataType = "date")]
        public System.DateTime DateTimeV;

        // By NOT specifing any custom Metadata Attributes, fields will be created as an element by default.
        public int ClientID;
        public int Age;

        // Set serialization to IGNORE this field (ie. not add it to the XML).
        [XmlIgnoreAttribute()]
        public bool ClientBalance;

        // Serializes an ArrayList as a "HomeAddresses" array of XML elements of custom type HomeAddress named "HomeAddress".
        [XmlArray("HomeAddresses"), XmlArrayItem("HomeAddress", typeof(HomeAddress))]
        public System.Collections.ArrayList HomeAddresses = new System.Collections.ArrayList();
    }




2. Serialize (write to file)
To Binary:
   T  serializableObject;   // class type T
            using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate))
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(fileStream, serializableObject);
            }

To XML text:
            T serializableObject;
   string path;
   System.Type[] extraTypes;

   using (TextWriter textWriter = new StreamWriter(path))            {
                Type ObjectType = typeof(T);
                XmlSerializer xmlSerializer = null;
                xmlSerializer = new XmlSerializer(ObjectType, extraTypes);   // tell it which type class to serialize.
                xmlSerializer.Serialize(textWriter, serializableObject);
            }


3. De-Serialize (read from file)
To Binary:
            string path;
            T serializableObject = null;
            using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate))            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                serializableObject = binaryFormatter.Deserialize(fileStream) as T;
            }


To XML text:
            string path;
   System.Type[] extraTypes;
            T serializableObject = null;
            using (TextReader textReader = new StreamReader(path))            {
                Type ObjectType = typeof(T);
                XmlSerializer xmlSerializer = null;
                xmlSerializer = new XmlSerializer(ObjectType, extraTypes);
                serializableObject = xmlSerializer.Deserialize(textReader) as T;
            }


Assemblies
============
Features of Assemblies:
- Self-describing. Contains meta-data to describe itself.
- Version Dependencies - are stored inside the manifest. Stores the version number of any referenced assemblies
  in the manifest.
- Assemblies can be loaded side by side. Two or more versions of the same assemblies can be loaded together.
- Application Domain - ensures that multiple applications can be runned within a single process, if they are
  in different application domains. The only way these different application domains can interact within the same
  process is via a proxy.
- Installation can be as easy as copying the files that belong to the assembly.

Application Domains
- AppDomain.CurrentDomain.FriendlyName - returns the name of the App Domain
- AppDomain.CreateDomain("New Domain Name") - To create a new appDomain -
- anAppDomain.ExecuteAssembly("AssemblyA.exe") - to execute (the Main method) of Assembly A.
- anAppDomain.CreateInstance(.....) - will execute the constructor and create a new instance of the class of the specified Assembly.

Components of Assembly
- Can be contained within a single file or spread over multiple files. Assembly is the installation units.
i) Assembly Metadata
ii) Type Metadata
iii) IL Code
iv) Resources

Private Assemblies - put in the same directory or sub-directory of the application.
Shared Assemblies - needs a Srong Name which consist of Version Number.
    - require public key, version and culture.
- reference of the required assembly is recorded in the manifest of the client assembly, including name, public key token and version.
- GAC and code bases specified in the config files are checked, followed by application directories and then probing rules applied.

Viewing Asemblies - use ildasm tool

Modules = a DLL without assemblies attributes (it can be added to assemblies later)
- to create a module from the C# file A.cs:   csc /target:module A.cs
  the output is A.netmodule
- to include the module in another DLL assembly:
      csc /target:library  /addmodule:A.netmodule /out:B.dll
- Advantages of modules
      - allows faster startup of assemblies
 - modules are only loaded when needed
 - allows multiple programs in different languages (eg VB.Net, C#) to be compiled to individual modules, then combine them together in one single assembly.

CLS = Common Language Specification
    - defines the minimum requirement of types that must be supporeted by a .Net language.
CTS = Common Type Specification
    - defines how value types and referenced types  can be defined from a .Net language.

Configuration Settings:
Startup settings - specify version of runtime
Runtime settings - specify garbage collection, binding, version and code base.
Remoting settings - to configure apps using .Net Remoting
Security settings - configuration for cryptography and permissions

Application Config file - *.config, web.config -  the latter is for ASP.Net applications.
   Placed at the same directory as the executable.
Machine config file - <runtime install path>/config/Machine.config
   The specifications in the machine config is overriden by those in the Application config.
Publisher policy files - kept in GAC
    Used by component creator to specify that a shared assembly is compatible with older version.







CLS Compliant Requirements
===========================
To enable cross language programming withing the .Net languages, the components need to satisfy CLS requirements.
To make the Assembly CLS compliant so that it can be used by other .Net languages, set the following attribute to the AssemblyInfo.cs:      [assembly: System.CLScompliant(true)]

The compiler will then issue an error message if any components are not CLS compliant.
However, some methods within the CLS compliant assembly, can be made non-CLS compliant by:
        [CLSCompliant(false)]
void Method(uint i) { ........ }

The specific requirements to be CLS compliant (applies only to public and protected methods, since private methods do not need to be CLS compliant) are:
- All argument types in methods must be CLS compliant.
- Array elements must have CLS compliant type and must be 0-based arrays.
- A CLS compliant class must inherit from CLS compliant class. The class System.Object is CLS compliant.
- Method names in CLS compliant classes are not case sensitive. Even so, method names need to be different, more than just different in case.
- Enumerations must be of type Int16, Int32, Int64.

Global Assembly Cache (GAC)
=============================
Native Image Generator - to compile MSIL into native code.
   - native image will be stored in the Native Image Cache (NIC), part of the GAC.
   - only beneficial to compile to native code if all assemblies it uses are in native code.
   - to display assemblies in the NIC:
           ngen /show <class name>,                  
      eg where <class name> = System.Windows.Forms
   - Do not delete original MSIL code, even after it is compiled into native code because meta-data are found in MSIL but not in the native code.

To view the GAC, use the GAC Viewer, go to Windows Explorer and type in the path:
   <windows Dir>\assembly
To see the Native Images or MSIL assemblies, go to CMD console and:
   <windows Dir>\assembly\GAC...
   <windows Dir>\assembly\NativeImages...

To install / uninstall or view assemblies, MSIL or Native, use gacutil.exe

Sharing an Assembly:
   - by default, assemblies are not shared.
   - shared assemblies have Strong Names. Strong names are composed of
i) assembly name
ii) version number
iii) public key that guarantees strong name is unique.
iv) culture
   - shared assemblies can be signed.

Global Assembly Cache Utility (gacutil.exe)
- gacutil /l = lists all assemblies
- gacutil /i mydll = installs the shared assembly into the assembly cache
- gacutil /u mydll = uninstalls the assembly
- gacutil /ungen mydll = uninstalls the assembly from the native image cache

 Steps to create a Shared Assembly
1. Create a public/private key pair, using the Strong Name Utility(sn.exe)
         sn - k mykey.snk
2. In the AssemblyInfo.cs, ensure the following is in the file:
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("../../mykey.snk")]
[assembly: AssemblyKeyName("")]
      Note that the assembly is treated as if running from %ProjectDirectory%\obj\<configuration>. So the above path assumes the key file is in the Project Directory.
3. Install the shared assembly:
      gacutil /i SharedDemo.dll
When the shared assembly is compiled, the public key is also embedded in the manifest of the shared assembly.
When a client uses the shared assembly by referencing it, then at compilation, the public key (actually, the token of the hash of the public key) of the shared assembly is written to the client assembly.

For encryption, see section on "Public Key Cryptography"

Delayed Signing of Assembly
    During development, the assembly need not be signed yet, but can be delayed until final release.
i) Create the public/private key pair.
      sn -k mykey.snk
ii) Extract the public key to give to others
      sn -p mykey.snk mykeypub.snk
iii) Developers modify their AssemblyInfo.cs from above to the following:
      [assembly: AssemblyDelaySign(true)]
      [assembly: AssemblyKeyFile("../../mykeypub.snk")]
iv) Turn off verification since assembly has no signature
      sn -Vr SharedDemo.dll
v) Before distributing the assembly, it can be signed, (or re-sign existing assembly) with:
      sn -R MyAssembly.dll mykey.snk

References: Assemblies can have a reference count such that it prevents the assembly from being deleted, unless it is properly uninstalled with its intended application. It can be referenced using the keywords: UNINSTALL_KEY, FILEPATH, OPAQUE.
To install:
    gacutil /i sharedemo.dll /r FILEPATH <path of app> "Shared Demo"
gacutil /i sharedemo.dll OPAQUE 4711 "Opaque installation"
In the example above, the one dll has got 2 references. To delete the assembly from the GAC, it has to be uninstalled twice:
gacutil /u sharedemo OPAQUE 4711 "Opaque installation"
    gacutil /u sharedemo FILEPATH <path of app> "Shared Demo"


Public Key Cryptography
=========================
The following section below, although independent from C# and GAC and .Net, is required for understanding the implementation of encrypting the Assembly. Consider the example:
        Julian creates a public key (Jpu) and a private key (Jpr)
        Sarah creates a public key (Spu) and a private key (Spr)
Sarah wish to send an encrypted mail to Julian.
Sarah encrypts the mail using Jpu.
To verify that the mail is actually from Sarah, she encrypts her signature using Spr and embeds this inside the mail, before encrypting the whole mail with Jpu.
When Julian receives the encrypted mail, he decrypts it using Jpr.
In the mail, Julian finds Sarah's encrypted signature.
Julian decrypts the signature using Spu.
Now Julian can verify that the mail is from Sarah.


Versioning shared assemblies and .Net Framework Runtime
=========================================================

Versioning:
Using different versions of Shared Assembly - multiple versions of the same shared assembly can be put into the GAC.

To direct each application to link to a specific version of the Shared Assembly, edit the applications configuration file.

An example of the XML application configuration file is:
<runtime>
   <assemblyBinding>
      <dependentAssembly>
         <assemblyIdentity name="SharedDeom" publickeytoken="....">
         <bindingRedirect oldVersion="1.0.0.0-1.0.999.9999"   New Version="1.0.1218.23234">

checking the manifest contents:
.assembly extern SharedDemo
{
   .publickeytoken = { ..... }
   .ver 1:0:1218:23234
}

The application configuration can also be changed via:
Control Panel - Administrative Tool - .Net Framework 2.0 Configuration
In the menu, Action - Add,
then choose the application - and create a configuration for this application
Under the application's tree, select Assembly Dependencies and change the version number.



To specify a default version for the Shared Assembly, go to the same .Net Framework Configuration tool as specified above.
Under ConfiguredAssembly, click Action - Add
A dialog will popup, then type:
   Requested Version: 1.0.0.0 - 1.0.999.9999
   New Version: 1.0.1218.23234


To make the new version of the shared assembly to be used by all applications, even not knowing which applications actually uses it, the method involves setting up Publisher Policy files.
1. Create publisher policy files
   - copy the xml application config file, in example above, and rename to eg "mypolicy.config"
2. Create publisher policy assembly
   - in the command line type:
     al /linkresource:mypolicy.config /out:policy.1.0.SharedDemo.dll /keyfile:....\mykey.snk
   - note the name of the policy file MUST start with "policy" followed by the major and minor numbers.
3. Add publisher policy assembly to GAC.
   - gacutil -i policy.1.0.SharedDemo.dll

To override the Publisher Policy, go to the .Net Framework x.x configuration tool (described above), and go to the shared assembly property. In the shared Assembly's property dialog:
in the General tab, uncheck "Enable publisher policy".


Fixing .Net Application
To fix or restore a .Net application because of corrupted configuration or conflict in new assemblies:
- open the .Net Framework configuration from Control Panel - Administrative Tools
- Click on the link: Fix An Application.
- A dialog box pops up with the option to select different configuration and also a SafeMode
- Note: Using SafeMode will disable any Publisher policies



Using multiple .Net Framework Runtime
Several .Net Framework Runtime can be installed on the same computer. To specify a .Net Application to use multiple .Net Framework Runtime in preference, open the configuration file and edit the version as shown below:
<configuration>
    <startup>
         <supportedRuntime version="v1.1.4322" />
         <supportedRuntime version="v1.0.3512" />



Configuring Directories for Shared Assemblies
Shared assemblies does not need to be in the GAC and can be shared from different directories, servers (via LAN), or across the internet(via HTTP). The location of the assemblies can be specified by configuring the directories in the following manner.

i) <codeBase> method - For those assemblies in the GAC.
Open the .Net Framework Configuration tool (from Control Panel - Administrative Tools).
In the left panel, click on Configured Assemblies.
If the assembly is not listed, then right click on Configured Assemblies and Add the particular assembly, by choosing from the GAC.
If the assembly is not in the GAC yet, then first right click on the Assembly Cache and add the particular assembly.
When the assembly is listed in the Configured Assemblies, right click on the particular assembly, choose Properties.
The assembly's properties dialog appears with 3 tabs.
Click on the Codebases tab and fill in the following:
   Requested Version: eg 1.0
   URI: eg "http://blah/assemblyDir" or "file:C:/assemblyDir"

ii) Probing method - this applies when the shared assembly is not in the GAC.
When the application that uses the shared assembly runs, by default it will look through some directories in order. The list of directories that it looks through can be configured by two ways:
- via the .Net Framework Configuration - under Applications (add the application if not there yet) - Properties. In the Properties dialog, fill in the "Relative search path for additional assemblies".
- via application's XML config file:
    <configuration>
 <runtime>
     <gcConcurrent enabled="enabled" />
 <assemblyBinding xmlns="urn:shemas-microsoft-com:asm.v1">
     <probing privatePath="bin;utils;" xmlns="" />
Note that the directories specified here must be under the application's base directory. If the assembly is outside the base directory, then use the codeBase method.


.Net Remoting
===============
Ref: Chap 16, Professional C# 3rd Edition, Robinson et. al.

.Net Remoting is for accessing objects in another application domain. Communicate between client - server, protocol include HTTP and TCP, able to use SOAP objects.

XML Web Services make use of SOAP protocol, able to call methods across the network in the server application. The goal of .Net Remoting is slightly different.

Goals for .Net Remoting: to be able to use
- Any Application Type : console app, Windows app, Windows service, COM+ component. Good for peer to peer communication.
- over Any Transport : HTTP and TCP using classes HttpChannel and TcpChannel. Also allow UDP, IPX, SMTP, shared memory, message queueing to be build.
- using any Payload Enconding: SOAP encoding, Binary encoding. Note only SOAP RPC style, not DOC style is supported.

- .Net Remoting is plaform dependent. Note XML Web Services is platform independent.
- CLR Object Remoting - where .Net Remoting extends CLR object functionality to include activation, distributed identities, lifetime and call contexts.

.Net Flow
On the client side Application Domain:
- Client eg calls HelloWorld() in a remote object by calling the TransparentProxy.
- TransparentProxy - enables clients to call methods implemented by the remote object. This calls the Invoke() method which uses message sinks to pass message to the Channel.
- RealProxy - uses message sink to pass message sinks to the Channel. However, the sink can intercept the messages and allow it to be processed before sending it to the Channel.
- Envoy Message Sinks - Can be used as interceptors to process the messages before going into the Channel. Real Proxy will pass the message to the first Envoy sink. The envoy sink can be debugging sinks, security sinks, synchronization sinks.
- Channel - the messages are serialized with the Formatter (SOAP or binary) before going to the server.
- Summary:
   Client (Hello) -> Transparent Proxy (Invokes()) -> real proxy (Process Message) -> Envoy sink -> Channel -> Formatter (Serialize)



On the server side:
- Channel - receives the messages and deserialize with the Formatter (SOAP or binary), then calls Server Context Sinks.
- Server Context Message Sinks - the message gets passed through the first to the last Server Context Sinks, then passed to the Object Context Message sinks. A sinlge server context sink can be used to access a number of object context sink.
- Object Context Message Sinks - the message gets passed through the first to the last Object Context Sinks, then passed to the remote object.
- Summary:
Formatter (Deserialize) -> Channel (Process Message) -> Server context sink (Process Message) -> object context sink (Hello) -> Remote Object

Context
- A context is a boundary containing a collection of objects.
- Used to group objects with similar execution requirements.
- Class derived from MarshalByRefObject are bound to application domain. Calling this from outside the application domain needs a proxy.
- Class derived from ContextBoundObject that is derived from MarshalByRefObject are bound to a context. Calling this from outside the context needs a proxy.
- ContextBoundObjects can have Context Attributes which define the Context Properties.
- Message Sinks are interceptors of method calls between different context bound objects. Message Sinks are contributed by Context Properties.
- Synchronization Attribute defines the synchronization property of the object.
- Communication between objects of different context requires a Proxy. The proxy creates a message that is transferred to a channel and is intercepted by a sink.
- A new context is created / instantiated when an instance of a class is created and the properties of the current context (of the class that creates the new instance of a class) is not acceptable to the attribute classes of the target class.
- Communication between contexts - The client uses a proxy. The proxy creates a message that is transferred to a channel and intercepted by sinks. The channel is a CrossContextChannel.

Remote Objects, Clients and Servers
Example:
    HelloClient( +Main() ) ---> Hello( +Greeting() ) ---> MarshallByRefObject
    HelloServer( +Main() ) ---> Hello( +Greeting() ) ---> MarshallByRefObject
   
Remote Object
- example is Hello, has the ordinary method Greeting()
- create this as a class project eg call this RemoteHelloObject. It will result in a dll.
- derived from System.MarshalByRefObject
- confined to the application domain.
- A proxy is used to communicate with the Remote Object from another application domain.

public class Hello : MarshalByRefObject    {
        public Hello() { Console.Out.WriteLine("Hello Constructor called"); }
        ~Hello(){Console.Out.WriteLine("Hello Destructor called"); }
        public string Greeting(string name)  {
            Console.WriteLine("Hello Greeting called");
            return "Hello, " + name;
        }
    }


Server for Remote Object
- example is HelloServer
- create this as a console application, ie. with a Main class
- add reference to System.Runtime.Remoting
- Add the following using statements:
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
- Add a reference and USING statement to the RemoteHelloObject
- Add the following code in the Main method:
- create a tcp channel
            TcpServerChannel channel = new TcpServerChannel(8086);
- register the channel to make it available for remote object
            ChannelServices.RegisterChannel(channel, false);
- register the remote object type
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(Hello), "Hi", WellKnownObjectMode.SingleCall);
Remote objects can be registered to be
 i) stateless - using "SingleCall" when registering the remote object above; or
 ii) stateful - also called "client activated" objects.
After registration, the server needs to be kept running, hence at the end of the Main method, add:
            System.Console.WriteLine("Press return to exit");
            System.Console.ReadLine();

public class HelloServer    {
        public static void Main(string[] args)        {
            TcpServerChannel channel = new TcpServerChannel(8086);
            ChannelServices.RegisterChannel(channel, false);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(Hello), "Hi", WellKnownObjectMode.SingleCall);
            System.Console.WriteLine("Press return to exit");
            System.Console.ReadLine();
        }
    }


Client for Remote Object
- example is HelloClient
- create this as a console application, ie. with a Main class
- add reference to System.Runtime.Remoting
- Add a reference and USING statement to the RemoteHelloObject
- Add the following code in the Main method:
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

- create a tcp channel that's registered in Channel Services
            ChannelServices.RegisterChannel(new TcpClientChannel(), false);
- create Activator class to return proxy to the remote object
Hello obj = (Hello)Activator.GetObject(typeof(Hello), "tcp://localhost:8086/Hi");
- checking if the server is located
            if (obj == null) { .... }
- using the remote object
            Console.WriteLine(obj.Greeting("my name"));

   class HelloClient    {
        static void Main(string[] args)        {
            ChannelServices.RegisterChannel(new TcpClientChannel(), false);
            Hello obj = (Hello)Activator.GetObject(typeof(Hello), "tcp://localhost:8086/Hi");
            if (obj == null)            {
                Console.WriteLine("Could not locate server.");
            }
            for (int ii = 0; ii < 5; ii++)            {
                Console.WriteLine(obj.Greeting("Christian"));
            }
        }
    }


To run the client server, open 2 Command Terminals. In each terminal, run the RemoteHelloServer and RemoteHelloClient respectively.

Channels
- Two types:
   HTTP - standard web type channel using HTTP protocol.
   TCP - can be more efficient than HTTP, but may need firewall to be open.
- Channels must implement IChannel class which has two properties:
   ChannelName
   ChannelPriority
- The two channels also support bindTo() to bind to a particular IP address.
- TCPserverChannel support rejectRemoteRequests to limit connections from local computer only.
- Additional channel interfaces are implemented:
   IChannelReceiver implemented by server channels
   IChannelSender implemented by client channels
- IChannelSender's (client) special methods
   CreateMessageSink() - used to put synchronous and asynchronous messages
- IChannelReceiver's (server) special methods
   StartListening()
   StopListening()
   ChannelData - stores the received data
- Channel Properties and sink providers can also be specified for channels as follows:

            IDictionary properties = new Hashtable();
            properties["name"] = "TCP channel with a SOAP formatter";
            properties["priority"] = "20";
            properties["port"] = "8085";
            SoapServerFormatterSinkProvider sinkProvider = new SoapServerFormatterSinkProvider();
            TcpServerChannel tcpchannel85 = new TcpServerChannel(properties, sinkProvider);
            ShowChannelProperties(tcpchannel85);

- Custom channels can be created to use other protocols besides TCP, HTTP.
  Sending part must implement IchannelSender. CreateMessageSink() for proxy to use to send messages to channel.
  Receiving part must implement IchannelReceiver. Listen to the ChannelData get property. Use ChannelService.SyncDispatchMessage() to dispatch message to object.

Formatter
- Two types (from System.Runtime.Serailization.Formatters):
  Binary.BinaryFormatter
  Soap.SoapFormatter
- Implements interface: System.Runtime.Remoting.Messaging.IRemotingFormatter.
  This has methods Serialize() and Deserialize() to transfer data to and from channel.
- Associated with Channels by formatter sink objects and formatter sink providers.
- Formatter sink providers, eg SoapServerFormatterSinkProvider
  Passed as an argument when creating a channel, eg. new TcpServerChannel(properties, new SoapServerFormatterSinkProvider())
  Implements IServerChannelSinkProvider, IClientChannelSinkProvider for server and client respectively.
  Both sink provider interfaces above has a method CreateSink() which returns SoapServerFormsatterSink object.
- Client side: SoapClientFormatterSink uses SoapFormatter.SyncProcessMessage() and SoapFormatter.AsyncProcessMessage() to serialize messages.
- Server side: SoapServerFormatterSink uses SoapFormatter classs to deserialize messages.

ChannelServices and RemotingConfiguration
- used to register channels into .Net Remoting runtime.
- used to access all registered channels, eg ChannelServices.RegisterChannel( new TcpChannel(8086) )
- ChannelServices.RegisteredChannels - returns a list of registered channels
- ChannelServices.getChannel - get a channel by name.
- RemoteConfiguration class
  on Server side: used to register remote object types for server activated (ie. WellKnown)  objects and marshal remote objects;
      eg RemotingConfiguration.RegisterWellKnownServiceType(typeof(Hello), "Hi", WellKnownObjectMode.SingleCall);.
 - can also be singleton above.
  on Client side: unmarshal a remote object to create a proxy from the object reference.
- WellKnownObjectMode.SingleCall - to create a stateless remote object, a new instance gets created with every call to the remote object.
  WellKnownObjectMode.Singleton - to create a stateful remote object, used to share data between clients. This is Ok for read-only but need to be careful for locking when read-write is involved.
- Server Side - Client activated (ie. Activated) objects - to hold state for a specific client.
  use RemotingConfiguration.RegisterActivatedServiceType(), not RegisterWellKnownServiceType(). No URI is provided because clients can instantiate different object types with the same URI. Instead client-activated objects are defined with ApplicationName. Eg.
    RemotingConfiguration.ApplicationName = "HelloServer";
    RemotingConfiguration.RegisterActivatedServiceType(typeof(Hello));
- Server Side - Server Activated Object
  This case is in the original example above and is done by:
    RemotingConfiguration.RegisterWellKnownServiceType(typeof(Hello), "Hi", WellKnownObjectMode.SingleCall);
  where the parameters above are <type>, <URI>, <mode>
   

Object activation
- Activating Well Known (Server Activated) Objects; Eg (from example code of the Client above)
     ChannelServices.RegisterChannel( new TCPClientChannel() );
Hello obj = (Hello)Activator.GetObject( type(Hello) , "tcp://localhost:8086/Hi");
  The GetObject() gets a proxy to a server-activated or well known remote object.
  An alternative to using the Activator.GetObject is:
      Hello obj = (Hello)RemotingServices.Connect(typeof(Hello) , "tcp://localhost:8086/Hi");
  Another alternative to use "new" instead of Activator is:
      RemotingConfiguration.RegisterWellKnownClientType(typeof(Hello) , "tcp://localhost:8086/Hi");
 Hello obj = new Hello();
  Note that the new operator above does not actually create a new remote object, it just returns a proxy similar to the method above.

- Activating Client Activated Objects;
      With the Activator.GetObject above, the remote object is destroyed when the method is finished.
 Using Activator.CreateInstance() to start making a client activated object, the object lives until lease time is finished.
 To continue to create remote objects, activation attributes need to be passed. Example

object[] attrs = {new UrlAttribute("tcp://localhost:8086/HelloServer") };
ObjectHandle handle = Activator.CreateInstance( "RemoteHello", "Wrox.ProCSharp.Remoting.Hello", attrs);
if(handle==null) {
   Console.WriteLine("could not locate server");
   return;
}
Hello obj = (Hello)handle.Unwrap();
Console.WriteLine(obj.Greeting("Christian"));

       Alternatively, the new operator can be used. This not only returns the proxy but also creates the remote object.

   RemotingConfiguration.RegisterActivatedClientType(typeof(Hello), "tcp://localhost:8086/HelloServer");
   Hello obj = new Hello();


- Client Side - Server activated object

- Client Side - Client activated object



Proxy Objects
- Transparent Proxy - looks like the remote object. Implement all public methods of the remote object. Calls the Invoke() of the real proxy and pass a message containing the methods to call
- Real Proxy - send message to channel with the help of message sinks.
- Activator.GetObject() and Activator.CreateInstance() returns proxy to the client - they are the two Transparent and Real proxies.
- RemotingServices.IsTransparentProxy(obj) to check if it is transparent proxy
- RemotingServices.GetRealProxy(obj) to get the RealProxy object.

Mesages
- The proxy sends messages into the channel. On the server side, a method call can be made after analyzing the message.
- Messages implement IMessage which has a single Properties, which has IDictionary which contain URI to object, MethodName, MethodSignature, TypeName, Args, CallContext.
- Can have direct access to method name, without using IDictionary, by using IMethodCallMessage, IMethodMessage. The hierarcy is:
     IMessage -> IMethodMessage ->  IMethodCallMessage -> {MethodCall, MethodCallWrapper}
                                ->  IMethodReturnMessage -> {MethodResponse, MethodReturnMessageWrapper, ReturnMessage}

Message Sinks
- Activator.GetObject() calls RemotingServices.Connect(). Connect() connects to a well known object and calls Unmarshal(). Unmarshal creates creates the proxy and envoy sinks.
- Proxy uses a chain of envoy sinks to pass the message to the channel.
- All sinks are interceptors and can be used to perform creating a lock, writing an event, perform security checking, etc.
- All message sinks implement IMessageSink with contains:
    - property NextSink -> points to next sink to pass message along.
- for synchronous messages, SyncProcessMessage() - has IMessage to send a message and to return a message.
- for asynchronous messages, AsyncProcessMessage() - 2 parameters, a message and a message sink that receives the reply.
- The types of sinks are:
    - Envoy sinks - ObjRef has EnvoyInfo property. Created from server context, so server can inject functionality to client. Can collect identity of client and pass info to server.
- Server Context sinks - Message received on the server side is passed to Server Context sinks. The last of these sinks route the message to the object sink chain.
- Object sink - associated with a particular object. If object defines particular context attributes, context sinks are created for the object.

Passing Objects in Remote Methods
- Marshal-by-value classes: Serializable attribute. Don't have remote identity - object that is serialized to client is independent to the server. Unbound classes - don't have data dependent on  application domain.
- Marshal-by-reference classes: Derive from MarshalByRefObject. Have remote identity - object not passed across wire, a proxy is returned instead. A specialized version is derived from ContextBoundObjects (which is derived from MarshalByRefObject) which require proxy when context are crossed, even in the same app domain.
- Non-remotable classes: Not serializable. Cannot be used as parameters in remote objects' public methods. Bound to the app domain which they are created in - eg used where class has a data meber valid in that app domain only.

Example: add the Marshal by Reference and Value classes, and their methods to the Remote Object class.
    [Serializable]
    public class MySerialized
    {
        protected int a;
        public MySerialized(int val)        {.....}
        public void Foo(){....}
    }   // End MySerialized class

public class MyRemote : System.MarshalByRefObject
    {
        protected int a;
        public MyRemote(int val)        {....}
        public void Foo(){....}
    } // End MyRemote class

Add wrapper of these two to the original remote class Hello:
        public MySerialized GetMySerialized() { return new MySerialized(4711); }
        public MyRemote GetMyRemote() { return new MyRemote(4712); }

Add the following to the client class HelloClient within its Main method.
            MySerialized ser = obj.GetMySerialized();
            if (!RemotingServices.IsTransparentProxy(ser))
            {
                Console.WriteLine("ser is not a transparent proxy");
            }
            ser.Foo();
            MyRemote rem = obj.GetMyRemote();
            if (!RemotingServices.IsTransparentProxy(rem))
            {
                Console.WriteLine("rem is not a transparent proxy");
            }
            rem.Foo();
   
Security and serialized object
- Since serializable objects are passed across networks, including private data, the data may be vulnerable in the serialization and deserialization phase.
- To overcome the security issue above, .Net Remoting has 2 levels of deserialization: low and full
- Default is Low level deserialization
- However ObjRef objects cannot pass via Low level deserialization unless they implement ISponsor and the following is done:
  Ex create a TCP channel with FULL serialization support - for Binary Format (SOAP format also possible)
 
  BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
  serverProvider.TypeFilterLevel = TypeFilterLevel.Full;


  BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();


  IDictionary props = new Hashtable();
  props["port"] = 6789;


  TcpChannel  channel = new TcpChannel(props, clientProvider, clientServer);
 


Lifetime Management
- How does client and server know that each other is there?
- Client detects if server is there - using System.Runtime.Remoting.RemoteException
- Server detects is client is there - using Leasing Distributed Garbage Collector (LDGC)
      - used for well known singleton objects and client activated objects (holds state).
      - when client activating object are referenced outside the application domain, a lease is created, with a lease time. When the lease time expires, the remote object is disconnected and garbage collected.
- Client calling a remote object where lease time has expired, will throw an exception. But the lease can be renewed via:
i) Implicit renewal - automatically renewed when a client calls an object -> RenewOnCallTime.
ii) Explicit renewal - client can specify lease time via GetLifetimeService() -> ILease.Renew().
iii) Sponsoring renewal - if require long live remote objects. Create sponsor using ISponsor and register using ILease.Register().
- Classes used for Lifetime management
i) ClientSponsor - used by client to extend lease.
ii) ILease - get all info about lease
iii) LeaseState - enumeration of the lease state
iv) LifetimeServices - get, set properties for lease of all remote objects in the app domain.
- Example of getting lease information
Change remoting configuration in HelloServer.cs
RemoteConfiguration.ApplicationName = "Hello";
RemoteConfiguration.RegisterActivatedServiceType(typeOf(Hello));
Change remote object instantiation in client, instead of using Activator.GetObject():
ChannelServices.RegisterChannel(new TcpClientChannel(), false);
object[] attrs = {new UrlAttribute("tcp://localhost:8086/Hello") };
    Hello obj = (Hello)Activator.CreateInstance(typeof(Hello), null, attrs);
To show leasing time:
ILease lease = (ILease).obj.GetLifetimeService();
if (lease != null){
Console.WriteLine .... lease.InitialLeasetime, lease.RenewOnCallTime, lease.SponsorshipTimeout, lease.CurrentLeasetime
Default leasetimes can also be tailored for each remote object, by overriding the InitializeLifetimeService() method. In add
Example:

  public class Hello : System.MarshalByRefObject{
public Hello() { // constructor }
public ~Hello() { // destructor }
public override Object InitializeLifetimeService(){
ILease lease = (ILease)base.InitializeLifetimeService();
lease.InitialLeaseTime = TimeSpan.FromMinutes(10);
lease.RenewOnCallTime = TimeSpan.FromSeconds(40);
return lease;
  }



Configuration Files
- XML file that can be any name with .config ending. Can also be in the main application config file.
Example on server side configuration

<configuration>
   <system.runtime.remoting>
      <application name="Hello">      ! name of remote application
    <service>                    ! on client, it has CLIENT instead of SERVICE
   ! can be wellknown or activated
! mode can be singleCall or Singleton
   <wellknown mode="SingleCall" type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" objectURI="Hi" />
</service>
<channels>
<channel ref="tcp" port="6791"/>
<channel ref="http" port="6792"/>
</channels> 
      </application>      
   </system.runtime.remoting>
</configuration>


On a client, the <wellknown> element is:
<wellknown type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" url="tcp://localhost:6791/Hello/Hi" />
For client activated objects:
   <activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" />

Predefined channels are found in machine.config in:
<windir>\Microsoft.Net\Framework\<version>\CONFIG

Server Configuration for well known objects:
<configuration>
   <system.runtime.remoting>
      <application name="Hello">      ! name of remote application
    <service>                    ! on client, it has CLIENT instead of SERVICE
   <wellknown mode="SingleCall" type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" objectURI="Hi" />
</service>
<channels>
<channel ref="tcp" port="6791" displayName="TCP Channel (Hello Server)/>
<channel ref="http" port="6792" displayName="HTTP Channel (Hello Server)/>
</channels>
      </application>    
   </system.runtime.remoting>
</configuration>
The assembly is RemoteHello, the remote object class is Hello and the object is Hi


Client Configuration for well known objects:
<configuration>
   <system.runtime.remoting>
      <application name="Client">    
    <client displayName="Hello client for well known objects">                  
<wellknown type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" url="tcp://localhost:6791/Hello/Hi" />
</client>
<channels>        ! no need to specify port - just use free port number
<channel ref="tcp" displayName="TCP Channel (HelloClient)/>
</channels>
      </application>    
   </system.runtime.remoting>
</configuration>

To use HTTP channels, change the above section to
    <client displayName="Hello client for well known objects">                  
<wellknown type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" url="http://localhost:6792/Hello/Hi" />
</client>
<channels>        ! no need to specify port - just use free port number
<channel ref="http" displayName="HTTP Channel (HelloClient)/>
</channels>


Server config for client activated objects. Changes are in the "application" and "service" elements:
<configuration>
   <system.runtime.remoting>
      <application name="HelloServer">    
    <service>                  
<activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello"  />
</service>
<channels>        ! no need to specify port - just use free port number
<channel ref="http" port="6788" displayName="HTTP Channel (HelloServer)/>
<channel ref="tcp" port="6789" displayName="TCP Channel (HelloServer)/>
</channels>
      </application>    
   </system.runtime.remoting>
</configuration>

Client config for client activated objects; changes in client element:
<configuration>
   <system.runtime.remoting>
      <application>    
    <client url="http://localhost:6788/HelloServer" displayName="Hello client for client activated objects">                  
<activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello"  />
</client>
<channels>        ! no need to specify port - just use free port number
<channel ref="http" displayName="HTTP Channel (HelloClient)/>
<channel ref="tcp" displayName="TCP Channel (HelloClient)/>
</channels>
      </application>    
   </system.runtime.remoting>
</configuration>

The server code need to instantiate all the channels defined in the config by calling Configure():

public static void Main(string[] args){
RemotingConfiguration.Configure("HelloServer.exe.config");
Console.WriteLine("Application: " + RemotingConfiguration.ApplicationName);
ShowActivatedServiceTypes();   //defined below
ShowWellKnownServiceTypes();   //defined below
......
}
public static void ShowWellKnownServiceTypes(){
WellKnownServiceTypeEntry[] entries = RemotingConfiguration.GetRegisteredWellKnownServiceTypes();
foreach(WellKnownServiceTypeEntry entry in entries) {
Console.WriteLine(entry.AssemblyName, entry.Mode, entry.ObjectUri, entry.TypeName); 
}
}
public static void ShowActivatedServiceTypes(){
ActivatedServiceTypeEntry[] entries = RemotingConfiguration.GetRegisteredActivatedServiceTypes();
foreach(ActivatedServiceTypeEntry entry in entries) {
Console.WriteLine(entry.AssemblyName, entry.TypeName); 
}
}


Client code using configuration file:
- configure remoting services using cient.exe.config
- use new operator to create instances of remote class.
- for client (ie. Activated) activated remote objects, can use non-default constructors with new operator
- for server (ie. WellKnown) activated remote objects, cannot use non-default constructors because
i) single call objects can have no state
ii) singleton objects are created just once.
- in the Main() of HelloClient.cs add the first two lines:

RemotingConfiguration.Configure("HelloClient.exe.config");
Hello obj = new Hello();
if (obj==null){ // could not locate server; return }
Console.WriteLine(obj.Greeting("Christian"));


Delayed loading of client channels
- channels can be configured in machine.config.
- the delayLoadAsClientChannel set to true means to use the channel from client that has not configured channel.

<system.runtime.remoting>
<application>
<channels>
<channel ref="http client" displayName="http client(delay loaded)" delayLoadClientAsClientChannel="true" />
<channel ref="tcp client" displayName="tcp client(delay loaded)" delayLoadClientAsClientChannel="true" />
</channels>
</application>
</system.runtime.remoting>

- so given the above, now the client config file can be simplified to:

<system.runtime.remoting>
<application name="Client">
<client url="tcp:/localhost:6791/Hello">
<wellknown type="WroxProCSharp.Remoting.Hello, RemoteHello" url="tcp://localhost:6791/Hello/Hi" />
</client>
</application>
</system.runtime.remoting>


Lifetime services in configuration files
- changing leasing config for remote servers
- can change remoting configuration, changing HTTP / TCP, port, channel name, adding channels etc.
- example:

<configuration>
<system.runtime.remoting>
<application>
<lifetime leaseTime="15M" sponsorshipTimeOut="4M" renewOnCallTime="3M" pollTime="30s" />
</application>
</system.runtime.remoting>
</configuration>


Formatted Providers
- example below shows serverProviders and clientProviders; also the builtin providers are wsdl, soap, binary

<configuration>
<system.runtime.remoting>
<application name="HelloServer">
<service>
<activated type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" />
</service>
<channels>
<channel ref="tcp" port="6789" displayName="TCP Channel (HelloServer)">
<serverProviders>
<provider ref="wsdl" />
<provider ref="soap" typeFilterLevel="Full" />
<provider ref="binary" typeFilterLevel="Full"/>
</serverProviders>
<clientProviders>
<provider ref="binary" />
</clientProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>


.Net Framework Configuration Tool
- open by Start - Control Panel - Administrative Tools - Microsoft .Net Framework 1.1/2.0 Configuration
- in the Config Tool, expand on My Computer - Applications - <your application> -
- can configure URL of remote object, its channels, etc.

Hosting Application
- can be hosted in self hosted .Net servers, Windows Service, and others.
- hosting on ASP.NET only supports WELL KNOWN OBJECTS.
Hosting Remote Servers in ASP.Net
- uses IIS for ASP.Net to serve the remoting servers.
- create a class derived from System.MarshalByRefObject and has default constructor. (code used in previous example for server to create and register channel is not needed since ASP.Net runtime will handle it)
- create virtual directory on IIS (under Default Web Site) that maps a directory. Put the web.config into this directory.
- put the assembly of the remote class in the Bin subdirectory of the mapped virtual directory.
- default port in IIS configuration is 80
- example of web.config?

<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="SingleCall" type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" objectURI="HelloService.soap" />
........

- the name of remote object must end in soap or bin, depending on the type of FORMATTER used.
- the client configuration example is shown below:

<configuration>
<system.runtime.remoting>
<application>
<client url="http:/localhost/RemoteHello">
<wellknown type="Wrox.ProCSharp.Remoting.Hello, RemoteHello" url="http://localhost/RemoteHello/HelloService.soap" />
........

- In the client config above, the URL for the remote object is based on localhost. The port number is default 80.
- the Channel section in the config is not specified, so the Delay Loaded HTTP channel from machine.config file is used.


Classes, Interfaces, SoapSuds
- in examples so far, assembly of Remote object is copied to both client and server. However the client needs only the meta data. To use the metadata only, use either interfaces or the SoapSuds.exe utility.
- Interfaces - it defines the methods without implementation. The client needs only the interface. This is done by:
i) define interface that will be placedin separate assembly
ii) Implement interface in the remote assembly. The assembly of the interface must be referenced.
iii) No more changes on the server side.
iv) On client side, reference the assembly of the interface, instead of the assembly of the remote obj.
v) Client uses interface to remote object rather than remote object class. Object created using Activator class as before. Can't use the NEW operator because the interface cannot be instantiated.
- Soapsuds - utility to get metadata from assembly if HTTP channel and SOAP formatter is used. Can convert assemblies to XML Schemas, XML schemas to wrapper classes and other way.
    - convert Hello from assembly RemoteHello to assembly RemoteWrapper where transparent proxy is generated that calls the remote object:
 <CMD>  soapsuds -type:Wrox.ProCSharp.Remoting.Hello,RemoteHello -oa:HelloWrapper.dll </CMD>
- to get type information from server, if HTTP channel and SOAP formatter is used.
 <CMD>  soapsuds -url:http://localhost:6792/hello/hi?wsdl -oa:HelloWrapper.dll</CMD>
- where oa is output assembly.
- client can just use the generated assembly from above.
- WSDL - supported by .Net Remoting if HTTP channel and SOAP formatter is used.
    - to see wsdl, add ?wsdl to the URI of remote object: http://localhost:6792/Hello/Hi?wsdl
- wsdl document can be accessed across network only for well-known remote object type.
- for client activated object, URI is created dynamically, can use assembly with SoapSuds with the -ia option (input assembly).


Asynchronous Remoting
- Remote object can be run and returns immediately to client, while remote object is still running, by using delegates.
- Create a delegate method, GreetingDelegate derived from MulticastDelegate, with same arguments and return values as Greeting().
- The delegate class has constructor with argument which is a reference to Greeting().
- Start greeting by calling BeginInvoke() of delegate class.
- Second argument of BeginInvoke() is an AsyncCallBack instance that defines HelloClient.Callback().
- the Callback is called when remote method is finished, using EndInvoke().

using System;
using System.Runtime.Remoting;
namespace Wrox.ProCSharp.Remoting{
public class HelloClient{
private delegate String GreetingDelegate(String name);
private static string greeting;


public static void Main(string[] args){
RemotingConfiguration.Configure("HelloClient.exe.config");
Hello obj = new Hello();
if (obj==null) {Console.WriteLine (..........); }


// synchronous version
// string greeting = obj.Greeting("Christian");


// asynchronous version
GreetingDelegate d  = new GreetingDelegate(obj.Greeting);
IAsyncResult ar = d.BeginInvoke("Christian", null, null);


// do some work and then wait
ar.AsyncWaitHandle.WaitOne();
if(ar.IsCompleted){ greeting = d.EndInvoke(ar);  }
Console.WriteLine(greeting);
}
}
}


OneWay Attribute of Asynchronous Remoting
- adding the OneWay attribute makes it asynchronous provided the method has void return.
- adding method TakeAWhile() to remote object class  creates fire-and-forget method.
- If client calls by proxy, proxy returns to client immediately.

public void TakeAWhile(int ms) {
Console.WriteLine("started");
System.Threading.Thread.Sleep(ms);
Console.WriteLine("finished");
}



Remoting and Events
A client can call a remote object on the server. BUT, the server can also call methods on the client, by using delegates and events.
The architecture is:
- remote object in server declares an external function(delegate) with signature of method that client implements in a handler.
- arguments passed to client with handler function must be marshalable, so all data to client must be serializable,
- remote object declares instance of the delegate function modified with EVENT keyword. Client use this to register handler.
- client creates a sink object with handler method with same signature as the delegate defined, and register sink object with the event in the remote object.

Server class (as before) will create a channel and register the remote object.
Remote object declares arguments of delegate and fires events in the registered handler functions. Argument passed to handler is type StatusEventArgs and must be Serializable so it can be marshalled to client.
Client creates instance of EventSink class and registers StatusHandler() as a handler for the delgate in teh remote object. EventSink must be remotable like RemoteObject.

The class structure summary is:
Client( +Main() )
Server( +Main() )
remotable EventSink ( +StatusHandler() )
remotable RemoteObject ( +LongWorking() )
serializable StatusEventArgs ( +Message )

RemoteObject

// external function so client can register event handler that can be called from remote object
// input parameters cannot have return types, ref, out parameters
public delegate void StatusEvent(object sender, StatusEventArgs e); 


public class RemoteObject : MarshalByRefObject {
public RemoteObject(){ 
Console.WriteLine("RemoteObject constructor called");
}
public event StatusEvent Status;   // declare event name Status of delegate type StatusEvent


public void LongWorking(int ms){
Console.WriteLine("RemoteObj: LongWorking()started");
StatusEventArgs e = new StatusEventArgs("Message for Client: LongWorking() started");


//fire event
if(Status != null) {     // check if event is registered
Console.WriteLine("RemoteObj: firing starting event");
Status(this, e);     // fire the event
}


// Threading
System.Threading.Thread.Sleep(ms);
e.Message = "Message for client: LongWorking Ended";


//fire ending event
if(Status != null) {
Console.WriteLine("RemoteObj: firing ending event");
Status(this, e);
}
Console.WriteLine("RemoteObj: LongWorking() ending");
}
}


Event arguments - StatusEventArgs used as argument for delegate. Serializable enables it to be transferred from server to client.

[Serializable]
public class StatusEventArgs{
public StatusEventArgs(string m){
message = m;
}
public string Message{
get{return message; }
set{message=value; } 
}
private string message;
}



Server - console application. wait for user to end server after reading config file, setting up channel and remote object.

using System;
using System.Runtime.Remoting;
namespace Wrox.ProCSharp.Remoting{
class Server{
static void Main(string[] args){
RemotingConfiguration.Configure("Server.exe.config");
Console.WriteLine("press Return to Exit");
Console.ReadLine();
}
}
}


Server Config file

<configuration>
<system.runtime.remoting>
<application name="CallbackSample">
<service>
<activated type="Wrox.ProCSharp.Remoting.RemoteObject, RemoteObject" />
</service>
<channel ref="http" port="6791" >
<serverProviders>
<provider ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>

Remote object is configured as client activated and not single call objects because client first registers the event handler and calls remote method afterward; the remote object must keep state for the client.
Full serialization is needed to support delegates.

Event Sink

using System;
using System.Runtime.Remoting;
namespace Wrox.ProCSharp.Remoting{
public class EventSink : MarshalByRefObject {
public EventSink(){   }
public void StatusHandler(object sender, StatusEventArgs e){
Console.WriteLine("EventSink: Event occurred: " + e.Message);
}
}
}

Required for use by client, and invoked by server.
EventSink implements StatusHandler that is defined with the delegate (see client code).
Method can only have input parameters and void return.
Inherit from MarshalByRefObject to make it remotable

Client

using System;
using System.Runtime.Remoting;
namespace Wrox.ProCSharp.Remoting{
class Client{
static void Main(string[] args){
RemotingConfiguration.Configure("Client.exe.config");


EventSink sink = new EventSink();            // not configured in client element
RemoteObject obj = new RemoteObject();       // configured in the client element


// register client sink in server - subscribe to event
obj.Status += new StatusEvent(sink.StatusHandler());     // register handler method of EventSink object in remote object
obj.LongWorking(5000);      // by calling LongWorking, server will call back into StatusHandler() at beginning and end of method.


// unsubscribe event
obj.Status -= new StatusEvent(sink.StatusHandler());
obj.LongWorking(5000);     // since event is unsubscribe, next call to LongWorking, no events will be received.


Console.WriteLine("press Return to Exit");
Console.ReadLine();
}
}
}


Client config file

<configuration>
<system.runtime.remoting>
<application name="Client">
<client url="http://localhost:6791/CallbackSample">
<activated type="Wrox.ProCSharp.Remoting.RemoteObject, RemoteObject" />
</client>
<channel ref="http" port="0" >
<serverProviders>
<provider ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>


Call Context
-Client activated: hold state for specific client. Server allocates resources for every client.
-Server activated single-call: don't hold state for client, new instance is created for every instance call, no resources held on server.
- State can be kept on client side using Call Context.
- Call Context flows with logical threads and is passed through every method call.
- Logical thread flows through method calls passing from threads, contexts, application domains, processes.
- Assign data to call context by defining in a class that implements iLogicalThreadAffinitive and Serializable.

using System;
using System.Runtime.Remoting;
namespace Wrox.ProCSharp.Remoting{
[Serializable]
public class CallContextData : iLogicalThreadAffinitive {
public CallContextData () {}
public string Data{
get {return data;}
set (data=value;}
protected string data;
}
}

Change Greeting() method to use CallContextData.

public string Greeting(string name){
Console.WriteLine("greeting start");
CallContextData cookie =(CallContextData )CallContext.GetData("mycookie");
if (cookie != null){
Console.WriteLine("Cookie: " + cookie.Data);
}
Console.WriteLine("greeting finished");
return "Hello " + name;
}

In client code, when Greeting() is called, context data is passed to server

CallContextData cookie = new CallContextData();
cookie.Data = "info for server";
CallContext.SetData("my cookie", cookie);
for (int ii = 0; ii<5; ii++){
Console.WriteLine(obj.Greeting("Christian"));
}



Presentation - Business - Data Layered applications
=====================================================
Presentation. The presentation layer provides the application's user interface (UI). Typically, this involves the use of Windows Forms for smart client interaction, and ASP.NET technologies for browser-based interaction.

Business. The business layer implements the business functionality of the application. The domain layer is typically composed of a number of components implemented using one or more .NET - enabled programming languages. These components may be augmented with Microsoft .NET Enterprise Services for scalable distributed component solutions and Microsoft BizTalk Server for workflow orchestration.

Data. The data layer provides access to external systems such as databases. The primary .NET technology involved at this layer is ADO.NET. However, it is not uncommon to use some .NET XML capabilities here as well.


Marshalling
=============
Defn: Marshalling = conversion of data types to their corresponding data types between .Net and typically other unmanaged code.


Var - Type Inference - C# 3.0
==============================
Ref: http://www.programmersheaven.com/2/CSharp3-1

Var - from C# 3.0 onwards
- for type inference, meaning programmer does not need to specify data type in code.
- at compile time, compiler determines what type is by inference and fixes the type.
- not same as dynamic typing
- no runtime overhead because type is already determined at compile time.
Example:

// Before:
Dictionary<int, List<int>> Coeffs = new Dictionary<int, List<int>>();
// After:
var Coeffs = new Dictionary<int, List<int>>();



Extension Methods - C# 3.0
===========================
Ref: http://www.programmersheaven.com/2/CSharp3-2

What is it?
- It is like a method belonging to a class, you call it by Objname.MethodName.
- It is like a static method because it is defined outside of its namesake class and instead defined inside another static class.

When or why is it needed?
- When we cannot inherit a class to extend its methods, eg when class is sealed. Examples are Int and String classes.
- when using some kind of object factory that instantiates objects of a given class, but you do not have the ability to modify it so that your subclass is instantiated instead.
- when implementing a method that can be invoked on all classes implementing a given interface; before, we had no way to attach a method implementation to an interface.
- when adding related things to a number of other classes, this allows grouping together in one place rather than spreading them amongst many classes.

How to Implement Extension Methods?
Example:
Suppose there is a structure:

struct UserInfo {
    public int UserID;
    public string Name;
    public DateTime DOB;
    public string CountryCode;
}


And the current class is:

public sealed class SerialGenerator {
    public long MakeCode(int ProductID, string CustomerName,DateTime CustomerDOB,string CustomerCountry)   {
        return someLongNumber;
    }
}


Then the extension method can be defined as:

static class Whatever {
    public static long MakeCode(this SerialGenerator SG, int ProductID, UserInfo User)    {
        return SG.MakeCode(ProductID, User.Name, User.DOB, User.CountryCode);
    }
}


The key features to implement extension method is:
- define the extension class inside a static class, which can be Whatever.
- the extension method must have as its First Parameter the following:
     this <Name of Class to Extend> <Instance Name>
in the example, it is:  this SerialGenerator SG
- the example extension method is a wrapper for an existing class, but in general it does not need to be a wrapper.

Then to use the example extension method:

static void Main(string[] args){
    SerialGenerator SG = new SerialGenerator();
    UserInfo User = new UserInfo();
    User.UserID = 453;
    User.Name = "Fred";
    User.DOB = DateTime.Now;
    User.CountryCode = "UK";
    long Code = SG.MakeCode(5181, User);
    Console.WriteLine(Code);
}

Note that the "this" argument is implicit and is not passed.

Interfaces and Extension method.
When an extension method is defined for an Interface class, then all classes that implement that interface can use it too.
For example, consider:
- List<T> implements IList<T>
- IList<T> is inherited from IEnumerable<T>
- When an extension class is implemented for IEnumerable<T>, then List<T> and any other classes like List<T> can access the extension method.

What is the Precedence of Extension Methods?
- When a class has a method with the same name and parameters of the extension class, the class method will win.
- When a parent class has the method already, but an extension method is defined for the child class, then the parent's method will be used.
- Extension method does not have overhead because the call to the method is determined at compile time.


Lambda Expressions - C# 3.0
=============================
Syntax - the various possible syntax for writing lambda expressions in C# is given below

(x,y) => x*y                // 2 parameters input
() => new Blah()            // no parameter needed
(x,y) => {                  // block of code
var result = x+ y;
return result;
}


The lambda expression is represented by "=>"
The left hand side consist of parameters.
The right hand side consist of actions taken on the parameters.
The return value is the entire expression.

Lambda expressions can be used to simplify anonymous methods. For example in sorting routine,
using Anonymous methods:

var Words = new List<string> { "amazingly", "my", "badger", "exploded" };
// Sort them by word length.
Words.Sort(delegate(string a, string b) {
    return a.Length.CompareTo(b.Length);
});
// Show results.
foreach (string Word in Words)
    Console.Write(Word + " ");


The List<T>.Sort method requires a method, implemented by the delegate, that takes in 2 strings and implement the comparison code. The equivalent can be done using lambda expressions as follows.

    Words.Sort((a,b)=>a.Length.CompareTo(b.Length));



Object and Collection Initializers - C# 3.0
============================================
Ref: http://www.programmersheaven.com/2/CSharp3-3

Object Initializers
- allow object to be initialized anonymously without first having to create and object, and finally to add that object into a collection.

Example of previous way:

Dog dog = new Dog();
dog.name = "fluff";
dog.age = 2;
Zoo.Add(dog);


Example using Object Initializers:
Zoo.Add( new Dog { name="fluff", age=2 }  );


Collection Initializers can be used provided:
- the Collection implements ICollection<T> interface
- elements of the collection must be the same type

Example of previous way:

var Zoo = new List<Animal>();
Zoo.Add(new Dog());
Zoo.Add(new Cat());


using Collection Initializers
var Zoo = new List<Animal> { new Dog(), new Cat() };


To use with Get and Set Properties:
in the item class

    class Node    {
        public int aID { get; set; }
        public int bID { get; set; }
    }

in the program that uses this:

       var AllNodes = new List<Node>();
       AllNodes.Add(new Node() { aID = _aID, bID = _bID }); 




Anonymous Types / Class - C# 3.0
==================================
Ref: http://www.programmersheaven.com/2/CSharp3-3

Anonymous types and class mean the same thing. Extending the idea of anonymous methods which are defined on the run and does not belong to any class and need to be stored immediately (using delegates), the anonymous class also need to be stored at the time it is instantiated. An example of an anonymous type is:

var aDog = new { name="spot", age=2  };


- There is no explicit class for aDof and the object is stored immediately into aDog. However, internally C# does retain a type information associated with the anonymous type.
- Also each field specified in the creation such as {name, age}, will become private fields with get/set properties.
- Two anonymous classes are considered equivalent if they have the same set of fields in the same order.
- Projection of Anonymous type. When defining the anonymous type, the fields can take values from variables or members of other objects that is already defined. For example:

   age = 2
   var aCat = new Cat("fluffy");
   var someDetails = new { age, aCat.Name };

this is equivalent of:
   var someDetails = new { age=age, Name=aCat.Name };


LINQ - C# 3.0
==============
Ref: http://www.programmersheaven.com/2/CSharp3-4

To include LINQ references, go to Project - Add Reference - .Net tab - System.Core.dll
Then include references in code:
   using System.Linq;               // for basic LINQ
   using System.Linq.Expressions;   // for expression trees
   using System.Xml.Linq;           // LINQ to XML
   using System.Data.Linq;          // LINQ to SQL

for LINQ to DataSet
   System.Data.dll and System.Data.DataSetExtensions.dll
   using System.Data;
   using System.Data.Common;
   using System.Data.SqlClient;

Simple LINQ statement:

var costList = from o in Orders
              where o.CustID==84
  orderby o.Cost ascending
  select o.Cost;

- the Orders is a List<Order> where Order is a defined class with fields CustID and Cost.
- the above is selecting an object from a list of Order objects.
- the return costList is a list of return types, in this case it is the Cost values.
- the orderby statement allow sorting by "ascending" or "descending" of the specified variable. The variable to be sorted could be any variable.
- the final line will execute the LINQ and tell it what to return.

LINQ statement with complex return objects:

var resultList = from o in Orders
              where o.CustID==84 && o.Cost > 50
  select new {
o.CustID,
o.Cost,
discount = o.Cost * 0.9
};

- a more complex object can be returned via an anonymous type in the example above.
- the return new object can have calculations performed.


LINQ statement of Joining (Inner Join) a list of two different classes.
- in this example, suppose the Orders class above has a connection to another class called Customer with fields {CustID, name}

var resultList = from o in Orders
                join c in Customers
on o.CustID equals c.CustID
    select new { c.name, o.CustID, o.Cost };

- the "join" keyword links the two lists together.
- the way in which it is joined is specified by the "on A equals B" phrase.


LINQ statement of ALL permutations, like Outer Join.

var resultList = from o in Orders
                from c in Customers
    select new { c.name, o.CustID, o.Cost };

- will return all possible combinations of Customer from all Order.
- the Inner Join can be achieved with this double from LINQ statement by adding:
   where o.CustID == c.CustID
- Note that using the double "from" and "where" is much less efficient that using the "join" and "on ... equals",


LINQ statement for Grouping of results

var resultByCust = from o in Orders
                group o.Cost by o.CustID;

- the "select" statement is replaced by "group A by B"
- the items that would normally be put in select, now appears in A.
- the fields to group by appear in B.
- the result is actually a list of Cost being grouped into sub-lists according to CustID
- the code below displays the results per group and each item within that group.

foreach( var cust in resultByCust ){
// each group with the same CustID
foreach( var cost in cust ) {
// each cost item in a specific Cust group
}
}



LINQ statement for query continuation

var resultByCust = from o in Orders
                group o.Cost by o.CustID into grp
select new { custID = grp.Key,  Total = grp.Count() };

- both select and group usually executes the LINQ statement. However, they can be used together as shown above.
- the group result is re-directed into grp, where grp is a group of lists.
- the select is used on the group of lists and group functions like Count() is accessible to count the items in each sub-lists.
- the .Key contains the value that it was grouped by, in this case it is the CustID.


LINQ relationship with Lambda Expressions and Extension Methods
- LINQ statements are transformed by the compiler into an intermediate stage which uses Lambda Expressions and Extension Methods, before the final compilation.
- For example with a generic LINQ statement:

var resultList = from o in Orders
              where o.CustID==84 
  select o.Cost;

- This above is transformed into the following

var resultList = Orders.Where(o => o.CustID==84).Select(o=>o.Cost);

- Where() and Select() are Extension Methods that are implemented at the IEnumerable interface level.
- The result of the Where() returns a list of objects Order that matches the criteria.
- The Select operates on each object and returns the list of fields for the output.


LINQ and DLinq and XLinq
Since the LINQ statements above are implemented using extension methods, it is possible to use the same LINQ syntax but implemented in a different manner. Hence:
- Dlinq - implementation of LINQ that allows LINQ statements to be translated into SQL statements for SQL databases.
- XLinq - implementation of LINQ that allows LINQ statements to be translated to query XML documents.


Auto-Implemented Properties - C# 3.0
======================================
Properties with get and set methods can be defined without much code at all. The new syntax for this is given below:

public class Customer{
    public int ID { get; set; }
    public string Name { get; set; }
}