views:

92

answers:

2

Does anyone know how to use an AsyncController in a mvc application that uses Ninject for DI?

AsyncController works fine when i dont use ninject but i cant make them work together.

I added following in my sitemodule but no go.

Bind<IAsyncController>( ).To<AsyncController>( ).InSingletonScope( );

sorry for not explaining this in details.

my controller looks like this

 [HandleError]
    public class HomeController : AsyncController
    {
        public void IndexAsync( )
        {
            AsyncManager.OutstandingOperations.Increment( );

            RssFeed feed = new RssFeed( );
            feed.GetRssFeedAsyncCompleted += ( s, e ) =>
                {
                    AsyncManager.Parameters[ "items" ] = e.Items;
                    AsyncManager.OutstandingOperations.Decrement( );
                };
            feed.GetRssFeedAsync( "http://feeds.abcnews.com/abcnews/topstories" );
        }

        public ActionResult IndexCompleted( IEnumerable<SyndicationItem> items )
        {
            ViewData[ "SyndicationItems" ] = items;
            return View( );
        }
    }

and my global.asax looks like this

public class MvcApplication :  System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
        }
        protected void Application_Start( )
        {
            AreaRegistration.RegisterAllAreas( );
            RegisterRoutes( RouteTable.Routes );
        }
    }

this works fine. but as soon as i use ninject (ninject 2.0 ) i get 404 page not found error when i try to access the index page. this is how i am configuring ninject

public class MvcApplication : NinjectHttpApplication //System.Web.HttpApplication
    {
        #region IOC
        static IKernel container;
        public static IKernel Container
        {
            get
            {
                if ( container == null ) { container = new StandardKernel( new SiteModule( ) ); }
                return container;
            }
        }

        protected override IKernel CreateKernel( )
        {
            return Container;
        }
        #endregion

        public static void RegisterRoutes( RouteCollection routes )
        {
            routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );
            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
        }

        //protected void Application_Start()
        //{
        //    AreaRegistration.RegisterAllAreas();

        //    RegisterRoutes(RouteTable.Routes);
        //}

        protected override void OnApplicationStarted( )
        {
            AreaRegistration.RegisterAllAreas( );
            RegisterRoutes( RouteTable.Routes );
        }
    }

    public class SiteModule : NinjectModule
    {
        public override void Load( )
        {

        }
    }

Do i need to bind anything on my sitemodule?

BTW i am using Jeff Prosise's example which he posted in his blog Here you can download his demo application and try Ninject-ify it :)

Any help appreciated.

+1  A: 

It appears it's not working because the standard NinjectControllerFactory inserts a NinjectActionInvoker into the controller's ActionInvoker property. The NinjectActionInvoker is derived from ControllerActionInvoker. An AsyncController, however, uses ActionInvokers derived from AsyncControllerActionInvoker. for some reason, this causes the controller to not match the route, and it returns a 404.

The real fix would be a patch to Ninject to support construction of AsyncController with AsyncControllerActionInvokers.

However, in the meantime, here is a workaround:

in your Global.asax, add this override:

    protected override Ninject.Web.Mvc.NinjectControllerFactory CreateControllerFactory()
    {
        return new MyNinjectControllerFactory( kernel );
    }

and then add this class for MyNinjectControllerFactory:

public class MyNinjectControllerFactory : Ninject.Web.Mvc.NinjectControllerFactory
{
    public MyNinjectControllerFactory( IKernel kernel ) : base( kernel ) { }

    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;
    }
}

this is a copy of the NinjectControllerFactory that leaves out the assignment of the ActionInvoker.

IF you have code that depends on dependencies being injected into your ActionFilters, you will need to create your own ActionInvoker that returns an AsyncControllerActionInvoker that uses Ninject. Look at the Ninject.Web.Mvc source for the NinjectActionInvoker.

HTH

dave thieben
yup that works for me. Thanks.
A: 

Like dave pointed out a patch is needed for Ninject to support async controller and Remo says he'll work on it as soon as he has sometime. meantime you can use dave's workaround or try this. this is straight from horse's mouth. i posted a msg in ninject group and Remo responded with this .

AsyncControllers are currently not supported. I'll add this as soon as I have the time to implement it properly. In the mean time you can use apply the following changes to the sources to add the support:

  1. Make a copy of NinjectActionInvoker name it NinjectAsyncActionInvoker and change base type to AsyncControllerActionInvoker

  2. Apply the following changes to NinjectControllerFactory diff --git "a/C:\Users\REMOGL~1\AppData\Local\Temp\ \NinjectControllerFactory_HEAD.cs" "b/C:\Projects\Ninject\ \ninject.web.mvc\mvc2\src\Ninject.Web.Mvc\ \NinjectControllerFactory.cs" index 2c225a1..3916e4c 100644 --- "a/C:\Users\REMOGL~1\AppData\Local\Temp\ \NinjectControllerFactory_HEAD.cs" +++ "b/C:\Projects\Ninject\ninject.web.mvc\mvc2\src\ \Ninject.Web.Mvc\NinjectControllerFactory.cs" @@ -53,10 +53,18 @@ namespace Ninject.Web.Mvc if (controller == null) return base.GetControllerInstance(requestContext, controllerType);

    • var standardController = controller as Controller;
    • var asyncController = controller as AsyncController;
    • if (asyncController != null)
    • {
    • asyncController.ActionInvoker = CreateAsyncActionInvoker();
    • }
    • else
    • {
    • var standardController = controller as Controller;
    • if (standardController != null)
    • standardController.ActionInvoker = CreateActionInvoker();
    • }

    • if (standardController != null)

    • standardController.ActionInvoker = CreateActionInvoker();

                  return controller; 
          }  @@ -69,5 +77,14 @@ namespace Ninject.Web.Mvc 
          { 
                  return new NinjectActionInvoker(Kernel); 
          } 
      
    • }
      • ///
    • /// Creates the action invoker.
    • ///
    • /// The action invoker.
    • protected virtual NinjectAsyncActionInvoker CreateAsyncActionInvoker()
    • {
    • return new NinjectAsyncActionInvoker(Kernel);
    • }
    • } } \ No newline at end of file

    • Remo

well.. i added Remo's response as a quote and it messed up the diff. but head over to ninject google group to view his response http://groups.google.com/group/ninject/browse_thread/thread/93a82b94291ff2aa