Using async/await without .NET Framework 4.5

Using async/await without .NET Framework 4.5

Rate This
  • Comments 45

[Update: We've uploaded a new version of Microsoft.Bcl.Async NuGet package. The previous version will not work correctly on Windows Phone 7.1]

Do you want to use await but don’t want to wait until you can target .NET Framework 4.5? The waiting is over and awaiting is about to begin.

Today, we are proud to announce an update to the Async Targeting Pack we had previously released. The previous targeting pack allowed you to use await when targeting .NET Framework 4.0 and Silverlight 5. Our updated targeting pack allows you to use await in Visual Studio 2012 when targeting any of the following platforms (or higher versions):

  • .NET Framework 4.0 (with KB2468871)
  • Silverlight 4
  • Windows Phone 7.5
  • and portable class libraries targeting those platforms

So effectively we added support for Windows Phone 7.5, Silverlight 4, and portable class libraries.

Hang on – isn’t this simply a language feature anyways?

Yes and no. It’s very tempting to think of the new async/await keywords in C# and Visual Basic as pure language features. And to an extent this is true: the compiler has to do some heavy lifting to turn your code into something that can await operations.

With this mindset developers expect to be able to use await as soon as they use Visual Studio 2012 – independent from the .NET platform they are targeting. However, if you consider how most language features are implemented, it becomes quickly clear that this is not a given. Many language constructs require the .NET platform to expose certain APIs in order to support them. For example, extension methods require the ExtensionAttribute and foreach depends on IEnumerable. In the case of await, both languages require Task and some plumbing that make them awaitable.

What do I need for await?

In order to use await you need two components:

  1. Visual Studio 2012
  2. Some specific .NET APIs

In case you are targeting any of our newer platforms (i.e. .NET 4.5 or .NET for Window Store apps) the second point is a no-op – those platforms already have the required APIs. When you target any of the platforms that shipped before Visual Studio 2012, that is .NET Framework 4.0, Silverlight 4, and Windows Phone 7.5, you need to add a NuGet package that provides those APIs.

Note: If you are a phone developer, you are probably aware of the fact that Visual Studio 2012 doesn’t allow you to build phone apps yet – stay tuned. See this post for details.

Before consuming the packages, make sure you've got the NuGet 2.1 or newer installed.

To add a reference to our NuGet Package, right click the project, select “Manage Package References” and search for Microsoft.Bcl.Async. Make sure you selected the “Online” tab on the left hand side and the top left drop down says “Include Prerelease”.

 Of course, you can also install the package via the Package Manager Console by running the following command:

install-package Microsoft.Bcl.Async –pre

Please note this package is marked as prerelease software – that is, there are some rough edges to be expected. We’ve published the known issues here. As usual, we’d like to know when you are having trouble using it. Simply use the comment section under this blog post.

Happy awaiting!

  • Das ist fantastisch! :)

  • It seems not working correctly.

    Here is my test code:

    class Program

    {

    static void Main(string[] args)

    {

    Console.WriteLine("1");

    Test();

    Console.WriteLine("2");

    }

    static async void Test()

    {

    Console.WriteLine("3");

    Console.WriteLine(await Doo("4"));

    Console.WriteLine("5");

    }

    static async Task<string> Doo(string s)

    {

    Console.WriteLine("6");

    return s;

    }

    }

    It's output is 1,3,6,4,5,2 (AsyncCTPV3) and 1,3,6,2 (Microsoft.Bcl.Async pre)

    My test was on VS2010 SP1 for both console application and WP7.1 application.

  • @Eric:

    To me, the behavior differences look like a race condition in your code. In essence, your main method doesn't await the completion of Test(), so it is undefined whether it completes before Console.WriteLine("2") or not. The fact you can consistently repro this is probably simply due to some unrelated implementation specific aspect, such as loading additional files.

    Since you can't use async/await in main, simply move all the code into another method and replace the body of main to only contain a call to that method. In this new method, await the completion of Test and the behavior should be consistent.

  • I'm not sure this is the correct place to ask this, but I'm at wit's end.

    I am converting WP7 code to use the Microsoft.Bcl.Async, and I have a requirement to set a time-out for Http requests.

    From my reading (more related to the c# 4.5+ features I think), there's samples that use :

      await Task.WhenAny(download, Task.Delay(3000)

    However, in this library Task.WhenAny doesn't exist, nor does Task.Delay

    I also thought of using a CancellationToken, but the DownloadStringTaskAsync extension method doesn't have an overload to take a cancellation token.

    Am I missing something? Is there any way to set a timeout?

  • @GrantDG: Due to technical restrictions we couldn't expose these methods on Task. You can find WhenAny and Delay on TaskEx. Sorry for that!

  • @Eric

    Maybe you can compile your project with 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe'.

  • I upgraded my WP71 project to VS 2012 and referenced this package. It compiles and it runs but it throws exception MethodAccessException all the time. How to fix this?

    The stack trace looks like this:

    System.MethodAccessException occurred

     Message=Attempt to access the method failed: System.Environment.get_ProcessorCount()

     StackTrace:

          at System.Delegate.InternalCreateDelegate(Type type, Object firstArgument, MethodInfo method, StackCrawlMark& scm)

          at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)

          at System.LightupServices.CreateDelegate(Type type, Object instance, MethodInfo method)

          at System.Lightup.CreateMethodAccessor(Type type, String name)

          at System.Lightup.GetMethodAccessor(Delegate& storage, Type type, String name)

          at System.Lightup.GetMethodAccessor[T](Delegate& storage, String name)

          at System.Lightup.TryCall[T](Delegate& storage, String methodName, Int32& returnValue)

          at System.Lightup.TryGet[T](Delegate& storage, String propertyName, Int32& value)

          at System.EnvironmentLightup.TryGetProcessorCount(Int32& count)

          at System.EnvironmentLightup.get_ProcessorCount()

          at System.Threading.PlatformHelper.get_ProcessorCount()

          at System.Threading.CancellationTokenSource..cctor()

          at [more MyApp code]

          at MyApp.App.Initialize()

          at MyApp.App.Application_Launching(Object sender, LaunchingEventArgs e)

          at Microsoft.Phone.Shell.PhoneApplicationService.FireLaunching()

          at Microsoft.Phone.Execution.NativeEmInterop.FireOnLaunching()

  • Here is another sample of the exception:

    System.MethodAccessException occurred

     Message=Attempt to access the method failed: System.Threading.ExecutionContext.Capture()

     StackTrace:

          at System.Delegate.InternalCreateDelegate(Type type, Object firstArgument, MethodInfo method, StackCrawlMark& scm)

          at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)

          at System.LightupServices.CreateDelegate(Type type, Object instance, MethodInfo method)

          at System.Lightup.CreateMethodAccessor(Type type, String name)

          at System.Lightup.GetMethodAccessor(Delegate& storage, Type type, String name)

          at System.Lightup.GetMethodAccessor[T](Delegate& storage, String name)

          at System.Lightup.TryCall[T](Delegate& storage, String methodName, Object& returnValue)

          at System.ExecutionContextLightup.Capture()

          at System.Threading.Tasks.Task.PossiblyCaptureContext(StackCrawlMark& stackMark)

          at System.Threading.Tasks.Task`1..ctor(Func`1 valueSelector, Task parent, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, StackCrawlMark& stackMark)

          at System.Threading.Tasks.Task`1.StartNew(Task parent, Func`1 function, CancellationToken cancellationToken, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, StackCrawlMark& stackMark)

          at System.Threading.Tasks.TaskFactory.StartNew[TResult](Func`1 function, CancellationToken cancellationToken)

          at [more MyApp code]

          at Microsoft.Phone.Shell.ApplicationBarItemContainer.FireEventHandler(EventHandler handler, Object sender, EventArgs args)

          at Microsoft.Phone.Shell.ApplicationBarIconButton.ClickEvent()

          at Microsoft.Phone.Shell.ApplicationBarIconButtonContainer.ClickEvent()

          at Microsoft.Phone.Shell.ApplicationBar.OnCommand(UInt32 idCommand)

          at Microsoft.Phone.Shell.Interop.NativeCallbackInteropWrapper.OnCommand(UInt32 idCommand)

  • It seems that I don't get MethodAccessException on WP8 Emulator only. WP71 Emulator and WP71 device both still have the issue. I can't upgrade to WP8 because I want to support WP71 devices.

  • How can I create a task based client in an portable library?

  • I'm working on a C# Windows Store App. I want some of my logic shared between an existing Windows Phone 7,5 app and this Windows 8 app. I use the portable class library to accomplish that. I always use async/await an would of course also use async/await in the portable class library project. But when I add Microsoft.Bcl.Async to the portable class library (which is referenced by the Windows Store App), the Windows Store App refuse to start. I just get the following error:

    Unable to activate Windows Store app '<someAppGuid>'. The app.exe process started, but the activation request failed with error 'The app didn't start'.

    In the event viewer the following event is recorded:

    Activation of the app <someAppGuid> for the Windows.Launch contract failed with error: The app didn't start..

    Any advice? :-)

  • @Vladislav What happens if you press F5 to continue the application when you hit these exceptions? Does the application continue to run? It looks like you might be hitting some "first-chance exceptions" that are handled later in the code by our implementation. An easy to test this, is to go to Tools -> Exceptions, and uncheck Thrown next to Common Language Runtime Exceptions and see if you they continue to occur.

    @NielsLBeck: Looks like you might be hitting a known issue. Can you see if an App.Config exists in the Windows Store project? If so, removing it, should fix the problem.

  • @David: Thanks! Now it works as expected :-)

  • Hi David,

    I am also having the same problem as Vladislav with the System.MethodAccessException so turned off Common Language Runtime Exceptions which silences the exception but I still don't believe it is working. The following code is a simple example and this code is running in the context of the OnNavigatedTo override on PhoneApplicationPage:

           protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

           {

               base.OnNavigatedTo(e);

               Debug.WriteLine("FOO");

               var syncRequired = await syncService.IsSyncRequired();

               Debug.WriteLine("BAR");

           }

    When this code is executed I get the output FOO but I never receive the BAR output, the debugger output shows as follows:

    FOO

    A first chance exception of type 'System.MethodAccessException' occurred in mscorlib.dll

    If I place a breakpoint on Debug.WriteLine("BAR"); it never breaks. My application continues to run as if nothing the OnNavigatedTo return after the FOO line.

    I am running this on a Nokia Lumia 800 using a 7.1 project with the latest version.

    Russell

  • Is it possible for this project to be put on Codeplex or something similar so it can be maintained. I am struggling to get this working on Windows Phone 7 but there appears to be no support.

    I appreciate this is a beta but as a developer there is nothing more frustrating than getting a blocking issue and finding that there is no way of solving it.

Page 2 of 3 (45 items) 123