I'm using ninject as my IoC and I wrote a role provider as follows:
public class BasicRoleProvider : RoleProvider
{
private IAuthenticationService authenticationService;
public BasicRoleProvider(IAuthenticationService authenticationService)
{
if (authenticationService == null) throw new ArgumentNullException("authenticationService");
this.authenticationService = authenticationService;
}
/* Other methods here */
}
I read that Provider classes get instantiated before ninject gets to inject the instance. How do I go around this? I currently have this ninject code:
Bind<RoleProvider>().To<BasicRoleProvider>().InRequestScope();
From this answer here.
If you mark your dependencies with [Inject] for your properties in your provider class, you can call kernel.Inject(MemberShip.Provider) - this will assign all dependencies to your properties.
I do not understand this.
I believe this aspect of the ASP.NET framework is very much config driven.
For your last comment, what they mean is that instead of relying on constructor injection (which occurs when the component is being created), you can use setter injection instead, e.g:
public class BasicRoleProvider : RoleProvider
{
public BasicRoleProvider() { }
[Inject]
public IMyService { get; set; }
}
It will automatically inject an instance of your registered type into the property. You can then make the call from your application:
public void Application_Start(object sender, EventArgs e)
{
var kernel = // create kernel instance.
kernel.Inject(Roles.Provider);
}
Assuming you have registered your role provider in the config. Registering the provider this way still allows great modularity, as your provider implementation and application are still very much decoupled.
Related
I have a custom ASP.NET MVC controller that retrieves operations from the user service. I want to pass the operations property to the scenario service using dependency injection.
public abstract class BaseController : Controller {
protected IUserService userService;
public OperationWrapper operations { get; private set; }
public BaseController(IUserService userService) {
this.userService = userService;
this.operations = userService.GetOperations(HttpContext.Current.User.Identity.Name);
}
}
public abstract class ScenarioController : BaseController {
protected IScenarioService scenarioService;
public ScenarioController(IScenarioService scenarioService, IUserService userService)
: base(userService) {
this.scenarioService = scenarioService;
}
}
public class ScenarioService : IScenarioService {
private OperationWrapper operations;
public ScenarioService(OperationWrapper operations) {
this.repo = repo;
this.operations = operations;
}
}
Here is my Windsor installer.
public class Installer : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.Register(Classes.FromThisAssembly()
.BasedOn<IController>());
container.Register(Classes.FromThisAssembly()
.Where(x => x.Name.EndsWith("Service"))
.WithService.DefaultInterfaces()
.LifestyleTransient());
}
}
I pretty sure I've done something similar with Ninject a couple of years back. What do I need to add to the installer in order to make this work? Is it even possible?
There are a few of options here:
1. Use LifeStylePerWebRequest() and UsingFactoryMethod()
First, you could register an OperationWrapper as LifestylePerWebRequest() and inject it into both the BaseController and ScenarioService. Windsor will let you register the dependency with a factory method for creating it, which can in turn call other services which have been registered.
container.Register(Component.For<OperationWrapper>()
.LifestylePerWebRequest()
.UsingFactoryMethod(kernel =>
{
var userService = kernel.Resolve<IUserService>();
try
{
return userService.GetOperations(
HttpContext.Current.User.Identity.Name);
}
finally
{
kernel.ReleaseComponent(userService);
}
}));
So, every time Windsor is asked for an OperationWrapper, it will run that call against an instance if IUserService, giving it the Name of the current User. By binding the lifestyle to LifestylePerWebRequest(), you can verify that each request will get its own instance of the OperationWrapper and it won't bleed across requests.
(The only edge case you'd run into is one where a user becomes authenticated mid-request and the OperationWrapper needs to be adjusted as a result. If that's a normal-path use case, this may need some re-thinking.)
Then, modify your base controller to take that registered object in as a dependency:
public abstract class BaseController : Controller {
protected IUserService userService;
protected OperationWrapper operations;
public BaseController(IUserService userService, OperationWrapper operations) {
this.userService = userService;
this.operations = operations;
}
}
2. Use Method Injection
It looks like OperationWrapper is some sort of context object, and those can sometimes be injected into the method instead of into the constructor.
For instance, if your method was:
int GetTransactionId() { /* use OperationWrapper property */ }
You could just modify the signature to look like:
int GetTransactionId(OperationWrapper operations) { /* use arg */ }
In this situation, it makes sense to use it if a small-ish subset of your service's methods use that dependency. If the majority (or totality) of methods need it, then you should probably go a different route.
3. Don't use DI for OperationWrapper at all
In situations where you have a highly-stateful contextual object (which it seems like your OperationWrapper is), it frequently just makes sense to have a property whose value gets passed around. Since the object is based on some current thread state and is accessible from everywhere in any subclassed Controller, it may be right to just keep the pattern you have.
If you can't answer the question "What am I unable to do with OperationWrapper now that DI is going to solve for me?" with anything but "use the pattern/container," this may be the option for this particular situation.
You should set dependency resolver in Application_Start method of global.asax
System.Web.MVC.DependencyResolver.SetResolver(your windsor resolver)
Create a class that inherits from DefaultControllerFactory. Something like this will do:
public class WindsorControllerFactory : DefaultControllerFactory
{
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(
404,
String.Format(
CultureInfo.CurrentCulture,
"The controller for path '{0}' was not found or does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
return (IController)_kernel.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
Kernel.ReleaseComponent(controller);
}
private readonly IKernel _kernel;
private IKernel Kernel
{
get { return _kernel; }
}
}
In the Application_Start method of your MvcApplication class add the following:
var container = new WindsorContainer();
container.Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(container.Kernel)
);
This should work with your existing installer and get you to the point where Windsor will start resolving your dependencies for you. You might have to fill-in a few gaps, but you'll get the point.
I've borrowed heavily from: https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md
Be wary of using IDependencyResolver as it doesn't make provision for releasing what's resolved.
I'm trying to use SimpleInjector 2.7.3 (IoC container) within an Asp.Net MVC + Web API application.
I've had a couple of problems trying to set it up for both MVC and Web API on the same project until I found this link:
http://methoddev.com/blg/let-s-talk-software/310/simple-injector-in-asp-net-mvc-webapi
After following the link's example, here's what I got:
One of my Web API controllers:
public class UserController : BaseApiController
{
private readonly IUserService service;
public UserController(IUserService userService)
{
// I should point that IUserService is being injected correctly here
this.service = userService;
}
public IHttpActionResult Post(CreateUserRequest request)
{
return Ok();
}
}
The problem happens when I try to execute the Post operation. The CreateUserRequest class itself has a dependency.
public class CreateUserRequest : IValidatableObject
{
private readonly IValidator<CreateUserRequest> validator;
public CreateUserRequest(IValidator<CreateUserRequest> _validator)
{
// _validator is not being injected, I'm getting null here
validator = _validator;
}
public string SomeProperty { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// My validation logic here must call the validator injected
// when the object was created.
return null;
}
}
I should point that IValidator is an interface from the FluentValidator package.
Anyway, when CreateUserRequest is instantiated the validator is null, which means it's not being injected.
When I'm creating the SimpleInjector Container I can see the type correctly registered, so I don't think that is a problem.
I did the following change to CreateUserRequest class:
public class CreateUserRequest : IValidatableObject
{
private readonly CreateUserRequestValidator validator;
// Changed here to the concrete class
public CreateUserRequest(CreateUserRequestValidator _validator)
{
validator = _validator;
}
// ...
}
So, I changed the interface to a concrete class and I'm still receiving a null there.
The only thing I can imagine is that this is somehow related to the custom dependency resolver suggested by the aforementioned link. I needed to use that in order to have the same dependency resolution logic for both MVC and Web API. Here's the code:
public class SimpleInjectorDependencyResolver : System.Web.Mvc.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyResolver,
System.Web.Http.Dependencies.IDependencyScope
{
public SimpleInjectorDependencyResolver(Container container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.Container = container;
}
public Container Container { get; private set; }
public object GetService(Type serviceType)
{
if (!serviceType.IsAbstract && typeof(IController).IsAssignableFrom(serviceType))
{
return this.Container.GetInstance(serviceType);
}
return ((IServiceProvider)this.Container).GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.Container.GetAllInstances(serviceType);
}
IDependencyScope System.Web.Http.Dependencies.IDependencyResolver.BeginScope()
{
return this;
}
object IDependencyScope.GetService(Type serviceType)
{
return ((IServiceProvider)this.Container).GetService(serviceType);
}
IEnumerable<object> IDependencyScope.GetServices(Type serviceType)
{
return this.Container.GetAllInstances(serviceType);
}
void IDisposable.Dispose()
{
}
}
I don't really know a lot of the plumbing behind MVC and Web API (specially the custom dependency resolver feature), so, I'm really stuck on this one.
I appreciate any help figuring that out. Thanks.
--UPDATE--
In addition to the answer given by Steven, I would like to leave a link to whoever falls into the same problem. It's a great resource:
https://brettedotnet.wordpress.com/2014/07/16/web-api-and-interface-parameters/
The reason why your view model object isn't auto-wired by Simple Injector is because both MVC and Web API don't build view model objects using the IDependencyResolver. So creating a special dependency resolver won't work. If you want to let your view models to be auto-wired, you will have to override the default model binder in MVC and Web API.
But I urge you not to do this. In my opinion, a model binder should just do data conversion and a view model should be a plain DTO. Although it is fine to mark view models with validation attributes, letting them have behavior using services that might even trigger any database communication is a big no-no in my book. This can complicate development tremendously.
This however means that this validator should be injected elsewhere. Without making any changes to your architecture, this basically means you will have to inject that validator in the controller instead:
public class UserController : BaseApiController
{
private readonly IUserService service;
private readonly IValidator<CreateUserRequest> validator;
public UserController(IUserService userService,
IValidator<CreateUserRequest> validator)
{
this.service = userService;
this.validator = validator;
}
}
Obviously this can easily complicate your controllers with extra dependencies and logic, but that's because validation is a cross-cutting concern that you would like to probably keep out of your controllers.
If you try to address this, you will eventually end up with a message passing architecture such as described here.
I'm using NInject with NInject.Web.Mvc.
To start with, I've created a simple test project in which I want an instance of IPostRepository to be shared between a controller and a custom model binder during the same web request. In my real project, I need this because I'm getting IEntityChangeTracker problems where I effectively have two repositories accessing the same object graph. So to keep my test project simple, I'm just trying to share a dummy repository.
The problem I'm having is that it works on the first request and that's it. The relevant code is below.
NInjectModule:
public class PostRepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IPostRepository>().To<PostRepository>().InRequestScope();
}
}
CustomModelBinder:
public class CustomModelBinder : DefaultModelBinder
{
[Inject]
public IPostRepository repository { get; set; }
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
repository.Add("Model binder...");
return base.BindModel(controllerContext, bindingContext);
}
}
public class HomeController : Controller
{
private IPostRepository repository;
public HomeController(IPostRepository repository)
{
this.repository = repository;
}
public ActionResult Index(string whatever)
{
repository.Add("Action...");
return View(repository.GetList());
}
}
Global.asax:
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(string), kernel.Get<CustomModelBinder>());
}
Doing it this way is actually creating 2 separate instances of IPostRepository rather than the shared instance. There's something here that I'm missing with regards to injecting a dependency into my model binder. My code above is based on the first setup method described in the NInject.Web.Mvc wiki but I have tried both.
When I did use the second method, IPostRepository would be shared only for the very first web request, after which it would default to not sharing the instance. However, when I did get that working, I was using the default DependencyResolver as I couldn't for the life of me figure out how to do the same with NInject (being as the kernel is tucked away in the NInjectMVC3 class). I did that like so:
ModelBinders.Binders.Add(typeof(string),
DependencyResolver.Current.GetService<CustomModelBinder>());
I suspect the reason this worked the first time only is because this isn't resolving it via NInject, so the lifecycle is really being handled by MVC directly (although that means I have no idea how it's resolving the dependency).
So how do I go about properly registering my model binder and getting NInject to inject the dependency?
The ModelBinders are reused by MVC for multiple requests. This means they have a longer lifecycle than request scope and therefore aren't allowed to depend on objects with the shorter request scope life cycle.
Use a Factory instead to create the IPostRepository for every execution of BindModel
It's actually really simple to get the Ninject factory extension up and running, but that wasn't clear to me from the existing answers.
The factory extensions plugin is a prerequisite, which can be installed via NUGet:
Install-Package Ninject.Extensions.Factory
You just need the factory injected into your model binder somewhere, eg:
private IPostRepositoryFactory _factory;
public CustomModelBinder(IPostRepositoryFactory factory) {
_factory = factory;
}
Then create an interface for the factory. The name of the factory and the name of the method doesn't actually matter at all, just the return type. (Good to know if you want to inject an NHibernate session but don't want to have to worry about referencing the correct namespace for ISessionFactory, also useful to know if GetCurrentRepository makes what it actually does more clear in context):
public interface IPostRepositoryFactory {
IPostRepository CreatePostRepository();
}
Then, assuming your IPostRepository is already being managed by Ninject correctly, the extension will do everything else for you just by calling the .ToFactory() method.
kernel.Bind<IPostRepository().To<PostRepository>();
kernel.Bind<IPostRepositoryFactory>().ToFactory();
Then you just call your factory method in the code where you need it:
var repo = _factory.CreatePostRepository();
repo.DoStuff();
(Update: Apparently naming your factory function GetXXX will actually fail if the service doesn't already exist in the session. So you do actually have to be somewhat careful with what you name the method.)
I eventually managed to solve it with a factory as suggested. However, I just could not figure out how to accomplish this with Ninject.Extensions.Factory which is what I would've preferred. Here is what I ended up with:
The factory interface:
public interface IPostRepositoryFactory
{
IPostRepository CreatePostRepository();
}
The factory implementation:
public class PostRepositoryFactory : IPostRepositoryFactory
{
private readonly string key = "PostRepository";
public IPostRepository CreatePostRepository()
{
IPostRepository repository;
if (HttpContext.Current.Items[key] == null)
{
repository = new PostRepository();
HttpContext.Current.Items.Add(key, repository);
}
else
{
repository = HttpContext.Current.Items[key] as PostRepository;
}
return repository;
}
}
The Ninject module for the factory:
public class PostRepositoryFactoryModule : NinjectModule
{
public override void Load()
{
this.Bind<IPostRepositoryFactory>().To<PostRepositoryFactory>();
}
}
The custom model binder:
public class CustomModelBinder : DefaultModelBinder
{
private IPostRepositoryFactory factory;
public CustomModelBinder(IPostRepositoryFactory factory)
{
this.factory = factory;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
IPostRepository repository = factory.CreatePostRepository();
repository.Add("Model binder");
return base.BindModel(controllerContext, bindingContext);
}
}
The controller:
public class HomeController : Controller
{
private IPostRepository repository;
public HomeController(IPostRepositoryFactory factory)
{
this.repository = factory.CreatePostRepository();
}
public ActionResult Index(string whatever)
{
repository.Add("Action method");
return View(repository.GetList());
}
}
Global.asax to wire up the custom model binder:
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(string), kernel.Get<CustomModelBinder>());
}
Which in my view, gave me the desired output of:
Model binder
Action method
I'm trying to use the [Inject] attribute on a BasicRoleProvider : RoleProvider provider.
In my provider, I did:
public class BasicRoleProvider : RoleProvider
{
[Inject]
private IAuthenticationService authenticationService;
/*Other stuff here*/
}
My Global.asax.cs file is as follows:
public class MvcApplication : NinjectHttpApplication
{
/* Other stuff here */
#region Inversion of Control
protected override IKernel CreateKernel()
{
return Container;
}
static IKernel _container;
public static IKernel Container
{
get
{
if (_container == null)
{
_container = new StandardKernel(new SiteModule());
}
return _container;
}
}
internal class SiteModule : NinjectModule
{
public override void Load()
{
//Set up ninject bindings here.
Bind<IAuthenticationService>().To<AuthenticationService>();
this.Kernel.Inject(Roles.Provider);
}
}
#endregion
}
Whenever a method in the BasicRoleProvider gets executed and is using the authenticationService, its null. I think my problem lies in the Global.ascx.cs file. Am I doing the injection right?
It seems possible that you are using Ninject in an unsupported way.
From https://github.com/ninject/ninject/wiki/Changes-in-Ninject-2
Things that were in Ninject 1.x that are not in Ninject 2:
Field injection: This is a bad
practice, and has been cut for
minimization.
Because you tagged your question MVC 3, I assume you are linking to Ninject 2. As far as I know, Ninject 1 in an MVC 3 app would be a dead end.
The Inject attribute still exists, and fields must still be a valid target for it, which is why you do not get a compile time error.
But Ninject 2 will happily ignore that Inject attribute on the fields, which is why it is null for you.
I'm using the Ninject.Web.Mvc (the MVC 2 version) add-on with ASP.NET MVC 2. This is an excerpt of my Global.asax.cs:
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes;
// RegisterAllControllersIn() is not available in the MVC 2 version of Ninject
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<IRepository>().To<NHibernateRepository>();
return kernel;
}
I also have a base RepositoryController:
public class RepositoryController : Controller
{
protected IRepository Repository { get; set; }
public RepositoryController()
{
}
public RepositoryController(IRepository repository)
{
Repository = repository;
}
}
So as you can see, it's a very simple setup where RepositoryController expects to be injected with an instance of an IRepository, and Ninject is configured to use a concrete instance of NHibernateRepository. However, this doesn't work and the Repository property is null whenever I try to access it in a controller. However, if I change the code to this instead:
[Inject]
public IRepository Repository { get; set; }
Then it works fine. Does anyone know why constructor injection isn't working, but property injection is?
Try removing the parameterless constructor.
Ninject might be picking the wrong constructor to resolve.
To test it out, you could put a breakpoint in both constructors and see which one fires, but I have a feeling it's the parameterless one.