How to use Ninject with XNA?
- by Rosarch
I'm having difficulty integrating Ninject with XNA.
static class Program
{
/**
* The main entry point for the application.
*/
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(NinjectModuleManager.GetModules());
CachedContentLoader content = kernel.Get<CachedContentLoader>(); // stack overflow here
MasterEngine game = kernel.Get<MasterEngine>();
game.Run();
}
}
// constructor for the game
public MasterEngine(IKernel kernel)
: base(kernel)
{
this.inputReader = kernel.Get<IInputReader>();
graphicsDeviceManager = kernel.Get<GraphicsDeviceManager>();
Components.Add(kernel.Get<GamerServicesComponent>());
// Tell the loader to look for all files relative to the "Content" directory.
Assets = kernel.Get<CachedContentLoader>();
//Sets dimensions of the game window
graphicsDeviceManager.PreferredBackBufferWidth = 800;
graphicsDeviceManager.PreferredBackBufferHeight = 600;
graphicsDeviceManager.ApplyChanges();
IsMouseVisible = false;
}
Ninject.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Modules;
using HWAlphaRelease.Controller;
using Microsoft.Xna.Framework;
using Nuclex.DependencyInjection.Demo.Scaffolding;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace HWAlphaRelease
{
public static class NinjectModuleManager
{
public static NinjectModule[] GetModules()
{
return new NinjectModule[1] { new GameModule() };
}
/// <summary>Dependency injection rules for the main game instance</summary>
public class GameModule : NinjectModule
{
#region class ServiceProviderAdapter
/// <summary>Delegates to the game's built-in service provider</summary>
/// <remarks>
/// <para>
/// When a class' constructor requires an IServiceProvider, the dependency
/// injector cannot just construct a new one and wouldn't know that it has
/// to create an instance of the Game class (or take it from the existing
/// Game instance).
/// </para>
/// <para>
/// The solution, then, is this small adapter that takes a Game instance
/// and acts as if it was a freely constructable IServiceProvider implementation
/// while in reality, it delegates all lookups to the Game's service container.
/// </para>
/// </remarks>
private class ServiceProviderAdapter : IServiceProvider
{
/// <summary>Initializes a new service provider adapter for the game</summary>
/// <param name="game">Game the service provider will be taken from</param>
public ServiceProviderAdapter(Game game)
{
this.gameServices = game.Services;
}
/// <summary>Retrieves a service from the game service container</summary>
/// <param name="serviceType">Type of the service that will be retrieved</param>
/// <returns>The service that has been requested</returns>
public object GetService(Type serviceType)
{
return this.gameServices;
}
/// <summary>Game services container of the Game instance</summary>
private GameServiceContainer gameServices;
}
#endregion // class ServiceProviderAdapter
#region class ContentManagerAdapter
/// <summary>Delegates to the game's built-in ContentManager</summary>
/// <remarks>
/// This provides shared access to the game's ContentManager. A dependency
/// injected class only needs to require the ISharedContentService in its
/// constructor and the dependency injector will automatically resolve it
/// to this adapter, which delegates to the Game's built-in content manager.
/// </remarks>
private class ContentManagerAdapter : ISharedContentService
{
/// <summary>Initializes a new shared content manager adapter</summary>
/// <param name="game">Game the content manager will be taken from</param>
public ContentManagerAdapter(Game game)
{
this.contentManager = game.Content;
}
/// <summary>Loads or accesses shared game content</summary>
/// <typeparam name="AssetType">Type of the asset to be loaded or accessed</typeparam>
/// <param name="assetName">Path and name of the requested asset</param>
/// <returns>The requested asset from the the shared game content store</returns>
public AssetType Load<AssetType>(string assetName)
{
return this.contentManager.Load<AssetType>(assetName);
}
/// <summary>The content manager this instance delegates to</summary>
private ContentManager contentManager;
}
#endregion // class ContentManagerAdapter
/// <summary>Initializes the dependency configuration</summary>
public override void Load()
{
// Allows access to the game class for any components with a dependency
// on the 'Game' or 'DependencyInjectionGame' classes.
Bind<MasterEngine>().ToSelf().InSingletonScope();
Bind<NinjectGame>().To<MasterEngine>().InSingletonScope();
Bind<Game>().To<MasterEngine>().InSingletonScope();
// Let the dependency injector construct a graphics device manager for
// all components depending on the IGraphicsDeviceService and
// IGraphicsDeviceManager interfaces
Bind<GraphicsDeviceManager>().ToSelf().InSingletonScope();
Bind<IGraphicsDeviceService>().To<GraphicsDeviceManager>().InSingletonScope();
Bind<IGraphicsDeviceManager>().To<GraphicsDeviceManager>().InSingletonScope();
// Some clever adapters that hand out the Game's IServiceProvider and allow
// access to its built-in ContentManager
Bind<IServiceProvider>().To<ServiceProviderAdapter>().InSingletonScope();
Bind<ISharedContentService>().To<ContentManagerAdapter>().InSingletonScope();
Bind<IInputReader>().To<UserInputReader>().InSingletonScope().WithConstructorArgument("keyMapping", Constants.DEFAULT_KEY_MAPPING);
Bind<CachedContentLoader>().ToSelf().InSingletonScope().WithConstructorArgument("rootDir", "Content");
}
}
}
}
NinjectGame.cs
/// <summary>Base class for Games making use of Ninject</summary>
public class NinjectGame : Game {
/// <summary>Initializes a new Ninject game instance</summary>
/// <param name="kernel">Kernel the game has been created by</param>
public NinjectGame(IKernel kernel) {
Type ownType = this.GetType();
if(ownType != typeof(Game)) {
kernel.Bind<NinjectGame>().To<MasterEngine>().InSingletonScope();
}
kernel.Bind<Game>().To<NinjectGame>().InSingletonScope();
}
}
} // namespace Nuclex.DependencyInjection.Demo.Scaffolding
When I try to get the CachedContentLoader, I get a stack overflow exception. I'm basing this off of this tutorial, but I really have no idea what I'm doing. Help?