2010-07-16

ReSharper and the Obscure CTS Corner Case

Like several other people, I collect tricky code snippets for fun. Today's image is courtesy of the Common Type System (part of the CLR). As such, it's not so much an artifact of the C# language as it is an artifact of the floating point standard.

Interestingly, the current version of ReSharper recommended a code transformation that is wrong.

Don't get me wrong; ReSharper is a great tool. This is the first time I've seen it make a mistake, and it's an obscure corner case. ReSharper did make another questionable recommendation a few weeks ago, and I felt the C# standard wasn't clear on the subject. However, Eric Lippert did confirm that ReSharper's refactoring was correct that time.

2010-06-30

Review of Bill Wagner's Effective C# (2nd ed), Part 2

Continuing my long and drawn-out review of Effective C#, this post takes a look at items 6-10.

Item 6: Understand the Relationships Among the Many Different Concepts of Equality

+ This is often a confusing topic for newcomers, and Bill explains it pretty well. He clearly distinguishes reference and value equality.

+ Correct recommendations on when and how to define equality for user-defined types.

+ Correctly discusses handling equality in the context of a type hierarchy. [Note: the class hierarchy example is only the simple case where objects of different types are always different. This does not handle the (uncommon) case where there is a sub-hierarchy where objects of different types can be equal.]

- Minor technical error: this section references the "IStructuralEquality" interface which had its name changed prior to the 4.0 release and is now called IStructuralEquatable.

- The only mention of overriding GetHashCode is buried in the text and not even a comment is included in the examples for overriding Equals.

Item 7: Understand the Pitfalls of GetHashCode()

- Repeatedly states that the result of GetHashCode must be equal if the two objects are equivalent as defined by operator==. This is incorrect; GetHashCode must be kept in sync with Object.Equals, not operator==.

+ Correctly explains efficiency problems with default GetHashCode implementations.

- Attempts to enforce more strict requirements on GetHashCode - specifically, that it can only be based on immutable fields. The actual requirements are only that the "key" field values do not change while the object's hash is being used.

- Incorrectly states that only immutable types can have a correct and efficient implementation of GetHashCode.

+ Pushes readers towards immutable value types. Even though GetHashCode doesn't require them, they are easier to work with.

Item 8: Prefer Query Syntax to Loops

- Assumes that query syntax is always cleaner than loops.

+ Points out the "composable API" benefit of query syntax.

Item 9: Avoid Conversion Operators in Your APIs

+ I agree completely, and would include operator overloading in the same cautionary advice.

Item 10: Use Optional Parameters to Minimize Method Overloads

+ Clearly explains all of the binary compatibility issues with optional parameters and default values.

2010-06-25

On A Lighter Note: SocketFlags.MaxIOVectorLength

Today I was just working along, minding my own business, when out of the blue my mind jumped back to something strange I had seen over a year ago. (Is anyone else insane like that, or is it just me?)

The seldom-used SocketFlags enumeration serves a dual purpose: it can represent flags passed to the Send or Receive operation, and it also represents flags passed back from the Send or Receive operation.

Reading through the enumeration values is pretty much straightforward: it's fairly obvious which ones are meant as "input" or "output" parameters, and what their meanings are. One value, however, is rather strange: MaxIOVectorLength, which (according to the MSDN documentation) "Provides a standard value for the number of WSABUF structures that are used to send and receive data."

That should give anyone pause. That value is clearly not a flag. It would make (a twisted sort of) sense if, by passing that flag, you could specify the maximum I/O vector length. But a quick look at the Send and Receive methods make it clear that this flag is not "enabling" some other parameter.

The fact is: this flag value should simply not exist. The value is real enough; it's defined in WinSock2.h as "MSG_MAXIOVLEN". However, it defines a limitation in the WinSock implementation, not a flag for Send or Recv.

Why do I find this amusing? Because someone, during the devlopment of the .NET framework, had to track down all the meanings of these flags. This person undoubtedly discovered that MSG_MAXIOVLEN was undocumented in its header file, and learned its meaning from someone else (likely someone responsible for the WinSock code). And in all of that research, that person never once noticed that this value was obviously not a flag? Not only that, but all of the reviewers reading this documentation never once realized how its description was completely different than all of the other descriptions!

This is a case of someone working too fast, and no one catching their fundamental mistake. The other flag values (which existed in WinSock.h with names like "MSG_OOB", "MSG_PEEK", and "MSG_DONTROUTE") had straightforward translations to SocketFlags, and MSG_MAXIOVLEN somehow got lumped in with them.

P.S. An interesting futher note: the person who put MaxIOVectorLength into SocketFlags correctly did not include a translation of MSG_INTERRUPT. The MSG_INTERRUPT flag was used to signal WinSock that the Send/Recv is being called in a hardware interrupt context (and therefore WinSock could not call other Windows methods). That was back in the 16-bit Windows days, and that flag is no longer used.

P.P.S. Bonus amusing fact: SocketFlags.MaxIOVectorLength has the same value as MSG_INTERRUPT. He, he, he... I just wonder what would happen if someone ever used it... :)

2010-06-21

SQLite and Entity Framework 4

I met a nice fellow at the Microsoft Code Camp in Chicago recently. He had a question about how well the Entity Framework worked with other ADO.NET providers. When I told him that I had a solution working using Entity Framework running on SQLite, he was quite interested. There are a handful of hurdles to get it all working, though.

ADO.NET Provider for SQLite

The first thing you need is an ADO.NET provider for SQLite. There's an excellent (and free) solution available called System.Data.SQLite. This is actually an ADO.NET 2.0/3.5 provider, and also includes support for the Entity Framework.

Supporting SQLite from a .NET 4.0 Project

By default, a .NET 4.0 process will happily load a .NET 2.0-3.5 managed DLL, but will refuse to load a .NET 2.0-3.5 mixed-mode DLL. This is a problem for SQLite, since it is a .NET 2.0 mixed-mode DLL. A full description of this problem and its solution is available online, but the short answer is to set useLegacyV2RuntimeActivationPolicy to true in your app.config.

Opening Alternative Data Files

SQLite has a simple "one database per file" concept that does not exist for all ADO.NET data sources. If you need to allow your application to access user-selected database files, it's possible to "redirect" an Entity Framework connection string to an alternative data file. The correct way to do this is to crack the Entity Framework connection string, extract the SQLite connection string, crack the SQLite connection string, replace the data file, rebuild the SQLite connection string, and finally rebuild the Entity Framework connection string:

/// <summary>
/// Redirects a SQLite Entity Framework connection string to an alternative database file, optionally encrypted with a password.
/// </summary>
/// <param name="originalConnectionString">The Visual-Studio-generated original Entity Framework connection string.</param>
/// <param name="databaseFile">The alternative database file to open.</param>
/// <param name="password">The password to use for encryption. May be <c>null</c> to indicate no password.</param>
/// <returns>A SQLite Entity Framework connection string referencing the alternative database file.</returns>
public static string RedirectedEntityFrameworkConnectionString(string originalConnectionString, string databaseFile, string password)
{
    // Parse the Entity Framework connection string.
    var connectionStringBuilder = new EntityConnectionStringBuilder(originalConnectionString);
    if (connectionStringBuilder.Provider != "System.Data.SQLite")
    {
        throw new ArgumentException("Entity Framework connection string does not use System.Data.SQLite provider.");
    }

    // Parse the underlying provider (SQLite) connection string.
    var providerConnectionStringBuilder = new SQLiteConnectionStringBuilder(connectionStringBuilder.ProviderConnectionString);

    // Redirect to the specified database file, and apply encryption.
    providerConnectionStringBuilder.DataSource = databaseFile;
    providerConnectionStringBuilder.Password = password;

    // Rebuild the Entity Framework connection string.
    connectionStringBuilder.ProviderConnectionString = providerConnectionStringBuilder.ConnectionString;
    return connectionStringBuilder.ConnectionString;
}

The redirected Entity Framework connection string may be passed to the ObjectContext-derived class constructor (e.g., the "MyEntities" class that the Entity Framework creates for you):

const string OriginalConnectionString = "..."; // (Copy out of app.config)
var connectionString = RedirectedEntityFrameworkConnectionString(OriginalConnectionString, myFileName, null);
using (var context = new MyEntities(connectionString))
{
    ...
}

The Entity Framework's Database Connection

The Entity Framework is actually an ADO.NET data provider that is itself wrapping an ADO.NET data provider (SQLite, to be specific). Normally, the Entity Framework will open a database connection whenever it needs one; these automatically-opened connections are automatically closed when the Entity Framework is finished with it. This default behavior works well with SQL Server due to its ADO.NET provider's connection pooling. However, it does not work well with SQLite, due to various "properties" existing on the SQLite connection itself. One example is "PRAGMA foreign_keys = ON", which enforces foreign keys only for that SQLite database connection. If the Entity Framework opens and closes its connections at will, then SQLite PRAGMAs such as these are lost.

As a general rule, you should explicitly call "Connection.Open()" for any ObjectContext. You must also ensure that the ObjectContext is disposed, so that the database connection is cleanly closed. Once "Connection.Open()" has been called, the Entity Framework will no longer open and close its own transient connections.

using (var myEntities = new MyEntities())
{
    // Open the connection (to make it long-lived)
    myEntities.Connection.Open();

    // Apply PRAGMA directives...

    // Use Entity classes...
}

It's often useful to get at the SQLiteConnection being used by the Entity Framework. This is available through the "EntityConnection.StoreConnection" property, as illustrated by this code sample:

var connection = (myEntities.Connection as EntityConnection).StoreConnection as SQLiteConnection;

Directly Accessing the Database Using SQL

Even when using the Entity Framework, there are situations where one wishes to execute SQL commands directly against the database. PRAGMAs are one common scenario; another is updating the schema structure to the latest version.

This is possible one of two ways; once the SQLiteConnection has been acquired (see above), it's possible to create a SQLiteCommand and execute it:

using (var command = connection.CreateCommand())
{
    command.CommandText = "PRAGMA encoding = \"UTF-8\"";
    command.ExecuteNonQuery();
}

However, there's an even easier way of doing this: Entity Framework exposes a method named "ExecuteStoreCommand":

myEntities.ExecuteStoreCommand("PRAGMA encoding = \"UTF-8\"");

Entity Framework Transactions

The official Entity Framework documentation recommends using generic transactions (e.g., TransactionScope). This has some benefits; it can be easily promoted to a distributed transaction, etc.

However, it has a timeout scheme that is not very friendly (I mentioned this a few weeks ago). In my situation, I had to potentially spend quite a bit of time upgrading the client's database on first run.

Fortunately, SQLiteTransaction works perfectly well with the Entity Framework. My database schema upgrade code now looks like this (referencing the SQLiteConnection from above):

using (var transaction = connection.BeginTransaction())
{
    // lots of time-consuming stuff

    transaction.Commit();
}

SQLiteTransaction does not have the same timeout restrictions that plague TransactionScope, et. al.

Reminder: You do want to use a SQLiteTransaction! The Entity Framework by default will create (and commit) a new transaction for each call to SaveChanges (or each call to ExecuteStoreCommand). This is true even if EF has a long-lived connection. By using SQLiteTransaction, you'll avoid serious performance issues.

Defining and Enforcing Foreign Keys

First, you need to enforce foreign keys on your database connection; see the SQLite foreign keys documentation for more information. This is done simply as such:

myEntities.ExecuteStoreCommand("PRAGMA foreign_keys = ON");

The next step is to actually establish the Entity Framework relationships. Some SQLite databases work just fine; the EF designer is able to understand the foreign key relationships and adds them correctly. Other SQLite databases just import the entities themselves without the relationships; I'm not sure why this is the case.

If you have a SQLite database that does not get its relationships imported, then you'll have to define them by hand. If your entity relationships are all imported fine, then you can just skip down to the "final notes".

Foreign Keys: 0..1 to N and 1 to N

In this type of relationship, the "parent" table has an identity, and the "child" table has its own identity and a foreign key referring to a row in the "parent" table. To establish this relationship, follow these steps:

  1. Right-click the "parent" entity in the Entity Framework designer, open the "Add" submenu, and select "Association...".
  2. Select the entity which has a foreign key pointing to this one, and ensure that the Multiplicity on both ends is correct (tip: read the plain English explanation carefully).
  3. Be sure to uncheck the "Add foreign key properties" option.
  4. Click OK. Entity Framework will create an association that you can see in the designer; however, it is not actually mapped to the correct columns yet.
  5. Double-click the newly-created association (the line between the entities).
  6. In the "Principal" drop-down, select the "parent" entity. If your foreign key columns in the "child" entity have the same names as the primary key columns in the "parent" entity, then the rest of the dialog is filled in for you. (If not, you'll have to select which "Dependent Property" maches each "Principal Key").
  7. Click OK. The foreign key association is now completed.

Thanks to the Entity Framework Design team for their blog post on FK Associations; my instructions above are derived from that post.

Foreign Keys: M to N

This type of relationship has a special table in the database, commonly called a "join table". Unfortunately, the Entity Framework support for SQLite does not pick up on these relationships either, so the join table will actually be added to the Entity Framework designer as an entity.

To convert this join table entity into an M to N relationship, follow these steps:

  1. Right-click one of the two entities in the relationship, open the "Add" submenu, and select "Association...".
  2. Select the other entity in the relationship, and change the Multiplicity so that they are both Many.
  3. Click OK. Entity Framework will create an association that you can see in the designer; however, it is not actually mapped to the correct table yet.
  4. Right-click the newly-created association (the line between the entities) and select "Table Mapping".
  5. Click the "<Add a Table or View>" and select the join table. If your foreign key columns in the join table have the same names as the primary key columns in the related tables, then the rest of the page is filled in for you. (If not, you'll have to select how the columns in each table are mapped).
  6. After the table has been mapped to the M to N association, you may delete the join table entity.
Final Notes on Foreign Key Associations

Once the entity associations are defined (as above), you may freely "update" your model from the database without losing those associations.

When using the Entity Framework with SQL Server, it is possible to detect some foreign key conflicts before they actually hit the database (e.g., a required "parent" reference). I haven't found a way to get this working with SQLite yet, but it's not a big deal, IMO.

2010-06-18

Reporting Progress from Tasks

The .NET 4.0 Task Parallel Library respresents a huge shift in the way future multithreaded code will be written. The TPL and higher-level abstractions (such as the Parallel class, Parallel LINQ, and the Reactive Extensions) will (hopefully) become the default approach for handling all multithreading situations. There is (almost) no reason to use the old Thread class anymore.

Similarly, the BackgroundWorker class has seen its heyday. It is time for this old class to retire as well. However, BGW does have one benefit over the TPL: it is easier to use for background tasks that need to report progress to the UI.

Background tasks come in two basic flavors. Some of them update the UI infrequently, and can be easily broken into separate tasks which only update at each "checkpoint." Other background tasks update the UI more frequently, and cannot be easily divided this way.

For the background tasks that infrequently update the UI, one common approach is to split them into separate Tasks. In between each separate Task, a task continuation can be used to update the UI. The C# FAQ blog has an entry describing this approach.

For the background tasks that need to frequently update the UI (and can't be easily split into separate Tasks), another approach is necessary. The easiest solution is to create an inner Task to update the UI.

This post introduces the ProgressReporter type, which greatly simplifies background tasks that need to do frequent progress reporting. The goal for ProgressReporter is to allow update code that is as simple as BackgroundWorker.ProgressChanged.

The Example Framework

The UI is a single form with 3 buttons and a progress bar. The three buttons are Start, Error, and Cancel. The buttons are enabled and disabled based on whether the background task is running. The progress bar shows the progress of the task.

The background task runs for 3 seconds, counting from 0 to 99, updating the progress bar every 30 milliseconds. The task will then produce a result of 42. If the Error button is used to start the task, then the task will throw an exception instead of producing a result. The task is also cancelable, checking for cancellation each time it reports progress.

This is a rather complex example; it covers each background task scenario (successful completion, error conditions, and cancellation).

The UI framework is the same regardless of whether a BackgroundWorker or Task object is used for the background task:

using System;
using System.Windows.Forms;

public sealed partial class MainForm : Form
{
  private readonly Button startButton;
  private readonly Button errorButton;
  private readonly Button cancelButton;
  private readonly ProgressBar progressBar;

  public MainForm()
  {
    this.startButton = new Button
    {
      Text = "Start",
      Height = 23, Width = 75,
      Left = 12, Top = 12,
    };
    this.errorButton = new Button
    {
      Text = "Error",
      Height = 23, Width = 75,
      Left = this.startButton.Right + 6,
      Top = 12,
    };
    this.cancelButton = new Button
    {
      Text = "Cancel",
      Enabled = false,
      Height = 23, Width = 75,
      Left = this.errorButton.Right + 6,
      Top = 12,
    };
    this.progressBar = new ProgressBar
    {
      Width = this.cancelButton.Right - 12,
      Height = 23,
      Left = 12,
      Top = this.startButton.Bottom + 6,
    };
    this.startButton.Click +=
      (sender, e) => this.startButton_Click(sender, e);
    this.errorButton.Click +=
      (sender, e) => this.errorButton_Click(sender, e);
    this.cancelButton.Click +=
      (sender, e) => this.cancelButton_Click(sender, e);
    this.Controls.AddRange(new Control[]
    {
      this.startButton,
      this.errorButton,
      this.cancelButton,
      this.progressBar,
    });
  }

  partial void startButton_Click(object sender, EventArgs e);
  partial void errorButton_Click(object sender, EventArgs e);
  partial void cancelButton_Click(object sender, EventArgs e);

  private void TaskIsRunning()
  {
    // Update UI to reflect background task.
    this.startButton.Enabled = false;
    this.errorButton.Enabled = false;
    this.cancelButton.Enabled = true;
  }

  private void TaskIsComplete()
  {
    // Reset UI.
    this.progressBar.Value = 0;
    this.startButton.Enabled = true;
    this.errorButton.Enabled = true;
    this.cancelButton.Enabled = false;
  }
}

class Program
{
  [STAThread]
  static void Main()
  {
    // Run the UI.
    Application.Run(new MainForm());
  }
}

This defines a form called MainForm that has the UI described above. The two methods TaskIsRunning and TaskIsComplete handle the enabling and disabling of the buttons. There are also partial methods as placeholders for the button click events; these are used by the sample code below.

You can copy the code above by double-clicking it and then pressing Ctrl-C; then paste it into the Program.cs of a Windows Forms project. It should compile and run, displaying the form, but the buttons don't do anything yet.

A BGW That Updates Progress Frequently

Here's what the code looks like for a BGW that checks in frequently:

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

partial class MainForm
{
  private BackgroundWorker backgroundWorker;

  partial void startButton_Click(object sender, EventArgs e)
  {
    // Start the background task without error.
    this.StartBackgroundTask(false);

    // Update UI to reflect background task.
    this.TaskIsRunning();
  }

  partial void errorButton_Click(object sender, EventArgs e)
  {
    // Start the background task with error.
    this.StartBackgroundTask(true);

    // Update UI to reflect background task.
    this.TaskIsRunning();
  }

  partial void cancelButton_Click(object sender, EventArgs e)
  {
    // Cancel the background task.
    this.backgroundWorker.CancelAsync();

    // The UI will be updated by the cancellation handler.
  }

  private void StartBackgroundTask(bool causeError)
  {
    this.backgroundWorker = new BackgroundWorker();
    this.backgroundWorker.WorkerReportsProgress = true;
    this.backgroundWorker.WorkerSupportsCancellation = true;
    this.backgroundWorker.DoWork += (_, args) =>
    {
      for (int i = 0; i != 100; ++i)
      {
        // Check for cancellation.
        if (this.backgroundWorker.CancellationPending)
        {
          args.Cancel = true;
          return;
        }

        Thread.Sleep(30); // Do some work.

        // Report progress of the work.
        this.backgroundWorker.ReportProgress(i);
      }

      // After all that work, cause the error if requested.
      if (causeError)
      {
        throw new InvalidOperationException("Oops...");
      }

      // The answer, at last!
      args.Result = 42;
    };
    this.backgroundWorker.ProgressChanged += (_, args) =>
    {
      // Update UI to reflect the progress.
      this.progressBar.Value = args.ProgressPercentage;
    };
    this.backgroundWorker.RunWorkerCompleted += (_, args) =>
    {
      // Update UI to reflect completion.
      this.progressBar.Value = 100;

      // Display results.
      if (args.Error != null)
        MessageBox.Show("Background task error: " + args.Error.ToString());
      else if (args.Cancelled)
        MessageBox.Show("Background task cancelled");
      else
        MessageBox.Show("Background task result: " + args.Result);

      // Reset UI.
      this.TaskIsComplete();
    };

    // Kick off the background task.
    this.backgroundWorker.RunWorkerAsync();
  }
}

You can copy and paste this code into a cs file in the Windows Forms solution, such as MainForm.cs. The solution should then build, and you can play with the buttons to test all three scenarios (successful completion, error condition, and cancellation).

A Task That Updates Progress Frequently

Using the ProgressReporter class (defined below), translating this BGW code to Task code is rather easy; no explicit continuation scheduling is needed:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

partial class MainForm
{
  private CancellationTokenSource cancellationTokenSource;

  partial void startButton_Click(object sender, EventArgs e)
  {
    // Start the background task without error.
    this.StartBackgroundTask(false);

    // Update UI to reflect background task.
    this.TaskIsRunning();
  }

  partial void errorButton_Click(object sender, EventArgs e)
  {
    // Start the background task with error.
    this.StartBackgroundTask(true);

    // Update UI to reflect background task.
    this.TaskIsRunning();
  }

  partial void cancelButton_Click(object sender, EventArgs e)
  {
    // Cancel the background task.
    this.cancellationTokenSource.Cancel();

    // The UI will be updated by the cancellation handler.
  }

  private void StartBackgroundTask(bool causeError)
  {
    this.cancellationTokenSource = new CancellationTokenSource();
    var cancellationToken = this.cancellationTokenSource.Token;
    var progressReporter = new ProgressReporter();
    var task = Task.Factory.StartNew(() =>
    {
      for (int i = 0; i != 100; ++i)
      {
        // Check for cancellation 
        cancellationToken.ThrowIfCancellationRequested();

        Thread.Sleep(30); // Do some work. 

        // Report progress of the work. 
        progressReporter.ReportProgress(() =>
        {
          // Note: code passed to "ReportProgress" can access UI elements freely. 
          this.progressBar.Value = i;
        });
      }

      // After all that work, cause the error if requested.
      if (causeError)
      {
        throw new InvalidOperationException("Oops...");
      }

      // The answer, at last! 
      return 42;
    }, cancellationToken);

    // ProgressReporter can be used to report successful completion,
    //  cancelation, or failure to the UI thread. 
    progressReporter.RegisterContinuation(task, () =>
    {
      // Update UI to reflect completion.
      this.progressBar.Value = 100;

      // Display results.
      if (task.Exception != null)
        MessageBox.Show("Background task error: " + task.Exception.ToString());
      else if (task.IsCanceled)
        MessageBox.Show("Background task cancelled");
      else
        MessageBox.Show("Background task result: " + task.Result);

      // Reset UI.
      this.TaskIsComplete();
    });
  }
}

You can copy and paste this code into a cs file in the Windows Forms solution, such as MainForm.cs. The solution won't build until you add the code for the ProgressReporter class below.

The ProgressReporter Class

The ProgressReporter class is responsible for two things: the reporting of progress by a background task, and the reporting of a final result by the background task.

A background Task calls ProgressReporter.ReportProgress to report progress to the UI thread. This method will pause the background task until the UI has finished updating; if the task does not need to wait, then it can call ProgressReporter.ReportProgressAsync.

The code starting the background Task can also use ProgressReporter to retrieve the final result of the background task. This is done by calling the ProgressReporter.RegisterContinuation method. The delegate passed to this method is executed in the UI thread context after the background task completes. The delegate can then examine the Task object for its status (see the example code above).

In addition to the RegisterContinuation method, the ProgressReporter provides RegisterSucceededHandler, RegisterFaultedHandler, and RegisterCancelledHandler methods if it is easier to handle these situations separately.

The code for this class is not very complex:

using System;
using System.Threading;
using System.Threading.Tasks;

/// <summary> 
/// A class used by Tasks to report progress or completion updates back to the UI. 
/// </summary> 
public sealed class ProgressReporter
{
  /// <summary> 
  /// The underlying scheduler for the UI's synchronization context. 
  /// </summary> 
  private readonly TaskScheduler scheduler;

  /// <summary> 
  /// Initializes a new instance of the <see cref="ProgressReporter"/> class.
  /// This should be run on a UI thread. 
  /// </summary> 
  public ProgressReporter()
  {
    this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
  }

  /// <summary> 
  /// Gets the task scheduler which executes tasks on the UI thread. 
  /// </summary> 
  public TaskScheduler Scheduler
  {
    get { return this.scheduler; }
  }

  /// <summary> 
  /// Reports the progress to the UI thread. This method should be called from the task.
  /// Note that the progress update is asynchronous with respect to the reporting Task.
  /// For a synchronous progress update, wait on the returned <see cref="Task"/>. 
  /// </summary> 
  /// <param name="action">The action to perform in the context of the UI thread.
  /// Note that this action is run asynchronously on the UI thread.</param> 
  /// <returns>The task queued to the UI thread.</returns> 
  public Task ReportProgressAsync(Action action)
  {
    return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, this.scheduler);
  }

  /// <summary> 
  /// Reports the progress to the UI thread, and waits for the UI thread to process
  /// the update before returning. This method should be called from the task. 
  /// </summary> 
  /// <param name="action">The action to perform in the context of the UI thread.</param> 
  public void ReportProgress(Action action)
  {
    this.ReportProgressAsync(action).Wait();
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task finishes execution,
  /// whether it finishes with success, failiure, or cancellation. 
  /// </summary> 
  /// <param name="task">The task to monitor for completion.</param> 
  /// <param name="action">The action to take when the task has completed, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle completion. This is normally ignored.</returns> 
  public Task RegisterContinuation(Task task, Action action)
  {
    return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.None, this.scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task finishes execution,
  /// whether it finishes with success, failiure, or cancellation. 
  /// </summary> 
  /// <typeparam name="TResult">The type of the task result.</typeparam> 
  /// <param name="task">The task to monitor for completion.</param> 
  /// <param name="action">The action to take when the task has completed, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle completion. This is normally ignored.</returns> 
  public Task RegisterContinuation<TResult>(Task<TResult> task, Action action)
  {
    return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.None, this.scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task successfully finishes execution. 
  /// </summary> 
  /// <param name="task">The task to monitor for successful completion.</param> 
  /// <param name="action">The action to take when the task has successfully completed, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle successful completion. This is normally ignored.</returns> 
  public Task RegisterSucceededHandler(Task task, Action action)
  {
    return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task successfully finishes execution
  /// and returns a result. 
  /// </summary> 
  /// <typeparam name="TResult">The type of the task result.</typeparam> 
  /// <param name="task">The task to monitor for successful completion.</param> 
  /// <param name="action">The action to take when the task has successfully completed, in the context of the UI thread.
  /// The argument to the action is the return value of the task.</param> 
  /// <returns>The continuation created to handle successful completion. This is normally ignored.</returns> 
  public Task RegisterSucceededHandler<TResult>(Task<TResult> task, Action<TResult> action)
  {
    return task.ContinueWith(t => action(t.Result), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.Scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task becomes faulted. 
  /// </summary> 
  /// <param name="task">The task to monitor for faulting.</param> 
  /// <param name="action">The action to take when the task has faulted, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle faulting. This is normally ignored.</returns> 
  public Task RegisterFaultedHandler(Task task, Action<Exception> action)
  {
    return task.ContinueWith(t => action(t.Exception), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, this.Scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task becomes faulted. 
  /// </summary> 
  /// <typeparam name="TResult">The type of the task result.</typeparam> 
  /// <param name="task">The task to monitor for faulting.</param> 
  /// <param name="action">The action to take when the task has faulted, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle faulting. This is normally ignored.</returns> 
  public Task RegisterFaultedHandler<TResult>(Task<TResult> task, Action<Exception> action)
  {
    return task.ContinueWith(t => action(t.Exception), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, this.Scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task is cancelled. 
  /// </summary> 
  /// <param name="task">The task to monitor for cancellation.</param> 
  /// <param name="action">The action to take when the task is cancelled, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle cancellation. This is normally ignored.</returns> 
  public Task RegisterCancelledHandler(Task task, Action action)
  {
    return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
  }

  /// <summary> 
  /// Registers a UI thread handler for when the specified task is cancelled. 
  /// </summary> 
  /// <typeparam name="TResult">The type of the task result.</typeparam> 
  /// <param name="task">The task to monitor for cancellation.</param> 
  /// <param name="action">The action to take when the task is cancelled, in the context of the UI thread.</param> 
  /// <returns>The continuation created to handle cancellation. This is normally ignored.</returns> 
  public Task RegisterCancelledHandler<TResult>(Task<TResult> task, Action action)
  {
    return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
  }
}

You can copy and paste this code into a cs file in the Windows Forms solution, such as ProgressReporter.cs. The solution should then build, and you can play with the buttons to test all three scenarios (successful completion, error condition, and cancellation).

2010-06-02

TransactionScope Has a Default Timeout

I've been experimenting with using Entity Framework 4.0 hooked up to System.Data.SQLite, an ADO.NET provider for SQLite. I ran into an interesting problem last night when a long-running database operation would suddenly abort the process. If run in the debugger, the application would abort (without an error or exception raised). If run outside the debugger, the application would bring up a Windows Error Reporting dialog.

It's possible to copy the captured minidump while the WER dialog is being shown. When this was loaded into Visual Studio, it was revealed that the crash was due to a System.Data.SQLLite.SQLiteException thrown with the error message "The database file is locked" (SQLITE_BUSY; note that this is different than SQLITE_LOCKED).

Running the program with DebugView showed more clearly what was happening. The TransactionScope class uses a default timeout (TransactionManager.DefaultTimeout, which has a default value of 1 minute). When the transaction timed out, it attempted to issue an abort command (SQLiteTransaction.Rollback -> SQLiteCommand.ExecuteNonQuery). However, this command is issued from a timer callback (on a threadpool thread), so SQLite rejects the rollback operation because another thread is still using those tables.

Passing TimeSpan.Zero into the TransactionScope constructor will instruct it to use the maximum timeout (TransactionManager.MaximumTimeout, which has a default value of 10 minutes) instead of the default. Unfortunately, the maximum timeout can only be increased by editing the machine.config file.

2010-05-17

Review of Bill Wagner's Effective C# (2nd ed), Part 1

I had always flat-out disregarded Effective C#. I was heavily into C++ (i.e., contributing to Boost) when Effective C++ came out, and it jumped onto the "must-read" C++ shortlist. The only reason it worked, though, was because most of the smartest programmers had decades of experience with C++, so the "dark corners" of the language eventually became known. C#, in constrast, simply hasn't had that kind of adoption for so long. It is also still experiencing drastic changes (e.g., generic variance and dynamic typing in 4.0). My conclusion was that Effective C# cannot possibly be the same as "Effective C++ for C#".

Indeed, it is not. Martin Shoemaker sums it up well in his Amazon review: "Bill Wagner failed to deliver [the same] enlightenment [as Scott Meyers]. But that's a good thing..." After reading his review, I decided to read the book on its own (not expecting it to be the same as Effective C++). Besides, Bill Wagner gave me a copy, which was really nice of him.

Disclaimer: I've met Bill Wagner and heard him speak. He gave me a copy of the book for free (not even to review; just as a gift). He's also the Microsoft regional director for my region. So hopefully he won't get too mad when I point out the trouble spots along the way. :)

The book is split into 50 sections, each one addressing in detail a particular coding recommendation. In my review, I treat each section separately, with "plus" and "minus" signs for each of my responses. Since I consider myself an "intermediate" C# programmer (with Jon Skeet and Jeffrey Richter being the only known "expert" C# programmers), anything new I learned is listed as a plus.

Item 1: Use Properties Instead of Accessible Data Members

+ This is excellent advice, and Bill goes into good detail explaining why, including examples of what happens if this is not followed.

- This advice is pretty old, though. Who doesn't already know this?

- Structures used for p/Invoke interop should be mentioned as an exception to this rule.

Item 2: Prefer readonly to const

+ I had never really thought of this before, but he's right.

+ Includes a few examples where const is OK, and even required.

+ Also points out that default values for optional parameters may be implicitly const values.

Item 3: Prefer the is or as Operators to Casts

+ Clearly explains the semantic difference between is/as and casting, particularly regarding user-defined conversions (which I didn't know previously).

- Correctly points out that as-casting does not work for value types but fails to point out the easy solution of as-casting to the corresponding nullable value type.

+ Delves a bit into how foreach uses casing (again, something new I learned).

Item 4: Use Conditional Attributes Instead of #if

- The only examples given for #if usage are contract checking and tracing. The usage of #if for cross-platform compatibility (e.g., Silverlight / WPF) is ignored, though this is a perfectly valid use of #if where conditional attributes are not even a possible alternative.

- Conditional attributes are suggested instead of #if statements for contract checking, when the users should have been directed to the new Contracts support in .NET 4.

- Conditional attributes are suggested instead of #if statements for tracing, but the majority of applications would benefit from leaving tracing on in the field (controlled via app.config).

Item 5: Always Provide ToString()

+ Excellent advice that is often overlooked.

+ Also includes helpful advice regarding IFormattable.

- Minor technical error: the book states that IFormattable should accept an empty string "format" parameter, but MSDN disagrees.