Autofac 3.0.2 update pushed to NuGet

by Alex Meyer-Gleaves 8 April 2013 - 10:04 PM

We have pushed some minor updates to the core Autofac package and a few of the integration packages to NuGet. There is a mix of enhancements and bug fixes across the different packages. You can find all the details below.

Autofac 3.0.2

Changes

  • Enabled XML documentation for all projects and added missing comments.
  • Minor performance improvements in reflection based activation.

Bug Fixes

  • Resolved issue 414 : Made sure the result from MetadataViewProvider is captured in the closure created for the delegate registration instead of being created on each invocation.
  • Resolved Issue 421 : Generic parameters constrained with complex generic types fail to resolve.

SignalR Integration 3.0.1

Changes

  • Added a RegisterHubs extension method for scanning based registration of hubs.
  • Changed the Autofac.Integration.SignalR project to target .NET 4.0 instead of .NET 4.5.
  • The RegisterHubs extension method now registers hubs as ExternallyOwned. There is no way to create a lifetime scope around hub invocations and we don't want the Disposer on the root lifetime scope holding onto instances.
  • Removed the IRegistrationSource for the SignalR dependency resolver so that registrations are not automatically created for the default services. This is because of a bug in the SignalR message bus blocking indefinitely when Dispose is called twice (discovered in self-hosting scenario). It is still possible to manually add registrations to replace the default services.

Web API Integration 3.0.1

Bug Fixes

  • Resolved  Issue 418 : Multiple IAutofacActionFilter causes each filter to execute multiple times. Filter wrappers are now only added once per ControllerType, FilterScope and MethodInfo combination.

Multitenant Support 3.0.2

Bug Fixes

  • Resolved Issue 409: Updated Castle references to 3.2.0.
  • Resolved Issue 402: Added extension method for easy tenant ID retrieval.

Castle DynamicProxy Integration 3.0.2

Bug Fixes

  • Resolved Issue 409 : Updated Castle references to 3.2.0.

Tags:

Autofac

Autofac 3.0 Final Release

by Alex Meyer-Gleaves 30 January 2013 - 10:02 PM

The NuGet packages and download zips are now available for the final release of Autofac 3.0. The biggest changes since Beta 2 are the introduction of an official SignalR integration (built against the RC1 version) and plenty more documentation on the wiki (with even more on the way). The release notes below outline the changes between Beta 2 and the final release. You find details for the previous beta versions on the release notes page. Thank you to everyone who tested the beta versions and provided the team with valuable feedback. A big shout out to Travis Illig for helping make 3.0 such a great release, and to Nicholas Blumhardt for starting such an awesome open source project.

Changes

  • Added SignalR Integration.
  • Updated Newtonsoft.Json package to the latest.
  • Added the inner exception message to DependencyResolutionException message for easier troubleshooting.

Bug Fixes

  • Issue 310 : Resolve fails on MEF export of type object
  • Issue 352 : Security exception in Silverlight 5
  • Issue 394 : ContainerBuilder.RegisterAssemblyType depends on assembly list order
  • Issue 326 : If MEF contract type has generics, MEF integration fails
  • Issue 343 : Include inner exception message in outer exception message when wrapping exceptions from constructors

Core NuGet Packages

Extras NuGet Packages

Tags:

Autofac

Autofac 3.0 Beta 2 packages available on NuGet

by Alex Meyer-Gleaves 23 December 2012 - 2:16 PM

Since releasing the first Beta we have been busy working through the issue list and have included a number of enhancements and bug fixes in Beta 2. We are hoping this will be the last Beta before the final release, and will be putting a hold on changes in the meantime to the keep the codebase stable. It would be great to make the release available early in the new year, so please grab the latest packages and let us know if you have any problems.

Changes

  • Added AutoActivate() registration extension to flag components to be automatically resolved on container build.
  • Added an InterceptTransparentProxy registration extension that allows transparent proxy instances to be intercepted using ProxyGenerator.CreateInterfaceProxyWithTargetInterface.
  • Added AutofacInstanceContext.Current static method akin to the MVC AutofacDependencyResolver.Current. Made OperationLifetime publicly gettable to allow for AutofacInstanceContext.Current.OperationLifetime access.
  • Added a RegisterTypes extension equivalent to RegisterAssemblyTypes but which allows you to pass in a specific list of types rather than simply scanning assemblies.
  • Removed the now confusing (Beta) suffix from the MVC 4 and Web API integration NuGet package titles.
  • The same registration can now be used to register a MVC and Web API filter. Multiple filter types on a single registration are also supported.
  • Updated all dependencies to the latest versions.
  • Switched Autofac.Extras.CommonServiceLocator to a portable class library.

Bug Fixes

  • Issue 303 : AutofacDomainServiceFactory creates instances in the root container.
  • Issue 305 : Add RegisterAssemblyTypes overload which gets a list of types.
  • Issue 365 : Configured Nested Containers Lose LimitType on Component Registrations - Affects WCF Service Resolution.
  • Issue 391 : Cannot use ActionFilterFor for both MVC and Web API controllers on the same registration.
  • Issue 396 : ExtensibleActionInvoker incorrectly holds attachment to expired lifetime scope in MVC4.
  • Issue 339 : Improve the way Autofac.Integration.Wcf exposes the LifetimeScope.
  • Issue 351 : Autofac.Integration.Mvc fails when Glimpse.Mvc3 is installed.
  • Issue 355 : AutofacContrib.DynamicProxy2: Internal interfaces are not intercepted (and no exception).
  • Issue 361 : DynamicProxy interception does not work for WCF clients.
  • Issue 397 : Nested lifetime scopes aren't disposed when the parent is disposed.
  • Issue 388 : Wrapper around IStartable to make a component implicitly activated.

Core NuGet Packages

Extras NuGet Packages

Tags:

Autofac

Autofac 3.0 Beta packages available on NuGet

by Alex Meyer-Gleaves 1 November 2012 - 11:32 PM

Those of you that follow the Autofac Google Group will no doubt be aware that despite some changes in project leadership plenty of work has been going into the 3.0 release. With the amount of refactoring that has been done we wanted to make a Beta release available for wider testing before declaring 3.0 stable. I want to take this opportunity to give a big shout out to my partner in crime, Travis Illig, who has been in there smashing through the issues with me.

Portable Class Library

The major task that has been undertaken in 3.0 is converting the core Autofac project into a PCL (Portable Class Library) allowing the one assembly to be used in multiple framework targets. You will be able to target the following frameworks with Autofac 3.0:

  • .NET Framework 4 and higher
  • Silverlight 5
  • .NET for Windows Store apps
  • Windows Phone 8

Windows Phone 7 and Silverlight 4 are not in the list of supported frameworks because they are missing many of the features that Autofac requires (such as a complete implementation of variance in generics). Those frameworks will continue to be supported using the existing 2.6 release. We wanted to make sure that we could cover as broad a base as possible without resorting to having multiple projects or preprocessor directives.

There was a point where we went down the plugin route, having platform specific assemblies that would be plugged into the core PCL at runtime, but found this to be problematic from a security perspective with issues arising in medium-trust scenarios. In the end we got everything that we wanted in the core PCL working by reducing the supported frameworks and the result is a much simpler solution to maintain.

The NuGet package for Autofac 3.0 uses the support for portable libraries added in NuGet 2.1 so remember to update your package manager.

Single Solution (Core and Extras)

In the past we had two separate solutions for the core Autofac projects and those for Autofac.Contrib. It was easy for these two solutions to get out of sync so we decided to move everything into a single solution keeping everything consistent and visible. Part of the move was to rebrand the contrib projects into “Extras” packages that are now deployed via NuGet just the same as the core packages. The division between the core and extras packages relates to whether or not the package takes a dependency on a third party library or offers fairly niche functionality.

These are the Core NuGet packages:

We did a little bit of clean up but the majority of the contrib projects have been moved across to Extras NuGet packages:

Semantic Versioning

Starting with 3.0 we will be following the Semantic Versioning specification and will utilise prerelease NuGet packages. As such, the 3.0 beta release packages are versioned 3.0.0-beta. Prerelease packages provide a great way to indicate the current stability of a package while still allowing for easy installation, and semantic versioning provides a means to quickly get a feel for the kind of changes that can be expected in a particular release.

SymbolSource Support

We are now also building symbol packages that are uploaded to SymbolSource.org allowing you to download and step through the Autofac source code. This support will be provided for all packages both core and extras. Instructions for configuring Visual Studio to work with the symbol server are available on the SymbolSource website. Being able to step through the source makes it much easier to understand what is happening under the hood and makes you feel a lot more in control.

Metadata Support

Interfaced based strongly-typed metadata was one particular feature that was difficult to port over to the PCL due to its dependency on MEF specific functionality, in particular the AttributedModelServices class, and indirectly through to the System.Reflection.Emit namespace. The PCL library does not have access to System.ComponentModel.Composition because it is not available in all of the target frameworks.

Recently, the MEF team released a lightweight version of MEF (Microsoft.Composition) that also had to address the issue of not being able to generate types for metadata interfaces; they too are targeting Windows Store apps and lost access to the System.Reflection.Emit namespace. To remove the need to dynamically generate a type at runtime they switched the interface based metadata views with a class based implementation.

Autofac 3.0 has taken the same approach to strongly-typed metadata when only the PCL is being referenced. If you are running in a Windows Store or Windows Phone 8 app you will need to use class based metadata. Following the example from my previous blog post about selectively resolving services at runtime, the metadata interface would change from:

public interface IExportMetadata
{
    ExportFormat Format { get; }
}

To a simple metadata class that has public properties with getters and setters:

public class ExportMetadata
{
    public ExportFormat Format { get; set; }
}

Registering the metadata remains exactly the same except you provide a class type as the generic type parameter for the WithMetadata method:

builder.Register(c => new PdfFormat())
    .As<IExport>()
    .WithMetadata<ExportMetadata>(m =>
        m.For(em => em.Format, ExportFormat.Pdf));

builder.Register(c => new HtmlFormat())
    .As<IExport>()
    .WithMetadata<ExportMetadata>(m =>
        m.For(em => em.Format, ExportFormat.Html));

builder.Register(c => new RtfFormat())
    .As<IExport>()
    .WithMetadata<ExportMetadata>(m =>
        m.For(em => em.Format, ExportFormat.Rtf));

You can also continue to provide default values using the DefaultValue attribute:

public class ExportMetadata
{
    [DefaultValue(ExportFormat.Html)]
    public ExportFormat Format { get; set; }
}

Another neat trick is the ability to pass the metadata dictionary into the constructor of your metadata class:

public class ExportMetadataWithDictionary
{
    public ExportMetadataWithDictionary(IDictionary<string, object> metadata)
    {
        Format = (ExportFormat)metadata["Format"];
    }

    public ExportFormat Format { get; set; }
}

If you have access to System.ComponentModel.Composition it is still possible to use interfaces for your metadata and even resolve them using Lazy<T, TMedata>. This is achieved by adding a reference to the Autofac.Mef package and calling the RegisterMetadataRegistrationSources method on the container builder before registering the metadata against the interface type.

builder.RegisterMetadataRegistrationSources();

builder.Register(c => new PdfFormat())
    .As<IExport>()
    .WithMetadata<IExportMetadata>(m =>
        m.For(em => em.Format, ExportFormat.Pdf));

builder.Register(c => new HtmlFormat())
    .As<IExport>()
    .WithMetadata<IExportMetadata>(m =>
        m.For(em => em.Format, ExportFormat.Html));

builder.Register(c => new RtfFormat())
    .As<IExport>()
    .WithMetadata<IExportMetadata>(m =>
        m.For(em => em.Format, ExportFormat.Rtf));

The final point to note is that you can use class based metadata and still resolve your types using Lazy<T, TMetadata> from System.ComponentModel.Composition. If you don’t add the Autofac.Mef package and therefore don’t call the RegisterMetadataRegistrationSources method, but have referenced System.ComponentModel.Composition, the metadata registration source in the PCL will figure out that Lazy<T, TMetadata> is available and will use that with the class based metadata.

There is a lot of confusing detail above so to summarise the important points:

  • Class based strongly-typed metadata is now available in all supported target frameworks.
  • Interface based strongly-typed metadata remains available when System.ComponentModel.Composition can be referenced and the Autofac.Mef package is installed.
  • Lazy<T, TMetadata> can be used with class based or interface based strongly-typed metadata.

XML Configuration

Those that prefer to configure their registrations without code will be pleased to know that Autofac.Configuration has been given some serious attention. To import XML configuration from an arbitrary file you can use the XmlFileReader module. It uses the same XML schema as the regular configuration settings but doesn't require the additional elements such as <configuration/> that standard .NET configuration files require.

var builder = new ContainerBuilder();
var module = new XmlFileReader("path/to/config.xml");
builder.RegisterModule(module);
var container = builder.Build();

The XmlFileReader and ConfigurationSettingsReader modules both derive from ConfigurationModule. You can control how configuration is loaded, and how that configuration is converted into registrations, through its two properties of type SectionHandler and IConfigurationRegistrar.

SectionHandler is the configuration section and now has a Deserialize method that accepts an XmlReader. This opens up the possibilities for how you store your configuration.

ConfigurationRegistrar, the default implementation of IConfigurationRegistrar, contains convenient virtual methods that allow you to control the parsing of the configuration section into registrations. The following methods can be overridden to customise the parsing behaviour:

  • RegisterConfiguredComponents
  • RegisterConfiguredModules
  • RegisterReferencedFiles
  • SetInjectProperties
  • SetComponentOwnership
  • SetLifetimeScope
  • LoadType

It is possible to set the IConfigurationRegistrar property on the XmlFileReader and ConfigurationSettingsReader directly without having to create a custom ConfigurationModule.

FindConstructorsWith

The FindConstructorsWith registration extension that took a BindingFlags parameter had to be refactor to take a Func<Type, ConstructorInfo[]>, because the BindingFlags type is not available in the PCL.

It is easy to update existing code where BindingFlags is available (such as .NET Framework 4.0) by passing a simple lambda to the method instead.

var builder = new ContainerBuilder();
builder.RegisterType<HasPrivateConstructor>()
    .FindConstructorsWith(type => type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic));

The function parameter also allows you to use the new reflection API found in WinRT to achieve the same result.

Matching multiple lifetime scopes

It is now possible for a registration to indicate that is should be matched against multiple named/tagged lifetimes scopes.

var builder = new ContainerBuilder();

builder.Register(c => new object()).InstancePerMatchingLifetimeScope("A", 123);

var container = builder.Build();

using (var lifetimeScope = container.BeginLifetimeScope("A"))
{
    var instanceForA = lifetimeScope.Resolve<object>();
}

using (var lifetimeScope = container.BeginLifetimeScope(123))
{
    var instanceFor123 = lifetimeScope.Resolve<object>();
}

The InstancePerMatchingLifetimeScope method takes a params array of objects that will be matched against the tag provided to the lifetime scope when it was created.

MVC 4 and Web API

The NuGet packages for MVC 4 and Web API have been updated to 3.0.0-beta and are compiled against the Autofac 3.0 beta package. You can read more about the features available in these integrations (including filters without attributes) in a previous post. These two NuGet packages have “(Beta)” in their titles but they are compiled against the RTW versions of MVC 4 and Web API. Looking at my package list I realise this is confusing and that has been fixed ready for the next push.

Bug Fixes and Enhancements

Below is a list of bug fixes and enhancements available in Autofac 3.0:

  • Issue 389: Exception thrown in AutofacFilterProvider when other filter instances registered in the container
  • Issue 379: There is an errror when using Autofac.Integration.Mvc, Autofac.Integration.WebApi and Autofac.Integration.Web together
  • Issue 376: Exception while trying to throw an exception in Metro app
  • Issue 368: MVC ExtensibleActionInvoker.GetParameterValue Can't Be Disabled
  • Issue 386: Support configuration reading from XML file that is not app.config
  • Issue 271: Could not register more then one Module with the same type but with different parameters in XmlConfiguration
  • Issue 378: Make Container.Empty immutable
  • Issue 358: Portable build warnings in a Metro style app
  • Issue 352: Provide Silverlight 5 Support
  • Issue 287: Guidance for building AutofacContrib packages and moving to nuget
  • Issue 252: Single solution for Autofac + AutofacContrib

What’s next?

Hopefully we get lots of feedback on the PCL support and can quickly iron out any issues. Once that is done we can make a release version of 3.0 available. In the meantime we are going to concentrate on improving the documentation on the wiki and maybe even look at hosting a website with some “Getting Started” examples for the different types of supported applications. Finally, you can discuss all things Autofac in the Google Group and raise issues in the Issue Tracker. Happy dependency injecting!

Tags:

Autofac

New features in the Autofac MVC 4 and Web API (Beta) Integrations

by Alex Meyer-Gleaves 1 September 2012 - 2:30 AM

This post outlines the new features in the latest pre-release NuGet packages for the Autofac integrations with MVC 4 and Web API. You can find more information about the initial support for dependency injection with Web API controller instances in my previous post.

A quick note on versioning

The integration packages that I recently pushed out are compiled against the RTM version of MVC 4 and Web API. They also reference the latest Autofac package  and all three versions are now the same (2.6.3.862). I also took advantage of the pre-release NuGet support to mark the two integration packages as beta. The idea is that after getting some feedback and releasing some additional pre-release packages the final release versions will all continue to be aligned.

Filters without attributes in MVC 4

This feature started because someone on Twitter was asking why constructor injection was not supported for filter attributes. Because attributes are created via the reflection API you don’t actually get to call the constructor yourself. That leaves you with no other option except for property injection when working with attributes. The question did get me thinking about an alternative approach for working with filters though. What I came up with was a mechanism that allows you to create classes that implement the filter interfaces (IActionFilter, IAuthorizationFilter, IExceptionFilter and IResultFilter) and wire them up to the desired controller or action method using the registration syntax on the container builder.

To get a feel for what this looks like imagine that you want to inject your logging service into an action filter to instrument an action method invocation.

You create an interface for your logging service.

public interface ILogger
{
    void Write(string message);
}

In this example the implementation will just write to the Debug class.

public class Logger : ILogger
{
    public void Write(string message)
    {
        Debug.WriteLine(message);
    }
}

Next you create an IActionFilter class that will have the logger injected into its constructor. This one simply logs the name of the action being invoked.

public class LoggingActionFilter : IActionFilter
{
    readonly ILogger _logger;

    public LoggingActionFilter(ILogger logger)
    {
        _logger = logger;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _logger.Write(filterContext.ActionDescriptor.ActionName);
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        _logger.Write(filterContext.ActionDescriptor.ActionName);
    }
}

For the action filter to execute you need to register the Autofac filter provider implementation, the logger service, and the action filter.

var builder = new ContainerBuilder();

builder.RegisterFilterProvider();

builder.Register(c => new Logger())
    .As<ILogger>()
    .InstancePerHttpRequest();

builder.Register(c => new LoggingActionFilter(c.Resolve<ILogger>()))
    .AsActionFilterFor<HomeController>(c => c.Index())
    .InstancePerHttpRequest();

builder.RegisterControllers(Assembly.GetExecutingAssembly());

var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

You need to register the filter provider because it is does the work of wiring up the filter based on the registration. To indicate what the action filter should be applied to the AsActionFilterFor method on the builder is used. It requires a generic type parameter for the type of the controller, and an optional lambda expression that indicates a specific method on the controller the filter should be applied to. If you don’t provide the lambda expression the filter will be applied to all action methods on the controller in the same way that placing an attribute based filter at the controller level would. In the example above we are applying the filter to the Index action method on the HomeController.

It is also possible to provide a base controller type in the generic type parameter to have the filter applied to all derived controllers. In addition, you can also make your lambda expression for the action method target a method on a base controller type and have it applied to that method on all derived controllers. Finally, you can also provide the sort order for the filter the same way you would with an attribute.

builder.Register(c => new LoggingActionFilter(c.Resolve<ILogger>()))
    .AsActionFilterFor<HomeController>(c => c.Index(), order: 1)
    .InstancePerHttpRequest();

When applying the filter to an action method that requires a parameter use the default keyword with the data type of the parameter as a placeholder in your lambda expression. For example, if you have an action method called GetStuff that requires an int parameter your registration would look like this.

builder.Register(c => new LoggingActionFilter(c.Resolve<ILogger>()))
    .AsActionFilterFor<MyController>(c => c.GetStuff(default(int)))
    .InstancePerHttpRequest();

You are able to choose the appropriate lifetime scope for your filter including InstancePerHttpRequest. Working with the other types of filters is exactly the same except you use the extension method on the container builder that matches the type of filter you are registering (AsAuthorizationFilterFor, AsExceptionFilterFor and AsResultFilterFor).

Filters without attributes in Web API

The same support for filters without attributes has been added to the Web API integration except you need to use filter interfaces provided by the Autofac integration (IAutofacActionFilter, IAutofacAuthorizationFilter and IAutofacExceptionFilter). You are no doubt wondering why I introduced special interfaces but this should become more apparent if you take a look at the signature of the IActionFilter interface in Web API.

public interface IActionFilter : IFilter
{
    Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation);
}

Now compare that to the Autofac interface that you need to implement instead.

public interface IAutofacActionFilter
{
    void OnActionExecuting(HttpActionContext actionContext);

    void OnActionExecuted(HttpActionExecutedContext actionExecutedContext);
}

The problem is that the OnActionExecuting and OnActionExecuted methods are actually defined on the the ActionFilterAttribute and not on the IActionFilter interface. Extensive use of the System.Threading.Tasks namespace in Web API means that chaining the return task along with the appropriate error handling in the attribute actually requires a significant amount of code (the ActionFilterAttribute contains nearly 100 lines of code for that). This is definitely not something that you want to be handling yourself so I introduced the new interfaces to allow you to concentrate on implementing the code for your filter and not all that plumbing. Internally I create custom instances of the actual Web API attributes that resolve the filter implementations from the container and execute them at the appropriate time.

Another reason for creating the internal attribute wrappers is to support the InstancePerApiRequest lifetime scope for filters. Unlike the filter provider in MVC the one in Web API does not allow you to specify that the filter instances should not be cached. This means that all filter attributes in Web API are effectively singleton instances that exist for the entire lifetime of the application. I raised my concern about this with the development team but the desire to ensure maximum performance by default won the argument. My personal opinion is that the lifetime for all services requested from the container should be determined by the developer configuring the container. The decision if a service should be singleton or transient in nature should be decided based upon the kind of work the service will perform. This caching of services makes it difficult to implement a Unit of Work pattern per-request because many of the services involved will not have their lifetimes and disposal managed by the container.

Regardless, in the end I got everything that I wanted working so let’s look at what the action filter example would look like for a Web API controller. Notice that the filter implements IAutofacActionFilter instead of IActionFilter from System.Web.Http.Filters.

public class LoggingActionFilter : IAutofacActionFilter
{
    readonly ILogger _logger;

    public LoggingActionFilter(ILogger logger)
    {
        _logger = logger;
    }

    public void OnActionExecuting(HttpActionContext actionContext)
    {
        _logger.Write(actionContext.ActionDescriptor.ActionName);
    }

    public void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        _logger.Write(actionExecutedContext.ActionContext.ActionDescriptor.ActionName);
    }
}

The registration code looks very similar to the MVC code shown earlier.

var builder = new ContainerBuilder();

builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

builder.Register(c => new Logger())
    .As<ILogger>()
    .InstancePerApiRequest();

builder.Register(c => new LoggingActionFilter(c.Resolve<ILogger>()))
    .AsActionFilterFor<ValuesController>(c => c.Get(default(int)))
    .InstancePerApiRequest();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

var container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

Just like with the MVC registrations we need to register the custom filter provider for Web API but this time we use the RegisterWebApiFilterProvider method. The methods on the container builder for assigning the filters to controllers and action methods follow the same naming convention as MVC with the exception that the AsResultFilterFor method does not exist because there is no result filter in Web API. The other difference is that there is no order parameter on the methods for Web API because the order property does not exist on the filter attributes. You use the generic type parameter for the controller and a lambda expression for the action method in the same way.

Per-controller type services in Web API

Web API has an interesting feature that allows you to configure the set of Web API specific services (those such as IActionValueBinder) that should be used per-controller type by adding an attribute that implements the IControllerConfiguration interface to your controller. Through the Services property on the HttpControllerSettings parameter passed to the Initialize method of that interface you can override the global set of services. This attribute based approach seems to encourage you to directly instantiate service instances and then override the ones registered globally. I thought it would be nice to allow these per-controller type services to be configured through the container instead of being buried away in an attribute without DI support.

There is no escaping adding an attribute to the controller that the configuration should be applied to because that is the extension point defined by Web API. The Autofac integration includes an AutofacControllerConfigurationAttribute that you can apply to your Web API controllers to indicate that they require per-controller type configuration. The point to remember here is that the actual configuration of what services should be applied will be done when you build your container and there is no need to implement any of that in an actual attribute. In this case the attribute can be considered as purely a marker that indicates that the container will define the configuration information and provide the service instances.

[AutofacControllerConfiguration]
public class ValuesController : ApiController
{
    // Implementation...
}

The supported services can be divided into single-style or multiple-style services. For example, you can only have one IHttpActionInvoker but you can have multiple ModelBinderProvider services.

You can use dependency injection for the following single-style services:

  • IHttpActionInvoker
  • IHttpActionSelector
  • IActionValueBinder
  • IBodyModelValidator
  • IContentNegotiator
  • IHttpControllerActivator
  • ModelMetadataProvider

The following multiple style services are supported:

  • ModelBinderProvider
  • ModelValidatorProvider
  • ValueProviderFactory
  • MediaTypeFormatter

In the list of the multiple-style services above the MediaTypeFormatter is actually the odd one out. Technically, it isn’t actually a service and is added to the MediaTypeFormatterCollection on the HttpControllerSettings instance and not the ControllerServices container. I figured that there was no reason to exclude MediaTypeFormatter instances from dependency injection support and made sure that they could be resolved from the container per-controller type too.

Here is an example of registering a custom IHttpActionSelector implementation as InstancePerApiControllerType for the ValuesController. When applied to a controller type all derived controllers will also receive the same configuration; the AutofacControllerConfigurationAttribute is inherited by derived controller types and the same behaviour applies to the registrations in the container. When you register a single-style services it will always replace the default service configured at the global level.

builder.Register(c => new CustomActionSelector())
    .As<IHttpActionSelector>()
    .InstancePerApiControllerType(typeof(ValuesController));

Multiple-style services are by default appended to the existing set of services configured at the global level. When registering multiple services with the container you can choose to clear the existing set of services so that only the ones you have registered as InstancePerApiControllerType will be used. This is done by setting the clearExistingServices parameter to true on the InstancePerApiControllerType method. Existing services of that type will be removed if any of the registrations for the multiple-style service indicate that they want that to happen.

builder.Register(c => new CustomModelBinderProvider())
    .As<ModelBinderProvider>()
    .InstancePerApiControllerType(typeof(ValuesController), clearExistingServices: true);

I’m not entirely happy with this particular feature because it is not possible to take dependencies on services that are registered as InstancePerApiRequest. The problem once again is that Web API is caching these services and is not requesting them from the container each time a controller of that type is created. I don’t think it would be possible for Web API to do that without introducing the notion of a key (for the controller type) into the DI support and that would mean that all containers would need to support keyed services.

Feedback welcome

I am very keen to receive feedback on these new features as I have not had the chance to use them in a production setting and put them through their paces. Hopefully you like the idea of filters that support constructor injection and don’t require attributes. I would be very interested to hear how useful you think the InstancePerApiControllerType feature is despite the issue with it not being able to take dependencies on services registered as InstancePerApiRequest.

Tags:

Autofac

Autofac 2.6.2.859 and ASP.NET MVC 4 RC Integrations Released

by Alex Meyer-Gleaves 8 June 2012 - 2:25 AM

I have released updated NuGet packages and downloads for Autofac. The core library only has a couple of updates: a new module scanning feature and some performance improvements for the .NET 4 build. The ASP.NET MVC 4 and ASP.NET Web API integrations have also been updated to the RC version.

Module Scanning

Module scanning is performed with the new RegisterAssemblyModules registration method that does exactly what its name suggests. It scans through the provided assemblies for modules, creates instances of the modules, and then registers them with the current builder.

The two simple module classes below live in the same assembly and each register a single component: AComponent and BComponent.

public class AModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register(c => new AComponent()).As<AComponent>();
    }
}

public class BModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register(c => new BComponent()).As<BComponent>();
    }
}

The first overload of RegisterAssemblyModules will register all classes implementing IModule found in the provided list of assemblies. You can see in the unit test below that both AComponent and BComponent are registered because AModule and BModule are both IModule implementations.

[Test]
public void RegisterAssemblyModules()
{
    var assembly = typeof(AComponent).Assembly;
    var builder = new ContainerBuilder();
    builder.RegisterAssemblyModules(assembly);
    var container = builder.Build();

    Assert.That(container.IsRegistered<AComponent>(), Is.True);
    Assert.That(container.IsRegistered<BComponent>(), Is.True);
}

The second overload allows you to specify a base type that the modules must derive from. This second unit test shows that only AComponent is registered because the scanning is restricted to modules of type AModule.

[Test]
public void RegisterAssemblyModulesOfType()
{
    var assembly = typeof(AComponent).Assembly;
    var builder = new ContainerBuilder();
    builder.RegisterAssemblyModules<AModule>(assembly);
    var container = builder.Build();

    Assert.That(container.IsRegistered<AComponent>(), Is.True);
    Assert.That(container.IsRegistered<BComponent>(), Is.False);
}

Performance Improvements

Nothing was drastically changed in the performance improvements but a number of small tweaks ended up resulting in a considerable improvement:

  • Removed duplicate argument null checking in internal types when the check has already been performed by the caller.
  • Removed the empty handlers from events and used old fashion null checking in order to prevent event argument instances from being created when no real subscriber requires them.
  • CircularDependencyDetector now uses Any() instead of Count() when checking the activation stack which is much quicker for deeper graphs.
  • ConstructorParameterBinding uses a delegate compiled from a LambdaExpression to invoke constructors. The compiled delegate is also cached per ConstructorInfo.

When running the IocBattle and IocPerformance benchmarks I noted about a 30% improvement in the reflection-based resolution of transient instances. I am happy with these results given the breadth of the feature set that Autofac supports and how simple the changes were.

ASP.NET MVC 4 RC Integration

This is basically just a recompilation as there is no new DI support that I am aware of at the moment. The same goodness that was available in the MVC 3 integration continues to be available in the MVC 4 integration.

ASP.NET Web API RC Integration

The DI support in Web API was improved after the Beta release and the IHttpControllerFactory and IHttpControllerActivator implementations from the Beta integration are no longer necessary. To achieve the per-controller lifetime scoping Web API introduced an IDependencyScope interface to compliment IDependencyResolver. A new BeginScope method was added to the IDependencyResolver allowing a nested dependency scope to be created. This has significantly simplified the integration and removes all the trickery I needed to perform with the Beta version.

public class AutofacWebApiDependencyResolver : IDependencyResolver
{
    readonly ILifetimeScope _container;
    readonly IDependencyScope _rootDependencyScope;

    internal static readonly string ApiRequestTag = "AutofacWebRequest";

    public AutofacWebApiDependencyResolver(ILifetimeScope container)
    {
        if (container == null) throw new ArgumentNullException("container");

        _container = container;
        _rootDependencyScope = new AutofacWebApiDependencyScope(container);
    }

    public ILifetimeScope Container
    {
        get { return _container; }
    }

    public object GetService(Type serviceType)
    {
        return _rootDependencyScope.GetService(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _rootDependencyScope.GetServices(serviceType);
    }

    public IDependencyScope BeginScope()
    {
        ILifetimeScope lifetimeScope = _container.BeginLifetimeScope(ApiRequestTag);
        return new AutofacWebApiDependencyScope(lifetimeScope);
    }

    public void Dispose()
    {
        _rootDependencyScope.Dispose();
    }
}

The dependency resolver creates a dependency scope in its constructor that wraps the root Autofac lifetime scope. Direct calls to GetService and GetServices on the dependency resolver are wired to the root dependency scope. For controller invocation Web API will use BeginScope to get a dependency scope instance that it can use to resolve the controller from. This provides the opportunity for a new Autofac lifetime scope to be created and wrapped in the dependency scope. At the end of the request the dependency scope will be disposed and along with it the nested Autofac lifetime scope.

public class AutofacWebApiDependencyScope : IDependencyScope
{
    readonly ILifetimeScope _lifetimeScope;

    public AutofacWebApiDependencyScope(ILifetimeScope lifetimeScope)
    {
        _lifetimeScope = lifetimeScope;
    }

    public object GetService(Type serviceType)
    {
        return _lifetimeScope.ResolveOptional(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        if (!_lifetimeScope.IsRegistered(serviceType))
            return Enumerable.Empty<object>();

        var enumerableServiceType = typeof(IEnumerable<>).MakeGenericType(serviceType);
        var instance = _lifetimeScope.Resolve(enumerableServiceType);
        return (IEnumerable<object>)instance;
    }

    public void Dispose()
    {
        if (_lifetimeScope != null)
            _lifetimeScope.Dispose();
    }
}

You no longer have to call the ConfigureWebApi method on the ContainerBuilder that was shown in my previous post about the Beta integration. That was required to make sure the custom IHttpControllerFactory and IHttpControllerActivator were added to the container so that Web API would use them. This method has now been deleted and will need to be removed from any existing code.

To save you having to look at the previous post again, hosting in ASP.NET now looks like this:

var builder = new ContainerBuilder();

// Register API controllers using assembly scanning.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// Register API controller dependencies per request.
builder.Register(c => new Logger()).As<ILogger>().InstancePerApiRequest();

var container = builder.Build();

// Set the dependency resolver implementation.
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;

Self-hosting remains just as simple except you are working with a new instance of HttpSelfHostConfiguration instead of the GlobalConfiguration static:

var configuration = new HttpSelfHostConfiguration("http://localhost:8080");

configuration.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
    );

var builder = new ContainerBuilder();

// Register API controllers using assembly scanning.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// Register API controller dependencies per request.
builder.Register<ILogger>(c => new Logger()).InstancePerApiRequest();

var container = builder.Build();

// Set the dependency resolver implementation.
var resolver = new AutofacWebApiDependencyResolver(container);
configuration.DependencyResolver = resolver;

// Open the HTTP server and listen for requests.
using (var server = new HttpSelfHostServer(configuration))
{
    server.OpenAsync().Wait();

    Console.WriteLine("Hosting at http://localhost:8080/{controller}");
    Console.ReadLine();
}

There are not a lot of other visible changes in the integration at this point, but you can expect some cool new features for the official release. These will include per-controller type registrations and model binding support similar to the MVC integration. Support for per-controller type configuration was added after the RC and the model binding interfaces changed significantly soon after but appear to have been locked down now.

Tags:

Autofac

Selectively resolving services at runtime with Autofac

by Alex Meyer-Gleaves 25 May 2012 - 2:10 AM

The question of how to selectively resolve a service at runtime was asked on the Autofac Google Group recently, and since this is not the first time the question has been asked I thought it would be a good idea to write a post for future reference. There are a couple of ways of doing this but I am going to outline one that does not require you to take a dependency on the container (more specifically the component context).

Here is the example from the question. There is a simple IExport interface defined that is used to describe services that can export a document in a particular format.

public interface IExport
{
    void Run(string content);
}

Then there are three different exports; one for PDF, HTML and RTF.

public class PdfFormat : IExport
{
    public void Run(string content)
    {
        // export in PDF format
    }
}

public class HtmlFormat : IExport
{
    public void Run(string content)
    {
        // export in HTML format
    }
}

public class RtfFormat : IExport
{
    public void Run(string content)
    {
        // export in RTF format
    }
}

Finally, there is a controller that has an IExport constructor injected:

public class HomeController : Controller
{
    readonly IExport _export;

    public HomeController(IExport export)
    {
        _export = export;
    }
    public void ExportDocument(string content)
    {
        _export.Run(content);
    }
}

The problem is that when ExportDocument is called we want to make sure that the correct export gets invoked based on a format selected by the user at runtime. To make this work some refactoring is required.

We are going to need something to key the services by and I find that an enum works well and does not introduce any magic strings:

public enum ExportFormat
{
    Pdf,
    Html,
    Rtf
}

A simple interface that defines some metadata for the export services will also be required:

public interface IExportMetadata
{
    ExportFormat Format { get; }
}

Now let’s jump into the container registration code and then break it down afterward:

var builder = new ContainerBuilder();

builder.Register(c => new PdfFormat())
    .As<IExport>()
    .WithMetadata<IExportMetadata>(m => 
        m.For(em => em.Format, ExportFormat.Pdf));

builder.Register(c => new HtmlFormat())
    .As<IExport>()
    .WithMetadata<IExportMetadata>(m => 
        m.For(em => em.Format, ExportFormat.Html));

builder.Register(c => new RtfFormat())
    .As<IExport>()
    .WithMetadata<IExportMetadata>(m => 
        m.For(em => em.Format, ExportFormat.Rtf));

builder.Register(c => new HomeController(
    c.Resolve<IEnumerable<Lazy<IExport, IExportMetadata>>>()));

The approach utilizes the IEnumerable<T> and Lazy<T, TMetadata> relationship types supported in Autofac. These correspond to the enumeration and metadata interrogation with delayed instantiation relationship types. Each implementation type is registered with the container and associates metadata with the registration using the WithMetadata method. This metadata will be used later to select the appropriate export service at runtime without having to instantiate the entire list of registered services.

Inspection of the registration for the HomeController shows that the constructor has been refactored to receive an IEnumerable<Lazy<IExport, IExportMetadata>> argument and that is the key to how the problem is solved. The container will automatically provide the controller with an enumerable list of Lazy<IExport, IExportMetadata>. It is the Lazy<IExport, IExportMetadata> that allows you to query the registered metadata for a service without actually instantiating an instance.

public class HomeController : Controller
{
    readonly IEnumerable<Lazy<IExport, IExportMetadata>> _exports;

    public HomeController(IEnumerable<Lazy<IExport, IExportMetadata>> exports)
    {
        _exports = exports;
    }

    public void ExportDocument(string content, ExportFormat format)
    {
        var lazy = _exports.FirstOrDefault(e =>  e.Metadata.Format == format);

        if (lazy == null)
            throw new ArgumentException("Export format is not supported.", "format");

        var export = lazy.Value;
        if (export != null)
            export.Run(content);
    }
}

To support the selection of a particular export format the ExportDocument method on the controller is refactored to receive an ExportFormat as an additional parameter. This would be selected by the user at runtime and the metadata will be queried to find the registration that matches the provided format. When the correct service has been found the Value property on the Lazy<IExport, IExportMetadata> is accessed and the instance is resolved from the container. There is no need to actually create instances of all the export services in order to invoke the correct one thanks to various relationship types.

Notice that I am using Lazy<T, TMetadata> from the System.ComponentModel.Composition assembly that shipped with .NET 4.0. If you are using an earlier version of .NET you can achieve the same result by using Meta<Lazy<IExport>, IExportMetadata>. The Meta<T, TMetadata> type is defined in Autofac and you will be introducing a container specific dependency, but that is probably not a huge issue given the value it provides when you cannot upgrade to .NET 4.0. Obviously you would always try to use Lazy<T, TMetadata> whenever possible though.

Tags:

Autofac

Autofac ASP.NET Web API (Beta) Integration

by Alex Meyer-Gleaves 9 March 2012 - 1:23 AM

With the beta release of ASP.NET MVC 4 and the ASP.NET Web API being released a few weeks ago, I decided it was about time to have a look at what the integration story would like for Autofac. The package is available for download on NuGet.

Install-Package Autofac.WebApi

While building the preview of the Web API integration I had the following goals in mind:

  • Ensure that it would work alongside the MVC integration without issues such as naming conflicts.
  • Support both the web hosting and self hosting scenarios in a single assembly.
  • Avoid taking dependencies on the System.Web.Http.SelfHost and System.Web.Http.WebHost assemblies (to help achieve the goal above).
  • Minimize the amount of configuration required to get up and running.
  • Provide a lifetime scope around each call to an API controller so that it and its dependencies are automatically disposed at the end of the call.

I had some concerns about how easy this would be given the two different modes of hosting that are supported. When self hosting the entry point is a WCF service, and when hosting in ASP.NET the entry point is a HTTP handler. My concern was that wrapping each call to the API controller in an Autofac lifetime scope would require two completely different mechanisms. Perhaps a HTTP module style implementation and WCF extension similar to those found in the existing MVC and WCF integrations. It turns out this was not the case and if you are keen on learning about the details I will discuss them after we have seen some example code (because everyone wants to see some code sooner rather than later).

Example Code

If you are hosting within ASP.NET your Application_Start method would look something like this:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    BundleTable.Bundles.RegisterTemplateBundles();

    var configuration = GlobalConfiguration.Configuration;
    var builder = new ContainerBuilder();

    // Configure the container with the integration implementations.
    builder.ConfigureWebApi(configuration);

    // Register API controllers using assembly scanning.
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    // Register API controller dependencies per request.
    builder.Register<ILogger>(c => new Logger()).InstancePerApiRequest();

    var container = builder.Build();

    // Set the dependency resolver implementation.
    var resolver = new AutofacWebApiDependencyResolver(container);
    configuration.ServiceResolver.SetResolver(resolver);
}

In the case of self hosting your bootstrapping code would look like this instead:

var configuration = new HttpSelfHostConfiguration("http://localhost:8080");

configuration.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new {id = RouteParameter.Optional}
    );

var builder = new ContainerBuilder();

// Configure the container with the integration implementations.
builder.ConfigureWebApi(configuration);

// Register API controllers using assembly scanning.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// Register API controller dependencies per request.
builder.Register<ILogger>(c => new Logger()).InstancePerApiRequest();

var container = builder.Build();

// Set the dependency resolver implementation.
var resolver = new AutofacWebApiDependencyResolver(container);
configuration.ServiceResolver.SetResolver(resolver);

// Open the HTTP server and listen for requests.
using (var server = new HttpSelfHostServer(configuration))
{
    server.OpenAsync().Wait();

    Console.WriteLine("Hosting at http://localhost:8080/{controller}");
    Console.ReadLine();
}

First we are keeping a hold of the HttpConfiguration instance so that it can be provided to the ConfigureWebApi extension method on the ContainerBuilder. This is a HttpConfiguration instance when hosting in ASP.NET and a HttpSelfHostConfiguration instance when self hosting.

Next the RegisterApiControllers extension method on the ContainerBuilder is used to perform assembly scanning, looking for types that derive from IHttpController and have names with a suffix of “Controller”. This is very similar to how the MVC integration registers controllers using assembly scanning.

The InstancePerApiRequest method applied to the ILogger registration will cause it to be resolved once per API controller invocation. After the call completes it will be disposed automatically along with the API controller instance.

To avoid naming conflicts with the MVC integration the IDependencyResolver implementation has been named AutofacWebApiDependencyResolver. You provide it with the constructed container instance and then set it as the service resolver through the SetResolver method on the ServiceResolver property of the HttpConfiguration instance.

You will notice that the steps required to configure the integration are the same for both hosting scenarios. The only real difference is that the type of the HttpConfiguration instance changes depending on the hosting mode.

To register a service for lifetime scoping with both MVC controllers and Web API controllers you can apply both the InstancePerHttpRequest and InstancePerApiRequest lifetime scopes to the registration:

// Register MVC controller and API controller dependencies per request.
builder.Register(c => new Logger()).As<ILogger>()
    .InstancePerHttpRequest()
    .InstancePerApiRequest();

Implementation Details

Because of the two different hosting mechanisms a new way to manage lifetime scopes needed to found. The approach in the MVC and WCF integrations are completely different and I didn’t want both ways to be present in the Web API integration. The IHttpControllerFactory interface provided the required abstraction, though not in a perfect way.

public interface IHttpControllerFactory
{
    // Methods
    IHttpController CreateController(HttpControllerContext controllerContext, string controllerName);
    void ReleaseController(IHttpController controller);
}

This service is resolved from the dependency resolver if present, and is called by the HttpControllerDispatcher regardless of the hosting mode. The DefaultHttpControllerFactory that ships out-of-the-box handles a number of duties such as building and caching the HttpControllerDescriptor, along with various bits of exception handling. Implementing all of that did not sound like fun so I made the AutofacControllerFactory derive from the default implementation.

public class AutofacControllerFactory : DefaultHttpControllerFactory
{
    readonly ILifetimeScope _container;
    readonly ConcurrentDictionary<IHttpController, ILifetimeScope> _controllers = new ConcurrentDictionary<IHttpController, ILifetimeScope>();

    internal static readonly string ApiRequestTag = "AutofacWebRequest";

    public AutofacControllerFactory(HttpConfiguration configuration, ILifetimeScope container) : base(configuration)
    {
        if (container == null) throw new ArgumentNullException("container");
        _container = container;
    }

    public override IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
    {
        var lifetimeScope = _container.BeginLifetimeScope(ApiRequestTag);
        controllerContext.Request.Properties.Add(ApiRequestTag, lifetimeScope);

        try
        {
            var controller = base.CreateController(controllerContext, controllerName);
            if (controller != null)
                _controllers.TryAdd(controller, lifetimeScope);

            return controller;
        }
        catch (Exception)
        {
            lifetimeScope.Dispose();
            throw;
        }
    }

    public override void ReleaseController(IHttpController controller)
    {
        ILifetimeScope lifetimeScope;
        if (controller != null && _controllers.TryRemove(controller, out lifetimeScope))
            if (lifetimeScope != null)
                lifetimeScope.Dispose();
    }
}

The AutofacControllerFactory has the current ILifetimeScope injected which happens to be the root lifetime scope at the point when it is created. This will be used to create nested lifetime scopes for each controller request. When Web API asks for a controller using the CreateController method a new lifetime scope is created based on a tag that is used during the container registration process. The same tag is used in the MVC 4 integration to allow services to be registered per MVC controller and per Web API controller. The new lifetime scope is then poked into a property on the HttpRequestMessage that is accessible from the provided HttpControllerContext. It may seem a little strange at first but the creation of the controller is being delegated to the base class, which in turn looks for an IHttpControllerActivator instance in the dependency resolver, and if located will use that to create the actual controller instance. As you have properly guessed already there is an Autofac implementation of the IHttpControllerActivator that will retrieve the lifetime scope from that property and use it to create the controller instance and its dependencies in the correct lifetime scope.

public class AutofacControllerActivator : IHttpControllerActivator
{
    public IHttpController Create(HttpControllerContext controllerContext, Type controllerType)
    {
        var requestProperties = controllerContext.Request.Properties;

        if (!requestProperties.ContainsKey(AutofacControllerFactory.ApiRequestTag))
            throw GetInvalidOperationException();

        ILifetimeScope lifetimeScope = requestProperties[AutofacControllerFactory.ApiRequestTag] as ILifetimeScope;
        if (lifetimeScope == null)
            throw GetInvalidOperationException();

        return lifetimeScope.ResolveOptional(controllerType) as IHttpController;
    }

    internal static InvalidOperationException GetInvalidOperationException()
    {
        return new InvalidOperationException(
            string.Format(AutofacControllerActivatorResources.LifetimeScopeMissing,
                typeof(ILifetimeScope).FullName, typeof(HttpRequestMessage).FullName, typeof(AutofacControllerFactory).FullName));
    }
}

AutofacControllerActivator expects that if it is present in the dependency resolver, then the Autofac controller factory should be as well, and should have put the lifetime scope into the property on the HttpRequestMessage. It also expects that if the property is present that it should contain an ILifetimeScope that it can use to attempt to resolve the controller. If the controller is not found in the lifetime scope a null reference is returned and that will cause an exception to be thrown in the DefaultHttpControllerFactory when the null is assigned to the Controller property of the HttpControllerContext. Looking at the code in the current implementation of the HttpControllerDispatcher it seems that it actually expects a null being returned from the factory as a possibility even though it seems like this cannot happen.

IHttpController httpController = this._controllerFactory.CreateController(controllerContext, str);
if (httpController == null)
{
    return TaskHelpers.FromResult<HttpResponseMessage>(request.CreateResponse(HttpStatusCode.NotFound));
}

Regardless, back in the AutofacControllerFactory any exceptions are caught to ensure that the lifetime scope can be disposed immediately before re-throwing the exception. The lifetime scope is placed into a ConcurrentDictionary using the controller instance as the key, so that it can be disposed when the ReleaseController method is called after the request is complete. Unfortunately, nothing else is passed to this method so the dictionary was required to tie the controller being released back to a lifetime scope. It would be great if more context was provided between these calls so that lifetime scope could be more easily managed.

The IDependencyResolver implementation is very basic and has been named AutofacWebApiDependencyResolver to avoid naming conflicts with the existing MVC implementation. In the Web API integration it works with the root container most of the time instead of looking for a current lifetime scope. Taking the approach of always looking for an ambient lifetime scope provided to be too difficult with the dual hosting model. I don’t think this will be a problem as outside of the lifetime scope for the API controller, it appears that most services are expected to be singleton or new instances on each call.

public class AutofacWebApiDependencyResolver : IDependencyResolver
{
    readonly ILifetimeScope _container;

    public AutofacWebApiDependencyResolver(ILifetimeScope container)
    {
        if (container == null) throw new ArgumentNullException("container");
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        return _container.ResolveOptional(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        var enumerableServiceType = typeof(IEnumerable<>).MakeGenericType(serviceType);
        var instance = _container.Resolve(enumerableServiceType);
        return (IEnumerable<object>)instance;
    }
}

The registration extensions are also straight forward. ConfigureWebApi registers the HttpConfiguration instance making available to other services, and ensures that the Autofac controller factory and activator are registered too. Obviously, not much is going to happen if this method is not called before building your container.

public static void ConfigureWebApi(this ContainerBuilder builder, HttpConfiguration configuration)
{
    builder.RegisterInstance(configuration);
    builder.Register<IHttpControllerActivator>(c => new AutofacControllerActivator())
        .SingleInstance();
    builder.Register<IHttpControllerFactory>(c => new AutofacControllerFactory(c.Resolve<HttpConfiguration>(), c.Resolve<ILifetimeScope>()))
        .SingleInstance();
}

Scanning for controllers is implemented similar to the MVC integration except we are looking for IHttpController derived types instead.

public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle>
    RegisterApiControllers(this ContainerBuilder builder, params Assembly[] controllerAssemblies)
{
    return builder.RegisterAssemblyTypes(controllerAssemblies)
        .Where(t => typeof(IHttpController).IsAssignableFrom(t) && t.Name.EndsWith("Controller"));
}

Finally, and once again similar to the MVC InstancePerHttpRequest method, the InstancePerApiRequest method applies the predetermined tag to the registration so that it can be resolved within the API controller lifetime scope.

public static IRegistrationBuilder<TLimit, TActivatorData, TStyle>
    InstancePerApiRequest<TLimit, TActivatorData, TStyle>(
        this IRegistrationBuilder<TLimit, TActivatorData, TStyle> registration)
{
    if (registration == null) throw new ArgumentNullException("registration");

    return registration.InstancePerMatchingLifetimeScope(AutofacControllerFactory.ApiRequestTag);
}

That pretty much covers it. Please download the package and report any bugs on the issue tracker or if you need help post your questions on Stack Overflow using the “autofac” tag. It will be interesting to see how much things change between this Beta and the final RTW. Happing API building!

Tags:

Autofac

Autofac ASP.NET MVC 4 (Beta) Integration

by Alex Meyer-Gleaves 9 March 2012 - 1:20 AM

Following the release of Autofac 2.6.1, the Autofac MVC 4 Beta integration is now ready for downloading via NuGet. I will look into what additional features might be possible later, but the immediate priority was to make something available ensuring people could starting enjoying Autofac with MVC 4 Beta. This work is currently being done in a branch and will be merged back into the mainline once the final RTW of MVC 4 is made available.

Install-Package Autofac.Mvc4

There are no breaking changes in the API between this and the MVC 3 version of the integration so the upgrade should be fairly painless. Detailed instructions for upgrading your actual MVC 3 project can be found in the MVC 4 release notes.

Please download the package and report any bugs on the issue tracker or if you need help post your questions on Stack Overflow using the “autofac” tag. The current MVC 3 documentation on the wiki still applies and can help you get up and running if your new to the integration.

A minor change was made in the internals to allow the lifetime scope applied to a registration to be shared between MVC and the Web API (which you have no doubt now deduced is on the way too).

// Register MVC controller and API controller dependencies per request.
builder.Register(c => new Logger()).As<ILogger>()
    .InstancePerHttpRequest()
    .InstancePerApiRequest();

Technically both extension methods use the same tag for the nested lifetime scope so only one is really needed, but I like adding both because makes it obvious that the service will be scoped to the controller, regardless of it being of the MVC or Web API variety. I don’t think there is too much more to add other than to watch out for the Web API integration which will probably be available by the time you read this.

Tags:

Autofac

FilterAttribute Property Injection in Autofac MVC 3 Integration

by Alex Meyer-Gleaves 24 March 2011 - 8:56 PM

The current mechanism for performing property injection on FilterAttribute instances via the ExtensibleActionInvoker had to be removed recently due to a rather nasty bug. These are the notes that Nick provided outlining the problem he discovered (possibly with the help of the exciting new Whitebox profiler).

Because the filters passed from the base action invoker also include the controller, property injection happens on the controller itself several times as the filters are processed.

The filter attributes also included in the collection may also be singletons cached by MVC, and so it is quite likely that dependencies may be overwritten with those from a concurrently executing request.

In all this behaviour is probably too risky to reliably support.

Removed property injection routine. (Breaking change.)

I have replaced the old mechanism using an approach that leverages the improved dependency injection support added to MVC 3 (this will be in the next release). To make use of property injection for your filter attributes all you will need to do is call the RegisterFilterProvider method on the ContainerBuilder before building your container and providing it to the AutofacDependencyResolver.

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.Register(c => new Logger()).As<ILogger>().InstancePerHttpRequest();
builder.RegisterFilterProvider();

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Then you can add properties to your filter attributes and any matching dependencies that are registered in the container will be injected into the properties. For example, the action filter below will have the ILogger instance that was registered above injected. Note that the attribute itself does not need to be registered in the container.

public class CustomActionFilter : ActionFilterAttribute
{
    public ILogger Logger { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Logger.Log("OnActionExecuting");
    }
}

The same simple approach applies to the other filter attribute types such as authorization attributes.

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public ILogger Logger { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        Logger.Log("AuthorizeCore");
        return true;
    }
}

After applying the attributes to your actions as required your work is done.

[CustomActionFilter]
[CustomAuthorizeAttribute]
public ActionResult Index()
{
    // ...
}

To make this work I added a custom FilterAttributeFilterProvider implementation. The custom filter provider delegates the job of collecting the filters to the base class. Once the filters have been retrieved by the base class, the ILifetimeScope for the current HTTP request is retrieved and used to perform property injection on the filters. The false passed to the base FilterAttributeProvider constructor sets the cacheAttributeInstances parameter to ensure that attribute instances are not cached. Allowing the attribute instances to be cached would result in race conditions and other unexpected behaviour.

/// <summary>
/// Defines a filter provider for filter attributes that performs property injection.
/// </summary>
public class AutofacFilterAttributeFilterProvider : FilterAttributeFilterProvider
{
    /// <summary>
    /// Initializes a new instance of the <see cref="AutofacFilterAttributeFilterProvider"/> class.
    /// </summary>
    /// <remarks>
    /// The <c>false</c> constructor parameter passed to base here ensures that attribute instances are not cached.
    /// </remarks>
    public AutofacFilterAttributeFilterProvider() : base(false)
    {
    }

    /// <summary>
    /// Aggregates the filters from all of the filter providers into one collection.
    /// </summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="actionDescriptor">The action descriptor.</param>
    /// <returns>
    /// The collection filters from all of the filter providers with properties injected.
    /// </returns>
    public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(controllerContext, actionDescriptor).ToArray();
        var lifetimeScope = AutofacDependencyResolver.Current.RequestLifetimeScope;

        if (lifetimeScope != null)
            foreach (var filter in filters)
                lifetimeScope.InjectProperties(filter.Instance);

        return filters;
    }
}

The RegisterFilterProvider method has been added to the ContainerBuilder using an extension method. This method will register the AutofacFilterAttributeFilterProvider using the IFilterProvider interface that MVC uses when asking the dependency resolver for filter providers. Following the instructions outlined in Brad Wilson’s post on the subject of dependency injection and filters, I made sure that the default FilterAttributeFilterProvider instance is removed from the static collection of providers.

/// <summary>
/// Registers the <see cref="AutofacFilterAttributeFilterProvider"/>.
/// </summary>
/// <param name="builder">The container builder.</param>
public static void RegisterFilterProvider(this ContainerBuilder builder)
{
    if (builder == null) throw new ArgumentNullException("builder");

    foreach (var provider in FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().ToArray())
        FilterProviders.Providers.Remove(provider);

    builder.RegisterType<AutofacFilterAttributeFilterProvider>()
        .As<IFilterProvider>()
        .SingleInstance();
}

If you were using the old mechanism you will have breaking changes to contend with, but as you can see it should be easy to get back on track again.

Tags: ,

Autofac | Web Development

About the author

Alex Meyer-Gleaves I'm a Technical Architect living in Australia (that island like continent in the southern hemisphere). I love Microsoft .NET and C#. I hate early mornings, slow drivers and Lotus Notes.

Twitter

Google Shared

 

Month List

Recent Comments

Comment RSS

Links

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010