views:

199

answers:

2

I am trying to build a class like so...

    public class IoCControllerFactory : DefaultControllerFactory
    {           
        protected override IController GetControllerInstance(RequestContext request_context, Type controller_type)
        {
            // Attempt to resolve controller type.
            IController resolvedController = null;
            if (controller_type != null)
            {

                if (!typeof(IController).IsAssignableFrom(controller_type))
                {
                    throw new ArgumentException(string.Format("Type requested is not a controller: {0}", controller_type.Name), "controller_type");
                }

                resolvedController = _container.Resolve(controller_type) as IController;
            }

            // Throw page not found if controller does not exist.
            if (resolvedController == null)
            {
                throw new HttpException((int)HttpStatusCode.NotFound, "The requested page was not found.");
            }

            return resolvedController;
        }

    }

The method is trying to override an internal virtual method that has the followign signature (from .net assembly... i cant modify this)

protected internal virtual IController GetControllerInstance(
    RequestContext requestContext,
    Type controllerType
)

When i try to compile i get the following...

'XXX.Web.Mvc.IoCControllerFactory.GetControllerInstance(System.Web.Routing.RequestContext, System.Type)': no suitable method found to override

Everybody on the web seems to be able to do this just fine, is there something obvious that I am missing?

+2  A: 

New (Possible) Answer

I am able to duplicate this issue if I've defined a type with the same name as one from the "System.Web.Mvc.dll" assembly in my own library. Could this be your problem? See the code below:

using System;
using System.Web.Mvc;
using System.Web.Routing;

namespace SystemWebMvcTest
{
    // See here: I've declared a type with the same name as a type
    // from the System.Web.Mvc namespace in System.Web.Mvc.dll.
    public interface IController
    {
    }

    public class IoCControllerFactory : DefaultControllerFactory
    {
        // Now this method signature, since it does not include the fullly
        // qualified name of its return type, is actually defined to return
        // an instance of the IController interface defined in THIS assembly,
        // rather than the System.Web.Mcv.IController interface.
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return null;
        }
    }
}

The same error should occur if you have a naming conflict with any of the relevant types: DefaultControllerFactory, IController, RequestContext, or Type.


Old Answer

The original method is protected internal, which means that it can be accessed by any type within the same assembly as well as any derived type; but you are trying to override it with a method that is protected, which removes access to all non-derived types, even in the same assembly as the base type.

This isn't really so different from trying to override a public member with a private one. You can't do that; you'd have to declare the derived member new instead of override (which is a pretty bad idea, almost all the time).

Mark your IoCControllerFactory.GetControllerInstance method protected internal and you should be good.

UPDATE: Actually, as Thomas pointed out in a comment, this totally depends on whether your derived type is in the same assembly as the base type or not. If not, then declaring the derived member protected internal would make no sense. If you're in a different assembly, then I'm not sure why declaring the member protected is causing an error as this is exactly what you're supposed to do.

UPDATE 2: It sounds like in the code you've posted, your base and derived types are in the same assembly. This is why the IoCControllerFactory.GetControllerInstance method must be marked protected internal, to match the accessibility of its base type. If you were in a separate assembly, internal would be wrong, as it would open up the accessibility to a whole new set of types (those within this new assembly). If you've seen code examples online where a type in one assembly inherited a protected internal member from a base type in another, this explains why the derived member was only protected -- to keep accessibility the same.

UPDATE 3: Never mind! Apparently the base type is in a .NET assembly, which is clearly different from whatever assembly your derived type is in. Based on this, your method signature should actually compile as-is, as far as I can tell. One question in my mind is whether all of these names -- DefaultControllerFactory, IController, RequestContext, etc. -- are not also present in your assembly. If you have a naming conflict, this could be one possible explanation. Otherwise, I fail to understand the compiler error you're getting.

Dan Tao
No, `protected internal` methods should be overriden as `protected`. If you try to override them as `protected internal`, you get a compile error. See [this answer](http://stackoverflow.com/questions/2375792/overriding-protected-internal-with-protected/2375947#2375947). `protected internal` would allow access to this method to all classes in your assembly, which incorrectly widens its accessibility
Thomas Levesque
well, this is my initial thought, but if you google this particular scenerio, with any MVC IoC framework, they 100% are able to accomplish this as described. When i move it to a different assembly and build it also works fine.
wcpro
@Thomas, @wcpro: See my update. I think it addresses what both of you are saying.
Dan Tao
@Thomas Levesque: Am I missing something? It seems you aren't convinced.
Dan Tao
this is a .NET assembly that I'm trying to override. I cannot change the signature of that assembly.
wcpro
@wcpro: I wasn't suggesting changing the method in the base type, but rather in the derived type. But I mistakenly thought both classes were in the same assembly. Now that you've clarified it's a .NET assembly it's clear that your derived type was in a separate assembly to begin with. So I'm not really sure what the problem could've been, unless you had a naming conflict somewhere.
Dan Tao
i double checked and there is definately not a naming issue with any names in the project itself, and the intellisense isnt showing any conflicts.
wcpro
@wcpro: Whoa, wait, what? Did you figure out what was going on here???
Dan Tao
A: 

I've just came across this problem; If the chosen solution wasn't really your problem, then is that the RequestContext type is forwared from the System.Web.Routing assembly into the System.Web one. The solution is to both reference System.Web and System.Web.Routing.

Sebastian Piu
cool thanks for sharing this.
wcpro