If I want to implement a Dependency Injection for ASP.NET MVC controllers, I can use IControllerFactory interface to create a factory class and then register it in Global.asax.cs, like:
ControllerBuilder.Current.SetControllerFactory(controllerFactory)
(reference: http://www.dotnetcurry.com/ShowArticle.aspx?ID=786)
Now my question is:
How could I set a factory for an IHttpControllerActivator derived class?
Do we have something in ASP.NET MVC 4.0 like:
HttpControllerBuilder.Current.SetApiControllerActivator(httpControllerActivator)
?
Update:
I want to add my current code, it might be helpful to understand the case:
My customized HttpControllerActivator:
public class MyCustomApiActivator : DefaultHttpControllerActivator
//or IHttpControllerActivator ?
{
private readonly Dictionary<string, Func<HttpRequestMessage, IHttpController>> _apiMap;
public MyCustomApiActivator(IMyRepository repository)
{
if (repository == null)
{
throw new ArgumentException("repository");
}
_apiMap = new Dictionary<string, Func<HttpRequestMessage, IHttpController>>();
controllerMap["Home"] = context => new HomeController();
_apiMap["MyCustomApi"] = context => new MyCustomApiController(repository);
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
if(_apiMap.ContainsKey(controllerType.Name))
return _apiMap[controllerType.Name](request);
return null;
}
}
My composition root:
public class CompositionRoot
{
private readonly IHttpControllerActivator _apiControllerActivator;
public CompositionRoot()
{
_apiControllerActivator = CompositionRoot.CreateHttpControllerActivator();
}
public IHttpControllerActivator ApiControllerActivator
{
get { return _apiControllerActivator; }
}
private static IHttpControllerActivator CreateHttpControllerActivator()
{
string defaultRepositoryTypeName = ConfigurationManager.AppSettings["DefaultRepositoryTypeName"];
var defaultRepositoryType = Type.GetType(defaultRepositoryTypeName, true);
var defaultRepository = (IMyRepository)Activator.CreateInstance(defaultRepositoryType);
var apiController = new MyCustomApiActivator(defaultRepository);
return apiController;
}
}
Finally this is inside my Global.asax.cs, where I need a trick:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var root = new CompositionRoot();
//The following line raise this compile-time error:
// cannot convert from 'System.Web.Http.Dispatcher.IHttpControllerActivator'
// to 'System.Web.Mvc.IControllerFactory'
ControllerBuilder.Current.SetControllerFactory(root.ApiControllerActivator);
}
Mark Seemann, author of Dependency Injection in .NET, has a short series on DI with ASP.NET WebAPI.
He places the composition root inside an IHttpControllerActivator
Dependency Injection and Lifetime Management with ASP.NET Web API
Dependency Injection in ASP.NET Web API with Castle Windsor
Maybe that helps.
Update
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new PoorMansCompositionRoot());
Registers your custom HttpControllerActivator globally.
In ASP.NET Web API HttpControllerDispatcher is responsible for constructing controllers. It works with the DependecyResolver by default but if you want to extend its functionality, you need to override its SendAsync method and register it again.
Example:
public class MyCustomDispatcher : HttpControllerDispatcher {
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken) {
// Do your stuff here
// According to your requirements, either run its default functionality
// or return your own stuff
return base.SendAsync(request, cancellationToken);
}
}
Note:
However, I wasn't able to find an elegant way to replace the default one
globally. You can replace the default one per-route easily by
attaching this custom dispatcher to a route but there seems to be no
way to do this globally. I opened up a discussion on that at the
project site: http://aspnetwebstack.codeplex.com/discussions/400366
Related
I'm trying to setup a project that uses both MVC and Web API via OWIN and I'm having trouble getting Autofac to take a effect.
Here's how I'm initializing Web API:
public partial class Startup
{
public static void ConfigureWebApi(IAppBuilder app)
{
var config = BuildHttpConfiguration();
var container = AutoFacConfig.BuildContainer();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
private static HttpConfiguration BuildHttpConfiguration()
{
var config = new HttpConfiguration();
// Response formatter config
config.Formatters.Remove(
GlobalConfiguration.Configuration.Formatters.XmlFormatter);
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
// Setup Web API error reporting
var customErrors = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
IncludeErrorDetailPolicy errorDetailPolicy;
switch (customErrors.Mode)
{
case CustomErrorsMode.RemoteOnly:
errorDetailPolicy
= IncludeErrorDetailPolicy.LocalOnly;
break;
case CustomErrorsMode.On:
errorDetailPolicy
= IncludeErrorDetailPolicy.Never;
break;
case CustomErrorsMode.Off:
errorDetailPolicy
= IncludeErrorDetailPolicy.Always;
break;
default:
throw new ArgumentOutOfRangeException();
}
config.IncludeErrorDetailPolicy = errorDetailPolicy;
config.MapHttpAttributeRoutes();
SwaggerConfig.ConfigureSwagger(config);
return config;
}
}
The BuildContainer() method looks like the following. This method is used to build the container for both MVC and Web API:
public static IContainer BuildContainer()
{
var builder = new ContainerBuilder();
// Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.PropertiesAutowired();
builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
// OPTIONAL: Register model binders that require DI.
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
// OPTIONAL: Register web abstractions like HttpContextBase.
builder.RegisterModule<AutofacWebTypesModule>();
// OPTIONAL: Enable property injection in view pages.
builder.RegisterSource(new ViewRegistrationSource());
// OPTIONAL: Enable property injection into action filters.
builder.RegisterFilterProvider();
// Bind the core types
Core.Infrastructure.AutoFacConfig.BuildContainer(builder);
builder.RegisterType<Postal.EmailService>().As<Postal.IEmailService>();
// Effectively auto-wires the anything with an interface within Web assembly infrastructure folder
builder.RegisterAssemblyTypes(typeof(IJwtHelper).Assembly)
.Where(t => t.Namespace != null && t.Namespace.StartsWith("MyApp.Web.Infrastructure") && t.GetInterfaces().Any())
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
// Set the dependency resolver to be Autofac.
return builder.Build();
}
I have Web API controllers setup in an area and I had everything working with standard MVC controllers. I would like to use Web API controllers for where it's appropriate, but every time I try to request a controller based on ApiController I get the error:
An error occurred when trying to create a controller of type 'XxxController'. Make sure that the controller has a parameterless public constructor.
-- Edit --
The API area config looks like the following. (Side note: I know this isn't the "proper" way to configure Web API. I include the {action} because I feel there are too many controller files otherwise.)
public class ApiAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Api"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapHttpRoute(
"Api_default",
"Api/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
The authentication controller looks like this:
public class AuthenticationController : MyAppApiJwtController
{
private readonly IUserRepository _userRepository;
private readonly IAppSettingsHelper _appSettingsHelper;
private readonly IJwtHelper _jwtHelper;
private readonly IDeviceRepository _deviceRepository;
private readonly IINLDataService _inlDataService;
public AuthenticationController(IUserRepository userRepository, IAppSettingsHelper appSettingsHelper, IJwtHelper jwtHelper, IDeviceRepository deviceRepository, IINLDataService inlDataService)
{
_userRepository = userRepository;
_appSettingsHelper = appSettingsHelper;
_jwtHelper = jwtHelper;
_deviceRepository = deviceRepository;
_inlDataService = inlDataService;
}
[HttpPost]
[AllowAnonymous]
public LoginResponseModel Login(LoginModel model)
{
...
}
}
The MyAppApiJwtController looks like this:
public class MyAppApiJwtController : ApiController
{
internal IAuthenticationManager AuthenticationManager
{
get { return Request.GetOwinContext().Authentication; }
}
private JwtUserIdentity _currentJwtUser;
public JwtUserIdentity CurrentJwtUser
{
get
{
if (_currentJwtUser != null)
return _currentJwtUser;
if (User == null)
return null;
_currentJwtUser = new JwtUserIdentity((ClaimsIdentity)User.Identity);
return _currentJwtUser;
}
}
}
-- Edit 2 --
The URL I'm attempting to use is http://localhost:20630/api/authentication/login
-- Edit 3 --
The MVC configuration looks like the following. This is called just before the Web API configuration:
public partial class Startup
{
public static void ConfigureMvc()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
MvcConfig.RegisterRoutes(RouteTable.Routes);
MvcConfig.ValueConfig();
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutomapperConfig.Configure();
JsonConfig.Configure();
AutoFacConfig.ConfigureContainer();
}
}
ASP.NET Web API does not support MVC areas by default.
This code:
public class ApiAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Api"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.MapHttpRoute(
"Api_default",
"Api/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
Will instruct the framework to map any route starting with Api to MVC controllers, but, at the same time, such controllers exists only for Web API. This conflict directly relates to the exception thrown when the Dependency Resolver tries to create an instance of the controller (the exception message may be misleading).
What could be happening:
MVC is executed first, and tries to map your route api/authentication/login. This URI matches your AreaRegistration, so it will try to route the request to the AuthenticationController inside your Api area.
MVC asks the Dependency Resolver to create an instance of the above controller, that must inherit from Controller (that's because we are in the MVC context).
The resolver does not have a registration for a MVC Controller that is called AuthenticationController (the AuthenticationController inherits from ApiController), and it returns null (because that's the expected behavior of the IServiceProvider.GetService method).
MVC then reverts to its default implementation for creating the controller, but finds that AuthenticationController class does not have a parameterless constructor. An exception is thrown.
Please try by removing this area declaration: it is not useful (add your api prefix inside RoutePrefix or Route attributes for your controllers/actions) and works only for MVC, while you are defining Web API as an OWIN middleware.
Reference:
ASP.Net WebAPI area support
I'm trying to resolve the dependencies of my custom AuthorizeAttribute which I use to decorate my API controllers in an MVC4 app. Problem is that I keep getting a NullReferenceException on the service dependency I use within my custom filter. Here is my Autofac configuration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(IUserProfileMapper).Assembly)
.Where(t => t.Name.EndsWith("Mapper"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileSvc).Assembly)
.Where(t => t.Name.EndsWith("Svc"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
}
}
and my custom authorize filter:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc _authenticationSvc;
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!base.IsAuthorized(actionContext))
{
return false;
}
var trueUserId = WebSecurity.CurrentUserId;
if (_authenticationSvc.GetUsersRoles(trueUserId).Any(x => x == "Admin")) return true;
// NullReferenceException on _authenticationSvc
}
}
According to the official docs all that is needed is:
var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
But that doesn't seem to do the trick either. Appreciate any help.
I think Autofac's documentation offers much simpler solution for WebApi action filters.
public interface ServiceCallActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Get the request lifetime scope so you can resolve services.
var requestScope = actionContext.Request.GetDependencyScope();
// Resolve the service you want to use.
var service = requestScope.GetService(typeof(IMyService)) as IMyService;
// Do the rest of the work in the filter.
service.DoWork();
}
}
It is not "pure DI" as it is using service locator, but it is simple and works with the request scope. You don't need to worry about registering specific action filter for each WebApi controller.
Source:
http://autofac.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection
You should configure property injection for your attribute
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
and the builder
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
In addition to #Toan Nguyen's answer, if you have this...
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
... it seems you also need (or may need) the first line below:
builder.RegisterFilterProvider();
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
Reference: http://itprojectpool.blogspot.com.au/2014/03/autofac-di-on-action-filters.html
In addition to configuring property injection, as outlined in other answers, you can also explicitly resolve dependencies in the OnActivating callback.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private IAuthenticationSvc _authenticationSvc;
public void SetAuthenticationSvc(IAuthenticationSvc svc)
{
this._authenticationSvc = svc;
}
}
And then register the type:
builder.RegisterType<MyAuthorizeAttribute>()
.OnActivating(_ => _.Instance.SetAuthenticationSvc(_.Context.Resolve<IAuthenticationSvc>()));
Note: You can do the same with a property instead of a method. I chose to use a method here only to illustrate that this solution was not dependent on PropertiesAutowired.
I have a controller and I want to use Dependency Injection with constructor,this is my code
private readonly IHomeService _iHomeService;
public HomeController(IHomeService iHomeService)
{
_iHomeService = iHomeService;
}
public HomeController()
{
}
When I remove Constructor without any parameter(Second Constructor),I see this error :
No parameterless constructor defined
and When I use Constructor without any parameter,I see my private field is null(_iHomeService = null) because program use constructor without parameter.
How can I resolve this problem for Dependency Injection?
Well, to do dependency injection youll need to either use a framework or use controller factory .
try ninject
public class HomeController : Controller
{
private readonly IWelcomeMessageService welcomeMessageService;
public HomeController(IWelcomeMessageService welcomeMessageService)
{
this.welcomeMessageService = welcomeMessageService;
}
public void Index()
{
ViewModel.Message = this.welcomeMessageService.TodaysWelcomeMessage;
return View();
}
}
public class WelcomeMessageServiceModule : NinjectModule
{
public override void Load()
{
this.Bind<IWelcomeMessageService>().To<WelcomeMessageService>();
}
}
The framework will take control on the controller instance creation and pass the constractor params
It sounds like you are expecting, automatically, the HomeService class to be instantiated and injected into the Controller.
Using an IoC framework like Ninject or StructureMap will do that for you - once you've set it up.
If you don't want to use an IoC framework, you'll need to manually instantiate the HomeService in your constructor.
ASP.NET uses a ControllerFactory to instantiate your controllers on-demand. This class requires that your controller has a parameterless constructor that it can use to create an instance of it.
You'll need to use a dependency injection framework to create your controllers and inject the required dependencies. ASP.NET has some dependency injection capability, but I understand that it is flawed. I suggest using Castle Windsor to manage your dependency injection. It integrates very well with ASP.NET, and there's a tutorial on integrating it here.
If you go down this route, you'd end up with an installer for your controllers and service:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());
container.Register(Component.For<IHomeService>.ImplementedBy<HomeService>());
}
}
..and a new ControllerFactory to create them:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
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.", requestContext.HttpContext.Request.Path));
}
return (IController) _kernel.Resolve(controllerType);
}
}
Finally, you'd create a container and set a new controller factory:
var container = new WindsorContainer().Install(new Installer());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
You could also use Ninject or StructureMap.
Did something change in MVC 3? I have tried all the examples on the Internet for setting up Unity as my IoC Container, but I keep getting an error saying that Unity cannot resolve my UserController. Here is my constructor on my UserController:
public UserController(IUserService userService)
{
_userService = userService;
}
I have the IUserService registered, that is not the problem. I keep getting errors, no matter what example I try. Does anyone have a good tutorial, or code, that works with Asp.Net MVC 3?
For reference, I have tried this, this, this, and this ... and tons of others.
Error:
The type UserController cannot be constructed. You must configure the container to supply this value.
ErrorLine:
controller = MvcUnityContainer.Container.Resolve(controllerType) as IController;
Configuration:
MvcUnityContainer.Container = new UnityContainer().RegisterType<IUserService, UserService>();
ControllerBuilder.Current.SetControllerFactory(typeof(UnityControllerFactory));
This worked for me for MVC3 RC. Notice IControllerFactory now has GetControllerSessionBehavior in MVC3 RC.
UnityMvcControllerFactory.cs:
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Practices.Unity;
using System.Web.SessionState;
public class UnityMvcControllerFactory : IControllerFactory
{
private IUnityContainer _container;
private IControllerFactory _innerFactory;
public UnityMvcControllerFactory(IUnityContainer container)
: this(container, new DefaultControllerFactory())
{
}
protected UnityMvcControllerFactory(IUnityContainer container,
IControllerFactory innerFactory)
{
_container = container;
_innerFactory = innerFactory;
}
public IController CreateController(RequestContext requestContext, string controllerName)
{
try
{
return _container.Resolve<IController>(controllerName.ToLowerInvariant());
}
catch (Exception)
{
return _innerFactory.CreateController(requestContext, controllerName);
}
}
public void ReleaseController(IController controller)
{
_container.Teardown(controller);
}
public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Default;
}
}
Global.asax.cs:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
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 = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
// Register Types and Set Controller Factory
ConfigureUnityContainer();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
private static void ConfigureUnityContainer()
{
IUnityContainer container = new UnityContainer();
// Set Controller Factory as UnityMvcControllerFactory
ControllerBuilder.Current.SetControllerFactory(
new UnityMvcControllerFactory(container)
);
}
}
To answer your question "What has changed in MVC3": MVC3 now has native support for dependency injection. Along with that change has come a redesign of the way controller objects are activated. Check out Brad Wilson's post (and the whole series about MVC 3.0) for more information:
http://bradwilson.typepad.com/blog/2010/10/service-location-pt10-controller-activator.html
Developers who previously implemented IControllerFactory by deriving from DefaultControllerFactory just to override the GetControllerInstance method for dependency injection purposes should now implement IControllerActivator instead.
In short, the unity controller factory (as well as the Ninject controller factory) are probably going to be broken until they release a new compatible version. A quick google did find this, however I have no idea if it works.
I'M just trying to get started with Ninject 2 and ASP.NET MVC 2. I have followed this tutorial http://www.craftyfella.com/2010/02/creating-aspnet-mvc-2-controller.html to create a Controller Factory with Ninject and to bind a first abstract to a concrete implementation. Now I want to load a repository type from another assembly (where my concrete SQL Repositories are located) and I just cant get it to work. Here's my code:
Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
}
Controller Factory:
public class Kernelhelper
{
public static IKernel GetTheKernel()
{
IKernel kernel = new StandardKernel();
kernel.Load(System.Reflection.Assembly.Load("MyAssembly"));
return kernel;
}
}
public class MyControllerFactory : DefaultControllerFactory
{
private IKernel kernel = Kernelhelper.GetTheKernel();
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)kernel.Get(controllerType);
}
}
In "MyAssembly" there is a Module:
public class ExampleConfigModule : NinjectModule
{
public override void Load()
{
Bind<Domain.CommunityUserRepository>().To<SQLCommunityUserRepository>();
}
}
Now when I just slap in a MockRepository object in my entry point it works just fine, the controller, which needs the repository, works fine. The kernel.Load(System.Reflection.Assembly.Load("MyAssembly")); also does its job and registers the module but as soon as I call on the controller which needs the repository I get an ActivationException from Ninject:
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency CommunityUserRepository into parameter _rep of constructor of type AccountController
1) Request for AccountController
Can anyone give me a best practice example for binding types from external assemblies (which really is an important aspect of Dependency Injection)? Thank you!
Ok, I did some refactoring and now I got it running. I'll post the code of my Global.asax since that's where everything happens. I'm using the latest Ninject 2 Build with the latest Ninject.Web.Mvc Build for MVC 2.
public class MvcApplication : NinjectHttpApplication
{
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 override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn(System.Reflection.Assembly.GetExecutingAssembly());
}
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(new ExampleConfigModule());
return kernel;
}
}
public class ExampleConfigModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
string connectionString =
ConfigurationManager.ConnectionStrings
["ConnectionString1"].ConnectionString;
string communityUserRepTypeName =
ConfigurationManager.AppSettings
["CommunityUserRepositoryType"];
var communityUserRepositoryType =
Type.GetType(communityUserRepTypeName, true);
Bind<Domain.CommunityUserRepository>().To(communityUserRepositoryType).WithConstructorArgument("conString",connectionString);
}
}
As you can see I got rid of my ControllerFactory, inherited from NinjectHttpApplication and load & bind the external assemblies' type in the Module. Now there might be a better way without specifiyng the type as a string in the config file, maybe you could declare the Module in the external assembly and let Ninject auto-load it from there but I still would need to pass the connection string down to the constructor of the concrete implementation. Maybe someone got an idea for this but for now this works fine.