Archive for December, 2007


Event performance optimization with the EventHandlerList

When using custom events (event delegates) in your ASP.NET pages, user controls and server controls, many developers might define their Events as public fields, like this:

public event EventHandler<EventArgs> MyCustomEvent;

And use this code to fire the event:

protected void OnMyCustomEvent(EventArgs e)
{
  if(MyCustomEvent != null)
  {
    MyCustomEvent(this, e);
  }
}

Nothing is wrong with the approach of the latter, but defining the MyCustomEvent as a public field introduces two problems:

  1. Even though no clients have registered any delegates to the invocation list of your event, the compiler generates
    one private delegate field for each event delegate in your class. This is a waste of server memory, especially if
    you have several events inside your class.
  2. One Add and one Remove method is generated for each event field of your class. When clients use += and -= to add
    and remove delegates from the invocation lists of your class’ events, these methods are called behind the scenes.
    These two compiler-generated methods are thread-safe, which means they include extra code to synchronize threads
    that are accessing these methods. This means, that everytime a client adds or removes a delegate to or from the
    invocation list of an event, they have to get a lock before they can do the actual work. This introduces an
    unnecessary overhead because most page developers don’t use multiple threads and therefore there is no need for
    thread synchronization.

The EventHandlerList is the answer to our issues. This class comes with the .NET Framework. The EventHandlerList is a linked list of delegates,which is optimized for adding and removing delegates. To use the EventHandlerList in your classes, you need to add a private static key for each event your class exposes. The code bellow defines a key for MyCustomEvent:

private static readonly object MyCustomEventKey = new object();

The memory is allocated only once, because the key is static.

After this, you need to define your events as properties – not fields. These event properties has a different syntax that normal get-set properties. Event properties uses add-remove instead of get-set. The following property, is an event property for MyCustomEvent:

public event EventHandler<EventArgs> MyCustomEvent
{
  add { Events.AddHandler(MyCustomEventKey, value); }
  remove { Events.RemoveHandler(MyCustomEventKey, value); }
}

Every Page, UserControl and WebControl – among others – has a protected property of type EventHandlerList named Events. With this approach, when clients use += to add a delegate to the invocation list of the MyCustomEvent, the add method of the event property calls the AddHandler method of the EventHanderList class, as the code above will tell you. As for -= the RemoveHandler method is called.

The EventHandlerList class maintains a linked list which can have none or one entry for each event. The AddHandler method checks whether this internal linked list contains an entry for an event with the given event key. If it does, the method calls the Combine method of the Delegate class to add the client delegate to the invocation list of the event. If this internal list doesn’t contain an entry for an event with the given event key, the AddHandler method just adds a new entry.

With this new approach, we need to update our OnMyCustomEvent Method, which is responsible for firing the event:

protected void OnMyCustomEvent(EventArgs e)
{
  EventHandler<EventArgs> handler = Events[MyCustomEventKey] as EventHandler<EventArgs>;

  if (handler != null)
    handler(this, e);
}

This method uses the MyCustomEventKey as an index in the Events list to access the MyCustomEvent-event. The Events list will return null if it does not contain an entry at the specified index. This will happen when no clients has subscribed to the MyCustomEvent.

Using the EventHandlerList class automatically resolves the two previously mentioned performance problems with the event fields.

Technorati Tags: ,

kick it on DotNetKicks.com

[obsolete]
As I wrote here, this is no longer the way to do it as Silverlight 2.0 provides a much better experience.

As I wrote recently in another blog post about a .NET Rocks interview with Brad Abrams, I was very impressed with his keynote at ReMix Boston, where he did the Linux / Vista / Mac debugging. I referred to Richard Campbell‘s opinion that he didn’t believe it would work. At the end of the post, I wrote that I want to try it for myself, to see if it really works. Brad Abrams posted a comment to my blog post, saying that it should work just fine. Well. This post tells the story.

Prerequisites

  • A Windows machine with Visual Studio 2008 and Silverlight Tools Alpha for Visual Studio 2008 installed.
  • A Macintosh with the Silverlight 1.1 Alpha installed.
  • A network connection on both machines and a way to transfer files between the Vista box and the Mac. (A USB flash drive/stick is fine)
  • A Silverlight 1.1 Alpha project linked to a website, ready to run.
  • The website has to be remotely accessible. (Otherwise you can copy the website to the Mac as static HTML files, and run it locally from there.)

Debugging environment

This is the environment I will use for the debugging. For starters, I want to concentrate on the Vista / Mac debugging, so I won’t set up a Linux box with Apache and serve the Silverlight app on a PHP page. But there really should be no problem to it. You can even copy a static HTML page with the XAML page, and the assemblies to the Mac, and run the Silverlight app locally, and attach the Visual Studio debugger to the Safari process on the Mac. Let’s save the Linux box for another time.

The mac: Basically just a Macbook with default configurations, and no special software.

The Vista box: This is my development box. Windows Vista with Visual Studio 2008, IIS 7 and an ASP.NET website set up at localhost.

Before we get started, locate your Visual Studio 2008 folder on the Vista box (usually: C:\Program Files\Microsoft Visual Studio 9.0), and find the Silverlight folder. This folder contains the necessary files to do the initial set-up. You’ll also find a guide to set-up and start debugging, but I’ve found a few mistakes in there, and you can find yourself confused.

Setting up the Mac for Silverlight debugging

Remote debugging is not as easy as pointing Visual Studio to a remote computer, and selecting a process to debug. You have to authenticate against the remote machine. This is done via an SSL encrypted TCP channel between the debugger (The Vista box) and the target machine (The Mac). You will need to set-up the TCP port along with a private/public key pair. This is done in 6 easy steps:

  1. Copy the contents of the C:\Program Files\Microsoft Visual Studio 9.0\Silverlight\MacIntel folder to a destination on the Mac of your choosing.
  2. Start up a Terminal on the Mac, and execute the ‘configcoreclrdebug’ using an absolute filepath. e.g.: /MacIntel/configcoreclrdebug.
  3. First, your private/public key pair will be generated, and then you have to specify a TCP port in the range of 49152 – 65535. Just pick a number.
  4. Then you need to enter a password, and confirm it. Choose a password of at least 8 characters.
  5. A hidden directory is created in your Users folder, located here: /Users/username/.coreclrdbg – copy the “ConfigureWindowsCoreCLRDebugging.exe” file to the Vista box, in a destination of your choosing.
  6. Execute the ‘core_clr_proxy’ file on the Mac from the Terminal, using an absolute filepath like this: /MacIntel/coreclr_dbg_proxy

image image

That was all the set-up needed on the Mac for now. Next up is setting up the Vista box.

Setting up the Vista machine for Silverlight debugging

This is the easy part.

  1. From a command prompt, run the “ConfigureWindowsCoreCLRDebugging.exe” which you just copied from the Mac.
  2. Enter the password you created on the Mac in step 4, and hit Enter.

Starting the debugger

Now to the exciting part. Will it work, or not?

  1. Launch Safari on the Mac, and point the address to the URL of your Silverlight application you wish to debug.
  2. Launch Visual Studio 2008 on the Vista box, and open the Silverlight project that you wish to debug.
  3. Open up a source file, and set a breakpoint.
  4. From the Debug menu, click Attach to Process. (Or hit Ctrl + Alt + P)
  5. From the Transport drop down menu, select ‘CoreCLR Remote Cross-platform Debugging’.
  6. Enter the IP address or hostname of the Mac in the Qualifier box bellow and hit Enter.
  7. Now you should see a list of processes running on the Mac. Anyone that has CoreCLR Remote in the Type column can be attached.
  8. Select the Safari process and hit Attach.
  9. There you go. You’ve just attached the Safari process on the Mac to the Visual Studio debugger.

image image image

Now. Perform whatever action on the Mac that makes you hit the breakpoint you set before, and take a moment to enjoy real-time cross-platform remote debugging.

Screenshots of the Mac showing the webpage with the Silverlight app:

image image

The second picture above, has the SetDefaultView() Button highlighted as if I was holding down the mouse bottom. This is because the screenshot is taken when I hit the breakpoint you can see on the third picture of Visual Studio further above.

One thing I noticed while using the Silverlight charts from the Mac, was the speed. When I paste the serialized string in to the textbox and click LoadData() – the Silverlight loads the string and deserializes it to some custom classes I made. On Vista it takes less than a second. On the Mac it takes about two seconds or maybe a bit more. And it is not because of network latency. Silverlight runs in the browser, which means the app is downloaded to the Mac, and when I click the buttons, all the logic handling events and doing stuff runs locally. So Silverlight is lot slower on the Mac than on Windows. Maybe this will get better when Silverlight 1.1 is officially released.

kick it on DotNetKicks.com

Configuring IIS 7 default document from web.config

IIS 7 has a lot of changes regarding the configuration model. Using the Integrated Configuration System in IIS 7 you can set configuration of your server on different levels, compared to IIS 6, where the ASP.NET developer were more restricted. Configuring IIS 7 from an ASP.NET Web Application’s web.config file works from both ASP.NET 2.0 and ASP.NET 3.5. Note that the server can be restricted to lock certain configuration settings from above the application level, you might encounter this if your website runs in a shared hosting environment.

Setting up the website

To have a test website, I will setup a new website on my Vista machine running IIS 7. I don’t want the website to run under the Default Web Site, so first thing, I’ll add a hostname to my hosts file. This is located in the drivers\etc folder of your windows directory’s system32 folder. Add the following line:

127.0.0.1         iis7test

Open up Internet Information Services (IIS) Manager, and create a new Application Pool. Name it iis7test, and leave the settings as default:

image

Add a new website with the following settings:

image

This should get us started. Open up Visual Studio 2008 (2005 will also work). Open the website you just created inside IIS.

image

The only item in the website is a web.config. Add a new Web Form called Test.aspx.

Right-click the Test.aspx file and click View in browser. You could get an HTTP Error 500.00, like this:

image

To get rid of it, set impersonate to false in the web.config file by adding this line to the system.web section:

<identity impersonate=”false” />

Now your site should work fine. Edit the Test.aspx file, so it has some content. Just write Test IIS 7 or something in the HTML mark-up.

If you right-click the website icon in the Solution Explorer, and click View in browser, you will get an error like the one bellow:

image

That is because our website does not have any pages that match the name of the default documents on IIS. If you don’t want to be limited by the few default documents that comes with IIS out-of-the-box, you can add your own from web.config by adding these lines:

<system.webServer>
<defaultDocument>
<files>
<clear />
<add value=”Test.aspx” />
</files>
</defaultDocument>
</system.webServer>

Maybe the system.webServer section already existed in your web.config file. If so, just add the defaultDocument section. Here you can specify all the filenames that should act as a default document in IIS 7. The <clear /> line is optional. If you want to keep the default settings, and only add your own – just delete that line.

Now when we save the new web.config file, and refresh the browser we se our Test.aspx file:

image

This setting is just one of many that you can specify in your application’s web.config file. In the near future I’ll be blogging more about specific settings you can use to configure IIS 7 from ASP.NET.

Technorati Tags: ,

kick it on DotNetKicks.com

Making your application send e-mails, is something you do almost in every application. It’s easy – all you need is an SMTP server to relay your mail through. Sending e-mail messages to several recipients at once can also be done, by adding multiple recipients to either of the MailMessage.To, MailMessage.Cc or MailMessage.Bcc properties in C#. But if you send a newsletter every month, week or day, it is very important to maintain your list of recipients, so that whenever people get a new e-mail address (and they do!) and the old one stop working – you avoid those undelivered mails everytime you send your newsletter.

I’ve made this simple class called BulkSender, that takes three parameters in the constructor:
mailMessage (System.Net.Mail.MailMessage), recipients (List<string>), mailSender (System.Net.Mail.SmtpClient).

It has one method: SendEmailMessage, and what it does is, that it adds all recipients to the Bcc collection on the MailMessage, and sends the mail in a try-catch block. Whenever the SmtpFailedRecipientsException or SmtpFailedRecipientException is handled, it adds the e-mail address to a local List<string> and returns the e-mail addresses with delivery failures as a List<string>.

Code snippet:
image

When you get the List<string> of failed recipients, you can add your own logic to take care of maintaining your list of recipients. Maybe an e-mail address has to fail 3 times, before it is deleted, or maybe you want to delete it the first time it fails.

Another good thing to have in mind when sending e-mails to multiple recipients at once, is to add the mail addresses to the Bcc collection, and NOT the To or Cc collection. This way the e-mail addresses is hidden, you only get to see ‘undisclosed-recipients’ in you mail client:
image

Note that the BulkSender class automatically clears the To, Cc and Bcc collections before adding the recipients to the Bcc collection. This way you know for sure, that you do not have any e-mail addresses publicly available when you send the e-mail.

You can download the code below. Feel free to tweak the class – and let me know if you have some interesting things regarding this topic.

Technorati Tags: ,

BulkSender.zip (818.00 bytes)

kick it on DotNetKicks.com

Optimizing Code Snippets

Code Snippets are a great productivity boost that was introduced in Visual Studio 2005, if I remember right. Code Snippets lets you type a shortcut for a piece of code. I use snippets for properties a lot. I hate writing properties “by hand” – it is much faster with Code Snippets. But since Visual Studio 2008, the default prop shortcut now uses Dynamic Properties – but I still work on some projects that does not support Dynamic Properties. So I changed my default Code Snippets, and added a few other.

First I changed the default prop snippet back to the old property with a backing field. Then I added snippets for a Dynamic Property, Business Object Property (to use with Rockford Lhotka’s CSLA architecture) and a ViewState Property. See the code they all produce here:

image This boosts productivity even more, and it is a great way to get rid of those lame things you do over and over again…

Download the snippets yourself bellow. Add them to your C:\Program Files\Microsoft Visual Studio 9.0\VC#\Snippets\1033\Visual C# directory, and replace the prop.snippet file when it prompts you.

Technorati Tags:

CodeSnippets.zip (2.29 kb)

Powered by WordPress | Theme: Motion by 85ideas.