unity breaks sporadically saying "does not have an accessible constructor"

Mar 13, 2014 at 9:52 AM
Edited Mar 13, 2014 at 9:54 AM
This is a continuation of this thread. It's been nearly a year and we haven't still come across a solution.

I'll describe the problem from scratch.

We have an asp.net-mvc4 application, which is composed of about 20-30 projects. We use unity at the asp.net-mvc project to resolve various classes.

One little quirk is, we want to automatically inject in a "correlation" object into all objects coming from unity. This correlation has information about the current user and what not.

Things look something like this:
    public class MyContainer : UnityContainer
    {
        public MyContainer(ICorrelationInfo corInfo)
        {
            this.CorrelationInfo = corInfo;
            this.RegisterInstance<ICorrelationInfo>(CORRELATION_STRING, corInfo);
            this.AddNewExtension<Interception>();
            this.RegisterType(typeof(ICallHandler), typeof(LogCallHandler), "MyCallHandler", new InjectionConstructor(corInfo));
            this.RegisterType(typeof(IMatchingRule), typeof(AnyMatchingRule), "AnyMatchingRule");
        }
        public ICorrelationInfo CorrelationInfo { get; private set; }

        public void SetupForInteception(Type t)
        {
            this.Configure<Interception>()
            .SetInterceptorFor(t, new InterfaceInterceptor())
            .AddPolicy("LoggingPolicy")
            .AddMatchingRule(new AnyMatchingRule())
            .AddCallHandler(new LogCallHandler(this.CorrelationInfo));
        }
    }
Now! inside the Global.asax.cs in our asp.net-mvc4 application :
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            TearDownDIContainer();
            ICorrelationInfo c = ... /* this is obtained somehow */
            MyContainer _container = new MyContainer(c);
            // REGISTRATION HAPPENS HERE
            // all the types we need are registered here like this:
            // Register<From, To> 
            //We call SetupForInteception(..) on certain types

            //this will setup our container for API controllers.
            GlobalConfiguration.Configuration.DependencyResolver =  new MyDependencyResolver(_container);
         }
        protected void Application_EndRequest(object sender, EventArgs e)
        {
             TearDownDIContainer();
         }
         private void TearDownDIContainer()
         {
            if (_container != null)
            {
                _container.Dispose();
                _container = null;
            }
          }
    }
Each controller in our asp.net-mvc application has a number of classes it declares in it's constructor like this:
public class AccountController : ApiController
{
    IUserManager _userMgr;
    IPolicySecurityManager _policySecurityManager;
    ILockManager _lockMgr;
    ISessionManager _sessionMgr;
    ICacheClient _cacheClient;
    ICleanupManager _cleanupMgr;

    public AccountController([Dependency(MyContainer.CORRELATION_STRING)]ICorrelationInfo corel, IUserManager userMgr, IPolicySecurityManager passSecMgr, ILockManager lockMgr, ISessionManager sessionMgr, ICacheClient cacheClient, ICleanupManager cleanupMgr)
    {
        _userMgr = userMgr;
        _policySecurityManager = passSecMgr;
        _lockMgr = lockMgr;
        _cacheClient = cacheClient;
        _sessionMgr = sessionMgr;
        _cleanupMgr = cleanupMgr;
        correlationInfo = corel;
    }
90% of the time all works well, and randomly all over the place we get this 1/10 times:

The exception log is big because somewhere deep in the hierarchy ICallHandler, or ICorrelationInfo or InjectionPolicy-> (which isn't OUR class!) fails to resolve!

Here is one case:
https://dl.dropboxusercontent.com/u/51373/unity_error_log1.txt

Here is another:
https://dl.dropboxusercontent.com/u/51373/unity_error_log2.txt

The exception is generally the same, it's just that the resolution fails randomly on different areas in the system and then the call stack looks a little different. Another thing to note is it is always ICallHandler, ICorrelationInfo or one of the unity policy classes that fail to resolve, it's NEVER one of our business layer classes!

Any clues and help will be greatly appreciated.
Mar 14, 2014 at 9:18 AM
Thanks for posting a detailed question.

It looks like you are hitting a timing issue because of how the container and resolver are being set up and used.

If you are using MVC 4 and Unity 3 then I would recommend looking at Unity bootstrapper for ASP.NET Web API. If the approach doesn't suit you 100% then you could look at the source to see the approach taken. Also Dependency Injection for Web API Controllers is a good article.

Some comments about the code:
  • In MvcApplication there is a local variable called _container but in TearDownDIContainer it seems to treat _container as an instance variable
  • Creating a new container for every request is expensive so you probably don't want to do that
  • Usually GlobalConfiguration.Configuration.DependencyResolver is set at application startup. Changing the global resolver could cause issues while requests are being served.
Here is how I would go about performing per request injection with Web API:
  • I would use the Unity bootstrapper for ASP.NET Web API.
  • I would switch to use the UnityHierarchicalDependencyResolver.
  • I would register all my types up front. For the correlation object I would use HierarchicalLifetimeManager (so that it would be a singleton per request).
  • I would create a custom IHttpControllerActivator that resolves the correlation object (from the correct scope) and sets all the applicable properties for the request and then resolves the controller.
Here's some code snippets:
    /// <summary>
    /// Specifies the Unity configuration for the main container.
    /// </summary>
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// <summary>
        /// Gets the configured Unity container.
        /// </summary>
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        /// <summary>Registers the type mappings with the Unity container.</summary>
        /// <param name="container">The unity container to configure.</param>
        /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to 
        /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
        public static void RegisterTypes(IUnityContainer container)
        {
            // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
            // container.LoadConfiguration();

            // TODO: Register your types here
            // container.RegisterType<IProductRepository, ProductRepository>();
            container.RegisterType<MyObject>(new HierarchicalLifetimeManager());
        }
    }

    /// <summary>Provides the bootstrapping for integrating Unity with WebApi when it is hosted in ASP.NET</summary>
    public static class UnityWebApiActivator
    {
        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start() 
        {
            // Use UnityHierarchicalDependencyResolver if you want to use a new child container for each IHttpController resolution.
            var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());
            //var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());

            GlobalConfiguration.Configuration.DependencyResolver = resolver;

            GlobalConfiguration.Configuration.Services.Replace(
                typeof(IHttpControllerActivator),
                new MyControllerActivator(GlobalConfiguration.Configuration.Services.GetHttpControllerActivator()));
        }
    }

    public class MyControllerActivator : IHttpControllerActivator
    {
        private IHttpControllerActivator defaultHttpControllerActivator;

        public MyControllerActivator(IHttpControllerActivator defaultHttpControllerActivator)
        {
            this.defaultHttpControllerActivator = defaultHttpControllerActivator;
        }

        public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
        {
            IDependencyScope scope = request.GetDependencyScope();

            var myObj = scope.GetService(typeof(MyObject)) as MyObject;
            myObj.ID = "userid"; // set per request properties

            return this.defaultHttpControllerActivator.Create(request, controllerDescriptor, controllerType);
        }
    }

In the above example MyObject is equivalent to ICorrelationInfo.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to