Moq-ing Dynamics

This post serves as a reminder to myself…largely because I have wasted time tracking this down twice now!

When you are mocking an interface that returns a dynamic object, moq is (as ever) your friend

public interface ISomething {
    dynamic GetSomething();
}

Using the standard moq syntax, you can very easily mock this call to return a real object..

    var theThing = new Mock<ISomething>();
    var mockInstance = new SomeMockClass();
    theThing,Setup(t => t.GetSomething()).Returns(mockInstance);

This is a pretty common pattern, but there’s an important gotcha to note: if you the C# runtime binder can’t see the type SomeMockClass then when your target code tries to evaluate the return value you’re going to get an error…

    'object' does not something something about GetSomething()

But you aren’t returning an instance of object are you. So why can’t it work out what you’re aiming for?

Turns out that it’s pretty simple. For the dynamic binder to pick up your mock type, it has to be able to see the type. Is your mock type publicly visible? Thought not.

Make your private mock class publicly visible and suddenly the runtime binder knows what you’re talking about!

Advertisements

Autofac and Async Resources

I came across a problem on a recent WebAPI project where I wanted to use Autofac to inject some tenant information (i.e. derived per request) into the constructor of each controller:

public class MyController : ApiController
{
  public MyController(TenantInformation tenantInfo)
  {
  }
}

The problem was that the TenantInformation had to be sourced from an async API call

var tenantInfo = await tenantApi.GetTenantInfoAsync();

This means that you cannot implement something like the below to register the component

static void Main(string[] args)
{
  var builder = new ContainerBuilder();

  builder.Register(context => context.Resolve<TenantApi>().GetTenantInfo());

  var container = builder.Build();
  var example = container.Resolve<ExampleController>();
  // --> throws 'Autofac.Core.Registration.ComponentNotRegisteredException'
}

On closer examination of container we can see that TenantInfo has not been registered; instead we have registered an instance of Task<TenantInfo>.  We can await this but not from a constructor.
One option that I briefly considered was importing the service directly into each controller and then getting the value within each async action method that required it.  This works but it feels messy and against the point of DI.  I want to be able to depend on my dependencies; not on the providers of my dependencies.

Using a Mediator

My solution was to create a mediator object representing an asynchronously-resolved component:

interface IAsyncRegistration
{
  Task Resolve(IComponentContext context);
}

class AsyncRegistration<T> : IAsyncRegistration
{
  private Func<IComponentContext, Task<T>> _resolve;

  public AsyncRegistration(Func<IComponentContext, Task<T>> resolve)
  {
    _resolve = resolve;
  }

  public bool Resolved { get; private set; }

  public T Value { get; private set; }

  public async Task Resolve(IComponentContext context)
  {
    this.Value = await _resolve(context);
    this.Resolved = true;
  }
}

This class wraps an resolution function for the type, the resolved value and a flag to indicate whether or not it has been resolved. It also implements a non-generic interface so we can find all instances of AsyncRegistration<T> regardless of T.

public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle> RegisterAsync<T>(this ContainerBuilder builder, Func<IComponentContext, Task<T>> resolve)
{
  builder.RegisterInstance(new AsyncRegistration<T>(resolve))
    .AsSelf()
    .AsImplementedInterfaces();

  return builder.Register<T>(context =>
  {
    var asyncRegistration = context.Resolve<AsyncRegistration<T>>();
    if (!asyncRegistration.Resolved)
      throw new DependencyResolutionException($"Async component {typeof(T).Name} has not been resolved");

    return asyncRegistration.Value;
  });
}

Next I created an extension method for ContainerBuilder that adds 2 registrations:

  1. A registration of AsyncRegistration<T>
  2. A registration of <T> that resolves the AsyncRegistration<T>, checks that it has been resolved and then returns the result

Finally I created an extension method that can be called on the container from anywhere within an async block that will resolve all of the values

public static Task ResolveAsyncRegistrations(this IComponentContext context)
{
  var registrations = context.Resolve<IEnumerable<IAsyncRegistration>>();
  return Task.WhenAll(registrations.Select(r => r.Resolve(context)));
}

All together this means that the following will work and we can now inject asynchronously-resolved services into controller constructors:

var builder = new ContainerBuilder();
builder.RegisterAsync(context =&gt; context.Resolve&lt;TenantApi&gt;().GetTenantInfo());

var container = builder.Build();

//...in an async block...
await container.ResolveAsyncRegistrations();

//...then some time later...
var tenantInfo = container.Resolve<TenantInfo>();

Plugging in to WebAPI

The easiest way to plug this in to the WebAPI pipeline is to create a message handler that

  1. Gets an IComponentContext for the current request
  2. awaits a call to the ResolveAsyncRegistrations extension method
public class AsyncRegistrationHandler : DelegatingHandler
{
  protected override async Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var scope = request.GetDependencyScope().GetRequestLifetimeScope();
    await scope.RegisterAsyncComponents();

    return await base.SendAsync(request, cancellationToken);
  }
}

Caveats

This system works for my particular scenario but there are a lot of possible situations where this would not work or would need extending.  The lifetime management of the dependencies, for example, is very rigid in this implementation and would need some work to be exposed properly.