ProfileView can now be used for user administration#
By far, the most common feature request for my ProfileView control was the ability to edit the profile of any user in the system. Until now, the control could only be used by the current user to edit their own profile. I thought it was a limitation of the Profile provider framework, until I discovered ProfileBase.Create(). I apologize to everyone that has been waiting for this much needed feature for so long.

Just set the UserName property on the control to edit a different user. The property is null by default, which loads the current user.

Example usage in a WebForm used to edit a profile:

    protected void Page_Load(object sender, EventArgs e)

    {

        if (!Page.IsPostBack)

        {

            string userName = Request.QueryString["username"];

            if (!String.IsNullOrEmpty(userName))

            {

                ProfileView1.UserName = userName;

            }

        }

    }



Download the latest code from the ProfileView project page.
Saturday, June 24, 2006 11:47:41 AM (Central Daylight Time, UTC-05:00) #    Comments [1]  | 

 

Safely running background threads in ASP.NET 2.0#
The .NET Framework 2.0 no longer allows background threads to die silently when an unhandled exception is thrown. I'm not going to dive into the details of the change, as it is already well-documented on the web (this post describes the behavior for different application types & Scott Allen focuses on the ASP.NET impact).

The impact is more significant for ASP.NET applications
I think this is actually a bigger change for ASP.NET apps, because it has always had a "safety net". In console/WinForms applications, if there is an unhandled exception on the primary thread, the application dies. Having your application die now because of an unhandled exception on a background thread is not that big of a difference. You have an unhandled exception in your application, the application dies. Consistent.

However, in ASP.NET, exceptions that you did not handle in your own code on the primary thread were always caught by a default handler (affectionately known as the "yellow screen of death"). Your application did not die. You could add a handler for the HttpApplication.Error event (Application_Error in global.asax) to centralize your exception handling and logging logic. In 1.x, exceptions that occurred on a background thread would die silently. Your application did not die. Consistent. But now, in 2.0, exceptions on your primary thread still do not kill your application, and can be logged by your global handler. But exceptions on your background threads will kill your application, and will not be logged.

My approach to exception handling and how it is now more difficult to implement
My philosophy is to never catch exceptions unless there is something I can do to address the issue. I prefer not to catch all possible exceptions throughout the internals of my code, and instead rely on try...finally blocks to clean up in case of an exception, and allow the exception to bubble up to a top-level handler where it can be logged (of course I catch exceptions when there is something the code can do to resolve the issue or continue in a known state).

The new background thread exception behavior forces me to create "top level handler and logging" code for the application (global.asax) AND within every method that I run on a background thread. I end up with a lot of duplicate code, and explicit exception handling and logging that I would prefer to be hidden behind the scenes instead of cluttering up my application logic.

A proposed solution
My goals:
  • Allow unexpected exceptions on all threads to be logged by a top level exception handler
  • Do not let the application die because of an exception, no matter which thread it is running on (at least not before I get a chance to log it).
  • Do not clutter the application logic with repeated try..catch and logging code.
To satisfy the top level exception handler goal, I would like to make use of the existing HttpApplication.Error / Application_Error mechanism. That means I need to somehow transfer the exception that occurred on a background thread to a primary ASP.NET thread. To satisfy the "do not die" and "do not clutter" goals, I need to wrap all calls to background thread methods with a single piece of code.

I've created the SafeWaitCallback class. It's Call method is used in place of a WaitCallback delegate. For example, if I want to execute the method DoTask on a background thread, I would call it like this:

System.Threading.ThreadPool.QueueUserWorkItem(new SafeWaitCallback().Call(DoTask));

SafeWaitCallback does two things: it wraps calls to the target method in a try...catch block, and it forwards the caught exception to a custom HttpHandler. It forwards the exception by serializing it to a byte array, and then POSTing it to the handler, which will receive the bytes and deserialize back to an Exception object.

using System;
using System.Net;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

public class SafeWaitCallback {
  public static Uri ApplicationUri;
  System.Threading.WaitCallback callback;

  public System.Threading.WaitCallback Call(System.Threading.WaitCallback callback) {
    this.callback = callback;
    return CallbackWrapper;
  }

  private void CallbackWrapper(object state) {
    try
    {
      callback(state);
    }
    catch (Exception e)
    {
      byte[] exceptionData;

      MemoryStream stream = new MemoryStream();
      BinaryFormatter formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Persistence));
      formatter.Serialize(stream, e);
      exceptionData = stream.ToArray();

      WebClient client = new WebClient();
      Uri handler = new Uri(ApplicationUri, "TransferException.axd");
      try
      {
        client.UploadData(handler, exceptionData);
      }
      catch (WebException) { }
    }
  }
}

By forwarding the exception to the custom HttpHandler, I can re-raise the exception, and since the handler will be running on a primary ASP.NET thread (not in the background), the exception will be caught by my global handler, and logged just like any other exception.

using System;
using System.Web;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;

public class TransferredExceptionHandler : IHttpHandler {
  public bool IsReusable { get { return true; }}

  public void ProcessRequest(HttpContext context) {
    byte[] exceptionData = new byte[context.Request.ContentLength];
    context.Request.InputStream.Read(exceptionData, 0, exceptionData.Length);

    Exception transferredException;
    MemoryStream stream = new MemoryStream(exceptionData);
    BinaryFormatter formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Persistence));
    transferredException = (Exception)formatter.Deserialize(stream);
    throw new Exception("[Background exception transferred - see InnerException]", transferredException);
  }
}

The handler is registered in web.config with the following entry:
      <httpHandlers>
        <add verb="POST" path="TransferException.axd" type="TransferredExceptionHandler" />
      </httpHandlers>

Let me know what you think
I've attached the full source code in the form of a Web Site project. It includes a Default.aspx page which demonstrates the different scenarios of an unhandled exception (primary thread, background thread, "safe" background thread using my new code).

This is not production ready code, it is still in the proof of concept stage. For one, it probably needs better exception handling within the CallbackWrapper exception handler (what if the serialization blows up?). More importantly, I'm not yet convinced this whole idea is a worthwhile approach. It meets my goals, but it feels a little hackish. I wanted to see if it was possible, and then throw it out there to get some feedback. Anyone see any major flaws in the concept? Even better, does anyone know of a more elegant approach to achieve the same goals?

Download AspNetBackgroundExceptions.zip (2.55 KB)

Wednesday, June 21, 2006 9:50:02 PM (Central Daylight Time, UTC-05:00) #    Comments [3]  | 

 

Add your two cents to the MSDN documentation#

Now, instead of burying in your blog your sage advice on how to really use the classes in the .NET Framework, despite what the documentation says, you can add it right to the source for everyone to see.
http://msdnwiki.microsoft.com

I only mention it, because that's where I will be putting most of my sage advice going forward.

Thursday, June 15, 2006 11:24:19 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

All content © 2010, josh
About this site
Send mail to the author(s) Contact me
Feed your aggregator (RSS 2.0)
Joshua Flanagan
I am a software developer focused on continuous improvement in the .NET community
Los Techies

On this page
Archives
Rest of the world

Acknowledgements

Powered by: newtelligence dasBlog 2.1.8209.14743

Special thanks to LosTechies.com

Site theme based on the essence design by Jelle Druyts

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.