I have an ASP.NET MVC which initializes Simple Injector in the Application_Start method.
The error appears intermittently during normal use of the site locally, and always disappears when the site is rebuilt in Visual Studio. On deployment, the error appears immediately but can be made to go away by restarting the app on the server. After a little while it reappears.
The start up code is as follows:
public class CmsApplication : System.Web.HttpApplication
{
private Container _container;
private IQueryProcessor queryProcessor;
private static ISiteManager _manager;
public static ISiteManager SiteManager { get { return _manager; } }
protected virtual void Application_Start()
{
// Mapping using AutoMapper
CMS.UI.Client.Mapping.MappingConfig.RegisterMappings();
// Initialize SimpleInjector
InitializeIoC();
AutoMapper.Mapper.AssertConfigurationIsValid();
// Get query processor - this is used for handling database calls.
queryProcessor = _container.GetInstance<IQueryProcessor>();
// Get configuration
IConfiguration configuration = CMS.Configuration.ConfigurationFactory.Get();
// MVC Stuff
AreaRegistration.RegisterAllAreas();
RouteConfig routeConfig = new RouteConfig(queryProcessor);
routeConfig.RegisterRoutes(RouteTable.Routes);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// Regular MVC startup
AreaRegistration.RegisterAllAreas();
// Global SiteManager property. THIS COULD BE CAUSING THE ISSUE!
_manager = _container.GetInstance<ISiteManager>();
}
/// <summary>
/// Method to initialize the IoC Container
/// </summary>
protected void InitializeIoC()
{
// Initialize DI container
_container = new Container();
// Allows container to inject into filter constructors
_container.RegisterMvcIntegratedFilterProvider();
// Mapping
_container.Register<AutoMapper.IMappingEngine>(() => (AutoMapper.IMappingEngine)AutoMapper.Mapper.Engine, Lifestyle.Singleton);
_container.Register<IMapProcessor, MapProcessor>(); // Map Processor
// Configuration
_container.Register<IConfiguration>(() => (CMS.Configuration.Configuration)System.Configuration.ConfigurationManager.GetSection("pipeline"), Lifestyle.Singleton);
// Site Manager
_container.Register<ISiteManager, SiteManager>(Lifestyle.Singleton);
// Context and UnitOfWork Factories
_container.RegisterPerWebRequest<IContext>(() => new CrmContext("Name=CrmContext"));
// Context and UnitOfWork
_container.RegisterPerWebRequest<Pipeline.Core.Data.UnitOfWork.IUnitOfWork, Crm.UnitOfWork.EFUnitOfWork>();
// Repositories
_container.Register<ISiteRepository, SiteRepository>();
_container.Register<IFolderRepository, FolderRepository>();
// Sitemap
_container.Register<ISitemapGenerator, SitemapGenerator>();
// Robots
_container.Register<IRobotsGenerator, RobotsGenerator>();
// Command Handlers
_container.RegisterOpenGeneric(
typeof(IBatchCommandHandler<>), typeof(BatchCommandHandler<>));
_container.RegisterManyForOpenGeneric(
typeof(ICommandHandler<>),
AppDomain.CurrentDomain.GetAssemblies());
_container.RegisterManyForOpenGeneric(
typeof(ICommandHandler<,>),
AppDomain.CurrentDomain.GetAssemblies());
// Validators
_container.RegisterManyForOpenGeneric(
typeof(IValidator<>),
AppDomain.CurrentDomain.GetAssemblies());
// Query Handlers
_container.RegisterManyForOpenGeneric(
typeof(IQueryHandler<,>),
AppDomain.CurrentDomain.GetAssemblies());
// Query Processor
_container.Register<IQueryProcessor>(() => new QueryProcessor(_container));
// Validation Decorators
_container.RegisterDecorator(typeof(ICommandHandler<,>),
typeof(ValidationCommandHandlerDecorator<,>),
c => typeof(ICommandHandler<,>)
.MakeGenericType(c.ServiceType.GetGenericArguments())
.IsAssignableFrom(c.ImplementationType));
// Verify the container
_container.Verify();
//// Register the container as MVC IDependencyResolver
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(_container));
}
The InitializeIoC
method is just registration of the various types and nothing special.
After the InitializeIoC
method, the RouteConfig
call uses a database call using a type resolved through SimpleInjector. This appears to be fine.
The error seems to be being thrown when the _manager field is set as the resolved type uses IQueryHandler<SiteQuery, ISiteInfo>
which is the source of the error. The ISiteManager is being set as a singleton by SimpleInjector, whether this is the source of the problem, I'm not sure.
The concrete handler is definitely present (as it does actually work, the bug is intermittent).
I'm a bit stumped on this!
Here is the error and stack trace:
Error Page
No registration for type IQueryHandler could be found. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: SimpleInjector.ActivationException: No registration for type IQueryHandler could be found.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[ActivationException: No registration for type IQueryHandler could be found.]
SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType) +136 SimpleInjector.Container.GetInstance(Type serviceType) +76
Pipeline.Crm.Services.QueryProcessor.QueryProcessor.Pipeline.Core.Services.Queries.Interfaces.IQueryProcessor.Process(IQuery query) in c:\Projects\Pipeline CMS\Pipeline.CMS.Services\QueryProcessor\QueryProcessor.cs:29
Pipeline.CMS.UI.Client.Management.SiteManager..ctor(IQueryProcessor queryProcessor, IConfiguration configuration) in c:\Projects\Pipeline CMS\Pipeline.CMS.UI.Client\SiteManager\SiteManager.cs:23
lambda_method(Closure ) +148
SimpleInjector.Lifestyles.SingletonLifestyleRegistrationBase1.CreateInstanceWithNullCheck() +62 System.Lazy
1.CreateValue() +415 System.Lazy1.LazyInitValue() +152 System.Lazy
1.get_Value() +75
SimpleInjector.Lifestyles.SingletonLifestyleRegistrationBase1.BuildExpression() +16 SimpleInjector.Registration.BuildExpression(InstanceProducer producer) +50
1.CreateValue() +415 System.Lazy
SimpleInjector.InstanceProducer.BuildExpressionInternal() +34
System.Lazy1.LazyInitValue() +152 System.Lazy
1.get_Value() +75
SimpleInjector.InstanceProducer.BuildExpression() +55[ActivationException: The registered delegate for type ISiteManager threw an exception. No registration for type IQueryHandler could be found.]
SimpleInjector.InstanceProducer.BuildExpression() +97
SimpleInjector.InstanceProducer.VerifyExpressionBuilding() +31[InvalidOperationException: The configuration is invalid. Creating the instance for type ISiteManager failed. The registered delegate for type ISiteManager threw an exception. No registration for type IQueryHandler could be found.]
SimpleInjector.InstanceProducer.VerifyExpressionBuilding() +85
SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt(InstanceProducer[] producersToVerify) +28
SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt() +127
SimpleInjector.Container.Verify() +109
Pipeline.CMS.UI.Client.CmsApplication.InitializeIoC() in c:\Projects\Pipeline CMS\Pipeline.CMS.UI.Client\CmsApplication.cs:156 Pipeline.CMS.UI.Client.CmsApplication.Application_Start() in c:\Projects\Pipeline CMS\Pipeline.CMS.UI.Client\CmsApplication.cs:47
Pipeline.CMS.Client.MvcApplication.Application_Start() in c:\Projects\Pipeline CMS\Banerjee.Web\Global.asax.cs:11[HttpException (0x80004005): The configuration is invalid. Creating the instance for type ISiteManager failed. The registered delegate for type ISiteManager threw an exception. No registration for type IQueryHandler could be found.]
System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +9936825
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +118
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +336
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +296[HttpException (0x80004005): The configuration is invalid. Creating the instance for type ISiteManager failed. The registered delegate for type ISiteManager threw an exception. No registration for type IQueryHandler could be found.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9915364 System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +101 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +254
My first intuition is that the assembly that contains the query handler implementations isn't loaded yet at the time that AppDomain.CurrentDomain.GetAssemblies()
is called during the registration process. Your query handler implementations probably live in a different assembly than the IQueryHandler<,>
interface does. Loading of assemblies can be a bit undeterministic in ASP.NET.
Instead of calling AppDomain.CurrentDomain.GetAssemblies()
, try specifying the assemblies directly as follows:
var assemblies = new[]
{
typeof(SomeQueryHandlerImplementation).Assembly,
typeof(SqlRepository<>).Assembly,
};
// Simple Injector v3.x
_container.Register(typeof(ICommandHandler<>), assemblies);
_container.Register(typeof(ICommandHandler<,>), assemblies);
_container.Register(typeof(IValidator<>), assemblies);
_container.Register(typeof(IQueryHandler<,>), assemblies);
// Simple Injector v2.x
_container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>), assemblies);
_container.RegisterManyForOpenGeneric(typeof(ICommandHandler<,>), assemblies);
_container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);
_container.RegisterManyForOpenGeneric(typeof(IQueryHandler<,>), assemblies);
One small note about the registration of the ValidationCommandHandlerDecorator
decorator. The registered predicate always returns true. The registration can therefore be simplified to the following:
_container.RegisterDecorator(typeof(ICommandHandler<,>),
typeof(ValidationCommandHandlerDecorator<,>));