Is possible with Castle Windsor Interceptor to intercept only a specific method in a class and ignore the other ones? - castle-windsor

Dears,
I have an interface IJob that has a method called ExecuteAsync and i want to intercept this method only but my derived classes may have many methods and i found the interceptor intercept them also.
My question is,
Is this possible with Castle Windsor
and this is my registration
iocManager.IocContainer.Kernel.ComponentRegistered += (key, handler) =>
{
var implementationType = handler.ComponentModel.Implementation.GetTypeInfo();
if(ShouldIntercept(implementationType))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(AuthenticateJobInterceptor)));
}
};
private static bool ShouldIntercept(Type type)
{
if (typeof(IJob).IsAssignableFrom(type))
{
return true;
}
return false;
}

Yes it is. There's a IProxyGenerationHook interface that you can implement to control what gets intercepted. The tutorial I wrote a decade ago still (for better or worse) seems to be the best resource about it.
There's a couple ways to set it up in Windsor.
Ideally, if possible, you'd do it during registration, in your IWindsorInstaller:
var yourHook = new YourHook();
container.Register(
Classes.FromThisAssembly()
.BasedOn<IJob>()
.LifestyleTransient()
.WithServiceBase()
.Configure(c =>
c.Interceptors<AuthenticateJobInterceptor>()
.Proxy.Hook(yourHook)));
Alternatively, if you want to keep your code similar to what it is now (I'd recommend wrapping in a ComponentModel construction contributor), you can do something like:
var options = handler.ComponentModel.ObtainProxyOptions();
options.Hook = yourHook; // InstanceReference(yourHook)

Related

Castle Windsor - how to resolve by name?

My application uses the "SignalR" client/server comms framework. If you aren't familiar with it, the server-side app typically contains one or more "hub" classes (similar to asmx web services), each providing methods that can be called by a client. During startup, the client needs to first create a connection, then create a "proxy" for each hub that it will need to talk to, e.g.:-
var hubConnection = new HubConnection("http://...");
var fooHubProxy = hubConnection.CreateHubProxy("FooHub");
var barHubProxy = hubConnection.CreateHubProxy("BarHub");
...etc...
The string parameter passed to CreateHubProxy() is the name of the server-side hub class. The method return type is IHubProxy.
It feels like I should be able to utilise Windsor here, but I'm struggling to find a solution. My first thought was to instantiate the hub proxies and register these instances with Windsor (by name), e.g.
var fooHubProxy = hubConnection.CreateHubProxy("FooHub");
container.Register(Component.For<IHubProxy>().Instance(fooHubProxy).LifestyleSingleton().Named("FooHub"));
...etc...
The problem is that when a class needs a hub proxy, the only way to resolve it by name is to use service locator pattern, which isn't recommended. What other Windsor features (e.g. typed factories, etc.) might be useful here?
Edit
I've just found Windsor's .UsingFactoryMethod, and am wondering if this would work, to simplify hub registration:
container.Register(Component.For<IHubProxy>()
.UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("FooHub"))
.LifestyleSingleton()
.Named("FooHub"));
I guess I still have the problem of how to resolve by name though.
Two years later, but I have a more elegant solution for other people that stummble accross this problem too.
It is possible to use TypedFactory facility and adapt it to you needs like here.
first create the factory interface (only! no need for the actual implementation, castle will take care of that):
public interface IHubProxyFactory
{
IHubProxy GetProxy(string proxyName);
}
Now we need a class that extend the default typed facotory and retreives the component's name from the input (proxyName):
class NamedTypeFactory : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
string componentName = null;
if (arguments!= null && arguments.Length > 0)
{
componentName = arguments[0] as string;
}
if (string.IsNullOrEmpty(componentName))
componentName = base.GetComponentName(method, arguments);
return componentName;
}
}
And then register the factory with castle and specify that your NamedTypeFactory will be used:
Component.For<IHubProxyFactory>().AsFactory(new NamedTypeFactory())
Now every class can get the factory interface in its constructor:
public class SomeClass
{
private IHubProxy _fooHub;
private IHubProxy _barHub;
public SomeClass(IHubProxyFactory hubProxyFactory)
{
_fooHub = hubProxyFactory.GetProxy("FooHub");
_barHub = hubProxyFactory.GetProxy("BarHub");
}
}
Okay, I think I've found a possible solution, partly using the approach detailed here which shows how it is possible to register Func<>s with Windsor.
First, I register a delegate (Func<>) that uses the container to resolve by name:-
Container.Register(Component.For<Func<string, IHubProxy>>()
.Instance(name => Container.Resolve<IHubProxy>(name))
.LifestyleSingleton());
Think of this as an IHubProxy "factory".
Next, I register my hub proxies as detailed in my original question:-
container.Register(Component.For<IHubProxy>()
.UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("FooHub"))
.LifestyleSingleton()
.Named("FooHub"));
container.Register(Component.For<IHubProxy>()
.UsingFactoryMethod((kernel, context) => hubConnection.CreateHubProxy("BarHub"))
.LifestyleSingleton()
.Named("BarHub"));
Here is an example of a class that needs instances of the hub proxies:-
public class SomeClass
{
private IHubProxy _fooHub;
private IHubProxy _barHub;
public SomeClass(Func<string, IHubProxy> hubProxyFactory)
{
_fooHub = hubProxyFactory("FooHub");
_barHub = hubProxyFactory("BarHub");
}
}
Untried so far, but it looks promising. It's a clever solution but injecting the Func<> feels a little hacky, so I would still be keen to hear of other possible solutions to my problem.
I just used a similar method to yours. I use a typed Factory. Advantage is I have type safety for my hubs. Registering the hubs is the same. The rest differs a bit but is technical the same.
IServiceFactory {
IHubProxy GetFooHub();
IHubProxy GetBarHub();
}
And Registration:
Container.AddFacility<TypedFactoryFacility>();
Container.Register(Component.For<IServiceFactory>().AsFactory());
Usage:
public class SomeClass
{
private IHubProxy _fooHub;
private IHubProxy _barHub;
public SomeClass(IServiceFactry hubProxyFactory)
{
_fooHub = hubProxyFactory.GetFooHub();
_barHub = hubProxyFactory.GetBarHub();
}
}
Btw. Factory.Get"Name"() resolves by name.

Intercepting the concrete implementation (as opposed to service) using Castle Windsor

I'm experimenting with interception in Castle Windsor and notice that interceptors seem to be created as decorators of my service interface.
In other words, if I have an interface "ISomethingDoer" and a concrete "ConcreteSomethingDoer", the proxy implements ISomethingDoer but does not inherit from ConcreteSomethingDoer.
This is fine, and no doubt by design, but what I'm wondering is whether I can intercept protected virtual methods in my concrete classes that wouldn't be known by the public interface. I am doing this in order to add logging support, but I might want to log some of the specific internal details of a class.
In my slightly unimaginative test case I have this:
public interface ISomethingDoer
{
void DoSomething(int Count);
}
[Loggable]
public class ConcreteSomethingDoer : ISomethingDoer
{
public void DoSomething(int Count)
{
for (var A = 0; A < Count; A++)
{
DoThisThing(A);
}
}
[Loggable]
protected virtual void DoThisThing(int A)
{
("Doing a thing with " + A.ToString()).Dump();
}
}
So what I want to do is log calls to "DoThisThing" even though it's not part of the interface.
I've managed to get this working in Autofac. (I've created a Linqpad script here: http://share.linqpad.net/frn5a2.linq) but am struggling with Castle Windsor (see http://share.linqpad.net/wn7877.linq)
In both cases my interceptor is the same and looks like this:
public class Logger : IInterceptor
{
public void Intercept(IInvocation Invocation)
{
String.Format("Calling method {0} on type {1} with parameters {2}",
Invocation.Method.Name,
Invocation.InvocationTarget.GetType().Name,
String.Join(", ", Invocation.Arguments.Select(a => (a ?? "*null*").ToString()).ToArray())).Dump();
Invocation.Proceed();
"Done".Dump();
}
}
What I really want to do is say "any classes with a [Loggable] attribute, should use the logging interceptor". In the Autofac example I've specifically attached a logger to the registration, whereas with Castle I'm using an IModelInterceptorsSelector which looks like this:
public class LoggerInterceptorSelector : IModelInterceptorsSelector
{
public bool HasInterceptors(ComponentModel Model)
{
return Model.Implementation.IsDefined(typeof(LoggableAttribute), true);
}
public InterceptorReference[] SelectInterceptors(ComponentModel Model, InterceptorReference[] Interceptors)
{
return new[]
{
InterceptorReference.ForType<Logger>()
};
}
}
Finally, the code to execute all this is:
var Container = new WindsorContainer();
Container.Register(
Component.For<Logger>().LifeStyle.Transient
);
Container.Kernel.ProxyFactory.AddInterceptorSelector(new LoggerInterceptorSelector());
Container.Register(
Component.For<ISomethingDoer>()
.ImplementedBy<ConcreteSomethingDoer>()
.LifeStyle.Transient
);
var Doer = Container.Resolve<ISomethingDoer>();
Doer.DoSomething(5);
When run I would expect to see "Calling method DoThisThing with parameters x" for each time the method is called. Instead I only get the call to DoSomething logged.
I can see why Castle Windsor is doing this, but I'm wondering if there is a way to tweak the behaviour?
(As a side-note I don't want to use Windsor's own interceptor attributes as I don't want to introduce dependencies to Castle outside of my composition root.)
I have tried resolving the ConcreteSomethingDoer specifically and this works, but not if I'm resolving the ISomethingDoer.
Apologies for the long post, and also apologies because I am pretty new to Castle Windsor!
I you could register like:
Container.Register(
Component.For<ISomethingDoer, ConcreteSomethingDoer>()
.ImplementedBy<ConcreteSomethingDoer>()
.LifeStyle.Transient
);
This should create a class proxy by deriving from ConcreteSomethingDoer. However this won't work with dynamic interceptors. However you probably can work around that by creating a facility which registers the interceptor when needed.

Can someone help me convert this AutoFac registration to Windsor?

containerBuilder
.Register<IGraphClient>(context =>
{
var graphClient = new GraphClient(new Uri("http://localhost:9999/db/data"));
graphClient.Connect(); // Particularly this line
return graphClient;
})
.SingleInstance();
While I can figure out how to register interfaces to concrete classes, this particular class needs to be a single instance (I'm pretty sure this is LifeStyle.Singleton) and also call the graphClient.Connect() method. That's the main part I'm stuck on.
Based on JeffN825's answer I did this:
container.Register(
Component.For(
typeof (IGraphClient))
.ImplementedBy(typeof (GraphClient))
.LifeStyle.Singleton.UsingFactoryMethod(() =>
{
var graphClient = new GraphClient(new Uri("http://localhost:7474/db/data"));
graphClient.Connect();
return graphClient;
}));
You can use the ComponentRegistration<T>.UsingFactoryMethod<T> method which takes a delegate (Func) if you want to control the instance creation yourself (which would also give you the chance to call Connect).

How to automaticly register components using a Generic FactoryMethod with Castle Windsor

I´m trying to work out a problem with registering my configuration classes. I have the following in my Installer:
First I register my open generic factory
container.AddFacility<FactorySupportFacility>()
.Register(Component.For(typeof (IConfigurationProvider<>))
.ImplementedBy(typeof (AppSettingsConfigurationProvider<>)));
Then I´m trying to register all concrete impl. of IConfiguration and I need to use my registered impl. IConfigurationProvider to resolve them.
Problem is that my factory looks like this:
public class AppSettingsConfigurationProvider<TConfiguration>
where TConfiguration : class, IConfiguration, new()
{
public TConfiguration Build()
{
var config = new TConfiguration();
var properties = typeof(TConfiguration).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var p in properties)
{
if (!p.CanWrite)
continue;
if (p.GetSetMethod(false) == null)
continue;
var settingsKey = string.Format("{0}.{1}", p.ReflectedType.FullName, p.Name);
p.SetValue(config, Convert.ChangeType(ConfigurationManager.AppSettings[settingsKey], p.PropertyType), null);
}
return config;
}
}
So I need to set the generic type.
Is there a way to get away with this, so that I dont need to register each configuration component one by one like this:
container
.Register(
Component.For<DummyConfiguration>()
.ImplementedBy<DummyConfiguration>()
.UsingFactoryMethod(kernel => kernel.Resolve<IConfigurationProvider<DummyConfiguration>>().Build()));
I would prefer a more automatic way to register my configuration componets.
Would something similar to what Ben Hall described, using DictionaryAdapter work for you? Notice that if you're using Windsor 2.5 you already have DictionaryAdapter (it is part of Castle.Core.dll now).

Castle Windsor and IPrincipal

Is is possible to inject IPrincipal using Castle Windsor into my asp.net mvc controller. This article by Scott Hanselman has code in the comments to do it with structure map, but I cannot figure out how to do it with Castle.
Update:
Here is what I ended up with for my controller factory. Note that most of the code is from Steve Sanderson's Pro ASP.NET MVC book with the addition of the code from the answers below.
public class WindsorControllerFactory : DefaultControllerFactory
{
readonly WindsorContainer _container;
// The constructor:
// 1. Sets up a new IoC container
// 2. Registers all components specified in web.config
// 3. Registers IPrincipal
// 4. Registers all controller types as components
public WindsorControllerFactory()
{
// Instantiate a container, taking configuration from web.config
_container = new WindsorContainer(
new XmlInterpreter(new ConfigResource("castle"))
);
_container.AddFacility<FactorySupportFacility>();
_container.Register(Component.For<IPrincipal>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(() => HttpContext.Current.User));
// Also register all the controller types as transient
var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach (var t in controllerTypes)
_container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);
}
// Constructs the controller instance needed to service each request
protected override IController GetControllerInstance(Type controllerType)
{
return (IController)_container.Resolve(controllerType);
}
}
If you're using Windsor 2.0, there's no need to modify the ControllerFactory:
var container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();
container.Register(Component.For<IPrincipal>()
.LifeStyle.PerWebRequest
.UsingFactoryMethod(() => HttpContext.Current.User));
// your component registrations...
This is just a wrapper around the Factory facility configuration. If you're using a previous version (RC3) you can configure this with XML too.
You try to let Windsor construct your IPrincipal where it has to just use the one that's there.
Inject it into the container through the AddComponentInstance method exposed by the MicroKernel in your ControllerFactory.
This would obviously require a custom ControllerFactory, but you should have that already.
I did something similar for HttpContext some time ago:
http://www.tigraine.at/2009/01/21/aspnet-mvc-hide-the-httpcontext-services-with-windsor-and-a-custom-controllerfactory/comment-page-1/#comment-2645
Your controller factory could look like this:
public IController CreateController(RequestContext requestContext, string controllerName)
{
container.Kernel.AddComponentInstance<IPrincipal>(typeof (IPrincipal),
System.Web.HttpContext.Current.User);
return (IController) container.Resolve(controllerName);
}
(Don't forget that your controllers have to be per-web-request or transient for this or you'll get in trouble)