Category Archives: .NET 4.5

indicates .NET 4.5 or higher is required

IKnow IEquatable

Well, now anyway. Sometimes I think the statement “Necessity is the mother of invention.” should – when applied to coders – be restated as “Necessity is the mother of fruitless hacks, StackOverflow searches and more code.” Catchy, eh?

Prior to my somewhat painful re-education (not going to use a diaeresis this time), I was operating under the ridiculous assumption that comparing to collections would be straightforward…if not downright simple. But my code kept telling me two identical collections were not. Of course a better coder would immediately recognize a reference problem underlying this. First I had blithely tried:

if (savedExercisesCollection != ExercisesCollection)
{
 for (int i = 0; i < ExercisesCollection.Count; i++)
 {
 ExercisesCollection[i].Order = i;
 }

App.StorageSettings["SettingsChanged"] = true;
}

But that was always returning true. Next, I turned to LINQ (’cause it is the solver of all problems, isn’t it?). Well, at any rate, my thinking was that it would actually compare the values. And it is elegantly concise:

if (savedExercisesCollection.Except(ExercisesCollection).Any())
{
 for (int i = 0; i < ExercisesCollection.Count; i++)
 {
 ExercisesCollection[i].Order = i;
 }</pre>
App.StorageSettings["SettingsChanged"] = true;
 }

I had also tried SequenceEqual but with the same sad results…until I stumbled across the IEqualityComparer<T> IEquatable @ http://msdn.microsoft.com/en-us/library/bb348567.aspx.

if (!savedExercisesCollection.SequenceEqual(ExercisesCollection))
{
 for (int i = 0; i < ExercisesCollection.Count; i++)
 {
 ExercisesCollection[i].Order = i;
 }

App.StorageSettings["SettingsChanged"] = true;
}

Now I was on the path to righteousness. All it would take is adding a comparer to my original class. I approached this with some trepidation since I’m relying on being able to serialize portions of that class. But the only way to know if something will blow up is to light the fuse. Turns out no worries.

I modified the class as follows:

[DataContract]
 public class Exercise : IEquatable<Exercise>
 {
 public List<Asset> AssetsList;

public Exercise(int id, int order, string description)
 {
 Id = id;

Order = order;

Description = description;

AssetsList = new List<Asset>();
 }

[DataMember]
 public int Id { get; set; }

[DataMember]
 public int Order { get; set; }

[DataMember]
 public string Description { get; set; }

 public bool Equals(Exercise other)
 {
 //Check whether the compared object is null.
 if (ReferenceEquals(other, null)) return false;

//Check whether the compared object references the same data.
 if (ReferenceEquals(this, other)) return true;

//Check whether the products' properties are equal.
 return Id.Equals(other.Id) && Order.Equals(other.Order);
 }

The take-home lesson from this is that unless an ObservableCollection is instantiated from the same source as another they are not automatically comparable. I can see this knowledge coming in handy when rehydrating a chunk of JSON, for instance to compare a remotely stored to-do list with one on the client.

Did ya hear the one about the serial killer?

Turns out his victim was found floating in a tub full of corn flakes and milk. Bahhh, dahhh, dahhh, da.

Anyway, in this case it was more that the serializer got killed…by an uncoöperative class. (BTW, that’s not an umlaut over the second “o”. It’s a diaeresis. Lovely sounding term. More on the subject: http://www.newyorker.com/online/blogs/culture/2012/04/the-curse-of-the-diaeresis.html). Typically, this happens because the class has a constructor with parameters. I couldn’t get around that. Well, I don’t want to anyway. I also didn’t want to depart from my vanilla JSON serializer, although in the past I’ve found SilverlightSerializer to be a solution when all else fails…like serializing an entire model. (Why would you want to do that? Long story, for some other time).

The solution is to simply mark up the class with the DataContract attribute and use DataMember for each of the members you want to serialize. In my case, this had the advantage of not serializing a voluminous sub-list I don’t want included. And it allows this class to be used in several places, rather than creating a separate Dictionary or similar.


[DataContract]
public class Exercise
{
 public List<Asset> AssetsList;

public Exercise(int id, int order, string description)
 {
 Id = id;

Order = order;

Description = description;

AssetsList = new List<Asset>();
 }

[DataMember]
 public int Id { get; set; }

[DataMember]
 public int Order { get; set; }

[DataMember]
 public string Description { get; set; }
}

And, voila, we end up with something that can be saved to IsolatedStorage:

[{“Description”:”JUMPING JACKS”,”Id”:0,”Order”:0},{“Description”:”WALL SIT”,”Id”:1,”Order”:1},{“Description”:”PUSH UPS”,”Id”:2,”Order”:2},{“Description”:”CRUNCHES”,”Id”:3,”Order”:3},{“Description”:”STEP UPS”,”Id”:4,”Order”:4},{“Description”:”SQUATS”,”Id”:5,”Order”:5},{“Description”:”TRICEPS DIP”,”Id”:6,”Order”:6},{“Description”:”PLANK”,”Id”:7,”Order”:7},{“Description”:”HIGH KNEES”,”Id”:8,”Order”:8},{“Description”:”LUNGES”,”Id”:9,”Order”:9},{“Description”:”PUSH UP & ROTATE”,”Id”:10,”Order”:10},{“Description”:”SIDE PLANK”,”Id”:11,”Order”:11}]

Using .NET 4.5 Task Async and Await with WPF and SQL Server

Most of the examples I’ve seen of  using the new async, await and Task methods in .NET 4.5 have been aimed at Windows 8 (Metro or “UI Style”) apps. This is understandable, given Microsoft’s push towards both a new OS and to populate the Windows 8 Store. But for some (many?) developers there is also a need to support both Windows 7 and Windows 8 Desktop. Notably missing from the WinRT scenario is the ability to directly connect to SQL Server. I (mostly) get the reasons for that, although it seems against Microsoft’s interests to cede that space to SQLite instead of a sandboxed, light version of SQL Server.

Anyway, I put together a sample WPF application (download below) that supports asynchronous connections to SQL Server. You can cancel or restart the demo query, which populates a ListView with data from the AdventureWorks DB Production.WorkOrder table, which had a decent number of records for testing. I really wanted to simulate some real world conditions, such as server-side delays, so that’s included too. One of my beefs with many of the samples I come across is that they never include decent error handling, especially to accomodate network latency or timeouts. This sample also includes the Microsoft.Data.ConnectionUI SQL Server connection dialog box.

One advantage of making a WPF app asynchronous is it no longer locks up while running a process. Try dragging the window around while the ListView is being populated with data. Yay, no UI-thread blocking!

Clicking the Start button triggers the StartTest method. Notice that in the query, I’ve embedded an artificial server-side delay of 3 seconds – WAITFOR DELAY ’00:00:03′; – which will simulate a slow server return. Also, a queryTimeout has been set to 120 seconds. If you set the WAITFOR delay longer than that, you will see an error occurs and is handled. I did my best to include specific SQL Server error handling so we get actual error details, rather than just “some crap happened and that’s all we know.”


private async void StartTest(object sender, RoutedEventArgs e)
{
try
{
 if (_connectionString == String.Empty)
 {
 var scsb = new SqlConnectionStringBuilder(Settings.Default.DBConnString);

_connectionString = scsb.ConnectionString;

if (_connectionString == String.Empty)
 {
 throw new Exception("Please use Change DB to first select a server and database.");
 }
 }

if (DbInfo.DbName == String.Empty)
 {
 throw new Exception("Please use Change DB to first select a database from the server.");
 }

// Note: If the start test button was disabled, this would be unnecessary
 _cts.Cancel();

// Re-initialize this. Otherwise, StartTest won't work.
 _cts = new CancellationTokenSource();

DataItemsList.Clear();

// Note the simulated delay, which will happen on the DB server. You can vary this to see its effect.
 // Try dragging the window around after hitting the start test button.
 const string query =
 @"WAITFOR DELAY '00:00:03'; SELECT * FROM [Production].[WorkOrder];";

// Note that setting the WAITFOR delay to exceed this, eg. 00:02:01, will trigger an exception
 int queryTimeout = 120;

RequestStatus = "started";

await ProcessQueryCancelleable(_connectionString, query, queryTimeout, _cts.Token);
}
catch (Exception ex)
{
 MessageBox.Show(ex.Message + " (from StartTest)");

Debug.WriteLine(ex.Message);
}
}

The ProcessQueryCancelleable method. Note the use of the CancellationToken…’cause users might actually want to cancel a long-running query. Inside this method is another simulated delay (await Task.Delay(TimeSpan.FromMilliseconds(1));):

/// <summary>
/// Runs a cancelleable query
/// </summary>
/// <param name="connectionString">SQL Server connection string</param>
/// <param name="query">SQL query</param>
/// <param name="timeout">SqlDataReader timeout (maximum time in seconds allowed to run query). Note: Try varying this in conjunction
/// with the WAITFOR DELAY in the SQL query, e.g. make it shorter than the WAITFOR or maybe a second longer</param>
/// <param name="cancellationToken">Allows cancellation of this operation</param>
/// <returns></returns>
private async Task ProcessQueryCancelleable(string connectionString, string query, int timeout,
 CancellationToken cancellationToken)
{
 // await Task.Delay(TimeSpan.FromSeconds(5));

try
 {
 // Keep sqlConnection wrapped in using statement so disposal is handled automatically
 using (var sqlConnection = new SqlConnection(connectionString))
 {
 await sqlConnection.OpenAsync(cancellationToken);

using (SqlCommand cmd = sqlConnection.CreateCommand())
 {
 cmd.CommandTimeout = timeout;

cmd.CommandText = query;

using (SqlDataReader dataReader = await cmd.ExecuteReaderAsync(cancellationToken))
 {
 while (!dataReader.IsClosed)
 {
 // While the dataReader has not reached its end keep adding rows to the DataItemsList
 while (await dataReader.ReadAsync(cancellationToken))
 {
 // Process dataReader row
 WorkOrder workOrder = GetWorkOrderFromReader(dataReader);

DataItemsList.Add(workOrder);

// Another simulated delay...this one internal
 await Task.Delay(TimeSpan.FromMilliseconds(1));
 }

if (!dataReader.NextResult())
 {
 dataReader.Close();
 }
 }

Debug.WriteLine("done with reader");

RequestStatus = "finished";
 }
 }
 }
 }
 catch (SqlException sqlEx)
 {
 Debug.WriteLine(sqlEx.Message);
 }
}

Download C# Project (an MDF with just the WorkOrders table is included)