Using System.IO.Path to manipulate physical paths

18 Feb

It often happens, in client and server applications, that we have to reference to physical files.

It can be necessary, for example, access files placed in subdirectory, organized by peculiar application logics. So we will have to combine some absolute and relative paths, taking care on generating valid paths, append filenames, change extensions, and so on…

We can always use the good old string concatenation and cross our fingers, hoping nothing go wrong, but the most secure way to do this is already included in the .NET Framework, and resides on System.IO.Path class.

System.IO.Path contains a whole serie of static, secure methods that allow us to manipulate in different ways physical paths and file names.

Let’s see some useful methods, and please note: the Path class doesn’t care if a path or a file really EXISTS on the file system, it only works on the PATTERN of paths, makes us sure that they are in the correct form.

Combine

Returns the concatenation of two or more physical paths, independently from the presence of the char “\” in the partial paths terminations.

Path.Combine(@"C:\mydirectory", "mysubdir");
// or
Path.Combine(@"C:\mydirectory\", "mysubdir");
// out: "C:\mydirectory\mysubdir"

GetDirectoryName

Returns only the directory (and drive) of a given path.

Path.GetDirectoryName(@"C:/mydirectory/text1.txt");
Path.GetDirectoryName(@"C:\mydirectory\text1.txt");
Path.GetDirectoryName(@"C:\\mydirectory/text1.txt");
// etc..
// out: "C:\mydirectory"

GetExtension

It’s self explained: returns only the extension of a given path (with the dot).

Path.GetExtension(@"C:\mydirectory\text1.txt");
// out: ".txt"

GetFileName

Returns the full name of a file in the given path, including extension.

Path.GetFileName(@"C:\mydirectory\text1.txt");
// out: "text1.txt"
Path.GetFileName(@"C:\mydirectory\xyz");
// out: "xyz"
Path.GetFileName(@"C:\mydirectory\xyz\");
// out: "" empty string, the "\" makes the difference

IsPathRooted

Returns true if the given path is absolute, false otherwise.

Path.IsPathRooted(@"C:\mydirectory\text1.txt");
// out: True
Path.IsPathRooted(@"\\mydirectory\text1.txt");
// out: True
Path.IsPathRooted(@"/mydirectory/text1.txt");
// out: True
Path.IsPathRooted(@"mydirectory/text1.txt");
// out: False

GetFileNameWithoutExtension

Returns only the name of a file, without extension.

Path.GetFileNameWithoutExtension(@"C:\mydirectory\text1.txt");
// out: "text"

GetInvalidFileNameChars

Returns an array containing the invalid chars for the underlying filesystem.

Path.GetInvalidFileNameChars();
// out: a char[]

HasExtension

Returns true if the given physical path contains the file extension.

Path.HasExtension(@"C:\mydirectory\text1");
// out: False

And these are only few examples. Full documentation can be found here.

In conclusion: if you’re doing something like:

public string MyHandMadeUnsafeMethodToGetFilePath(string subdir)
{
    // application logic, and then an horror as
    return String.Concat(@"C:\mydirectory\", subdir, "filename.txt");
}

please stop!

Select item from asp:DropDownList by extension method

19 Jan

Ok, this is really basic, but I’ve noticed that working with Asp.Net WebForms one of the first troubles that a novice can experience is, unbelievably, to change programmatically the selected item in a DropDownList.

For example, having a DropDownList as

<asp:DropDownList ID="ddlExample" runat="server">
    <asp:ListItem Text="item 1" Value="A1" Selected="true" />
    <asp:ListItem Text="item 2" Value="A2" />
    <asp:ListItem Text="item 3" Value="A3" />
</asp:DropDownList>

we need to select, i.e. during the Page_Load, the second item.

The most trivial solution would be to set on true the Selected attribute of the item:

...
ddlExample.Items.FindByValue("A2").Selected = true;
...

It’s needless to say that’s wrong. You’ll receive as error saying that is impossible to select more than one element in a DropDownList. The previous selected item, indeed, should be deselected.

What you’ve to do is to change the SelectedIndex attribute of the DropDownList, setting it as the index (base 0) of the item you want to select.

...
ddlExample.SelectedIndex = 1;
...

Obviuosly we should know each element’s index, even if usually we know their Value. So the code will be something like:

...
ddlExample.SelectedIndex = ddlExample.Items.IndexOf(ddlExample.Items.FindByValue("A2"));
...

That’s a really ugly line of code, if we think that’s just to select an item…

At this point it makes sense to write a centralized method that it’s ok to our purpose, once we’ve specified the DropDownList and the Value to find. Even better is to write an Extension Method.

The extension methods are a comfortable system to append functionalities to a certain objects, in an “external” way, that is without modifying and recompile the original class. They are static methods, but are visible as instance methods of the objects of the class that they extend. For more information on extension methods, read this.

We create a static class for our extensions, in wich we will define a static method called SelectedItem, that will accept 2 parameters: the DropDownList and the item Value to select. Note the synthax of the first parameter (DropDownList), that is preceded by the keyword this, defining that this is an extension of the DropDownList class.

namespace LetMeCode
{
    using System.Web.UI.WebControls;

    public static class Extensions
    {
        public static void SelectItem(this DropDownList d, string Value)
        {
            ListItem li = d.Items.FindByValue(Value);
            if (li != null)
                d.SelectedIndex = d.Items.IndexOf(li);
        }
    }
}

Once you’ve done, simply import the namespace LetMeCode in order to make visible the extension method related to the DropDownLists. So we can write:

...
ddlExample.SelectItem("A2");
...

that will select the wanted item without pain.
That’s all.

Using LINQPad for image manipulation

29 Dec

In these days I’m working on an Asp.Net image manipulation HttpHandler (well, I’m REworking on my old HttpHandler) that is built upon WPF libraries.

I’m new at image manipulation programming, and I don’t know WPFs so well, so I need to TRY nearly every single line of code. This handler is compiled in an assembly, referenced by a test website. This means that each time I make a change in the source code I need to recompile the assembly (wich contains a lot of other classes), update the reference, refresh the page on the browser just to see that I’ve done another horrible mistake.

Luckly I’ve found out that the latest beta version of LINQPad (4.31, at the time of writing) allows us to dump images on the result window.

Don’t you know LINQPad?

Damn, you MUST.

LINQPad is an awesome tool developed by Joseph Albahari, that works as code snippet editor, database navigator, learning tool and more. It’s free (without intellisense), cheap (with intellisense), it’s built upon the .NET framework and can execute your C#/VB.Net statements, programs or expressions (and SQL, of course). It can reference assemblies from GAC, or it can be linked to your own DLLs, allowing you to call compiled methods, instantiate classes, etc., speeding up the development.

In this tip I just want to show to you how to configure LINQPad for working with WPF and how to have fun with image manipulation, in a fast and easy way.

Download LINQPad

First of all you have to download the latest version of LINQPad (at least the version 4.31, that by now it’s only in beta). There are two versions: for the .NET framework 3.5 or 4.0, depending on your system.

Referencing the needed Assemblies

For my tests I need 3 assemblies from the GAC:

  1. WindowsBase.dll
  2. PresentationCore.dll
  3. System.Xaml.dll

To use them in the project just click on Query -> Query Properties

On “Additional References” tab click on “Add…”. You can now find and add to the query environment the previous mentioned dlls.

In order to simplify the writing of your code, you can import necessary namespaces on the query (as the “using” keyword does on Visual Studio) from the Query Properties’ tab “Additional Namespace Imports”. I’ve just added:

  • System.Windows
  • System.Windows.Media
  • System.Windows.Media.Imaging

Ready to start.

A sample program

Related to C#, LINQPad allows you to write expressions, statements or entire programs that contain classes, methods and so on. To make the code most portable as possible I’ve selected “C# Program” from the Language combo on the query window, obtaining a basic snippet:

void Main()
{

}

// Define other methods and classes here

Now let’s start to code.

This example will load an image (a frame from the Futurama titles), then composes a new image applying scaling, rotation and watermarking a text.

It’s completely unnecessary for the target of this article… but it’s funny, you know.

The scale factor is 35% and the image will be rotated 10° counterclockwise.

void Main()
{
	RotateAndScale("C:\\futurama.jpg", 0.35, -10);
}

public void RotateAndScale(string ImagePath, double Scale, double Degrees)
{
	BitmapImage originalImage = new BitmapImage();
	originalImage.BeginInit();
	originalImage.CacheOption = BitmapCacheOption.OnLoad;
	originalImage.UriSource = new Uri(ImagePath);
	originalImage.EndInit();

 	double newWidth = originalImage.Width * Scale;
	double newHeight = originalImage.Height * Scale;

	RenderTargetBitmap targetImage = new RenderTargetBitmap((int)Math.Ceiling(newWidth),
															(int)Math.Ceiling(newHeight),
															96, 96,
															PixelFormats.Default);

	DrawingVisual dv = new DrawingVisual();

	using (DrawingContext dc = dv.RenderOpen())
	{
		dc.PushTransform(new RotateTransform(Degrees, newWidth/2, newHeight/2));

		ImageBrush db = new ImageBrush(originalImage);

		dc.DrawRectangle(db, new Pen() { Brush = Brushes.Transparent }, new Rect(0, 0, newWidth, newHeight));

		FormattedText formattedText = new FormattedText("Is back",
													  System.Globalization.CultureInfo.CurrentCulture,
													  System.Windows.FlowDirection.RightToLeft,
													  new Typeface(new FontFamily("Tahoma"),
													  			   FontStyles.Italic,
																   FontWeights.Normal,
																   FontStretches.Normal),
													  18,
													  System.Windows.Media.Brushes.Black);

		dc.PushTransform(new RotateTransform(-Degrees, newWidth/2, newHeight/2));

		dc.DrawText(formattedText, new Point(newWidth - 5, newHeight - 18));
	}

	targetImage.Render(dv);

	StreamOut(targetImage);
}

public void StreamOut(BitmapSource image)
{
	BitmapEncoder encoder = new PngBitmapEncoder();
	encoder.Frames.Add(BitmapFrame.Create(image));

	using (MemoryStream stream = new MemoryStream())
	{
		encoder.Save(stream);
	}
}

Now you can execute this small program by pressing F5, or the Execute button on the top of the query window.

…But nothing happens.

That’s because we haven’t put the BitmapSource image on the result window.

Dump to output

LINQPad has an extension method called Dump() that you can use to push something on the result window. It works with any .NET types, and for the complex types it bulds an HTML table representing the object you’re dumping. But we can’t dump the stream we have built on the last step, because we will obtain something like this:

But we need to SEE the resulting image.

As I mentioned before, the latest beta version of LINQPad has an awesome helper method to stream out images, that is called Image() and it’s accessible from the Util class. This method returns an object that can be safely dumped to the result window.

So we’ll modify the StreamOut method as follows:

public void StreamOut(BitmapSource image)
{
    BitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(image));

    using (MemoryStream stream = new MemoryStream())
    {
        encoder.Save(stream);

        Util.Image(stream.ToArray()).Dump();
    }
}

F5 angain and…

…you can see the result of the program in real-time. Now every time we make a change to the previous code, we just need to press F5 to see the effects of our changes.

When the code above will be ready, we have to copy it back to the handler class and replace the specificity of LINQPad with the correct method for the output (that in my case means to change the StreamOut() method with):

public void StreamOut(BitmapSource image)
{
    BitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(image));

    using (MemoryStream stream = new MemoryStream())
    {
        encoder.Save(stream);

        stream.WriteTo(HttpContext.Current.Response.OutputStream);
    }
}