If I have multiple implementations of the same interface eg: IRule, how would I be able to resolve it in my controller?
private readonly IRule[] _rules;
public HomeController(IRule[] rules)
{
_rules = rules;
}
public RunRules()
{
foreach (IRule rule in rules)
rule.RunRule();
}
I ran into an issue where I wanted to set up my controller to pull in a collection of rules, but didn't want to list each rule by itself so I had an array of IRule[] that I set up.
Controller:
private readonly IRule[] _rules;
public HomeController(IRule[] rules)
{
_rules = rules;
}
Installer:
Set up castle windsor installer.
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IRule>().ImplementedBy<ValidateNPIRule>());
container.Register(Component.For<IRule>().ImplementedBy<ValidateZipRule>());
}
The important part was the line to .AddSubResolver
Adding in the CollectionResolver was what I needed for the installer to resolve all of my rules at once and I could pull them in an array.
Global.asax:
protected void Application_Start()
{
WindsorContainer container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true));
container.Install(FromAssembly.This());
}
Related
I am hoping someone can tell me what is wrong with my implementation of Castle Windsor. I have followed the tutorial Here. I have added a second installer that looks like this:
public class DataInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//breakpoint on the line below is hit when the application starts.
container.Register(Component.For<IDataProvider>().ImplementedBy<MyDataProvider>());
}
}
My controller looks like this:
public IDataProvider Provider { get; set; }
public JsonResult Get()
{
//Provider is always null!!!
var data = Provider.Retrieve(a => true).ToArray();
//convert to JSON and return.
}
Why is my provider always null? My second installer is being hit when the application fires up, because it hits a breakpoint, but from what I can tell the rest of the application just ignores this.
Contents of my global.asax.cs
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
BootstrapContainer();
}
private static void BootstrapContainer()
{
container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
//container.Register(Component.For<IDataProvider>().ImplementedBy<MyDataProvider>().LifestyleSingleton());
}
I tried what the person did in this question, but that still resulted in the same problem. What am I missing here?
Edit: Someone asked if I registered the controller. The tutorial had me create the following class. I believe this would be registering the controllers?
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());
}
}
I'm trying to use Castle Windsor to reuse a single instance of my WebApp settings class (MySettings).
This settings rarely changes, but when it changes, I need to update the instance in the container.
I can easily track when the Settings changes, but I can't figure out the right way to do it, can anybody help me?
The Windsor Installer class is bellow:
public class SettingsInstaller : IWindsorInstaller
{
private MySettings Settings { get; set; }
public void Install(IWindsorContainer container, IConfigurationStore store)
{
UpdateSettings();
container.Register(
Component.For<MySettings>()
.Instance(this.Settings));
}
public MySettings UpdateSettings()
{
using (DbContext db = new DbContext())
{
this.Settings = db.Settings.FirstOrDefault();
}
return this.Settings;
}
}
How can I call the UpdateSettings() and make sure that the container will use the updated Settings in the next Dependency Injection resolution?
I think what you want is for MySettings to be a singleton whose state you can then update in other parts of the application. If you register MySettings as a singleton, then whenever the container resolves a MySettings for you, it will return the same instance. This is essentially what you are doing in your answer, but you're just storing the instance in a local variable (instead of letting the container do it for you).
Your registration code can then get very simple:
public class SettingsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<MySettings>().LifestyleSingleton());
}
}
Whenever you need to access the settings, you can request a MySettings from the container using constructor injection (or any other method of getting an instance from a container):
public class ClientClass
{
private readonly MySettings _settings;
public ClientClass(MySettings settings)
{
_settings = settings;
}
public void UpdateSettings()
{
_settings.SomeSetting = myNewSetting; // reset them however you need to here
}
}
After you've called UpdateSettings() in your application somewhere, then the instance the container is holding on to (a singleton) will be updated with myNewSetting, and when the next class requests a MySettings you'll get the same instance with the updated value.
If you actually need a new instance of MySettings, then in your UpdateSettions() method you can create an entirely new one using
_settings = new MySettings() and the container will serve up the new instance for you from then on.
I had no answer yet. I have done this, and it is working:
public class SettingsInstaller : IWindsorInstaller
{
private static MySettings Settings { get; set; }
public void Install(IWindsorContainer container, IConfigurationStore store)
{
UpdateSettings();
container.Register(
Component.For<MySettings>()
.UsingFactoryMethod(() =>
{
return SettingsInstaller.Settings;
})
.LifestyleTransient());
}
public static MySettings UpdateSettings()
{
using (DbContext db = new DbContext())
{
SettingsInstaller.Settings = db.Settings
.AsNoTracking()
.FirstOrDefault();
}
return SettingsInstaller.Settings;
}
}
CCI am writing a facade to get data from different sources, normalize, and format it. I am new to using asp.net 5 and giving dependency injection a go but I am having an issue. I want to know how to resolve dependencies based on runtime input. Based on the route I want to instantiate the correct repository. For instance if I get passed Toyota I have want to instantiate a ToyotaRepository, if I get passed Ford I want to instantiate a FordRepository. Those repositories also have dependencies that are unique to each repository. All the repositories share the same ICarRepository Interface, and depend on the same interfaces but different concrete implementations. I thought about using a factory to create the repositories but then the dependencies of each repository would have to be injected into the factory, and that just doesn't feel right. As the number of repositories grow so with the number of dependencies that will need to be injected. Currently I am just newing up the repositories and their dependencies in the factory which also feels wrong, not very SOLID. Maybe there is an issue with my architecture?
[Route("api/v1/[controller]")]
public class CarsController : Controller
{
private IDataFormatter<Product> _formatter;
private ILogger _logger;
private ICarRepositoryFactory _repositoryFactory;
public CarssController(ILogger<CarsController> logger, IProductRepositoryFactory repositoryFactory, IDataFormatter<Car> formatter)
{
_logger = logger;
_repositoryFactory = repositoryFactory;
_formatter = formatter;
}
[HttpGet("{carType}")]
public async Task<IEnumerable<Car>> GetCars(string carType)
{
var repository = _repositoryFactory.Create(carType);
var cars = await repository.GetAll();
foreach(var car in cars)
{
_formatter.Format(car);
}
return cars;
}
}
public class CarRepositoryFacotry : ICarRepositoryFactory
{
private Dictionary<string, Func<ICarRepository>> _carRepositories = new Dictionary<string, Func<ICarRepository>>();
private ILogger<ICarRepository> _logger;
private IOptions<WebOptions> _webOptions;
private IOptions<DisplayInfoOptions> _displayOptions;
public CarRepositoryFacotry(ILogger<ICarRepository> logger, IOptions<WebOptions> webOptions, IOptions<DisplayInfoOptions> displayInfoOptions)
{
_logger = logger;
_webOptions = webOptions;
_displayInfoOptions = displayInfoOptions;
_carRepositories.Add("toyota", () => new ToyotaRepository(_logger, new DisplayInfoRepository(_displayInfoOptions), new ToyotaMapper(), _options));
_carRepositories.Add("ford", () => new FordRepository(_logger, new DisplayInfoRepository(_displayInfoOptions), new FordMapper(), _options));
}
public ICarRepository Create(string carType)
{
Func<ICarRepository> repo;
_carRepositories.TryGetValue(carType, out repo);
return repo.Invoke();
}
}
I am currently using the builtin dependency framework in asp.net 5 but Im willing to use autofac if it makes things eaisier. Any help or comments would be a big help.
Using factory with all repositories injected is feasible approach ( and much better than temporary "new-ing" dependencies )
example
public interface IVehicleRepository
{
bool CanHandle(string vendor); // example how to deal with choosing appropriate repository
IEnumerable<Vehicle> GetAll();
}
public class VehicleFactory
{
private readonly IVehicleRepository[] repositories;
public VehicleFactory(IVehicleRepository[] repositories)
{
this.repositories = repositories;
}
public IVehicleRepository Create(string vendor) {
return repositories.Single(r => r.CanHandle(vendor));
}
}
usage:
[Route("api/v1/[controller]")]
public class CarController : Controller
{
private readonly VehicleFactory factory;
public CarController(VehicleFactory factory)
{
this.factory = factory;
}
[HttpGet("{vehicleType}")]
public IEnumerable<Vehicle> GetVehicles(string vehicleType)
{
var repository = factory.Create(vehicleType);
var vehicles = repository.GetAll();
foreach (var vehicle in vehicles)
{
// Process(vehicle)
}
return vehicles;
}
}
I see it in that way:
Your CarsController take ICarRepository as a constructor parameter
and work with it
You have to wright and register your own
IControllerFactory which will analyze route parameters and create
concrete instance of Controller with concrete repository
First link at Google. May be not the best, but good.
http://www.codeproject.com/Articles/560798/ASP-NET-MVC-Controller-Dependency-Injection-for-Be
My team uses Castle Windsor, an IoC container that can resolve all our dependencies with ease. (Should be similar to Autofac, but I've seen Castle Windsor more often in enterprise apps)
In your case, you can
1. Register FordRepository like this:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.FromThisAssembly(),
Component.For<DisplayInfoRepository>().ImplementedBy<DisplayInfoRepository>
.DependsOn(Dependency.OnValue("_displayInfoOptions", displayInfoOptionsObject)),
// whatever property name you have in DisplayInfoRepository
Component.For<ICarRepository>().ImplementedBy<FordRepository>().Named("Ford")
.DependsOn(Dependency.OnComponent(typeof(Logger), nameof("Logger")))
.DependsOn(Dependency.OnComponent(typeof(DisplayInfoRepository), nameof(DisplayInfoRepository)))
.DependsOn(Dependency.OnComponent(typeof(FordMapper), nameof(FordMapper)))
.DependsOn(Dependency.OnValue("_option", optionObject)),
// what ever property name you have in FordRepository
);
}
}
2. Start up the container:
// application starts...
var container = new WindsorContainer();
container.Install(FromAssembly.This());
// clean up, application exits
container.Dispose();
3. Get your car repositories based on strings like this
var carRepo = container.Resolve<ICarRepository>("Ford");
Let me know if any questions! Upvotes are greatly appreciated!
I'm trying to setup Castle Windsor for the first time and I'm having some problems with it. I have three projects in my solution:
Domain
DAL
Web
The services are located in DAL. They all inherit from IService. (UserService implements IUserService, IUserService implements IService). The web application is an MVC 5 application. All Controllers inherit from BaseController.
I used this post to help me setup Windsor but I keep getting the exception:
An exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll but was not handled in user code
Additional information: No component for supporting the service Solution.Web.Controllers.HomeController was found
The strange thing is that the path for the controller is correct.
Below is my code for the configuration:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.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);
}
}
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(BaseController))
.LifestyleTransient());
}
}
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Types.FromAssemblyContaining(typeof(IService).GetType())
.BasedOn<IService>().WithService.FromInterface()
.LifestyleTransient()
);
}
}
And in the Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
private static IWindsorContainer container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// Setup Castle.Windsor IOC
MvcApplication.BootstrapContainer();
}
protected void Application_End()
{
container.Dispose();
}
private static void BootstrapContainer()
{
container = new WindsorContainer().Install(FromAssembly.This());
container.Install(FromAssembly.Containing(typeof(IService).GetType()));
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
}
Any help or guidance in the right direction is greatly appreciated!
I'm assuming it's blowing up here:
return (IController)kernel.Resolve(controllerType);
What you're asking castle to do here in English is "give me the component that implements a service defined by controllerType".
The problem comes in your registration of your controllers.
container.Register(
Types.FromThisAssembly()
.BasedOn(typeof(BaseController))
.WithServices(typeof(BaseController))
.LifestyleTransient());
In this block you are telling castle to register all of your types that implement BaseController and the services they are exposing is also BaseController.
So castle is looking for a component that satisfies the service HomeController and can't find anything because the only service you've got is BaseController.
Long story short, if you remove
.WithServices(typeof(BaseController))
Castle will assume that each of your controllers is a service and then you can ask for components that implement your controller in the way that you want.
As a separate note, for clarity I'd change Types.FromThisAssembly() to Classes.FromThisAssembly() because you are only looking for classes, not stucts/classes/interfaces, etc that Types will scan for.
I made it work. Apperantly the problem was that my services didn't get registered. I changed the ServiceInstaller and the registration in Global.asax.
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromAssemblyContaining<BaseService>()
.BasedOn(typeof(IService))
.WithService.AllInterfaces()
.LifestyleTransient());
}
}
private static void BootstrapContainer()
{
container = new WindsorContainer();
container.Install(new ServiceInstaller());
container.Install(new ControllersInstaller());
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
I decided to clean this post up and I posted a sample project at ge.tt/3EwoZEd/v/0?c
Spent around 30 hours on this already and still can't figure it out... help would be really appreciated!
I have an ASP.NET Web API solution that uses this code: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/ to implement "Basic HTTP authentication in ASP.NET Web API using Message Handlers". I'm new to IoC/DI and I'm trying to get this to work with Castle Windsor.
I've been trying a lot of different things but I get 1 of the following errors depending on what I did wrong:
"Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule"
"Object reference not set to an instance of an object." for the PrincipalProvider in BasicAuthMessageHandler
"No component for supporting the service *.DummyPrincipalProvider was found"
Below is my code:
Global.asax.cs:
private static IWindsorContainer _container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var config = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
IncludeErrorDetailPolicy errorDetailPolicy;
switch (config.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();
}
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = errorDetailPolicy;
ConfigureWindsor(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler()
{
PrincipalProvider = _container.Resolve<IProvidePrincipal>()
});
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
// Create / Initialize the container
_container = new WindsorContainer();
// Find our IWindsorInstallers from this Assembly and optionally from our DI assembly which is in abother project.
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
//Documentation http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx
// Set the WebAPI DependencyResolver to our new WindsorDependencyResolver
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
Windsor Installer:
public class PrincipalsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<DelegatingHandler>());
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
}
}
Modified DummyPrincipalProvider (from the original I got from the URL above):
public class DummyPrincipalProvider : IProvidePrincipal
{
private IUserRepository _userRepo;
public DummyPrincipalProvider(IUserRepository userRepo)
{
this._userRepo = userRepo;
}
public IPrincipal CreatePrincipal(string username, string password)
{
try
{
if (!this._userRepo.ValidateUser(username, password))
{
return null;
}
else
{
var identity = new GenericIdentity(username);
IPrincipal principal = new GenericPrincipal(identity, new[] { "User" });
if (!identity.IsAuthenticated)
{
throw new ApplicationException("Unauthorized");
}
return principal;
}
}
catch
{
return null;
}
}
}
WindsorDependencyResolver.cs:
internal sealed class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public void Dispose()
{
}
}
WindsorDependencyScope.cs:
internal sealed class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
_scope = container.BeginScope();
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public void Dispose()
{
_scope.Dispose();
}
}
I assume IProvidePrincipal is your own implementation.
Best way, the only one IMHO, to use an IoC container is the Composition Root.
The entry point/composition root for web api has been well explained by ploeh's blog.
DelegatingHandler are not part of the "request resolving", so you may choose to resolve it within global asax Application_start where the container lives as private variable.
GlobalConfiguration.Configuration.MessageHandlers.Add(container.Resolve<BasicAuthMessageHandler>());
If you properly registered your handler and all its dependencies in the container, nothing else has to be done: handler instance you extracted from the container and added among MessageHandlers will have an IPrincipalProvider and (I)UserRepository. Keep in mind BasicAuthMessageHandler will act a singleton, so if you need a new instance of (I)UserRepository on each method call... you may consider TypedFactory to create your (I)UserRepository as late dependencies
Of course, any component starting from you top graph component have to be register in the container.
That's the easy way... in case you need somenthing more sophisticate, you may end up creating your "composition root" for DelegatingHandlers as well.
BTW: never, ever, doing somenthing like
UserRepository userRepo = new UserRepository();
or PrincipalProvider = new DummyPrincipalProvider()
none of the "Behaviour instance" should be created explicitly: container take care of providing right instance at the right time...
As per Jon Edit:
now DummyPrincipalProvider looks fine: just keep in mind since DummyPrincipalProvider is created among the message handler(act as singleton due to global registration), you are reusing always same instance.
Instead of your plumbing
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
I rather use ploeh implementation(see above).
Your registration
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
.UsingFactoryMethod(kernel => kernel.Resolve<DummyPrincipalProvider>())
);
should be replaced with
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
that's wrong... container has to resolve it, not you explicitly
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler());
stick with my configuration as above: BasicAuthMessageHandler resolved via container.
Let me know if it works.
PS: You registered the TypedFactory facility in the container, but you are not using it... just to let you know.
You registered DelegatingHandler(s) as Transient, but keep in mind they gonna be "singleton" by design: adding it to the MessageHandlers collection imply they gonna be reused on each request.
As per Jon Edit 2:
I added a sample on github. You should be able to build it and run it using NuGet Package Restore
Your issue about PerWebRequestdepends on the depencies of UserRepository on the NHibernate factory session creating session "PerWebRequest": you cannot resolve IPrincipalProvider->IUserRepository->ISession in Application_Start due to HttpContext. If you really need a IUserRepositry working w/ IPrincipalProvider dependency has to be to a IUserRepositoryFactory(TypedFactory) instead.
I tried to fix your sample using the typed factory and it works, but than I had an issue w/ NHibernate configuration and since I'm not an expert of that, I didn't go any further.
If you need help w/ the factory thing... LMK and I'll update my git sample using a factory within the DummyPrincipalProvider