c# – ASP.NET MVC3控制器AOP代理不拦截所有方法,只有IController.Execute
作者:互联网
我有一个包含多个层的项目 – 其中包括Web前端(ASP.NET MVC3)和服务后端(主要是业务逻辑).这个项目已经有几个月了,所以一切都按预期工作.现在我尝试使用自定义[Log]属性为某些MVC3控制器方法添加日志记录方面.
我使用Castle Windsor进行依赖注入.为了获得日志记录方面,我利用Castle DynamicProxy到SNAP.控制器正在使用KrzysztofKoźmic的有用教程中的WindsorControllerFactory
进行解析 – 但我修改了它以寻找控制器的默认接口(见下文).
在我的服务层:
[Log(LoggingLevel.Info)]
public void Save(MyBusinessDto dto)
{
// business logic and other checks
this.repository.Save(mbo);
}
在我的网络前端IWindsorInstaller
控制器:
private static BasedOnDescriptor FindControllers()
{
return AllTypes
.FromThisAssembly()
.BasedOn<IController>()
.WithService.DefaultInterface();
}
在我的(稍微定制的)WindsorControllerFactory中,它查找控制器的默认接口:
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;
}
在我的控制器中:
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);
}
}
这一切在服务项目中都可以正常工作,但在控制器中,方法不会被截获.
>我已确认WindsorControllerFactory返回代理控制器.
>我已确认控制器已注册拦截器.
>我已经确认SNAP中的MasterProxy拦截了控制器 – 但它只拦截了IController.Execute(RequestContext requestContext).
如何拦截具有[Log]属性的所有控制器方法?
更新1:我已经考虑过直接使用DynamicProxy而不是SNAP,但这也是让它适用于控制器的次要因素.
更新2 4:似乎从github back on github中缺少SNAP.
更新3:这是我在WindsorControllerFactory中打破Visual Studio调试器时看到的内容(见上文).被检查的控制器变量是返回给MVC的,它确实是代理的.
> controller {Castle.Proxies.IMyBusinessControllerProxy}
> __interceptors {Castle.DynamicProxy.IInterceptor [1]}
> [0] {Snap.MasterProxy}
> __target {My.Business.Web.Controllers.MyBusinessController}
> service {Castle.Proxies.IMyBusinessServiceProxy}
>(其他构造物注射)
> MyInjectedProperty {My.Business.Useful.MyOtherType}
解决方法:
在IController GetControllerInstance(…)中,不要提供接口代理,使用虚方法提供类代理.
从IController GetControllerInstance(…)返回的控制器中的用户实现的方法不会通过代理的IMyBusinessController接口访问,而是从IController转换到控制器的实际类;例如MyBusinessController.改为使用类代理,使MVC3的强制转换返回代理.此外,将方法标记为虚拟,否则拦截代理将无法拦截方法调用并检查自定义属性.
在控制器中,使用属性为方法添加虚拟:
public class MyBusinessController : MyBusinessControllerBase, IMyBusinessController
{
[Log(LoggingLevel.Debug)]
public virtual ActionResult CreateOrUpdate(MyBusinessFormModel fm)
{
// Convert form model to data transfer object,
// perform validation and other checks
this.service.Save(dto);
return View(fm);
}
}
为什么只有Execute(…)被截获? IController接口仅包含Execute(…).在返回的控制器接口代理上调用Execute,因此可以截获它.但是一旦MVC3的内部ControllerBase.Execute(…)获得调用,它就会对从ControllerFactory所期望的类执行强制转换.
问题类似于this
leaking,因为它们都绕过了接口代理.我想它可以通过多种方式解决;也许通过创建自定义类型转换器,从工厂中的接口代理目标创建类代理,一个聪明的Windsor配置等.
KrzysztofKoźmic的IController installer和WindsorControllerFactory
应该开箱即用.可以在更大的图片中推荐接口代理(并且它们在控制器中使用拦截器之前工作良好)但在这种情况下可能有理由不去那么远,以避免进一步的副作用.
感谢Marius指出我正确的方向!
标签:c,asp-net-mvc-3,aop,castle-windsor,castle-dynamicproxy 来源: https://codeday.me/bug/20190530/1184785.html