views:

302

answers:

2

We are using the beloved Ninject+Ninject.Web.Mvc with MVC 2 and are running into some problems. Specifically dealing with 404 errors. We have a logging service that logs 500 errors and records them. Everything is chugging along just perfectly except for when we attempt to enter a non-existent controller. Instead of getting the desired 404 we end up with a 500 error:

Cannot be null
Parameter name: service
[ArgumentNullException: Cannot be null
Parameter name: service]
   Ninject.ResolutionExtensions.GetResolutionIterator(IResolutionRoot root, Type service, Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional) +188
   Ninject.ResolutionExtensions.TryGet(IResolutionRoot root, Type service, IParameter[] parameters) +15
   Ninject.Web.Mvc.NinjectControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +36
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +68
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +118
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +46
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +63
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +13
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8679426
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

I did some searching and found some similar issues, but those 404 issues seem to be unrelated. Any help here would be great.

Thanks! Josh

+2  A: 

EDIT: This is in the trunk now for MVC2: http://github.com/enkari/ninject.web.mvc

controllerType is coming in null now, we can pass it to the base and let the 404 happen properly:

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if(controllerType == null)
        {
            // let the base handle 404 errors with proper culture information
            return base.GetControllerInstance(requestContext, controllerType);
        }

        var controller = Kernel.TryGet(controllerType) as IController;

        if (controller == null)
            return base.GetControllerInstance(requestContext, controllerType);

        var standardController = controller as Controller;

        if (standardController != null)
            standardController.ActionInvoker = CreateActionInvoker();

        return controller;
    }
Ian Davis
I am using the MVC2 extension.
Josh Barker
Ninject is failing to resolve the controller and hands it off to the DefaultControllerFactory which is then out of Ninjects hands. MS may have changed how they deal with 404 errors in MVC2. Are the requesContext or controllerType null?
Ian Davis
controllerType is null, requestContext is not.
Josh Barker
I would imagine this is because the controller does not exist...?
Josh Barker
According to the MS MVC2 source code of DefaultControllerFactory, if controllerType is null, it should be throwing an HTTP exception with error code 404.
Ian Davis
Yeah, interesting... so within Ninject.Web.Mvc in GetControllerInstance I should modify the code to check of controllerType is null and then throw a 404... seems to me that we need submit a patch to Ninject.Web.Mvc.
Josh Barker
@Ian Davis - if you want to copy your answer from github as a new answer, I can accept it.
Josh Barker
@Ian Davis thanks!
Josh Barker
+1  A: 

Needed to modify NinjectControllerFactory.cs source code by adding the 404. I have added the source code for anyone interested in fixing:

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
            throw new HttpException(
                404, String.Format(
                         "The controller for path '{0}' could not be found " +
                         "or it does not implement IController.",
                         requestContext.HttpContext.Request.Path));

        var controller = Kernel.TryGet(controllerType) as IController;

        ...

Josh

Josh Barker