编程语言
首页 > 编程语言> > c# – ASP.NET MVC3控制器AOP代理不拦截所有方法,只有IController.Execute

c# – ASP.NET MVC3控制器AOP代理不拦截所有方法,只有IController.Execute

作者:互联网

我有一个包含多个层的项目 – 其中包括Web前端(ASP.NET MVC3)和服务后端(主要是业务逻辑).这个项目已经有几个月了,所以一切都按预期工作.现在我尝试使用自定义[Log]属性为某些MVC3控制器方法添加日志记录方面.

我使用Castle Windsor进行依赖注入.为了获得日志记录方面,我利用Castle DynamicProxySNAP.控制器正在使用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 installerWindsorControllerFactory应该开箱即用.可以在更大的图片中推荐接口代理(并且它们在控制器中使用拦截器之前工作良好)但在这种情况下可能有理由不去那么远,以避免进一步的副作用.

感谢Marius指出我正确的方向!

标签:c,asp-net-mvc-3,aop,castle-windsor,castle-dynamicproxy
来源: https://codeday.me/bug/20190530/1184785.html