DCSIMG
Google+ August 2007 - Posts - Doron's .NET Space

August 2007 - Posts

This is the first of a couple of tips I would like to share reguarding WPF. WPF binding is extremely powerful, but you are bound to run into a few issues, especially if, like myself, you have no WinForms experience. As I was writing my small LiveSpaceToBlogML GUI, I used binding in order to populate an object called ConversionOptions, which pretty much held all the data on the form.

The form look something like this (a pretty simplified version, in order to focus on what matters):

<Window x:Class="LiveSpaceToBlogML.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Window.Resources> <local:ConversionOptions x:Key="Options" BlogName="MyBlog" SecretWord="MySecret"/> </Window.Resources> <StackPanel DataContext="{Binding Source={StaticResource Options}}"> <TextBlock >Your Windows Live Spaces blog address:</TextBlock> <TextBox Text="{Binding Path=BlogName}"/> <TextBlock >Your Windows Live Spaces e-mail publishing secret word:</TextBlock> <TextBox Text="{Binding Path=SecretWord}"/> <TextBlock>Output file:</TextBlock> <TextBox Text="{Binding Path=OutputPath}"/> <Button Content="Convert!" x:Name="Convert" HorizontalAlignment="Center" Click="Convert_Click"/> </StackPanel> </Window>

As you can see I am binding the StackPanel and text-boxes inside of it to an object of type ConversionOptions. At first, that object looked something like this:

public class ConversionOptions { public string BlogName { get; set; } public string OutputPath { get; set; } public string SecretWord { get; set; } }

As you can see, pretty simple. Just three properties, and C# 3.0 new property syntax makes things pretty short for us. No need to actually declare the private fields and all. Anyway, this works nice enough and when the user clicks "Convert!" I have a ConversionOptions object filled with all the data from the text-boxes.

But something is missing. I want to be able to set default values on the text-boxes, by changing my Options object, and not the controls themselves. In fact, what I need is for the binding to work in the other direction. Changes to the ConversionOptions object should be reflected in the controls. Digging a little, I found the useful INotifyPropertyChanged interface, which apparently has been with us since the WinForms days. This interface has only one member - the PropertyChanged event, which you are supposed to call whenever a property changes. This, in turn, will notify WPF to update the controls on the screen.

Here's a simple implementation for my ConversionOptions:

public class ConversionOptions : INotifyPropertyChanged { private string _blogName; public string BlogName { get { return _blogName;} set { _blogName = value; OnPropertyChanged("BlogName"); } } private string _secretWord; public string SecretWord { get { return _secretWord; } set { _secretWord = value; OnPropertyChanged("SecretWord"); } } private string _outputPath; public string OutputPath { get { return _outputPath;} set { _outputPath = value; OnPropertyChanged("OutputPath"); } } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; } }

As you can see, I am calling the PropertyChanged event whenever a property changes. There were two annoying things about writing this class:

  1.  I had to give up the cool property syntax. This was especially annoying as the new "prop" snippet only supports the short syntax, so I actually had to write the properties by myself (ReSharper doesn't support C# 3.0 yet, and that makes me sad).
  2. I had to name my properties in strings. That's never fun to do, as you don't get Refactoring (renaming a property will not change the string as well), intellisense and all that jazz. Strings suck.

This reminded me of a cool post I once read, by Jafar Husain. This extremely clever post talks about my problem exactly, and provides a great Linq solution. He uses the Linq Expression engine in order to enable access to property names in a strongly typed manner. This is the method Jafar wrote:

public static class SymbolExtensions { public static string GetPropertySymbol<T,R>(this T obj, Expression<Func<T,R>> expr) { return ((MemberExpression)expr.Body).Member.Name; } }

I won't explain it here, you can read about it in Jafar's post. The important thing is, this enabled me to change my class to this:

public class ConversionOptions : INotifyPropertyChanged { private string _outputPath; public string OutputPath { get { return _outputPath;} set { _outputPath = value; OnPropertyChanged(o => o.OutputPath); } } private string _blogName; public string BlogName { get { return _blogName;} set { _blogName = value; OnPropertyChanged(o => o.BlogName); } } private string _secretWord; public string SecretWord { get { return _secretWord; } set { _secretWord = value; OnPropertyChanged(o => o.SecretWord); } } protected virtual void OnPropertyChanged<R>(Expression<Func<ConversionOptions, R>> propertyExpr) { OnPropertyChanged(this.GetPropertySymbol(propertyExpr)); } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; }

As you can see, the strings are no more! All I had to do is reference Jafar's GetPropertySymbol extension method, and add an overload to my own OnPropertyChanged method. The overload accepts an expression. Every property passes it a delegate that takes a ConversionOptions object and returns the property. In this manner, GetPropertySymbol can extract the property name for the method. And it's all type-safe, refactoring and intellisense friendly. Thank you Linq, and thank you Jafar.

Now everything works. We have two-way binding, and I can count on the fact that my window and my data are always consistent. A couple of notes for the end:

  1. I have no idea what is the performance for GetPropertySymbol. I have a feeling it might be rather reflection-like slow, but I need to study the issue more thoroughly to tell you for sure.
  2. The version of LiveSpaceToBlogML that I uploaded to this blog does uses the standard way of calling OnPropertyChanged. The reason being that I targeted the .NET 3.0 Framework when I built it, and using Linq requires .NET 3.5.

I will conclude by recommending again that you read Jafar's blog. He has some really pretty (or handsome?) Linq-related code there.

Posted by dorony | 11 comment(s)
תגים:, , , ,

Up until recently I've been totally unaware to an extremely useful .NET feature known as IsolatedStorage. It goes like this. Let's say you have a client application, right? And that application needs to store some data, right? Some user preferences maybe. Thing is, trying to simply write that data into a file can be a problem. Your application might not have the permissions needed to write to the file system. In fact, if we're talking about a browser application, that's a very likely situation.

Here IsolatedStorage comes to our rescue. It allows you to write application or assembly specific data to a designated isolated place in the file system. This way, the user is safe from malicious code and your application can persist some data.

So how do you use it? Like any other file stream. You have to import the System.IO.IsolatedStorage namespace, and write something like this:

IsolatedStorageFile f = IsolatedStorageFile.GetUserStoreForAssembly(); using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(FileName, FileMode.Create)) { using (StreamWriter writer = new StreamWriter(stream)) { writer.WriteLine("Hello World"); } }

The first line determines which kind of isolated storage are you interested in. You can read more about that here.

I've created a small helper that will allow me to simplify my code that uses IsolatedStorage into something like this:

private void SaveDirectoryPath(string path) { IsolatedStorageHelper.Write(writer => writer.WriteLine(path)); } private string LoadDirectoryPath() { string path = IsolatedStorageHelper.Read<string>(reader => reader.ReadLine()); return path; }

Basically, I'm using IsolatedStorageHelper encapsulates opening and closing the IsolatedStorageStream, and allows you to focus on just writing\reading your data (read this if you're unfamiliar with the lambda "=>" syntax).

Here's the full source for IsolatedStorageHelper (You can also download the source from here):

public delegate void WriteCallback(StreamWriter writer); public delegate TResult ReadCallback<TResult>(StreamReader reader); public class IsolatedStorageHelper { private const string FileName = "appSettings"; public static void Write(WriteCallback callback) { IsolatedStorageFile f = IsolatedStorageFile.GetUserStoreForAssembly(); using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(FileName, FileMode.Create)) { using (StreamWriter writer = new StreamWriter(stream)) { callback(writer); } } } public static TResult Read<TResult>(ReadCallback<TResult> callback) { IsolatedStorageFile f = IsolatedStorageFile.GetUserStoreForAssembly(); using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(FileName, FileMode.OpenOrCreate)) { using (StreamReader reader = new StreamReader(stream)) { return callback(reader); } } }

Oh, and if you were wondering where the IsolatedStorage is stored, it's somewhere in the Documents and Settings folder. Exact locations can be found here.

And remember, using IsolatedStorage to store application or user specific data is a best practice. Your application shouldn't require any privileges that it doesn't really need.

Posted by dorony | with no comments

I came in need of an ASP.NET text box control that allows the user to enter rich text. Quickly enough I found FreeTextBox, an awesome control that is widely used in several well-known projects (such as Community Server, which hosts the blog you're currently reading). And, as it name suggests, the basic version of the control (which is more than enough for my needs) is free.

So I started playing around with it a bit, throwing it in a web-page, editing some HTML and posting the page. Boom.

...A potentially dangerous Request.Form value was detected from
the client...

Well, of course. ASP.NET was smart enough to detect that some HTML was posted in the form, and it thought to itself "Hmm, that could also be a script. Shouldn't let that happen." And it was right, too. Still, I do want to let my users edit HTML, don't I?

If you google that error, you will get one of two solutions:

  1. Set validateRequest="false" on the <pages> element in your web.config. This, will in turn cancel all request validation in all the pages in your application.
  2. Set ValidateRequest="false" on the <%Page...%> directive in the page you're using your FreeTextBox. This will cancel request validation only for the specific page.

The first suggestion is a big no-no, as it can seriously harm security on your web-site, allowing malicious users to inject scripts to your sites, and cause some serious damage (unless, of course, you validate all of your input yourself with regular expressions, which most people don't).

The second suggestion is better, as it exposes you to danger only in the page you have the FreeTextBox. There you'll have to be extra careful. First, if you have the HTML-mode enabled, allowing the user to enter raw HTML, the user can just put in <script> tags and post the form. So you might think that turning off HTML-mode, allowing only the design mode which creates HTML for you, you're off the hook.

Well, that won't be very smart of you. I showed here how any client-side validation turns to dust with a simple tool as the FireBug debugger for Firefox. With the same technique, you could go to the console view of Firebug, and hit the following:

-document.getElementById('FreeTextBox1').value = '<script> alert('hi!'); </script>';

-document.forms[0].submit();

So any method that tries to prevent the user to enter malicious data on the client is rather worthless. Luckily, FreeTextBox has a property StripAllScripting that removes all the scripts on the server-side, so no client-side hacks can help you there. I am not 100% sure this is a bullet-proof solution, but it seems to work well.

You should also be extra careful with any other fields you have on the same page that are not FreeTextBoxes. You don't get any request validation for them neither, so you should remember to validate them with regular-expressions, or simply Server.HtmlEncode their ass. Why couldn't we HTML-Encode our FreeTextBox input as well, you might ask? Well, that would kind of ruin the point of letting our users enter rich HTML content, wouldn't it? If we let them edit text with HTML, we would probably want to display their text as rich text, and not as a series of <htmlTags/>.

FreeTextBox really is a great control, just be careful not to leave huge security holes in your application while you're using it.

Posted by dorony | 9 comment(s)

My old blog resided in Windows Live Spaces, and I needed a way to move all its contents to the new place. I was quickly introduced BlogML, which is an XML standard that represents the entire contents of a blog. Still, I needed a way to convert a Live Space to BlogML, and I found a converter created by Jason Stangroome. It works by requiring you to enable e-mail publishing for your live space, and then uses the Live Space MetaWeblog API to do the conversion.

Jason's work is great, and can be obtained from the BlogML repository (you won't find it in the latest release). The thing is, his solution requires you to write some code (although fairly simple) to use it, so I decided to create a simple GUI for it. I wanted to practice some WPF anyway, so I picked up my newly downloaded VS 2008 Beta 2, and wrote up a simple application. It's not much, but it will save you some trouble if you need this conversion. Also, WPF-wise, it probably won't be best-practice code, as I am new to WPF and to Smart-Client development in general. 

That's how it looks:

LiveSpaceToBlogML

 The code that actually does the conversion is only a few lines, thanks to Jason's great work.

using (XmlWriter writer = XmlWriter.Create(options.OutputPath)) { LiveSpaceBlogMLWriter liveSpaceWriter = new LiveSpaceBlogMLWriter(options.BlogName, options.SecretWord); if (options.PostCount != null) liveSpaceWriter.PostCount = options.PostCount.Value; liveSpaceWriter.Write(writer); }

This will convert all your posts and categories. Things that will not get converted are:

  1. The comments - the main limitation. Hopefully Jason can get this fixed in a newer version.
  2. Your lists - you'll have to move that "Blog Roll" section on your own.
  3. Links inside your blog. If you have links from one post to another post, the links will still direct you to your older blog.

You can download the binaries here, and the source here. Note that the binaries require .NET 3.0 to run, and that the source require VS 2008 beta 2 to open.

Enjoy!

Posted by dorony | 4 comment(s)
תגים:,

Hello, and welcome to the brand new version of Doron's .NET Space! If you don't know me yet, my name is Doron Yaacoby, and I've been immersed in the .NET world in the last couple of years. I've been blogging for about 6 months.

It's a bit disconcerting, moving to a new blog. You worry about your readers, about the platform. It's rather like moving to a new home. It is also an opportunity, to reach a new crowd, and to escape the limitations of the old place.

The transition was made by porting my old blog to the BlogML format, and uploading it here. More on that - on my next post. In the meantime, I encourage you to subscribe to the RSS feed, and wish me good luck.

Posted by dorony | 7 comment(s)
תגים: