No registration for type ViewPage<TModel> could be found.

Sep 22, 2014 at 7:49 PM
Following the guide outlined here, I get this as soon as I call VerifyPages. What am I missing?
Coordinator
Sep 22, 2014 at 8:08 PM
Hi @mrchief, please would you add the whole exception / stack trace?
Coordinator
Sep 22, 2014 at 10:47 PM
Hi mrchief, you have to supply us with more information about your problem. For instance, what is this ViewPage<TModel>, how do other types depend on it, and why didn't you register it in the container?

From the exception message I would even say that you are trying to resolve an open generic type directly from the container. Is the exception perhaps thrown from a line of code that looks like this?:
container.GetInstance(typeof(ViewPage<>));
If that's the case, please don't forget that it's the container's task to create object graphs of instances for you, but it is technically impossible to create an open-generic type at runtime. All generic arguments need to be filled in for anyone to be able to create an instance of a type. So you should at least do something as follows:
container.GetInstance(typeof(ViewPage<MyCustomType>));
But where possible, try to inject instances into constructors (or if not possible into properties), instead of calling the container directly to resolve types (service locator). This often gives the best results.
Marked as answer by dot_NET_Junkie on 9/28/2014 at 4:02 AM
Oct 1, 2014 at 8:28 PM
Edited Oct 1, 2014 at 8:29 PM
Sorry for the delay:


Here's the stack trace
Server Error in '/' Application.

No registration for type ViewPage<TModel> 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 ViewPage<TModel> could be found.

Source Error:


Line 53: foreach (Type pageType in pageTypes)
Line 54: {
Line 55: container.GetInstance(pageType);
Line 56: }
Line 57: }

Source File: d:\src\poc\MyApp\App_Start\SimpleInjectorWebFormsInitializer.cs Line: 55

Stack Trace:


[ActivationException: No registration for type ViewPage<TModel> could be found.]
SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType) +66
SimpleInjector.Container.GetInstance(Type serviceType) +76
MyApp.App_Start.SimpleInjectorWebFormsInitializer.VerifyPages(Container container) in d:\src\poc\MyApp\App_Start\SimpleInjectorWebFormsInitializer.cs:55
MyApp.App_Start.SimpleInjectorWebFormsInitializer.Bootstrap() in d:\src\poc\MyApp\App_Start\SimpleInjectorWebFormsInitializer.cs:34
MyApp.MvcApplication.Application_Start() in d:\src\poc\MyApp\Global.asax.cs:40

[HttpException (0x80004005): No registration for type ViewPage<TModel> could be found.]
System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +9936761
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): No registration for type ViewPage<TModel> could be found.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9915300
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +101
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +254

Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18446
SimpleInjectorWebFormsInitializer.cs
    public class SimpleInjectorWebFormsInitializer
    {
        public static Container Bootstrap()
        {
            // 1. Create a new Simple Injector container.
            var container = new Container();

            // Registere a custom PropertySelectionBehavior to enable property injection.
            container.Options.PropertySelectionBehavior =
                new ImportAttributePropertySelectionBehavior();

            // 2. Configure the container (register)
            container.RegisterPerWebRequest<MyAppContext, MyAppContext>();

            // 3. Store the container for use by Page classes.
            //applicationContainer = container;

            // 4. Optionally verify the container's configuration.
            //    Did you know the container can diagnose your configuration? 
            //    For more information, go to: https://bit.ly/YE8OJj.
            container.Verify();
            VerifyPages(container);

            return container;
        }

        // This method tests if each Page class can be created. Because Page classes 
        // manually call Global.Initialize in their ctor, we want to test on application 
        // startup if all pages can be initialized, to prevent having to go through 
        // each page in the application during testing.
        private static void VerifyPages(Container container)
        {
            var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();

            var pageTypes =
                from assembly in assemblies
                from type in assembly.GetExportedTypes()
                where typeof(Page).IsAssignableFrom(type) && !type.IsAbstract
                select type;

            foreach (Type pageType in pageTypes)
            {
                container.GetInstance(pageType);
            }
        }

        private class ImportAttributePropertySelectionBehavior : IPropertySelectionBehavior
        {
            public bool SelectProperty(Type serviceType, PropertyInfo propertyInfo)
            {
                // Makes use of the System.ComponentModel.Composition assembly
                return typeof(Page).IsAssignableFrom(serviceType) &&
                    propertyInfo.GetCustomAttributes<ImportAttribute>().Any();
            }
        }
    }
Global.asax.cs
        private static Container container;

        // for webforms
        public static void Initialize(Page page)
        {
            container.GetRegistration(page.GetType().BaseType, true).Registration
                .InitializeInstance(page);
        }

        protected void Application_Start()
        {
            // MVC stuff

            container = SimpleInjectorWebFormsInitializer.Bootstrap();      
        }
As you can see, I'm using the Webforms integration code verbatim. I moved it to a separate file to de-clutter Global.asax but moving them to global also results in same error.

MyAppContext is the only thing I'm injecting.

Let me know if you have any other questions.
Coordinator
Oct 1, 2014 at 8:32 PM
You seem to have a generic Page (base?) calss called ViewPage<TModel> and the VerifyPages method found it and tries to resolve it. You should suppress the loading of generic types. You can change the LINQ query of the VerifyPages method to the following:
            var pageTypes =
                from assembly in assemblies
                from type in assembly.GetExportedTypes()
                where typeof(Page).IsAssignableFrom(type) && !type.IsAbstract
                where !type.IsGenericType
                select type;
That should do the trick.


Cheers
Oct 1, 2014 at 9:37 PM
That's the thing - I don't have any such type. So I debugged the call and its seems that that is actually System.Web.Mvc.ViewPage1, System.Web.Mvc, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35`. I have MVC in this project also.

Adding your fix produces a different error:
Server Error in '/' Application.

Object reference not set to an instance of an object.

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: System.NullReferenceException: Object reference not set to an instance of an object.

Source Error: 


Line 17:        public static void Initialize(Page page)
Line 18:        {
Line 19:            container.GetRegistration(page.GetType().BaseType, true).Registration
Line 20:                .InitializeInstance(page);
Line 21:        }
Coordinator
Oct 1, 2014 at 9:50 PM
Well look at that. Who would have thought of that. There's a System.Web.Mvc.ViewPage<TModel> class and it derives from System.WebMvc.ViewPage. And ViewPage derives from System.Web.UI.Page. How funny is that.

Happily, filtering out the generic type solves the problem. Another thing you could do is filter the assemblies that are verified to the assemblies for your projects, or perhaps even just Assembly.GetExecutingAssembly().
Oct 1, 2014 at 10:13 PM
Both of them filter out the problem. But then, this lines throws error:
Exception Details: SimpleInjector.ActivationException: No registration for type BasePage could be found.

Source Error: 


Line 23:        public static void Initialize(Page page)
Line 24:        {
Line 25:            container.GetRegistration(page.GetType().BaseType, true).Registration
Line 26:                .InitializeInstance(page);
Line 27:        }
BasePage
public abstract class BasePage : Page
{
    public BasePage()
    {
        MvcApplication.Initialize(this);
    }
}
Coordinator
Oct 1, 2014 at 10:20 PM
That Initialize method you are using is specially crafted to work with the special derived types that ASP.NET generates. It derives from your class to add the mark up. That's why that method calls page.GetType().BaseType, because page.GetType() would usually be the type that is generated by ASP.NET and the base type is your own type.

During verification however, this is not the case, since there are no derived markup-pages. But if you remove the .BaseType part, it should be working just fine.
Oct 1, 2014 at 10:25 PM
Ok, bit confused there. How can I remove BaseType? It seems that I would need it during normal page execution but not during Verify. Or maybe check if Page type is BasePage, then use just the GetType():
public static void Initialize(Page page)
{
    var type = page is BasePage ? page.GetType() : page.GetType().BaseType;
        
    container.GetRegistration(type, true).Registration
        .InitializeInstance(page);
}
Coordinator
Oct 1, 2014 at 10:30 PM
I have to apologize here. The Web Forms integration guide clearly contains code that hasn't been tested thoroughly and this is my bad. You seem to be the first to notice, which indicates that most web form developer aren't doing much dependency injection.

Removing .BaseType should still work, since the derived class that is generated by ASP.NET has a public constructor and Simple Injector can build a registration for that. The only downside is that each page class gets registered twice in the container: once by its own type and once for the type that is generated by ASP.NET. But this should normally not cause any problems.
Oct 1, 2014 at 10:34 PM
That's Ok! I was wondering if I was missing something obvious. :)

Forget my previous code, that will not work since every derived type will pass the test. This works however:
public static void Initialize(Page page)
{
    var type = page.GetType().BaseType;

    if (type != typeof(BasePage))
    {
        container.GetRegistration(type, true).Registration
            .InitializeInstance(page);
    }
}
And by works, I mean the app goes past the initialization error. Not sure if this will cause issue downstream but I'll verify that tomorrow. Gotta leave now.

Thanks for your prompt responses.
Coordinator
Oct 1, 2014 at 10:41 PM
I think that your code now doesn't do any validation at all. I think you need something like this:
public static void Initialize(Page page)
{
    var type = page.GetType().BaseType == typeof(BasePage) ? page.GetType() : page.GetType().BaseType;

    container.GetRegistration(type, true).Registration.InitializeInstance(page);
}
Oct 2, 2014 at 2:35 PM
That is what I meant I suppose. Was in just too much of a hurry the first time. But I guess we're still not done talking:
The configuration is invalid. The type login is directly or indirectly depending on itself.

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: The configuration is invalid. The type login is directly or indirectly depending on itself.

Source Error:


Line 25: var type = page.GetType().BaseType == typeof(BasePage) ? page.GetType() : page.GetType().BaseType;
Line 26:
Line 27: container.GetRegistration(type, true).Registration
Line 28: .InitializeInstance(page);
Line 29: }
And login is defined as:
public partial class login : BasePage
{

    [Import]
    public MyAppContext DbContext { get; set; }
...
Coordinator
Oct 2, 2014 at 2:39 PM
What Simple Injector is saying is that there is a cyclic dependency in your code. So you are injecting login into itself or login depends on a type that again depends on login. These types can't be composed by Simple Injector (as you would not be able to construct this in plain C# if you would use constructor injection).
Oct 2, 2014 at 2:54 PM
As far as I can see, there is no such dependency. Is there way I can find out how?

I've searched (plain text search) and thru Resharper, there is no other Login class (other than the partial class declared in login.aspx.designer.cs.
Coordinator
Oct 2, 2014 at 3:01 PM
Take a good look at what you're injecting. What properties have this [Import] attribute. And go to their type definitions to see what dependencies they have. It's a bit unfortunate that Simple Injector can't show you the complete dependency chain here, but up until now, Simple Injector has never been wrong in detecting these cyclic dependencies.
Oct 2, 2014 at 3:32 PM
That's just it. I was the first one to setup DI in this legacy project. The only import is in the login page (the snippet I posted above). Now if there was a cyclic dependency, then SI wouldn't/shouldn't be able to inject or construct the types, right? But it can. The injected property (DbContext) just works fine. I can login, query DB which wouldn't be possible if it was failing to inject. VerifyPages seems to be the only issue here.

I'll keep fiddling with it and let you know if I find anything.
Oct 2, 2014 at 7:36 PM
Ok, I'm not sure if I understand this fully, but I had a hunch and this seems to confirm it. I finally got VerifyPages to work. I had to make few some changes though:

First, I get only pages that can be injected or rather need injection:
private static IEnumerable<Type> GetInjectablePageTypes()
{
    var assembly = Assembly.GetExecutingAssembly();

    var pageTypes =
        from type in assembly.GetExportedTypes()
        where typeof (BasePage).IsAssignableFrom(type) && !type.IsAbstract    // Get pages deriving from BasePage only
        select type;
    return pageTypes;
}
And then register the pages explicitly:
container.RegisterAll<BasePage>(GetInjectablePageTypes());
At this point, all seems good. Injected properties work too.

I changed VerifyPages to verify will only BasePage derived pages, but even without that, it seems fine.
private static void VerifyPages(Container container)
{
    var pageTypes = GetInjectablePageTypes();

    foreach (Type pageType in pageTypes)
    {
        container.GetInstance(pageType);
    }
}
At this point, I'm not sure if I'm missing something internal, so I thought of running this by you.
Coordinator
Oct 3, 2014 at 6:14 AM
So what you're saying is that the cyclic dependency error goes away if register your pages as collection?
Oct 3, 2014 at 6:17 AM
Yup! As long a I explicitly register, all is good. Filtering by BasePage is just an optimization (why go thru all non injected pages anyway).
Oct 3, 2014 at 6:18 AM
And not only as collection, even individual registration works (that is what I tried with initially).
Coordinator
Oct 3, 2014 at 9:36 AM
I've been able to reproduce the problem. It is probably caused by the call to Global.Initialize from within the base constructor. I will get back to you on this when I have a better solution.
Oct 15, 2014 at 9:23 PM
Is there a way to either get https://simpleinjector.codeplex.com/wikipage?title=Web%20Forms%20Integration&referringTitle=Integration%20Guide updated or mrcheif to post his working code? I have been getting the same error and can't seem to figure out where to register things. Thanks!
Coordinator
Oct 15, 2014 at 10:22 PM
Hi guys,

Sorry for my long delay. I was so busy with the release of Simple Injector 2.6, that I forgot all about this.

I'm however pleased to announce that I completely rewrote the code sample on the integration page. This new sample not only fixes the problem, but the solution is much cleaner, because:
  • The BasePage is not needed anymore, because the new example hooks onto the application's PreRequestHandlerExecute event to initialize any HTTP handler (not only pages).
  • No separate verification of pages is needed (because page's are simply registered and the call to Verify() takes care of this).
Please note that the old documentation on Codeplex is deprecated and will soon be replaced with blank pages that point at the new documentation at readthedocs.org. You can find the new Web Forms integration page here.
Oct 16, 2014 at 1:47 PM
Thanks, I really appreciate it. It works great. Just as an FYI - in the page class code, you forgot to change the BasePage back to Page.
Coordinator
Oct 16, 2014 at 1:55 PM
@stevegfcimorg: Thanks for noticing. I will fix the documentation soon and remove the reference to BasePage.
Nov 18, 2014 at 10:13 PM
Using this new approach causes another problem:
The constructor of type MvcHandler contains the parameter of type RequestContext with name 'requestContext' that is not registered. Please ensure RequestContext is registered in the container, or change the constructor of MvcHandler.

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: The constructor of type MvcHandler contains the parameter of type RequestContext with name 'requestContext' that is not registered. Please ensure RequestContext is registered in the container, or change the constructor of MvcHandler.

Source Error: 


Line 25:        public static void InitializeHandler(IHttpHandler handler)
Line 26:        {
Line 27:            _container.GetRegistration(handler.GetType(), true).Registration
Line 28:                .InitializeInstance(handler);
Line 29:        }
This is legacy app where I'm trying to introduce MVC. This error wasn't happening with the old approach (same app).
Coordinator
Nov 18, 2014 at 10:31 PM
Does the project have a reference to the System.Web assembly?
Coordinator
Nov 18, 2014 at 10:37 PM
The MvcHandler is defined in System.Web.Mvc and is used to select "the controller that will handle an HTTP request". You can't initialize this handler and there is no use in doing this. So you can skip it from initializing like this:
public static void InitializeHandler(IHttpHandler handler)
{
    if (handler.GetType() != typeof(MvcHandler)) {
        _container.GetRegistration(handler.GetType(), true).Registration.InitializeInstance(handler);
    }
}
You'll only run into this problem if you mix Web Forms with MVC.
Nov 19, 2014 at 3:38 PM
I'm surprised my email reply didn't make it here, but this check works!
Nov 25, 2014 at 7:01 PM
Looks like checking for just MvcHandler is not enough. It causes issue for other handlers, such as Visual Studio's browserlink. Now browserlink I care about the least, but I'm wondering if other handlers down the line may need to be excluded.

Upon venturing about a way to isolate only web forms requests, there seems to be no authoritative way. For now, this seems to work:
public static void InitializeHandler(IHttpHandler handler)
{
    var ns = handler.GetType().Namespace;

    // poor man's check for web forms
    if( ns != null && ns.Equals("ASP"))
    {
        _container.GetRegistration(handler.GetType(), true).Registration.InitializeInstance(handler);
    }
}
Coordinator
Nov 25, 2014 at 7:13 PM
What you can see that I did in the ASP.NET Web Forms integration Guide is that I excluded all handlers, that are defined in a the System.Web namespace or sub namespace:
context.PreRequestHandlerExecute += (sender, e) => {
    var handler = context.Context.CurrentHandler;
    if (handler != null && !handler.GetType().Assembly.FullName.StartsWith("System.Web")) {
        Global.InitializeHandler(handler);
    }
};
This will catch the following handlers:
  • System.Web.Handlers.AssemblyResourceLoader
  • System.Web.Handlers.TraceHandler
  • System.Web.DefaultHandler
  • System.Web.WebHost.HttpControllerHandler
  • System.Web.HttpApplication
  • System.Web.Mvc.MvcHandler
  • System.Web.Mvc.MvcHttpHandler
  • System.Web.Mvc.Html.ChildActionMvcHandler
  • System.Web.Routing.UrlAuthFailureHandler
I think it covers most cases. One case I already noticed it doesn't cover is:
  • Microsoft.Owin.Host.SystemWeb.OwinHttpHandler
Fortunately, this handler has one single public constructor (the default constructor), so initialization on this handler will succeed because of this.

Can you think of any other case where this might fail?
Nov 25, 2014 at 7:25 PM
Was this a recent update? I don't have in this my code which I copied from here few days back. Anyway, this will not exclude the browserlink handler (RequestDataHttpHandler) which is under Microsoft.VisualStudio.Web.PageInspector.Runtime. Other than that, any 3rd party or user defined handlers will also get included .
Coordinator
Nov 25, 2014 at 7:47 PM
Edited Nov 25, 2014 at 7:48 PM
This was indeed a recent update. I made this update a few days back.

It's true that this code might still break when other handlers from 3rd parties are included. The only real solution is to not use the container's GetRegistration method, since it will force the type to be able to be created by the container itself (which lies restrictions on the definition and number of constructors). The real stable solution is to use the same method as which the SimpleInjectorFilterAttributeFilterProvider of the Simple Injector MVC integration package uses. If we use that approach, our HttpApplication will look as follows:
public class Global : HttpApplication {
    private static Container container;
    private static readonly ConcurrentDictionary<Type, Registration> registrations =
        new ConcurrentDictionary<Type, Registration>();
    private static readonly Func<Type, Registration> registrationFactory =
        concreteType => Lifestyle.Transient.CreateRegistration(concreteType, container);
    
    public static void InitializeHandler(IHttpHandler handler) {
        var registration = registrations.GetOrAdd(handler.GetType(), registrationFactory);
        registration.InitializeInstance(handler);           
    }

    protected void Application_Start(object sender, EventArgs e) {
        Bootstrap();
    }

    private static void Bootstrap() {
        // 1. Create a new Simple Injector container.
        container = new Container();

        // etc
    }
}
The reason the integration guide doesn't use this code snippet is because I found this too complex and I didn't want to scare developers. The current guide is a bit easier to follow.
Nov 25, 2014 at 8:45 PM
Works like a charm!

Also, with this approach, its no longer required to filter inside IHttpModule.Init, correct? I revereted to
void IHttpModule.Init(HttpApplication context)
{
    context.PreRequestHandlerExecute += (sender, e) =>
    {
        if (context.Context.CurrentHandler != null)
        {
            MvcApplication.InitializeHandler(context.Context.CurrentHandler);
        }
    };
}
and things are working so far.
Coordinator
Nov 25, 2014 at 9:24 PM
Indeed. With this approach, you don't need to filter the handler anymore.