rin*_*nat 15 .net c# asp.net-mvc aop structuremap3
我有一个使用Structuremap的ASP MVC 4应用程序.我正在尝试通过Structuremap拦截向我的应用程序添加日志记录.在注册表中,我扫描一个特定的程序集,以便使用默认约定注册它的所有类型:
public class ServicesRegistry : Registry
{
public ServicesRegistry()
{
Scan(x =>
{
x.AssemblyContainingType<MyMarkerService>();
x.WithDefaultConventions();
});
}
}
Run Code Online (Sandbox Code Playgroud)
拦截器:
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var watch = Stopwatch.StartNew();
invocation.Proceed();
watch.Stop();//log the time
}
}
Run Code Online (Sandbox Code Playgroud)
我可以为一个特定的插件类型添加拦截器,如下所示:
var proxyGenerator = new ProxyGenerator();
container.Configure(x => x.For<IServiceA>().Use<ServiceA>().DecorateWith(instance => proxyGenerator.CreateInterfaceProxyWithTarget(instance, new LogInterceptor())));
Run Code Online (Sandbox Code Playgroud)
但是我想让结构图为在注册表中扫描的所有类型创建日志代理.有没有办法实现这个目标?
它看起来不像是一个简单的扩展点,但我使用自定义约定使用相当不错的解决方案.为了帮助您理解我做出的决定,我将引导您完成几个步骤(跳过我在路上遇到的许多错误).
首先让我们看一下您已经使用的DefaultConvention.
DefaultConvention:
public class DefaultConventionScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!TypeExtensions.IsConcrete(type))
return;
Type pluginType = this.FindPluginType(type);
if (pluginType == null || !TypeExtensions.HasConstructors(type))
return;
registry.AddType(pluginType, type);
this.ConfigureFamily(registry.For(pluginType, (ILifecycle)null));
}
public virtual Type FindPluginType(Type concreteType)
{
string interfaceName = "I" + concreteType.Name;
return Enumerable.FirstOrDefault<Type>((IEnumerable<Type>)concreteType.GetInterfaces(), (Func<Type, bool>)(t => t.Name == interfaceName));
}
}
Run Code Online (Sandbox Code Playgroud)
非常简单,我们得到类型和接口对,并检查以确保它们有一个构造函数,如果他们我们注册它们.修改它以便它调用DecorateWith会很好,但你只能在For <>()上调用它.使用<>(),而不是For().使用().
接下来让我们看一下DecorateWith的作用:
public T DecorateWith(Expression<Func<TPluginType, TPluginType>> handler)
{
this.AddInterceptor((IInterceptor) new FuncInterceptor<TPluginType>(handler, (string) null));
return this.thisInstance;
}
Run Code Online (Sandbox Code Playgroud)
所以这会创建一个FuncInterceptor并注册它.我花了很多时间尝试用反射动态创建其中一个,然后再决定创建一个新类更容易:
public class ProxyFuncInterceptor<T> : FuncInterceptor<T> where T : class
{
public ProxyFuncInterceptor() : base(x => MakeProxy(x), "")
{
}
protected ProxyFuncInterceptor(Expression<Func<T, T>> expression, string description = null)
: base(expression, description)
{
}
protected ProxyFuncInterceptor(Expression<Func<IContext, T, T>> expression, string description = null)
: base(expression, description)
{
}
private static T MakeProxy(T instance)
{
var proxyGenerator = new ProxyGenerator();
return proxyGenerator.CreateInterfaceProxyWithTarget(instance, new LogInterceptor());
}
}
Run Code Online (Sandbox Code Playgroud)
当我们将类型作为变量时,这个类更容易使用.
最后,我根据默认约定制定了自己的公约.
public class DefaultConventionWithProxyScanner : ConfigurableRegistrationConvention
{
public override void Process(Type type, Registry registry)
{
if (!type.IsConcrete())
return;
var pluginType = this.FindPluginType(type);
if (pluginType == null || !type.HasConstructors())
return;
registry.AddType(pluginType, type);
var policy = CreatePolicy(pluginType);
registry.Policies.Interceptors(policy);
ConfigureFamily(registry.For(pluginType));
}
public virtual Type FindPluginType(Type concreteType)
{
var interfaceName = "I" + concreteType.Name;
return concreteType.GetInterfaces().FirstOrDefault(t => t.Name == interfaceName);
}
public IInterceptorPolicy CreatePolicy(Type pluginType)
{
var genericPolicyType = typeof(InterceptorPolicy<>);
var policyType = genericPolicyType.MakeGenericType(pluginType);
return (IInterceptorPolicy)Activator.CreateInstance(policyType, new object[]{CreateInterceptor(pluginType), null});
}
public IInterceptor CreateInterceptor(Type pluginType)
{
var genericInterceptorType = typeof(ProxyFuncInterceptor<>);
var specificInterceptor = genericInterceptorType.MakeGenericType(pluginType);
return (IInterceptor)Activator.CreateInstance(specificInterceptor);
}
}
Run Code Online (Sandbox Code Playgroud)
它与一个添加几乎完全相同,我为我们注册的每种类型创建一个拦截器和拦截器类型.然后我注册了该政策.
最后,一些单元测试证明它有效:
[TestFixture]
public class Try4
{
[Test]
public void Can_create_interceptor()
{
var type = typeof (IServiceA);
Assert.NotNull(new DefaultConventionWithProxyScanner().CreateInterceptor(type));
}
[Test]
public void Can_create_policy()
{
var type = typeof (IServiceA);
Assert.NotNull(new DefaultConventionWithProxyScanner().CreatePolicy(type));
}
[Test]
public void Can_register_normally()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
}));
var serviceA = container.GetInstance<IServiceA>();
Assert.IsFalse(ProxyUtil.IsProxy(serviceA));
Console.WriteLine(serviceA.GetType());
}
[Test]
public void Can_register_proxy_for_all()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.Convention<DefaultConventionWithProxyScanner>();
}));
var serviceA = container.GetInstance<IServiceA>();
Assert.IsTrue(ProxyUtil.IsProxy(serviceA));
Console.WriteLine(serviceA.GetType());
}
[Test]
public void Make_sure_I_wait()
{
var container = new Container();
container.Configure(x => x.Scan(y =>
{
y.TheCallingAssembly();
y.Convention<DefaultConventionWithProxyScanner>();
}));
var serviceA = container.GetInstance<IServiceA>();
serviceA.Wait();
}
}
}
public interface IServiceA
{
void Wait();
}
public class ServiceA : IServiceA
{
public void Wait()
{
Thread.Sleep(1000);
}
}
public interface IServiceB
{
}
public class ServiceB : IServiceB
{
}
Run Code Online (Sandbox Code Playgroud)
这里有一些清理空间(缓存,使其干燥,更多测试,使配置更容易),但它适用于您需要的,并且是一种非常合理的方式.
如果您对此有任何其他疑问,请询问.
| 归档时间: |
|
| 查看次数: |
875 次 |
| 最近记录: |