I have the following NinjectModule, where we bind our repositories and business objects:
/// <summary>
/// Used by Ninject to bind interface contracts to concrete types.
/// </summary>
public class ServiceModule : NinjectModule
{
/// <summary>
/// Loads this instance.
/// </summary>
public override void Load()
{
//bindings here.
//Bind<IMyInterface>().To<MyImplementation>();
Bind<IUserRepository>().To<SqlUserRepository>();
Bind<IHomeRepository>().To<SqlHomeRepository>();
Bind<IPhotoRepository>().To<SqlPhotoRepository>();
//and so on
//business objects
Bind<IUser>().To<Data.User>();
Bind<IHome>().To<Data.Home>();
Bind<IPhoto>().To<Data.Photo>();
//and so on
}
}
And here are the relevant overrides from our Global.asax, where we inherit from NinjectHttpApplication in order to integrate it with Asp.Net Mvc (The module lies in a separate dll called Thing.Web.Configuration):
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
//routes and areas
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//Initializes a singleton that must reference this HttpApplication class,
//in order to provide the Ninject Kernel to the rest of Thing.Web. This
//is necessary because there are a few instances (currently Membership)
//that require manual dependency injection.
NinjectKernel.Instance = new NinjectKernel(this);
//view model factory.
NinjectKernel.Instance.Kernel.Bind<IModelFactory>().To<MasterModelFactory>();
}
protected override NinjectControllerFactory CreateControllerFactory()
{
return base.CreateControllerFactory();
}
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load("Thing.Web.Configuration.dll");
return kernel;
}
Now, everything works great, with one exception: For some reason, sometimes Ninject will bind the PhotoController twice. This leads to an ActivationException, because Ninject can't discern which PhotoController I want. This causes all requests for thumbnails and other user images on the site to fail.
Here is the PhotoController in it's entirety:
public class PhotoController : Controller
{
public PhotoController()
{
}
public ActionResult Index(string id)
{
var dir = Server.MapPath("~/" + ConfigurationManager.AppSettings["UserPhotos"]);
var path = Path.Combine(dir, id);
return base.File(path, "image/jpeg");
}
}
Every controller works in exactly the same way, but for some reason the PhotoController gets double-bound. Even then, it only happens occasionally (either when re-building the solution, or on staging/production when the app pool kicks in). Once this happens, it continues to happen until I redeploy without changing anything.
So...what's up with that?
As noted in the comments of your answer to another similar question, this was a race condition bug in Ninject 2.0, which was fixed in version 2.2. I can't find any release notes for Ninject, but it solved this exact problem for me.
Related
I'm developing ASP.NET MVC 5 app. I need to use parameters in controller's constructor. DefaultControllerFactory can't resolve it and i inherited from it my own ControllerFactory:
public class ControllerFactoryProvider : DefaultControllerFactory
{
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
string controllerType = string.Empty;
IController controller = null;
// Read Controller Class & Assembly Name from Web.Config
controllerType = ConfigurationManager.AppSettings[controllerName];
if (controllerType == null)
throw new ConfigurationErrorsException("Assembly not configured for controller " + controllerName);
// Create Controller Instance
IDataTransmitter _dataTransmitter = new DataTransmitter();
controller = Activator.CreateInstance(Type.GetType(controllerType), _dataTransmitter) as IController;
return controller;
}
public void ReleaseController(IController controller)
{
//This is a sample implementation
//If pooling is used to write code to return the object to pool
if (controller is IDisposable)
{
(controller as IDisposable).Dispose();
}
controller = null;
}
}
I registered it in Global.asax:
ControllerBuilder.Current.SetControllerFactory(new
ControllerFactoryProvider());
But when i run my app it whatever use DefaultControllerFactory didn't see constructor with parameters.
Where can i have an error?
As I said in the comments, there is no need to override your controller factory. You just need to plug in your preferred dependency injection container.
I haven't had the opportunity to work with every dependency injection containers for .net but I'll try to give an objective answer.
Ninject
To set up Ninject in an asp.net Mvc 5 project is very straight forward.
Installing the nuget package
There's a very handy nuget package called Ninject.MVC5.
You can install it:
Using the manage nuget packages dialogue, or
By running Install-Package Ninject.MVC5 in the package manager console.
After installing Ninject.MVC5 you will see a new file in your solution in App_Start/ called NinjectWebCommon.cs. Here you can see what the contents of that file will end up being.
Wiring up your dependencies
Now that the package is installed you want to register your denpencies using ninject's api.
Let's say you have an IFoo interface and its implementation Foo
public interface IFoo
{
int Bar()
}
public class Foo : IFoo
{
public int Bar()
{
throw new NotImplementedException();
}
}
In your NinjectWebCommon class you're going to tell ninject how to resolve an IFoo interface:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFoo>().To<Foo>();
}
Keep in mind that by default Ninject has implicit self binding of concrete types, that means that
If the type you’re resolving is a concrete type (like Foo above), Ninject will automatically create a default association via a mechanism called implicit self binding. It’s as if there’s a registration like this:
Bind<Foo>().To<Foo>();
I've read and Googled everything on this, but can't seem to get it to work. I created a custom LifetimeManager for Unity in my MVC5 application based on these posts:
MVC3 Unity Framework and Per Session Lifetime Manager
This may be the issue I am experiencing
Here is my SessionLifetimeManager
public class SessionLifetimeManager : LifetimeManager
{
private string key = Guid.NewGuid().ToString();
public override object GetValue()
{
return HttpContext.Current.Session[key];
}
public override void RemoveValue()
{
HttpContext.Current.Session.Remove(key);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Session[key] = newValue;
}
}
I only have a few types I'm playing with, here is the relevant registrations in UnityConfig.cs:
container.RegisterType<IEpiSession, EpiSession>(new SessionLifetimeManager(),
new InjectionConstructor(config.AppServerURI, config.PathToSysConfig));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Note that the EpicorReportRepository has a dependency on IEpiSession via constructor injection.
public class EpicorReportRepository : IReportRepository
{
private IEpiSession session;
// DI constructor
public EpicorReportRepository(IEpiSession session) {
this.session = session;
}
// ...
}
My Problem: After the first user / session connects to the application, every new user / session after that seems to still be using the EpiSession object and credentials that the first user had create/injected for him. This seems to be a common pattern used on the interwebs, so I'm wondering what I am missing.
How did you test that IEpiSession is the same in different Sessions?
Try to open you application from different browsers. If you open several tabs in the same browser then the same session is used.
I checked your code and it works for me.
There is the only one difference in SetResolver():
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
The full registration code is the following:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
var container = new UnityContainer();
container.RegisterType<IEpiSession, EpiSession>(
new SessionLifetimeManager(),
new InjectionConstructor("config.AppServerURI", "config.PathToSysConfig"));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
}
}
I have Unity running great for all the controllers in my ASP.NET Web API project - just using the default set up that comes out of the NuGet box. I have also managed to hook it up to MVC Filter Attributes - but can't seem to do the same for ASP.NET Web API filter attributes.
How to I extend this default implementation to inject a dependency into an ActionFilterAttribute, for example...
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
[Dependency]
public IMyService myService { get; set; }
public BasicAuthenticationAttribute()
{
}
}
This filter is applied to controllers using attributes:
[BasicAuthentication]
I'm pretty sure I need to hook up the Unity container so it handles the creation of the attribute class, but need some clues about where to start as it does not use the same extensibility points as the MVC filters.
I just wanted to add, other things I have tried include service location rather than dependency injection, but the DependencyResolver you get back is not the same one you configure.
// null
var service = actionContext.Request.GetDependencyScope().GetService(typeof(IMyService));
Or
// null
var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IApiUserService));
The problem is that the Attribute class is created by .NET and not by the WebAPI framework.
Before reading farther, did you forget to configure your DependencyResolver with your IApiUserService?
(IUnityContainer)container;
container.RegisterType<IApiUserService, MyApiUserServiceImpl>();
...
var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IApiUserService));
I created an App_Start\UnityConfig class that holds my UnityContainer:
public class UnityConfig {
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() => {
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer() {
return container.Value;
}
#endregion
public static void Configure(HttpConfiguration config) {
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
}
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
private static void RegisterTypes(IUnityContainer container) {
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<MyClass>(new PerRequestLifetimeManager(), new InjectionConstructor("connectionStringName"));
}
}
The UnityDependencyResolver and PerRequestLifetimeManager came from this blog post and Unity.WebApi (Project/Nuget Package) which I internalized. (since it's a bootstrap)
When I need to make use of the UnityContainer in my other code, I passed it into the constructor:
config.Filters.Add(new MyFilterAttribute(UnityConfig.GetConfiguredContainer()));
I am following "ASP.Net MVC 3" by Steven Sanderson and Adam Freeman, and at one point they define ControllerFactory. The exposed interface is for creating controllers, and what is injected into them (like classes providing data) is black box (for outside world).
I am at the point, that I don't really want to get any controller, but the binding set for controller -- namely class providing data.
I could add another method for controller factory (like GetBinding) and it would work, but would it be the right way to do it?
Just to focus on something. I have IDataProvider and two classes -- MockupProvider and ProviderForReal. I would like to set it once, that for now whenever I need IDataProvider I will get MockupProvider. This is set up (by me) in controller factory.
And I would like to retrieve what I set up in most elegant way, so I won't bind again interface-class again. Is adding such method -- GetBinding -- to controller factor a good pattern?
I am not constructing the controller, I need binding controllers use.
In other words...
There is controller factory. Inside there are defined some bindings. I have to use retrieve them (binding, not controller). Technically I could do this in several ways:
take a look at the code, look at specific binding, and use the the bound type (hardcoding it) somewhere else
add public method to controller factory GetBinding
...?
What is the right way?
Update
My controller factory:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninject_kernel;
public NinjectControllerFactory()
{
ninject_kernel = new StandardKernel();
AddBindings();
}
private void AddBindings()
{
ninject_kernel.Bind<IBookRepository>().To<DataManagement.Concrete.EFBookRepository>();
// ninject_kernel.Bind<IBookRepository>().ToConstant(DataManagement.Mocks.Mocks.BookRepository);
}
public T GetBinding<T>()
{
return ninject_kernel.Get<T>();
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
else
return (IController)ninject_kernel.Get(controllerType);
}
}
I'm trying to answer your questions following the comments. If it won't be suitable for you I'm prepared to delete it.
So in my ASP.NET MVC applications I'm using ninject and its mvc extension to inject dependencies to my controllers (and underlying services and repositories).
Global.asax
public class MvcApplication : Ninject.Web.Mvc.NinjectHttpApplication
{
/// this is here only to see that NinjectHttpApplication uses its own ControllerFactory, which is supposed to create your controllers with dependencies injected
protected override Ninject.Web.Mvc.NinjectControllerFactory CreateControllerFactory()
{
return base.CreateControllerFactory();
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
// here you can configure your bindings according to actual requirements
kernel.Bind<IDataProvider>().To<ProviderForReal>().InRequestScope();
kernel.Bind<IDataService>().To<RealDataService().InRequestScope();
return kernel;
}
}
Controller
public class MyController : Controller
{
private readonly IDataProvider dataService;
// i will get injected an IDataProvider according to my actual configuration
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
IDataService
public class RealDataService: IDataService{
private readonly IDataProvider dataProvider;
public RealDataService(IDataProvider dataProvider){
this.dataProvider = dataProvider;
}
}
Update
You do not need to write your own controller factory. In the code above I have put my override of CreateControllerFactory method only to show that Ninject.Web.Mvc.NinjectHttpApplication implicitly overrides this method and uses its own NinjectControllerFactory implmentation which will resolve dependencies for you (even if that dependencies are indirect - as you can see in my updated code => Ninject will resolve it for you because it will see that MyController needs IDataService and will look into bindings and will see that there is binding to RealDataService, but it has only constructor with dependency on IDataProvider. So it will look again to bindings and will see that IDataProvider is bound to ProviderForReal than it will create ProviderForReal inject it to ReadDataService and than RealDataService to MyController).
I am attempting to redesign an existing application using dependency injection with Ninject in MVC3. Here is a portion of the legacy behavior I'm having difficulty with (and yes I know its bad, that's why I'm trying to refactor it):
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
MyUserSession userSession = filterContext.HttpContext.Session[SESSIONKEY_USER] as MyUserSession;
// if session empty, rebuild user information
if (userSession == null)
{
string userName = HttpContext.User.Identity.Name;
userSession = new MyUserSession();
using (ADSearcher ad = new ADSearcher(ldapPath, excludeOUString.Split(',')))
{
// get basic user information from Active Directory
ADUserInfo aduser = MyActiveDirectorySearcher.GetUserRecord(userName);
// ... set several properties queries from AD...
userSession.propertyXYZ = aduser.propXYZ
}
// if user can proxy as another indivudual, set property
using (EDMContainer db = new EDMContainer())
{
if (db.Proxies.Any(p => p.ProxyLogin == userSession.userLogin))
userSession.CanProxy == true;
}
// save new user object to session
filterContext.HttpContext.Session[SESSIONKEY_USER] = userSession;
if(userSession.canProxy)
filterContext.Result = RedirectToAction("Proxy", "Home");
return;
}
}
So currently, the controller users several objects directly: Session, ActiveDirectorySearch, EF Database. I understand it would be better to create a class that exposes a single method "GetUser" masking all the complexity but I'm struggling with how to inject the dependencies.
If I create a class SomeUserProvider, it will also need access to the Session to check for existing user information, and then ActiveDirectorySearcher and Database to rebuild the user properties if session was empty.
My confusion is over the fact that the controller itself will need access to ActiveDirectorySearcher in other action methods and then other classes will also use the same database. Do I inject an IActiveDirSearchrer into the controller's constructor and then pass it down into the ISomeUserProvider? What about IMyDatabase? Is it also injected in controller constructor and passed down?
And last but not lease, ISessionWrapper? I know session is controversial, but I need to track who the current user is and who they are proxied as during each request (GETs and POSTs). So, does that get injected as well?
If the answer is yes to each of those, is it bad to have 3+ injected contstuctor parameters?
I realize my question may be vague, so please ask for clarification where needed. I am open to any and all suggestions and recommendations. My goal is to learn how to do it correctly.
Thanks.
I'm not certain if this is exactly what you're looking for, but this should get you started down the path of refactoring your app for DI
public class YourController : Controller
{
private readonly ISessionWrapper _sessionWrapper;
private readonly IActiveDirSearcher _adSearcher;
private readonly IMyDatabase _database;
public YourController(ISessionWrapper sessionWrapper,
IActiveDirSearcher adSearcher, IMyDatabase database)
{
this._sessionWrapper = sessionWrapper;
this._adSearcher = adSearcher;
this._database = database;
}
// now all actions in this controller have a _sessionWrapper,
// _adSearcher and _database
}
Then you have to bind your injections the Ninject way. Subclass your application from NinjectHttpApplication and override OnApplicationStarted and CreateKernel
public class MvcApplication : NinjectHttpApplication
{
// ...
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<ISessionWrapper>().To<YourSessionWrapperImplementation>();
kernel.Bind<IActiveDirSearcher>().To<YourADImplementation>();
kernel.Bind<IMyDataBase>().To<YourEDMContainerIThink>();
return kernel;
}
}
The implementations of these appear to be described in your question. However, you mentioned other actions (and other classes) depend on these implementations. Good news--the bindings in CreateKernel will take care of any missing dependencies elsewhere in your app. e.g.
public class MyActiveDirImplementation : IActiveDirSearcher
{
private readonly IMyDatabase _database;
// injected automagically WOOHOO!
public MyActiveDirImplementation(IMyDatabase database)
{
this._database = database;
}
public ADUserInfo GetUserRecord(string username)
{
return _database.GetSomeUserRecord(username);
}
}
You could, of course, similarly implement your ISessionWrapper or IMyDatabase