Wednesday, March 21, 2012

Task-based Asynchronous Programming in .NET 4.5

.NET 4.5 introduces the new "async" and "await" keywords to simplify the asynchronous programming. They are task-based asynchronous model, and are extensively used in the new Metro applications for better responsive UI experience. Following code example illustrate the simple usage of "async" and "await" (run in Visual Studio 11 Beta):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;
using System.IO;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder syncContent = new StringBuilder(), asyncContent = new StringBuilder();
            Stopwatch watch = new Stopwatch();
            string testUrl = "http://www.google.com";
            GetWebContent(testUrl); // Warming up network connection

            Console.WriteLine("Sync web request calls start...");
            watch.Start();
            for (int i = 0; i < 100; i++)
            {
                syncContent.Append(GetWebContent(testUrl));
            }
            watch.Stop();
            Console.WriteLine("Sync web calls completed within {0} ms", watch.ElapsedMilliseconds);
            Console.WriteLine("Sync web content lengh: {0}", syncContent.ToString().Length);

            List<Task<string>> tasks = new List<Task<string>>();
            Console.WriteLine("\nSync web request calls start...");
            watch.Restart();
            for (int i = 0; i < 100; i++)
            {
                tasks.Add(GetWebContentAsync(testUrl));
            }
            watch.Stop();

            Console.WriteLine("Async web calls returned within {0} ms", watch.ElapsedMilliseconds);
            watch.Restart();
            Task.WaitAll(tasks.ToArray());
            watch.Stop();
            tasks.ForEach(v => asyncContent.Append(v.Result));
            Console.WriteLine("ASync web calls completed within {0} ms", watch.ElapsedMilliseconds);
            Console.WriteLine("Async web content lengh: {0}", asyncContent.Length);

            Console.Read();
        }

        static async Task<string> GetWebContentAsync(string url)
        {
            var webClient = new WebClient();
            var content = await webClient.DownloadStringTaskAsync(url);
            return content;
        }

        static string GetWebContent(string url)
        {
            var webClient = new WebClient();
            var content = webClient.DownloadString(url);
            return content;
        }
    }
}
The synchronous method is included in the demo cod for comparison purpose. The console app result:



Basically you need to add "async" keyword to the function definition telling compiler they could be asynchronous call(s) inside that method; "async" methods can return Task (no actual return value), Task<T> (return value of T) or void (only used in event handler without any return).

Inside a method marked as "async", you are able to use "await" keyword for a call that promises return or return value. Once "await" keyword is used, compiler will do some magic stuff for you and make that asynchronous invocation happen. Many IO and network related methods in .NET 4.5 have been refactored to support this task-based asynchronous model. Those asynchronous methods, with naming convention of xxxxAsync where xxxx is the method name, are out-of-box and can be used directly with "await" keyword.

This async programming model is much easier to work with comparing to the old .NET asynchronous programming model. In old days, developers need to spend a lot of effort to handle those callback functions such as Beginxxxx/Endxxxx methods and IAsyncResult parameter. That's painful and sometimes it's impossible to do nested async calls and error handling. With the new task-based async model, all those hustles are gone.

You can easily wrap a method as async method using TPL introduced in .NET 4.0. Code snippet below shows one way to achieve this:
        static async Task<double> MyComplicatedHeavyCalculationAsync(double x, double y)
        {
            double value = await Task<double>.Run(() => MyComplicatedHeavyCalculation(x, y));
            return value;
        }

        static double MyComplicatedHeavyCalculation(double x, double y)
        {
            // Do your complicated work ...
            return x + y;
        }
All sound good. But how about the thread context such as updating the UI content? In WPF, Silverlight and Metro apps you are most likely safe to do so since compiler are smart enough to inject the delegate code that could marshall the update back to the UI thread. For ASP.NET things are a bit more tricky. You have thread pool and httpcontext for each request is dynamically generated. Good news is that the new ASP.NET 4.5 will support task-based asynchronous model in certain ways, refer next version ASP.NET white paper for detail.

Monday, March 19, 2012

Setup Windows 8 Dev Virtual Machine

Windows 8 Customer Preview Edition has been released for about two weeks. Finally I got a chance to install a Windows 8 dev virtual machine using free VMWare Player in a Samsung 900X laptop (BTW Samsung touchpad really sucks). The setup is quick and straightforward:

1. Download required software (all free):
Windows 8 CP ISO (64-bit English version) http://windows.microsoft.com/en-us/windows-8/iso
Windows 8 CP Product Key: DNJXJ-7XBW8-2378T-X22TX-BKG7J
Visual Studio 2011 Ultimate Beta ISO http://www.microsoft.com/visualstudio/11/en-us/downloads#ultimate
VMWare Player http://downloads.vmware.com/d/info/desktop_end_user_computing/vmware_player/4_0

I also tried the Oracle Virtual Box. Everything is okay (latest Virtual Box even has the Windows 8 OS in the option list), except the screen resolution setting is not desired. VMWare Player 4.0.2 recognized the video card properly and I simply turned the screen size to 1366x768 without any tweaking.

2. Install VMWare player and then reboot the laptop as prompted.

3. Open VMWare player, from File menu click Create a New Virtual Machine…In New Virtual Machine Wizard select I will install the operating system later option.


4. Select Windows 7 x64 as Guest Operating System.


5. Select a meaningful name for the VM and its installation location.


6. Choose a VM disk size (default 60G) and select Store virtual disk as a single file.


7. Click Customize Hardware button to configure more memory such as 4G and more CPU resources such as 2 CPUs; in CD/DVD option make sure to use downloaded Windows 8 ISO file. Leave other option unchanged and click finish (you can disconnect printer, sound card here).


8. Highlight the newly added VM in VMWare player window, and click Play virtual machine to start the VM instance.


9. The virtual machine will start to install the Windows 8 from the DVD mounted in step 7. You will see a dummy fish all around during the installation. Anybody could tell the story about that dummy fish?


10. Follow the Windows 8 setup wizard to complete the installation. It took less than 10 minutes to finish in a laptop (Intel i5 with 8G memory). One tip is to select "Don't want to sign in with a Windows account" and setup a local account to sign in the new system, which is preferable for a dev VM. Below is the Windows 8 Metro-style welcome screen:


11. Mount and Install Visual Studio 11 Beat. In the Virtual Machine Setting, under CD/DVD option, select "Use ISO image file" and pick the downloaded Visual Studio 11 Beta ISO file. Click Okay then you will be able to see the Visual Studio Installer from the DVD drive (desktop mode) inside the VM. Just click the installer and all the rest is the same as VS2010 setup.


I got the error message of "You need a developer license to develop this style of app for Windows 8 Consumer preview..." when first ran the Visual Studio 11 Beta in the VM. The laptop was not connected to Internet during the Visual Studio setup and maybe that caused the issue. Simply signing in with a Microsoft account on the popup window you would be able to get a developer license (valid for one month). The developer license is free and it's per-machine basis.

Next step is play around the Metro UI and the new Windows RT...

Thursday, March 08, 2012

A Lesson Learned From A SharePoint Patch Installation

A busy morning started from tons of reported issues on our SharePoint 2010 portal: my sites, audience, and some navigations were not working...Open up SharePoint Central Admin we first noticed saw an error "User Profile Application's connection is currently not available.." in the user profile service:


Inside profile synchronization service we saw the "An error has occurred while accessing the SQL Server database or the SharePoint Server Search service. If this is the first time you have seen this message, try again later. If this problem persists, contact your administrator.":


It looked like something wrong with the database connection. But there's no recent change on SQL database and service accounts. From the SharePoint log we noticed many unexpected errors from User Profile Web Services:

w3wp.exe (0x0B3C) 0x0268 SharePoint Portal Server User Profiles eh0u Unexpected ProfilePropertyService.GetProfileProperties Exception:
System.MissingMethodException: Method not found: 'Microsoft.SharePoint.Administration.SPIdentifierType Microsoft.SharePoint.Administration.SPAce`1.get_BinaryIdType()'. at
Microsoft.Office.Server.Administration.SPAclFormatter.Serialize[TRights](XmlWriter xmlWriter, SPAcl`1 acl) at
Microsoft.Office.Server.Administration.SPAclFormatter.Serialize[TRights](SPAcl`1 acl) at
Microsoft.Office.Server.Administration.UserProfileApplication.get_SerializedAdministratorAcl() at
Microsoft.Office.Server.Administration.UserProfileApplication.GetProperties() at
Microsoft.Office.Server.UserProfiles.ProfilePropertyService.GetProfileProperties() 4507cc64-e9bd-43d3-9191-5e10b9509083

"Method not found" implies that the service calls and web services were not matching and they had different method signature. What on earth was happening? We recalled that a SharePoint security patch KB2597124 was installed last night (described in Microsoft Security Bulletin). Would it be the culprit? Not likely at the first glance since we a few developers had already installed that patch and didn't find any issue on it.

We traced down the SharePoint update history and found the security patch was installed successfully. The only difference between development and production machines is that production servers didn't have SharePoint Oct. 2011 cumulative updates installed but development machines did:
Production environment: SharePoint2010_SP1(14.0.4763.1000) + KB_2597124_Patch
Dev environment: SharePoint2010_SP1(14.0.4763.1000) + Oct_2011_CU(14.0.6112.5000) + KB_2597124_Patch

Would that difference caused the problem? We read through the patch instruction and it clearly showed it can be applied to SharePoint 2010 or SharePoint 2010 SP1 server without any other prerequisite information.

Anyway we did some tests. We installed KB2597124 Patch in a SharePoint 2010 SP1 test machine (14.0.4763.1000 without any CU installed). Bamm, we then saw all those issues in the test machine!

The conclusion was clear. That the security patch has dependency on previous cumulative updates (Oct. 2011 CU or latest Dec. 2011 CU). But this dependency information is not included in patch’s document, and security patch doesn’t do any prerequisite check.

Those "Method not found" errors now are understandable. Those CU updates modify some user profile web services, and the security patch makes some changes on top of those updated web services. I guess Microsoft found the security vulnerability. They thought it's critical so they teamed up some developers to work on it quickly. What those developers did was grab the latest code including the CU build, fix the issue, test it and make it public. But should Microsoft be a little bit more responsible for that? At least do some testing for different environments before the release right?

The security patch can not be uninstalled. The only option for us was to apply the CU after the security patch which is not the right order. We installed Oct. 2011 CU in that test machine with security patch installed. The CU install was smooth but it failed in SharePoint configuration wizard after machine reboot as prompted:

A few errors can be found in the log file:

03/08/2012 16:08:49 14 ERR The exclusive inplace upgrader timer job failed.
03/08/2012 16:08:49 14 ERR Task upgrade has failed with a PostSetupConfigurationTaskException An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
03/08/2012 16:08:49 14 ERR An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException: Exception of type 'Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException' was thrown.
at Microsoft.SharePoint.PostSetupConfiguration.UpgradeTask.Run()
at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask()
03/08/2012 16:08:49 14 ERR Task upgrade has failed
03/08/2012 16:08:49 1 ERR Task upgrade has stopped and failed. Total failed is now 1
03/08/2012 16:08:49 8 ERR Task upgrade SharePoint Products failed, so stopping execution of the engine
03/08/2012 16:08:49 8 ERR Failed to upgrade SharePoint Products.
An exception of type Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException was thrown. Additional exception information: Failed to upgrade SharePoint Products.
Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException: Exception of type 'Microsoft.SharePoint.PostSetupConfiguration.PostSetupConfigurationTaskException' was thrown.
at Microsoft.SharePoint.PostSetupConfiguration.UpgradeTask.Run()
at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask()
03/08/2012 16:08:49 8 ERR One or more configuration tasks has failed or some tasks were not run
03/08/2012 16:08:49 8 ERR Configuration of SharePoint Products failed. Configuration must be performed in order for this product to operate properly. To diagnose the problem, review the extended error information located at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS\PSCDiagnostics_3_8_2012_15_42_40_120_1586599544.log, fix the problem, and run this configuration wizard again.

We could see there were a few configuration tasks errors during the configuration wizard, which may because "Configuration must be performed in order for this product to operate properly" (message from log error). Fortunately, we found the site was back to normal after the CU installation: user profile service was up, mysites and navigation were all working properly. Reapplying the security patch was not implemented and we just didn't have enough time to test all that.

Lesson learned: make sure the test machine has the exact same configuration, fully test before applying any SharePoint patch, and don't take Microsoft for granted.