Dmitry Shechtman's Blog

December 13, 2014

AsyncActivator: Targeting Silverlight


This is an (unplanned) article in a series concerning AsyncActivator, a generalization of the .NET Asynchronous Factory pattern:

  1. Basics
  2. Cancellation
  3. Portability
  4. Silverlight

Dependency injection is quite a complex issue that garners a series of its own.

If you’ve been following this blog, you might have noticed that I’m a bit of a perfectionist. Although my latest article concluded:

Our portable AsyncActivator is now compatible with all platforms we’re aware of, save for legacy (i.e., non-Windows-Phone) Silverlight, which supports neither async/await (out of the box) nor reflection (to our requirements).

that little Silverlight box left unchecked kept bothering me. So with a little extra effort I made Ditto.AsyncInit and (some of) its upcoming child libraries compatible with Silverlight 5.

Now, don’t get me wrong. I’m fully aware of Silverlight’s current status — if it’s of any indication, Microsoft’s Immutable Collections library, released in mid-2013, targets every possible platform (including Xamarin), but not Silverlight.

However, that old dog can be taught the async/await trick, meaning many developers maintaining existing applications could benefit from asynchronous initialization having taken care of. If you happen to be a Silverlight developer with asynchrony in mind, you may find this article useful. Regardless of your plans of using any of the Ditto.AsyncInit components, you might still be interested in some of the challenges I encountered while making them compatible with Silverlight.

async/await

As already mentioned, Silverlight doesn’t support async/await out of the box. You’ll find that easy to fix with a little help from NuGet. If you need async/await in your project, simply install the Microsoft.Bcl.Async package. That will result in three added package dependencies:

  • Microsoft Async (Microsoft.Bcl.Async)
  • Microsoft BCL Build Components (Microsoft.Bcl.Build)
  • Microsoft BCL Portability Pack (Microsoft.Bcl)

You only need to do this if you are:

  1. targeting a legacy platform or
  2. using a library that lists them as dependencies.

Silverlight 5 happens to be an example of the former. An example of the latter is the upcoming Ditto.AsyncInit.Mvvm package, which depends on Microsoft.Bcl.Async.

Non-Public Constructors

As you may recall from the previous article, the portable version of AsyncActivator had to rely on a radically different implementation of CreateInstance<T>(). Unfortunately, neither works for Silverlight, since both TypeInfo and Activator.CreateInstance(Type, bool) are unavailable there.

Let’s recall our first attempt at a solution:

        var ctor = typeof(T).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
        if (ctor == null)
            throw new MissingMemberException("No parameterless constructor defined for this object.");
        return (T)ctor.Invoke(new object[0]);

The good news is that’s perfectly valid Silverlight code. We may even trade the exception type for the more appropriate MissingMethodException and pass null instead of the empty object array.

The bad news is it doesn’t work on Silverlight, which extends visibility restrictions to reflection access. Namely, it forbids anyone other than the declaring type from invoking a private constructor. That’s what I was referring to when I wrote that Silverlight didn’t meet our requirements.

So why not relax those a little? If we make the constructor internal, it can be invoked by any type defined in that assembly. Moreover, an assembly may extend its internal members’ visibility as follows:

[assembly: InternalsVisibleTo("Ditto.AsyncInit")]

Properties/AssemblyInfo.cs would be a good place for such an attribute.

Since all asynchronously initialized types must declare internal constructors (on Silverlight), it is advisable to keep them in an assembly of their own, in order to prevent others from inadvertently accessing uninitialized instances thereof.

If you’re looking to use Ditto.AsyncInit with Silverlight, you may clone the sources from the repository, and you’re good to go.

If you’d like to learn about a couple more Silverlight portability quirks, you’re welcome to read on.

TaskAwaiter

One would expect the APIs provided by Microsoft.Bcl.Async to be compatible with those built into the mainstream .NET framework. They mostly do, with TaskAwaiter being a notable exception.

During an early stage of my work on supporting dependency injection I came up with the following:

public interface IAwaitable<TResult>
{
    TaskAwaiter<TResult> GetAwaiter();
}

which would allow anyone with a reference to e.g. an IAwaitable<int> init to do:

   int result = await init;

However, when I added it to the Silverlight class library, it wouldn’t compile. As it turns out, the built-in TaskAwaiter is defined in the System.Runtime.CompilerServices namespace, while the drop-in TaskAwaiter resides in Microsoft.Runtime.CompilerServices.

Here’s my first take on the issue:

#if SILVERLIGHT
using Microsoft.Runtime.CompilerServices;
#else
using System.Runtime.CompilerServices;
#endif

It worked, but it wasn’t pretty, and implementing types would have to follow suit. I went on to revert that commit and instead create a separate version of IAwaitable.cs just for Silverlight. I then extracted a small base class from the implementing type, also with a separate Silverlight version, as I didn’t expect either to change very often.

The “missing” IAwaitable/IAwaiter interfaces are addressed by this excellent post.

TaskEx

As I proceeded with my implementation, I found all the familiar static Task methods missing, namely:

  • Delay()
  • FromResult()
  • Run()
  • WhenAll()
  • WhenAny()
  • Yield()

As these were added in .NET 4.5, Microsoft.Bcl.Async defined them as members of a separate TaskEx class. Since I didn’t want to rely on #ifs or maintain a thin wrapper around the newer Task APIs, I opted for adding Microsoft Async as a dependency in all versions of my library.

More Reflection

Unfortunately, in several cases thin wrappers were the only reasonable solution.

One such case was PropertyInfo.GetMethod available to PCLs as a property, which Silverlight instead exposes as a method. I used the Silverlight syntax and defined the following for the portable library:

static class PropertyInfoExtensions
{
    public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo)
    {
        return propertyInfo.GetMethod;
    }
}

Had C# had extension methods (and had Silverlight supported them), I could have defined one just for Silverlight and would have stayed with the (more common) property syntax everywhere.

Although an initial version of Ditto.AsyncInit.Mvvm is mostly done, I believe it should be published along with a complementary article (or three). Stay tuned!

Advertisements

3 Comments »

  1. […] Silverlight […]

    Pingback by AsyncActivator: Targeting Multiple Platforms | Dmitry Shechtman's Blog — December 13, 2014 @ 21:13

  2. […] Silverlight […]

    Pingback by AsyncActivator: Handling Cancellation | Dmitry Shechtman's Blog — December 13, 2014 @ 21:17


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.