Thursday, May 24, 2007

Syntax-Highlighted Code from Visual Studio as HTML

Maybe you wondered about syntax-highlighted code in this blog but blogger.com does not provide any tool for this. If you use Visual Studio, just try this CopySourceAsHtml add-in.

CopySourceAsHtml generates HTML source of your syntax-highlighted code in VS. You can select and copy your code as HTML to clipboard, so your syntax-highlighted code can be placed anywhere.

Here are my settings of CopySourceAsHtml add-in:


My "File Style" is:

border:1px solid black;

padding: 8pt;

width: 94%;

overflow: auto;

background-color: #F0F0F0;


Here is an example output:

using System;

 

class HelloWorld

{

  static void Main()

  {

    Console.WriteLine("Hello, World!");   

  }

}



kick it on DotNetKicks.com

Wednesday, May 23, 2007

OpenGL in .NET

There is a very simple way how to use OpenGL library in .NET application using C#. The library what you need can be downloaded here csgl.sourceforge.net. The simplest way is to add these downloaded files to your project:

  • csgl.dll
  • csgl.native.dll
See the following "Hello world!" project step by step.

Create a new Windows application project. In the new solution add a new project Class library named GLViewControl. Add csgl.dll and csgl.native.dll to the GLViewControl project and reference csgl.dll library. Reference also System.Windows.Forms and System.Drawing.
Set the "Copy to output directory" property for csgl.native.dll file. Presence of this file in the output directory is important unless you have to install csgl on each system particularly.

Now the project is ready for our code. Add a new class in GLViewControl:

using System;

using CsGL.OpenGL;

 

namespace GLViewControl

{

  public class GLView : OpenGLControl

  {

    public override void glDraw()

    {

      GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);// Clear the Screen and the Depth Buffer

      GL.glMatrixMode(GL.GL_MODELVIEW); // Modelview Matrix

      GL.glLoadIdentity();              // reset the current modelview matrix   

      GL.glTranslatef(0.0f, 0.0f, -4.0f); 

 

      GL.glBegin(GL.GL_POLYGON);

        GL.glColor3d(0, 0, 1);

        GL.glVertex3f(-1, -1, 0);

        GL.glColor3d(0, 1, 0);

        GL.glVertex3f(1, -1, 0);

        GL.glColor3d(1, 0, 0);

        GL.glVertex3f(0, 1, 0);

      GL.glEnd();

    }

 

    protected override void InitGLContext()

    {     

      GL.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // black background

      GL.glClearDepth(1.0f);                  // depth buffer setup

      GL.glEnable(GL.GL_DEPTH_TEST);          // enables depth testing

      GL.glDepthFunc(GL.GL_LEQUAL);            // type of depth testing

      GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);  // nice perspective calculations           

    }

 

    protected override void OnSizeChanged(EventArgs e)

    {

      base.OnSizeChanged(e); 

      GL.glMatrixMode(GL.GL_PROJECTION);

      GL.glLoadIdentity();

      GL.gluPerspective(45.0f, (double)Size.Width / (double)Size.Height, 0.1f, 100.0f);

      GL.glMatrixMode(GL.GL_MODELVIEW);

      GL.glLoadIdentity();

    }

  }

}



And now just drag and drop a new GLView control from the toolbox in VS on your form and run the application. The result looks like this:



kick it on DotNetKicks.com

Wednesday, May 16, 2007

User Defined Aggregate Function in SQL for String Concatenation using CLR

If you tried to concatenate strings from group in SQL, probably you would start looking for an aggregate function similar to SUM or COUNT. There is no function like this in SQL Server 2005 and even further there is no way how to create a custom aggregate function using SQL. You can use just built-in aggregates.

Fortunately, SQL Server 2005 integrates common language runtime (CLR). So, the solution is to write an aggregate function in C# and include it among built-in functions in SQL Server.

Let us show an example with aggregate function for strings concatenation. At first you should create a new project in VS - use template Class Library, name it for example MyCLRLib.

The key methods are:

  • Init() - initializes private variables
  • Accumulate() - appends the next value
  • Merge() - merges partial aggregates
  • Terminates() - returns a result aggregation
Here is completed a copy-paste code:

using System;

using System.Text;

using System.IO;

using Microsoft.SqlServer.Server;

using System.Data.SqlTypes;

 

[Serializable]

[SqlUserDefinedAggregate(

    Format.UserDefined,        //use custom serialization to serialize the intermediate result

    IsInvariantToNulls = true//optimizer property

    IsInvariantToDuplicates = false, //optimizer property

    IsInvariantToOrder = false, //optimizer property

    MaxByteSize = 8000)        //maximum size in bytes of persisted value

]

public class Concatenate : IBinarySerialize

  // Intermediate result data of concatenation

  private StringBuilder intermediateResult;

 

  public void Init()

  {

    this.intermediateResult = new StringBuilder();

  }

 

  // If the next value is not null, append it to the end of string

  public void Accumulate(SqlString value)

  {

    if (value.IsNull)

    {

      return;

    }

    this.intermediateResult.Append(value.Value).Append(", ");

  }

 

  //Merges the partial aggregate with this aggregate

  public void Merge(Concatenate part)

  {

    this.intermediateResult.Append(part.intermediateResult);

  }

 

  //Returns the result of the aggregation when finished

  public SqlString Terminate()

  {

    string result = string.Empty;   

    if (this.intermediateResult != null

        && this.intermediateResult.Length > 0)

    {

      result = this.intermediateResult.ToString(0, this.intermediateResult.Length - 1);

    }

 

    return new SqlString(result);

  }

 

  public void Read(BinaryReader reader)

  {

    intermediateResult = new StringBuilder(reader.ReadString());

  }

 

  public void Write(BinaryWriter writer)

  {

    writer.Write(this.intermediateResult.ToString());

  }

}


Now you can register this function in SQL Server. First of all, enable .NET CLR code execution in your SQL Server:

EXEC sp_configure 'clr enabled', 1;

RECONFIGURE WITH OVERRIDE;

GO


and then create new aggregate function from your compiled assembly:

CREATE ASSEMBLY MyCLRLib FROM 'D:\MyCLRLib.dll'

GO

CREATE AGGREGATE Concatenate (@input nvarchar(1000)) RETURNS nvarchar(max)

  EXTERNAL NAME MyCLRLib.Concatenate

GO


Now you can write:

SELECT Surname, dbo.Concatenate(FirstName)

FROM Families

GROUP BY Surname



kick it on DotNetKicks.com

Tuesday, May 15, 2007

Regular Expressions in .NET

There are powerful tools in Unix such as grep, sed etc. These programs make use of regular expressions - regexp. Luckily, .NET contains a very useful class - a Regex class in a System.Text.RegularExpressions namespace.

Before using of regular expressions you need to understand the syntax. Here is a basic:














.Matches any single character
^Matches the beginning of a string
$Matches the end of a string
*Matches the preceding character or subexpression zero or
more times
+Matches the preceding character or subexpression one or
more times
( )subexpression

For more information about regular expressions syntax see this link

Now I can show how it is being used. The key method is Regex.IsMatch():

Regex regex = new Regex("^a...b$");

bool test1 = regex.IsMatch("axyzb");    //true

bool test2 = regex.IsMatch("axyzxyzb"); //false

bool test3 = regex.IsMatch("d");        //false



The following example validates an e-mail adress:

using System.Text.RegularExpressions;

 

class EmailAdress

{

  static Regex emailRegex = new Regex( @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");

  public static bool Validate(string email)

  {

    return emailRegex.IsMatch(email);

  }

}



For more information see:

.NET Framework Regular Expressions (MSDN)
System.Text.RegularExpressions Namespace (MSDN)

kick it on DotNetKicks.com

Friday, May 11, 2007

Simple Serialization and Deserialization in C#

.NET provides a functionality for storing and loading objects. This post shows how it can be used. The mechanism is called serialization and its purpose is to convert any object to stream of bytes that can be saved on a disk, sent by a protocol via internet etc.

So, at the beginning you have a class which you want to serialize. For example it looks like this:

public class MyExampleClass

{

  public string name;

  public int age;

  public readonly DateTime dateOfBirth;

  public double[] score;

  public MyExampleClass(string name, int age, DateTime dateOfBirth)

  {

    this.name = name;

    this.age = age;

    this.dateOfBirth = dateOfBirth;

    this.score = new double[0];

  }

}


Now, you want to save object of this class on a disk. At first add some namespaces:

using System.IO;    //Stream class

using System.Runtime.Serialization.Formatters.Binary;



Add [Serializable] attribute to your class:

[Serializable]

public class MyExampleClass



and then add methods for save and load in MyExampleClass:

public void SaveToFile(string filename)

{

  using (Stream stream = File.Open(filename, FileMode.Create))

  {

    BinaryFormatter formatter = new BinaryFormatter();

    formatter.Serialize(stream, this);

  }

}

 

public static MyExampleClass LoadFromFile(string filename)

{

  using (Stream stream = File.Open(filename, FileMode.Open))

  {

    BinaryFormatter formatter = new BinaryFormatter();

    return (MyExampleClass)formatter.Deserialize(stream);

  }

}



Here is an example how to use these methods:

//create new object

MyExampleClass myObject = new MyExampleClass("John", 30, new DateTime(1967, 1, 1));

myObject.score = new double[] { 5.5, 5.6, 6.1 };

myObject.SaveToFile("store");

 

myObject = null; //discard object

 

//load saved object

myObject = MyExampleClass.LoadFromFile("store");

Console.WriteLine(myObject.name);



That is all. It is very simple to use.

Note: Instead of BinaryFormatter you can use SoapFormatter.
The code is the same, only replace BinaryFormatter by SoapFormatter and use System.Runtime.Serialization.Formatters.Soap namespace. For this namesapce you have to add reference to System.Runtime.Serialization.Formatters.Soap.dll assembly in your project.

The difference is in the saved file. With SoapFormatter you get a file that is human readable. For our example, the saved file contains:

<a1:MyExampleClass id=\"ref-1\">

  <name id=\"ref-3\">John</name>

  <age>30</age>

  <dateOfBirth>

    1967-01-01T00:00:00.0000000+01:00

  </dateOfBirth>

  <score href=\"#ref-4\"/>

</a1:MyExampleClass>

<SOAP-ENC:Array id=\"ref-4\" SOAP-ENC:arrayType=\"xsd:double[4]\">

  <item>5.5</item>

  <item>5.6</item>

  <item>6.1</item>

</SOAP-ENC:Array>



Notice how the reference-typed objects are stored.

Anyone can change the content of this file and the object will reflect these changes after deserialization.

kick it on DotNetKicks.com

Sunday, May 6, 2007

NDoc for .NET 2.0

Very popular NDoc Code Documentation Generator for .NET does not supprot .NET assemblies 2.0. There is a very good unofficial tool for .NET 2.0 by Kevin Downs. You can find more information on this website. I have already tried it and it works very good.

Download NDoc 2.0 Alpha