Science With the Virtual Observatory
2005 Summer School

C# mini tutorial

Gretchen Greene(STScI) and Matthew Graham(Caltech)

Presentation outline

What is C#?

In June 2000, Microsoft announced a new strongly-typed object-oriented language: C#. It is designed with the hindsight of many languages, most notably Java and C++, to give the optimum blend of simplicity, expressiveness and performance. Although initially symbiotic with the .NET framework, open source support (e.g. Mono) has allowed it to migrate to non-Windows platforms.

Since Microsoft delivered the Common Language Infrastructure (CLI) to the ECMA standards, an ISO standard now exists for C# (Standard ECMA-334).

Why C#?

C# takes the simplicity of Java, with its automatic garbage collection, monolithic inheritance (single root object hierarchy), and standard class library, and adds a number of advanced features, such as properties, delegates, and attributes. Interestingly , many of these features have ended up in the latest versions of Java, e.g. enumerations and the foreach statement in Java 1.5. Interestingly both the latest version of .NET and Java incorporate 'generics', the newest form of what we called in C++ templates.

C# was also developed very much with the Web foremost in mind, and whilst some say that C# is more expressive than Java and is more suited to performance-critical code, when it comes to web services both C# and Java are much better than C++. C# and the .NET environment provides the framework for building web applications, web services, assembly packages...in a fully integrated system, much like the J2EE enterprise class service oriented architecture.

One of the key philosophical differences between using Java and C# is to understand the meaning of interoperability specific to each language definition. While Java is considered to be platform interoperable, the C# language is built upon the concept of language interoperability. What is meant by this is the use of the IL (Intermediate Language) compiler. It is more evolved in the Microsoft .NET framework, yet the Mono environment also incorporates the concept of mixed language interoperability.

By contrast, C# is a relatively new language. Microsoft has studied Java, building on its successes, and changed some aspects of the language to better suit certain types of applications. Over time Java's headstart may become less relevant.

C# in the VO

There are several examples of C# used throughout the VO community. Since C# of a powerful managed language, the primary area of use is in the VO applications development. The .NET framework is also a leader in the development of web services which may interoperate with other languages and system architectures via the standard SOAP protocols. VO applications in C# include:

C# and Java similarities

In the grand tradition of programming tutorials that began with C, a comparison of Java and C# begins with a familiar "Hello, world!" example. The code for this multilingual example appears in Table 1.

Table 1. "Hello, world!" in four languages (Java, C#, Croatian, French)
Java C#


public class GlobalGreeting {
   public static void main(String[] args) {
      System.out.println("Zdravo, zemlya!");
   }
}


class GlobalGreeting {
   static void Main(string[] args) {
      System.Console.WriteLine("Salut, le monde!");
   }
}

External reference

Usage of code external to a module is handled similarly in Java and C#. Java uses the import keyword to declare references to external names; C# provides the using keyword, as shown in Table 2.

Table 2. The Java import keyword and the C# using keyword
Java C#


import java.lang.System;
public class GlobalGreeting2 {
   public static void main(String args[]) {
      System.out.println("Zdravo, zemjata!");
   }
}


using System;
class GlobalGreeting2 {
   static void Main(string args[]) {
      Console.WriteLine("Salut, monde!");
   }
}

The two keywords work in a similar manner; both allow you to use names from another compilation unit without fully specifying the name. Neither C# nor Java use the C preprocessor construct #include, because the reference to the external module is at a logical, not a lexical, level. This means the external reference is resolved at link time, as well as at compile time. This has special significance for C#, since it allows modules to subclass and operate with modules written in other languages.

The difference between import in Java and using in C# is that Java has a concept of packages, which has a specific meaning in the context of symbol accessibility, while C# uses namespaces much like those of C++. The using keyword makes all names in the given namespace accessible to a module. So, the line using System; lets you access the .Net runtime namespace System. The System namespace contains the static global method System.Console.WriteLine(), which is accessible as Console.WriteLine() without specifying the System namespace. (Compare Tables 1 and 2.) In the Java example, System is a class defined in java.lang, which is implicitly imported into every Java source file; therefore, the import statement is not needed. Ho wever, including import java.lang.System.*; does not permit you to omit the System. from System.out.println as in C#, because System is a class, not a namespace. Thus, external names are referenced in a way that seems similar, but has different underlying mechanisms. This difference could be more confusing to programmers accustomed to Java than to C++ programmers who understand and use namespaces. Neither option is more expressively powerful; the two languages simply use different mechanisms to disambiguate names.

How do I do C#?

On Windows platforms, C# can used with the .NET Framework; however, a more platform agnostic option is to use the open source implementation of Mono, which is what we focus on in this mini tutorial.

To compile a C# code, we use the Mono mcs compiler:

>mcs SomeFile.cs

This will create an executable file called SomeFile.exe. To run this, we use the mono program:

>mono SomeFile.exe

C# example code 1: Handling XML

The first example code will load a specified XML document, apply a specified XPath string against it and print out the results. The source code, which can be found in $NVOSS_CSHARP_HOME/examples/XPathExample.cs, is:

using System;
using System.Xml;

public class XPathExample {
public static void Main(string[] args) {
string filename = args[0];
string query = args[1];

XmlDocument document = new XmlDocument();
document.Load(filename);
XmlNodeList nodes = document.SelectNodes(query);
Console.WriteLine("{0} nodes match the query {1}",
nodes.Count, query);
foreach (XmlNode node in nodes) {
Console.WriteLine(node.Value);
}
}
}

To compile this:

>cd $NVOSS_CSHARP_HOME/examples
>mcs XPathExample.cs

This will create an executable XPathExample.exe in the directory.

The sample XML file summary.xml contains a list of resource types and how many there are of each. Let's suppose that we want to know the names of the resources for which there are entries, i.e. where the value of the <howmany> element is greater than zero: the XPath statement that will give us this for this file is:

//resourceType[howmany > 0]/name/text()

So we call the executable with:

>mono XPathExample.exe summary.xml "//resourceType[howmany > 0]/name/text()"
3 nodes match the query //resourceType[howmany > 0]/name/text()
Authority
Organisation
Registry

C# example code 2: Calling a web service ("ASP.NET")

Mono comes with its own code for generating client proxy code from a web service WSDL. There is an sample WSDL file downloaded from a NED name resolver web service (see voservices.org). If we go into the csharp/examples/WSClient directory we can run the tool.

>wsdl -o:NED.cs ned.WSDL
Mono Web Services Description Language Utility
Writing file 'NED.cs'

This creates a file called NED.cs containing the automatically generated client proxy code. Now we use the client proxy class to build simple client applications to lookup source measurements by name, and also find source measurements near an input coordinate. (the source code can be found in $NVOSS_CSHARP_HOME/examples/WSClient):

The sample file NEDObjByName is listed here. This client calls the NED web service and resolves the specific metadata about a particular object NAME. A default name is set although you may try another example.

using System;
using System.Xml;
using System.Xml.Serialization;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Text;


namespace NEDObjByName
{
    class NEDObjByName
    {
        static void Main(string[] args)
        {
            String objName = null; 
            // Check for Input Name Argument if null use Default
            if (args.Length == 1)
            {
                objName = args[0];
            }
            else // Set a Test Default Name
            {
                objName = "M100";
            }

            // Default Test Source

            NED objResolved = new NED();
            ObjInfo objInf = new ObjInfo();
            objInf = objResolved.ObjByName(objName);

            Console.Out.WriteLine("NED Name Resolver: Object Name: "+ objName);
            Console.Out.WriteLine("Number of Cross IDs: " + objInf.ArrayOfCrossID.Length.ToString());
            Console.Out.WriteLine("Object Type: " + objInf.objtype);
            Console.Out.WriteLine("Right Ascension: " + objInf.ra.ToString());
            Console.Out.WriteLine("Declination: " + objInf.dec.ToString());
            Console.Out.WriteLine("****************************************");
     
            // This is the Serialized Output (XML) for the Object Info returned
            // From the NED Name Resolver ObjByName Web Service method

            Console.Out.WriteLine("Serialized NED Object");
            XmlSerializer serializer = new XmlSerializer(typeof(ObjInfo));
            XmlTextWriter writer = new XmlTextWriter(Console.Out);
            writer.Formatting = Formatting.Indented;
            serializer.Serialize(writer, objInf);
            writer.Close();

            return;            
}


Listing 1:  NEDObjByName.cs

You may build the executable for this client using the following Mono compiler. Note the additional 'g' in front of the mcs compiler name. This is for the compiler version which includes the generics assembly. The /r option includes the required assembly reference for web services.

gmcs /r:System.Web.Services NEDObjByName.cs ned.cs

This results in creation of the executable file, NEDObjByName.exe. You can run this web service client from the Mono command prompt by typing the following:

>mono NEDObjByName.exe
Partial Output.....

NED Name Resolver: Object Name: M100
Number of Cross IDs: 35
Object Type: G
Right Ascension: 185.72875
Declination: 15.82238889
****************************************
Serialized NED Object
<?xml version="1.0" encoding="Windows-1252"?>
<ObjInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.o rg/2001/XMLSchema-instance">
<ArrayOfCrossID xmlns="http://voservices.net/ned">
<CrossID>
<objname>MESSIER 100</objname>
<objtype>G</objtype>
</CrossID>
<CrossID>

This web service has effectively used SOAP and WSDL to call a remote service and demonstrates the efficiency of using XML as a data exchange format for a basic scientific utility.

C# example code 3: Making a SQL query ("ADO.NET")

There are a couple command line tools that Mono provides to help with Database access. SQL# (sqlsharp.exe), a command line tool for entering SQL commands and XSD (xsd.exe). The xsd tool is very powerful with the development of schemas and web services client/services. This tool is also available in the Microsoft .NET framework and functions similarly. With the xsd you can generate xml schema files from xml, create datasets from xml schema, and create C# classes from the xsd schema.

Mono comes with data providers for many of the most common relational databases: MySQL, SQL Server, PostgreSQL, Oracle, Sybase, DB2, SQLite, OLE DB and ODBC. For connecting MySQL to .NET you need to include the MySQL Net Connector assembly which you can download from here. In this example, a sample query will be issued against the MySQL database containing the SPOCS sample data (the source code can be found in $NVOSS_CSHARP_HOME/examples/MySQLClient.cs):

One thing you need to do when you are using an external assembly is to install it into the Global Assembly Cache (GAC). The GAC management utility is a tool used by developers to install assemblies into the system to become available for all applications at runtime.

cd path_to_your MySql.Data.dll assembly
  gacutil -i MySql.Data.dll

Here is an example client for accessing the SPOC MySQL database.

using System;
using System.Data;

using MySql.Data.MySqlClient;


public class MySQLClient {


  public static void Main(string[] args) {


    string connectionString = string.Format("Server=localhost;Database=SPOCS;User ID={0};Password={1};", "root", "nvo");
    MySqlConnection conn = null;

    try {
      conn = new MySqlConnection(connectionString);
      MySqlCommand command = new MySqlCommand("select id, name, teff, logg, metal from SPOCS where teff between 5720 and 5820 and logg between 4.34 and 4.54 and metal between -0.1 and 0.1 order by teff", conn);
      conn.Open();
      MySqlDataReader reader = command.ExecuteReader();
      while (reader.Read()) {
        Console.WriteLine("Id = {0}, Name = {1}, Teff = {2}, Logg = {3}, Metal = {4}", reader["id"], reader["name"], reader["teff"], reader["logg"], reader["metal"]);
    }

      reader.Close();

    } catch (Exception e) {
      Console.Error.WriteLine(e);
    } finally {
      if (conn != null && conn.State == ConnectionState.Open) {
        conn.Close();
      }
    }
  }
}

Listing 2: MySQLClient.cs

We compile this with:

>mcs -r:MySql.Data.dll -r:System.Data MySQLClient.cs

and this produces an executable called MySQLClient.exe. We run this with:


>mono MySQLClient.exe
Id = 405, Name = HD75302, Teff = 5721, Logg = 4.49, Metal = 0.08
Id = 660, Name = HD138573, Teff = 5722, Logg = 4.45, Metal = -0.05
Id = 759, Name = HD159909, Teff = 5723, Logg = 4.4, Metal = 0.06
Id = 371, Name = HD68168, Teff = 5724, Logg = 4.4, Metal = 0.1
Id = 90, Name = HD10086, Teff = 5725, Logg = 4.46, Metal = 0.09
...

Optional: Serving a web service

In C#, the set of technologies which support web functionality is known as ASP.NET. ASP.NET supports two kinds of applications: web forms (known as ASPX) and web services (known as ASMX). An ASP.NET application requires a container to run in (just like Java and Apache Tomcat). Fortunately Mono provides an Apache module mod_mono which can be used with the Apache web server to provide support for ASP.NET and a standalone ASP.NET server xsp (Note that Mac OS X users will have to compile and install xsp themselves).

The listing below gives a sample ASMX file for a directory listing service:

<%@ WebService Language="C#" Class="DirectoryListing" %>
using System.IO;
using System.Web.Services;
[WebService(Namespace="http://nvo.caltech.edu/",Description="This provides a directory listing.")]
public class DirectoryListing {
[WebMethod(Description="This lists the contents of the specified directory.")]
public string[] ListDirectory(string path) {
return Directory.GetFileSystemEntries(path);
}
}

This file DirectoryListing.asmx should be placed in the xsp root directory and the service can then be accessed at: http://localhost:8080/DirectoryListing.asmx provided you are operating xsp on this port.

 

Odds and Ends

SharpDevelop (also known as #develop) is a free, open source IDE for .NET development that runs on Windows. Despite being completely free, this tool has a very compelling set of features, including:

  • Support for Microsoft .NET and Mono language compilers
  • Visual designer support for Windows Forms applications
  • Support for the forthcoming (at the time of this article) Windows Presentation Foundation UI toolkit
  • Integration with several popular open source .NET development tools (nant, ndoc, nunit, etc)
  • IntelliSense, code completion and code snippet technologies
  • Conversion Tools between Java and C#:

    Visual Studio provides the Java Language Conversion Assistant (JLCA) to convert Java applications to C#.

    JaCIL (a .NET to Java compiler) converts .NET assemblies to JAVA class files. JaCIL can be downloaded from Sourceforge. Also assumed is that you have a C# compiler in your path. The .NET Framework C# compiler, csc, or the open source Mono Project C# compiler, mcs, are both suitable.

    Useful links


    The NVO Summer School is made possible through the support of the National Science Foundation and the National Aeronautics and Space Administration.