我有 CacheAttribute 接受持续时间这样的值
public class MyTestQuery : IMyTestQuery
{
private readonly ISomeRepository _someRepository;
public TestQuery(ISomeRepository someRepository)
{
_someRepository = someRepository;
}
[Cache(Duration = 10)]
public MyViewModel GetForeignKeysViewModelCache()
{
...code here...
return viewModel;
}
}
属性看起来像这样
[AttributeUsage(AttributeTargets.Method)]
public class CacheAttribute : Attribute
{
public int Duration { get; set; }
}
当使用 Castle.Proxy.IInterceptor 截获时,它可以正常工作,但当我通过 IInvocation.MethodInvocationTarget 或 Attribute.GetCustomAttribute 时> IInvocation.Method 都返回 null 值
这是代码
public class CacheResultInterceptor : IInterceptor
{
public CacheAttribute GetCacheResultAttribute(IInvocation invocation)
{
var methodInfo = invocation.MethodInvocationTarget;
if (methodInfo == null)
{
methodInfo = invocation.Method;
}
return Attribute.GetCustomAttribute(
methodInfo,
typeof(CacheAttribute),
true
)
as CacheAttribute;
}
public void Intercept(IInvocation invocation)
{
var cacheAttribute = GetCacheResultAttribute(invocation);
//cacheAttribute is null always
...more code here...
}
}
这就是我注册的方式
public class Bootstrapper
{
public static ContainerBuilder Builder;
public static void Initialise()
{
Builder = new ContainerBuilder();
...other codes in here...
CacheInstaller.Install();
var container = Builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
public class CacheInstaller
{
public static void Install()
{
Bootstrapper.Builder.RegisterType<CacheResultInterceptor>()
.SingleInstance();
Bootstrapper.Builder.RegisterAssemblyTypes(Assembly.Load("MyApplication.Web"))
.Where(t => t.Name.EndsWith("Query"))
.AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CacheResultInterceptor))
.SingleInstance();
}
}
我的昂贵方法类以查询结束
现在问题是为什么invocation.MethodInvocationTarget
和/或invocation.Method
返回null?
我究竟做错了什么?
任何其他策略,所以我可以传递参数值,而不为我能想到的每个值创建一个方法?
BTW我正在使用
更新1 以下是为了清晰起见而返回的内容
答案 0 :(得分:3)
这是我找到的。
invocation.Method
返回接口上的方法声明,在您的情况下为IMyTestQuery
。
另一方面,invocation.MethodInvocationProxy
返回调用invocation.Proceed()
时要调用的方法。这意味着它可以是:
正如您所看到的,MethodInvocationProxy
的确定性不如Method
,这就是为什么我建议您避免使用它,至少对于您尝试实现的目标而言。
当你考虑它时,一个拦截器不应该绑定到一个实现,因为它代理一个接口,那么为什么不把[Cache]
属性放在接口级呢?
使用您的代码,我可以在界面上成功检索它。
修改强>
好的,我已经整理了一个repository on GitHub,它使用了你提到的NuGet包的特定版本,并展示了如何检索截获方法的属性。
提醒一下,以下是使用过的NuGet包:
Microsoft.AspNet.Mvc
v5.2.3 Autofac
v4.3.0 Autofac.Mvc5
4.0.0 Autofac.Extras.DynamicProxy
v4.2.1 Castle.Core
v4.0.0 我创建了2个查询接口,IMyQuery
和IMySecondQuery
。请注意,正如我在原始答案中所提到的,[Cache]
属性放在接口方法上,而不是在实现类上。
public interface IMyQuery
{
[Cache(60000)]
string GetName();
}
public interface IMySecondQuery
{
[Cache(1000)]
string GetSecondName();
}
然后我们有两个这些类的非常基本的实现。根本不相关,但为了完整起见:
public class DefaultMyQuery : IMyQuery
{
public string GetName()
{
return "Raymund";
}
}
public class DefaultMySecondQuery : IMySecondQuery
{
public string GetSecondName()
{
return "Mickaël Derriey";
}
}
然后是拦截器:
public class CacheResultInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var cacheAttribute = invocation.Method.GetCustomAttribute<CacheAttribute>();
if (cacheAttribute != null)
{
Trace.WriteLine($"Found a [Cache] attribute on the {invocation.Method.Name} method with a duration of {cacheAttribute.Duration}.");
}
invocation.Proceed();
}
}
请注意,GetCustomAttribute<T>
方法是MemberInfo
命名空间中System.Reflection
的扩展方法。
让我们继续进行Autofac容器中的注册。我试着尽可能地遵循你的注册风格:
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder
.RegisterType<CacheResultInterceptor>()
.SingleInstance();
builder
.RegisterAssemblyTypes(typeof(MvcApplication).Assembly)
.Where(x => x.Name.EndsWith("Query"))
.AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(CacheResultInterceptor));
DependencyResolver.SetResolver(new AutofacDependencyResolver(builder.Build()));
然后在HomeController
:
public class HomeController : Controller
{
private readonly IMyQuery _myQuery;
private readonly IMySecondQuery _mySecondQuery;
public HomeController(IMyQuery myQuery, IMySecondQuery mySecondQuery)
{
_myQuery = myQuery;
_mySecondQuery = mySecondQuery;
}
public ActionResult MyQuery()
{
return Json(_myQuery.GetName(), JsonRequestBehavior.AllowGet);
}
public ActionResult MySecondQuery()
{
return Json(_mySecondQuery.GetSecondName(), JsonRequestBehavior.AllowGet);
}
}
我测试这个只是在拦截器中放置一个断点,F5
应用程序,打开浏览器并导航到http://localhost:62440/home/myquery
和http://localhost:62440/home/myquery
。
它确实击中了拦截器并找到了[Cache]
属性。在Visual Studio输出窗口中,它确实显示:
Found a [Cache] attribute on the GetName method with a duration of 60000.
Found a [Cache] attribute on the GetSecondName method with a duration of 1000.
希望这可以帮助您确定项目中发生的事情。
我pushed changes to the repository,以便第一个查询调用第二个查询。
它仍然有效。你应该真的付出努力并在问题上加上一些代码。