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());
}
}
Related
I have a Web Api project and using Castle Windsor as the IoC. I have done this quite a few times and honestly I cannot understand why this is not working so here goes everything that I am doing:
Controller on the Web Api project:
Nothing fancy here
public class TestController : ApiController, ITestController
{
... //Currently with its default constructor.
}
Global.asax
public class WebApiApplication : System.Web.HttpApplication
{
private readonly IWindsorContainer container;
public WebApiApplication()
{
container = new WindsorContainer().Install(FromAssembly.Named("DependenciesConfiguration"));
}
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new DiControllerActivator(container));
}
}
DiControllerActivation class
This is the class that is replacing the default controller activator in the Global.asax class.
public class DiControllerActivator : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public DiControllerActivator(IWindsorContainer container)
{
this.container = Argument.NotNull(container, (nameof(container)));
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
//This is the line that fails saying "No component for supporting the service TestController was found.
var controller = (IHttpController)container.Resolve(controllerType);
request.RegisterForDispose(new Release(() => container.Release(controller)));
return controller;
}
}
internal class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
And finally the Web Services Installer
public class ServicesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromAssemblyNamed("WebServices")
.Where(type => type.Name.EndsWith("Controller"))
.WithService.DefaultInterfaces()
.Configure(c => c.LifestylePerWebRequest()));
}
}
What it is really frustrating is that, like I said, I have donde this before, I went to my previous work to see if I was missing anything and I cannot find anything and this has always worked well.
When running the application after the installer runs I can see that the service is in the container and when it fails saying "No component for supporting the service TestController was found" I can still see the service within the container in the Watch Window.
I am using Castle version 4.0
Thank you for any pointers and help.
As it turns out there is a subtle but critical difference in this code from the other times I did this.. The fact that the TestController is implementing an interface and is registered as such messes up the whole thing.
Since the Create method in the DiActivator class is trying to resolve the controller based on its type and not its default interface the container cannot find it.
One solution is just to remove the interface from the controller or to add the necessary code in the Create method that gets the default interface of the received type and resolves for it.
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());
}
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;
}
}
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