I have a project with several layers - among them the web front end (ASP.NET MVC3) and the service back end (mainly business logic). The project is a few months old, so everything is working as expected. Now I am trying to add a logging aspect to some of the MVC3 controller methods using custom [Log]
attributes.
I am using Castle Windsor for dependency injection. To get a logging aspect I leverage Castle DynamicProxy through SNAP. Controllers are being resolved using WindsorControllerFactory
from Krzysztof Koźmic's helpful tutorial - but I modified it to look for the default interface for the controller (see below).
In my service layer:
[Log(LoggingLevel.Info)]
public void Save(MyBusinessDto dto)
{
// business logic and other checks
this.repository.Save(mbo);
}
In my web front end's IWindsorInstaller
for controllers:
private static BasedOnDescriptor FindControllers()
{
return AllTypes
.FromThisAssembly()
.BasedOn<IController>()
.WithService.DefaultInterface();
}
In my (slightly customized) WindsorControllerFactory
that looks for the default interface for the controller:
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format(Error404, requestContext.HttpContext.Request.Path));
}
string controllerName = controllerType.Name;
string defaultInterfaceName = 'I' + controllerName;
Type defaultInterface = controllerType.GetInterface(defaultInterfaceName);
object controller = this.kernel.Resolve(defaultInterface);
return (IController)controller;
}
In my controllers:
public class MyBusinessController : MyBusinessControllerBase, IMyBusinessController
{
[Log(LoggingLevel.Debug)]
public ActionResult CreateOrUpdate(MyBusinessFormModel fm)
{
// Convert form model to data transfer object,
// perform validation and other checks
this.service.Save(dto);
return View(fm);
}
}
This all works fine in the service project, but in the controllers the methods are not being intercepted.
- I have confirmed that the
WindsorControllerFactory
returns proxied controllers. - I have confirmed that the controllers have the interceptor registered.
- I have confirmed that the
MasterProxy
in SNAP intercepts the controller - but it only interceptsIController.Execute(RequestContext requestContext)
.
How can I intercept all controller methods that have my [Log]
attribute?
Update 1: I have considered using DynamicProxy directly instead of SNAP, but this is secondary to getting it to work for controllers as well.
Update 2+4: It seems that SNAP is missing from github back on github.
Update 3: This is what I see in the Visual Studio debugger when breaking in the WindsorControllerFactory
(see above). The inspected controller
variable is what is returned to MVC, and it is indeed proxied.
controller
{Castle.Proxies.IMyBusinessControllerProxy}__interceptors
{Castle.DynamicProxy.IInterceptor[1]}[0]
{Snap.MasterProxy}
__target
{My.Business.Web.Controllers.MyBusinessController}service
{Castle.Proxies.IMyBusinessServiceProxy}- (other contructor injections)
MyInjectedProperty
{My.Business.Useful.MyOtherType}