Google
 
Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Friday, September 22, 2023

Handling special content with Handlebars.net Helpers

Generating formatted reports based on application data is a very common need. For example, you may want to create an HTML page with content from a receipt. This content may be sent in an HTML formatted email or converted to PDF or any other use case. To achieve this, a flexible and capable templating engine is needed to transform the application data to a human readable format.
.net has a very powerful templating engine that's used in its asp.net web framework which is Razor templates. But what if you want to use a templating engine that is simpler, and doesn't require a web stack as in the case of building background jobs, desktop or mobile applications?

 


Handlebars.net is a .net implementation of the famous HandlebarsJS templating framework. From Handlebars.net Github repository:

"Handlebars.Net doesn't use a scripting engine to run a Javascript library - it compiles Handlebars templates directly to IL bytecode. It also mimics the JS library's API as closely as possible."
For example: consider this collection of data that should be rendered as an HTML table:

var employees = new [] 
{
    new Employee
    {
        BirthDate= DateTime.Now.AddYears(-20),
        Name = "John Smith",
        Photo = new Uri("https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Houghton_STC_22790_-_Generall_Historie_of_Virginia%2C_New_England%2C_and_the_Summer_Isles%2C_John_Smith.jpg/800px-Houghton_STC_22790_-_Generall_Historie_of_Virginia%2C_New_England%2C_and_the_Summer_Isles%2C_John_Smith.jpg")
    },
    new Employee
    {
        BirthDate= DateTime.Now.AddYears(-25),
        Name = "Jack",
        Photo = new Uri("https://upload.wikimedia.org/wikipedia/commons/e/ec/Jack_Nicholson_2001.jpg")
    },
    new Employee
    {
        BirthDate= DateTime.Now.AddYears(-40),
        Name = "Iron Man",
        Photo = new Uri("https://upload.wikimedia.org/wikipedia/en/4/47/Iron_Man_%28circa_2018%29.png")
    },
};

A Handlebars template may look like:

<html>
<body>
	<table border="1">
		<thead>
			<tr>
				<th>Name</th>
				<th>Age</th>
				<th>Photo</th>
			</tr>
		</thead>
		<tbody>
			{{#each this}}
			<tr>
				<td>{{Name}}</td>
				<td>{{BirthDate}}</td>
			</tr>
			{{/each}}
		</tbody>
	</table>

</body>
</html>

The template is fairly simple. Explaining the syntax of Handlebars templates is beyond the scope of this article. Check Handlebarjs Language Guide for information regarding its syntax.

Passing the data to the Hanledbar.net and render the template is easy:

var template = File.ReadAllText("List.handlebars");
var compiledTemplate = Handlebars.Compile(template);
var output = compiledTemplate(employees);

Console.WriteLine(output);

Line 1 reads the List.handlebars template which is stored in the same application folder, alternatively the template can be stored as an embedded resource or retrieved from a database or even created on the fly.
Line 2 compiles the template, generating a function that can be invoked later. 

Note: For good performance, the compiled template should be generated once and used multiple times during the lifetime of the application.

Line 3 invokes the function passing the employees collection and receives the rendered output in a string variable.

This is the generated HTML:

<html>
<body>
	<table border="1">
		<thead>
			<tr>
				<th>Name</th>
				<th>Age</th>
				<th>Photo</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>John Smith</td>
				<td>2003-09-09T22:08:23.3541971+10:00</td>
				<td><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Houghton_STC_22790_-_Generall_Historie_of_Virginia%2C_New_England%2C_and_the_Summer_Isles%2C_John_Smith.jpg/800px-Houghton_STC_22790_-_Generall_Historie_of_Virginia%2C_New_England%2C_and_the_Summer_Isles%2C_John_Smith.jpg" width="200px" height="200px" /></td>
			</tr>
			<tr>
				<td>Jack</td>
				<td>1998-09-09T22:08:23.3839317+10:00</td>
				<td><img src="https://upload.wikimedia.org/wikipedia/commons/e/ec/Jack_Nicholson_2001.jpg" width="200px" height="200px" /></td>
			</tr>
			<tr>
				<td>Iron Man</td>
				<td>1983-09-09T22:08:23.3839479+10:00</td>
				<td><img src="https://upload.wikimedia.org/wikipedia/en/4/47/Iron_Man_%28circa_2018%29.png" width="200px" height="200px" /></td>
			</tr>
		</tbody>
	</table>

</body>
</html>

And this is how the output is rendered by a browser:


Putting aside lack of styling which has nothing to do with Handlebars, the output seems good but suffers for two issues:

  1. The format of the Age property is not great.
  2. The image tags rendered by the template reference the full URL of the images. Every time the generated HTML is consumed and rendered, it will have to fetch the images from their sources, which may be inconvenient. Additionally, the generated template is not self-contained, and other services that consume the generated HTML (like an HTML to PDF conversion service) will have to download the images.

Although the Handlebars has a powerful templating language, it's impossible to cover all needs that may arise, this is why Handlebars.net provides the ability to define custom helpers.
 

Custom Helpers: 

Helpers provide an extensibility mechanism to customize the rendered output. Once created and registered with Handlebars.net, they can be invoked from templates as if they were part of Handlebar's templating language.
Let's use helpers to solve the date format issue:
Handlebars.RegisterHelper("formatDate", (output, context, arguments)
                => { output.Write(((DateTime)arguments[0]).ToString(arguments[1].ToString())); });

This one-line registers a formatDate helper that takes the first argument and formats it using the second argument. To call this helper in the template:

<td>{{formatDate BirthDate "dd/MM/yyyy"}}</td>

The rendered output is much better now:


Embedding images in the HTML output

To solve the second issue mentioned above, we can write a custom helper to embed image content using the data URI scheme.
This is a basic implementation of this "embeddedImage" helper:

Handlebars.RegisterHelper("embeddedImage", (output, context, arguments) =>
{
    var url = arguments[0] as Uri;
    using var httpClient = new HttpClient();

    // add user-agent header required by Wikipedia. You should safely ommit the following line for other sources
    httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("example.com-bot", "1.0"));

    var content = httpClient.GetByteArrayAsync(url).Result;
    var encodedContent = Convert.ToBase64String(content);
    output.Write("data:image/png;base64," + encodedContent);
});

The code uses an HttpClient to download the image as a byte array, then encode it using base64 encoding, then writes the output as a data URI using the standards format. And the usage is very simple:

<img width="200px" height="200px" src="{{embeddedImage Photo}}"  />

And the HTML output looks like: (trimmed for brevity)

<img width="200px" height="200px" src="data:image/png;base64,/9j/4gIcSUNDX1BST0ZJTEUAAQEAAAIMbGNtcwIQAABtbnRyUkdCIFhZWiAH3AABABkAAwApAD.....

 

Conclusion

One of the most important design principals is the Open-Closed Principal: software entities should be open for extension but closed for modification. Handlebars and Handlebars.net apply this principal by allowing users to extend the functionality of the library without having to modify its source code, which is a good design.
With a plethora of free and commercial libraries available for developers, the level of extensibility should be one of the evaluation criteria used during the selection process.
And you, what other templating libraries have you used in .net applications? How extensible are these libraries?

Wednesday, May 10, 2023

Setting exit code of a .net worker application

When building a .net worker application with a hosted service based on the BackgroundService class, it's some times it's required to set the application exit code based on the outcomes of the execution of the hosted service.

One trivial way to do this is to to set the Environment.ExitCode property from the hosted service:


public class Worker : BackgroundService
{
    public Worker()
    {

    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            throw new Exception("Something bad happened");
        }
        catch
        {
            Environment.ExitCode = 1;
        }
    }
}

This works, however consider these unit tests:


[Test]
public async Task Test1()
{
    Worker sut = new Worker();
    await sut.StartAsync(new CancellationToken());

    Assert.That(Environment.ExitCode, Is.EqualTo(1));
}

[Test]
public void Test2()
{
    // another test
    Assert.That(Environment.ExitCode, Is.EqualTo(0));
}

Test1 passes, however Test2 fails as Environment.ExitCode is a static variable. You can reset back to zero it after the test, but this is error-prone. So what is the alternative?

One simple solution is to use a status code-holding class as a singleton and inject it into the background service:


public interface IStatusHolder
{
    public int Status { get; set; }
}

public class StatusHolder : IStatusHolder
{
    public int Status { get; set; }
}

public class Worker : BackgroundService
{
    private readonly IStatusHolder _statusHolder;

    public Worker(IStatusHolder statusHolder)
    {
        _statusHolder = statusHolder;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            throw new Exception("Something bad happened");
        }
        catch
        {
            _statusHolder.Status = 1;
        }
    }
}

As simple Program.cs would look like:


using EnvironmentExit;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
        services.AddSingleton<IStatusHolder, StatusHolder>();
    })
    .Build();

host.Start();

var statusHolder = host.Services.GetRequiredService<IStatusHolder>();
Environment.ExitCode = statusHolder.Status;

Note that line number 8 registers IStatusHolder as a singleton, which is important to maintain its state.

Now all tests pass. Additionally, when the application runs, the exit code is 1.

Sunday, April 4, 2010

LINQ to entities unncecessary casts

Using LINQ with Entity Framework can give a big productivity boost. It removes the burden of O/R mapping and writing SQL queries. But Adding this layer can come with costs.
I was writing a desktop application that uses a SQL CE database and I used LINQ to entities to talk to the database.
One of the methods was slow and I suspected that the reason can be a slow query. In normal, hand-written SQL queries, I inspect query plans to check the reason for the bad performance. So I started to log queries generated by LINQ statements using:

(myQuery as ObjectQuery).ToTraceString()

Then I took the SQL query from log file to SSMS and I started to make some enhancements. One of them was adding an index to a smallint column used in a foreign key. But I discovered that the index was not used by SQL CE. That was strange, but looking to the where statement generated I found something like:

WHERE ( CAST( [Extent1].[PageNumber] AS int)) = ( CAST( @p__linq__468 AS int))

And the index on the PageNumber column (smallint) was not used as I found from execution plan that filtering is made after a table scan (not index seek).
I suspected that the cast used in the above query is what caused the optimizer not to recognize that the index should be used, and I verified this by removing the cast and running the query in SSMS again. This time the index is being used.
I started to Google about this issue. But found that SQL Server is smart enough not to be tricked by the silly cast. But since I'm using SQL CE. I had to find a way to fix this issue.
Removing the unnecessary cast was out of my hands, so I decided to change the data type of the column to int and sacrifice some space to gain some speed. I did that and updated the model. And the where clause became:

WHERE [Extent1].[PageNumber] = ( CAST( @p__linq__468 AS int))

No casts for the PageNumber column and the index is used.

When you use a high level technology, you take it with its pros and cons. But there are no excuses, you are responsible for what you ship to your client.

Thursday, July 2, 2009

Not calling Dispose can cause InvalidComObjectException

During load testing an application that performs thousands of operations against Active Directory and under high load conditions. The process stopped working and our logs showed this error:

System.Runtime.InteropServices.InvalidComObjectException: COM object that has been
separated from its underlying RCW cannot be used.

Searching for this error, most answers on forums referred to trying to access a COM object from a thread other than the thread that created it. We use multithreading, but we did not use objects across threads.

Logs pointed us the location of the code where we should investigate. I made a review on a method that was called thousands of times and creates DirectoryEntry instances. The DirectoryEntry was not disposed!!

We were not sure that this can cause the above exception, but it was a bug and it needed to be fixed anyway. We fixed it and reapplied the scenarios that caused this exception, and it disappeared.

Other that understanding a new reason for that mysterious exception, there are some useful lessons:
  • Proper logging can help identifying errors quickly.
  • Failing to dispose disposable objects causes performance penalties that some developers underestimate their effect. It can make your application stop working!!
  • Early code review is important to spot these kinds of errors.
  • Test your application under real-life conditions.
  • Using memory profilers and dispose trackers is worth trying in some cases.

Friday, December 5, 2008

Handling errors when calling PowerShell using C#

In a previous post, I explained how to call PowerShell Commands from C# code in an easy way. But what about error handling?
First, we should know about the types of errors that need to be handled:
  • Exceptions due to error in syntax of the command or script.
  • Errors generated from commands themselves due to logical errors or invalid parameters.
Handling Exceptions:
Several exceptions can be thrown. The base for PowerShell exceptions is the System.Management.Automation.RuntimeException class. Exceptions can originate from bad syntax or calling invalid commands.
Handling this kind of errors follows the common exception handling in .net as this example shows:


try
{
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "c:\\" + " -recurse -Filter *.exe");
}
}
catch (System.Management.Automation.RuntimeException ex)
{
Console.WriteLine(ex.Message);
//Specific handling for PowerShell errors
}
catch (Exception ex)
{
//general handling and logging
}

Command Errors:
These errors that commands return. For example, when you run this command in PowerShell while you don't have a Q drive:
dir Q:
You'll get this error:
Get-ChildItem : Cannot find drive. A drive with name 'q' does not exist.
At line:1 char:4
Which makes sense. But how to check for this kind of errors?
The Invoke method of the RunspaceInvoke class has an overload that accepts an IList as the 3rd parameter. This out parameter will contain a list of errors that has occurred.


IList errors;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "Q:\\" + " -recurse -Filter *.exe", null, out errors);
}

if (errors.Count > 0)
{
PSObject error = errors[0] as PSObject;
if (error != null)
{
ErrorRecord record = error.BaseObject as ErrorRecord;
Console.WriteLine(record.Exception.Message);
Console.WriteLine(record.FullyQualifiedErrorId);
}

return;
}

In the above code, I cast the error to PSObject and get its BaseObject and cast it to ErrorRecord which contains the error information.

An interesting part here, is that you can check the FullyQualifiedErrorId property which is a string to distinguish errors and create logic to handle specific errors. ErrorDetails property can also be checked. But be careful because it can be null.

I hope this post can make your programming with PowerShell easier.

Thursday, November 20, 2008

Storing Arabic (or Unicode) data in MySQL using Connector/Net 5.2

Storing Unicode data in varchar columns in MySQL can be tricky. I spent some time to use MySQL Connector/Net 5.2 to store Arabic data.
Once you know it, it's simple:

  • The varchar column Charset should be utf8
  • The varchar column Collate property should be utf8_general_ci. I tried utf8_bin and worked too. This is a screen shot from MySQL Administrator table editor:


  • In the .net application, the connection string must include charset=utf8. For example:

"server=localhost;uid=root;password=123;database=test;port=3306;charset=utf8"

Friday, November 14, 2008

Scripting SQL Server database objects using SMO

Scripting a database objects from development environment is a necessary step before deployment to production or test environments and to add the script to source control. Doing this manually is error prone and time consuming.
Also If you practice continuous integration, it's a must to automate the script generation process.

I used Database Publishing Wizard which is hosted on codeplex. It's good but the command line options lack the ability to determine which objects to script. That caused a problem because it scripted users as well. Which I did not want it to do.

Although it's hosted on codeplex, I could not download the source code to make the necessary modifications.

So, I had to go the hard way. And I did it myself. Using SQL Server Management Objects (SMO), I built a small command line utility to script: Tables, Indexes, UDFs, Veiws, SPs, Defaults, Checks, Foreign keys.
There are limitations ofcourse, But at least it's under control as long as the code is available.

The application depends on the core class ScriptingEngine, which in turn depends on Microsoft.SqlServer.Management.Smo.Scripter class.

Points of interest:
  • Order of scripting is important for the script to be used to regenerate objects.
  • Determining object dependencies is an important trick. Using DiscoverDependencies method, it's possible to order objects bu


public void ScriptViews()
{
List<urn> urns=new List<urn>();

foreach (View view in _database.Views)
{
if (view.IsSystemObject)
continue;
urns.Add(view.Urn);

}

DependencyTree tree = _scripter.DiscoverDependencies(urns.ToArray(), true);
DependencyCollection dc = _scripter.WalkDependencies(tree);

RemoveUrnType(dc,"Table");
RemoveUrnType(dc, "UserDefinedFunction");

_scripter.ScriptWithList(dc);

}

  • Note the RemoveUrnType method, it's used to filter unwanted object types from the DependencyCollection:


private void RemoveUrnType(DependencyCollection dc,string type)
{
for (int counter = 0; counter < dc.Count; counter++)
{
if (dc[counter].Urn.Type==type)
{
dc.RemoveAt(counter);
counter--;
}
}
}

  • Usage:
SqlScripter.exe -server:server\instance -database:dbname -login:login -password:pwd -filename:pathtoscriptfile

You can download the source from skydrive:

Friday, September 5, 2008

Calling PowerShell Commands from C# code

Windows PowerShell is a solution to what the windows platform lacked, a really powerful shell !! But it does not stop at this point. Calling PowerShell commands (Cmdlets) from .net code, using the return values can add real power to you application.

In this post, I'll explian how to gain this power in a simple C# application to recursively search the file system and getting the results. The same technique can be used in many other scenarios.

Before starting to code:
First you need to install Windows PowerShell for your windows version. So you need to check How to Get Windows PowerShell 1.0

Next, add a reference to System.Management.Automation.dll to the application, It can be found under C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0 in case of windows XP installation.

After adding this using statement, you'll be ready to code:
using System.Management.Automation;

Starting simple : Getting a list of files and folders recursively:
There are many ways to integrate with PowerShell, here, I'll use a relatively simple way which is the RunspaceInvoke class.

first, let's examine this command in PowerShell:
dir C:\WINDOWS -Recurse
Executing this command in PowerShell will get all files and folders under C:\windows recursively. By the way, dir is an alias to the command Get-ChildItem, not a command itself.

This code creates a RunspaceInvoke instance and invokes dir:

System.Collections.ObjectModel.Collection<psobject> result = null;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "D:\\Codes\\C#\\PSDir" + " -recurse");
}

Note that the Invoke method returns a generic collection of PSObjects. We'll use this collection to retrieve the results. This is one of the real powerful features of PowerShell, it talks objects not text as the old command line commands.

But what can we get from the Collection of PSObjects? PSObject class contains the ImmediateBaseObject property that contains the actual object returned by the command. In the case of dir, we expect that this command will return objects of types: System.IO.DirectoryInfo and System.IO.FileInfo. We'll see later how can we discover this. But for now, lets get the results:

foreach (PSObject item in result)
{
if (item.ImmediateBaseObject is System.IO.DirectoryInfo)
{
System.IO.DirectoryInfo info = item.ImmediateBaseObject as System.IO.DirectoryInfo;
Console.WriteLine("Directory:" + info.FullName);
}
else if (item.ImmediateBaseObject is System.IO.FileInfo)
{
System.IO.FileInfo info = item.ImmediateBaseObject as System.IO.FileInfo;
Console.WriteLine("File:" + info.FullName);
}
}

As you see in the above code, I check the type of the result and display the appropriate value based on it. The result will be something like this:




A more useful example: Searching the file system:
You can use dir to search for all files of a specific type under a specific path using the filter parameter. This is a complete code listing:

System.Collections.ObjectModel.Collection result = null;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "D:\\Codes\\C#\\PSDir" + " -recurse -Filter *.exe");
}

foreach (PSObject item in result)
{
if (item.ImmediateBaseObject is System.IO.DirectoryInfo)
{
System.IO.DirectoryInfo info = item.ImmediateBaseObject as System.IO.DirectoryInfo;
Console.WriteLine("Directory:" + info.FullName);
}
else if (item.ImmediateBaseObject is System.IO.FileInfo)
{
System.IO.FileInfo info = item.ImmediateBaseObject as System.IO.FileInfo;
Console.WriteLine("File:" + info.FullName);
}
}

Console.ReadKey();

Exploring PowerShell commands results:
In the above code, I expect the result to be .net types System.IO.DirectoryInfo and System.IO.FileInfo. But how could one detect the type?
PowerShell is very discoverable. for example, executing these statements in PowerShell lets us know the return type (Note that results depend on your file system):
$result = dir c:\
$result[0].GetType().Name

this returns:
DirectoryInfo
Trying another index like 9:
$result[9].GetType().Name
returns:
FileInfo

In this post, we made use of PowerShell commands and manipulated their results. In another post, I'll explain how to check for errors that may occur when running PowerShell commands and how to handle them.

Sunday, August 24, 2008

Getting machine name in .net

Environment.MachineName is commonly used to get the machine name in .net. Few days ago, I met a problem with it after renaming a machine and joining a domain: Environment.MachineName returned the old name machine name.

While searching for the reason, I found that Environment.MachineName gets the NetBIOS name, which is stored in the registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Contro l\ComputerName\ComputerName\ComputerName and reflects in the Computername envronment variable.

A big limitation of NetBIOS name in this case is that it's limited to the first 15 characters of the machine name. An alternative is needed to get the full name. Which is System.Net.Dns.GetHostName() method which gets the DNS host name of the local computer, which is not limited to the first 15 characters.

Back to my problem, I edited the registry key to reflect the new machine name. That was good enough for me!!

Friday, August 1, 2008

Validating SMTP host information

This is a simple class to check if a connection to SMTP host is possible. It can be useful in case of gathering user input and the user is required to enter a valid smtp host.

The idea is simple, open a TCP connection to the host, and read the initial welcome message sent by the smtp host, it should start with response code 220.
I everything is ok, we need to end the sesion by sending QUIT command and close the connection.
For more information check RFC 821 SIMPLE MAIL TRANSFER PROTOCOL

I used Visual C# 2008 Express edition to build this example. You can check the code below, or download the code with a test application from this link:




public static class SmtpChecker
{
public static bool Check(string host,int port,out string welcomeMessage)
{
try
{
using (TcpClient smtp = new TcpClient(host, port))
using (StreamReader reader = new StreamReader(smtp.GetStream()))
{
welcomeMessage = reader.ReadLine();

//validate the reasponse
if (welcomeMessage.StartsWith("220", StringComparison.InvariantCulture))
{
//Send QUIT as recommended by RFC 821
try
{
using (StreamWriter w = new StreamWriter(smtp.GetStream()))
{
w.WriteLine("QUIT");
w.Flush();
string result =reader.ReadLine();
}
}
catch
{}

return true;
}
else
{
welcomeMessage = "";
return false;
}
}
}
catch (Exception)
{
welcomeMessage = "";
return false;
}
}
}

Friday, June 20, 2008

Converting a colored image to gray scale using C#

This is a simple method that creates a gray scale image from a colored image in C#:

public Image ToGrayScale(Image img)
{
Bitmap bitmap = new Bitmap(img);

for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
byte r = pixelColor.R;
byte g = pixelColor.G;
byte b = pixelColor.B;

byte gray=(byte)(0.299*(float)r+0.587*(float)g+0.114*(float)b);
r = g = b = gray;
pixelColor = Color.FromArgb(r, g, b);

bitmap.SetPixel(i, j, pixelColor);
}
}

Image grayImage = Image.FromHbitmap(bitmap.GetHbitmap());
bitmap.Dispose();
return grayImage;
}


The whole magic is in this line of code:

byte gray=(byte)(0.299*(float)r+0.587*(float)g+0.114*(float)b);

It extracts the Luminance component of the color in the YCbCr color system which represents the intensity of the image.

The rest is easy, all color components (R,G,B) will be the same for the image to be a gray scale.

Saturday, April 26, 2008

EDC: VS2008 New Enhancements

In this post I'll try to shed some light on what Chad Hower covered in his edc2008 session :"VS2008 New Enhancements".

The new keyword "var":
It's both used in LINQ expressions and when using anonymous types (more about them later). It also can be used in any regular variable declaration and initialization, for example:

StringBuilder b = new StringBuilder();
b.Append("abc");
var varB = new StringBuilder();
varB.Append("abc");


In the above example, var keyword was used instead of the StringBuilder class name in the second declaration. And the StringBuilder is used regularly. What worth mentioning is:


  • Some ex-vb developers may think that var is the same as the vb6 Variant datatype, which will cause some performace degradation when calling methods due to late binding. This is not true. The compiler replaces the var with the type initialized in the RHS. So the compiler output of these 2 lines is the same:

    StringBuilder b = new StringBuilder();

    var b = new StringBuilder();
    We just saved some keystrokes :).

  • VS2008 has full intellisense support for var. as you can see in the screenshot:


LINQ:

Using Language Integrated Query with collections can make many of programming tasks easier, like searching for an object or objects in a collection that meet a certain criteria.
For example, if we have a List< string > and we want to find all strings that start with the letter 'S', this is the old way to do this :

List< string > found=new List< string >();
foreach (string s in items)
{
if (s.StartsWith("S"))
found.Add(s);
}

Using LINQ:

var found = from s in items
where s.StartsWith("S")
select s;

Ok, more value can be gained if you need to get them sorted by length:

var found = from s in items
where s.StartsWith("S")
orderby s.Length
select s;


Some people may think that the 'var' keyword is what indicates a LINQ expression, but no, it's actually the 'from'.

A good place to think about using LINQ is where you usually use for and foreach.

LINQ is a new feature of C# v3.0 and VB.NET v9.0

Anonymous types:
I'll talk about Anonymous types usage in LINQ, although there are other cases when are useful.
In the above LINQ example, what if we don't need to get the result as a collection of complete objects of the original collection, and we just need one or two attributes (just as we can select just a few columns from a SQL database, not all columns from the table).
Anonymous types can be used in this case:

var found = from s in items
where s.StartsWith("S")
orderby s.Length
select new { value = s, length = s.Length };


Here, we created a new type on the fly, it has 2 properties: value which is a string and length which is an integer.
But how to iterate on found when we don't know the type of the objects it holds (remember, it's anonymous). This is where var comes to be useful again:

foreach (var s in found)
{
Console.WriteLine(s);
}



Others:
Chad talked about other thinks like OBA (Office Business Applications), WPF. The most important thing is that WPF works fine with Winforms. Winforms can host WPF components.

A very interesting presentation that Chad has shown for us was the History of Microsoft Office Download it and enjoy !!
Besides being funny, it shows how MS Office navigation had to evolve.


Chad just scratched the surface, but left us hungry for more knowledge about the existing new features.

Monday, January 28, 2008

Windows forms: Adjust width of combobox drop down according to content

Combobox control has the DropDownWidth property to control the width of the dropped portion that appears when the user clicks the drop down arrow. This property takes the width in pixels.

It's nice to have the width of the drop down set according to the contents. This code does the job:
Assuming the name of the control is cmb:


int ItemMaxWidth = this.cmb.DropDownWidth;
Graphics gx = cmb.CreateGraphics();


for (int i = 0; i < this.cmb.Items.Count; i++)
{
//get the width of item
SizeF s = gx.MeasureString(cmb.Items[i].ToString(), cmb.Font);
if ((int)s.Width > ItemMaxWidth)
{
ItemMaxWidth = (int)s.Width;
}
}

gx.Dispose();

//Set the width :
cmb.DropDownWidth = ItemMaxWidth;

Sunday, July 22, 2007

Moving a form without a title bar

How to make a form without a title bar movable?

This is a common request in programming forums, and here is a simple solution that depends on handling mouse down and mouse move events:


public partial class Form1 : Form
{
int m_PrevX;
int m_PrevY;

public Form1()
{
InitializeComponent();
}

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;

Left = Left + (e.X - m_PrevX);
Top = Top + (e.Y - m_PrevY);

}

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button!=MouseButtons.Left)
return;

m_PrevX = e.X;
m_PrevY = e.Y;
}

Friday, April 27, 2007

Misleading performance comparisons: C# vs. Java

In a blog post: The Ultimate Java Versus C# Benchmark the author tried to prove that Java outperforms C# in a real life benchmark.
The benchmark actually measures the performance of regular expressions in both languages (say frameworks).
He concludes the post saying that C# failed even to give the results, and consumed too much memory till an OutOfMemoryException was thrown.
I tried both code samples (C# using .net 2.0, Java using Java SE runtime version 1.6).
The Java version worked as mentioned in the blog post (took about 4031 milliseconds on my PC), the C# version took too long time so I had to terminate it.
I noticed that the whole benchmark is about comparing these lines of code:
C#:
Regex regexpr = new Regex(matchthis, RegexOptions.Compiled);
Boolean b = regexpr.IsMatch(_doc);

Java:
Pattern regexpr = Pattern.compile(matchthis); Matcher matcher = egexpr.matcher(_doc);
boolean b = matcher.find();


When I changed the C# code to:
Regex regexpr = new Regex(matchthis);
Boolean b = regexpr.IsMatch(_doc);


Execution took about 14672 milliseconds. Which is somehow acceptable, even if a lot longer that Java execution time. Note that this version does not compile the regular expression.

When I removed the regular expression comparison from both codes the result was:
C#: 891 milliseconds
Java: 1750 milliseconds

See the difference!!

Conclusion:
  1. It's unfair to compare two versions of code written in a way that is optimized for one language but not for another. In .net, compiling regular expressions is good when you are going to reuse them.
  2. Taking a single point of comparison (regular expression in this case) is not a valid measurement when you compare two huge frameworks like .net and Java.
I'm not trying to defend C#, and I'm not claim that .net outperforms Java generally. I just suggest that performance comparisons should not be performed by biased persons. The test should not be optimized for one language without the other.