0

Is it possible to share/use the nested container created by the WebAPI dependency resolver?

The structuremap.web (I'm using structuremap and NServiceBus.StructureMap and UseContainer<StructureMapBuilder>(x => x.ExistingContainer(container))) package provides IDependencyResolver, IDependencyScope implementations that are pretty self explanatory - the resolver is created with the root container and when a scope is requested, it returns a new scope that is created with a nested container from the root.

What I want to know is that in the context of a WebAPI endpoint, can I share that nested container with NSB. Looking here, the structure map builder does pretty much what the WebAPI resolver does - container.GetNestedContainer(). This means I get two nested containers for each (HTTP) request that uses the bus.

My use case is that I want to create a sort of headers bucket that I can put headers into from a DelegatingHandler and then pull them back out of in an OutgoingMessageMutator.

Simon Fox
  • 10,409
  • 7
  • 60
  • 81

2 Answers2

1

This question has also been posted on the google group here. I quickly summarize the discussions for people reading this question:

  • NServiceBus only creates nested containers when receiving messages. By using IBus.Send or similar methods from within the ASP.NET Pipeline, NServiceBus uses the container it has been configured with initially (e.g. for resolving message mutators).
  • OWIN HTTP pass through places messages from incoming requests directly on the queue. This also supports custom extension (e.g. adding headers).
  • You can resolve dependencies from different (nested) containers with DI trickery e.g. by using delegates, but there is some complexity involved. While thread static may be used for DI trickery, be aware that this will be broken with version 6 of NServiceBus which introduces async APIs.
  • IBus can be wrapped in a helper which can be resolved using the pipelines current container and appends the headers.
Sabacc
  • 789
  • 6
  • 13
1

@Sabacc has summarized the options available as discussed in the NServiceBus google group. We decided that the IBus wrapper approach was best for our needs. Below is an example implementation of this for reference

First a delegating handler for adding to a header bucket, this example adds the authorization token. If the header is set, a HeaderBucket instance is resolved from the current dependency scope which is accessible via HttpRequestMessage.GetDependencyScope().

public class AuthorizationTokenCapturingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AuthenticationHeaderValue header = request.Headers.Authorization;
        if (header != null)
        {
            HeaderBucket bucket = (HeaderBucket)request.GetDependencyScope().GetService(typeof(HeaderBucket));
            bucket.Add(new HeaderBucket.Header(HeaderConstants.AUTHORIZATION_TOKEN, header.Parameter));
        }

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

The HeaderBucket is configured transient in container configuration so will be shared just for the lifetime of the nested container.

The IBus wrapper is simple - just wraps the bus intercepting calls to Send and sets the headers that have been added to the bucket on the message being sent.

public class HeaderAwareBus : IHeaderAwareBus
{
    private IBus _bus;
    private HeaderBucket _bucket;

    public HeaderAwareBus(IBus bus, HeaderBucket bucket)
    {
        _bus = bus;
        _bucket = bucket;
    }

    public ICallback Send(object message)
    {
        foreach (HeaderBucket.Header header in _bucket)
        {
            _bus.SetMessageHeader(message, header.Key, header.Value);
        }
        return _bus.Send(message);
    }
}

Now just declare your controller dependency as IHeaderAwareBus and the ASP.Net pipeline will resolve that, and thus the HeaderBucket, from the same nested container accessed from the DelegatingHandler

Simon Fox
  • 10,409
  • 7
  • 60
  • 81