C# 使用上下文信息解析谓词
我有一个服务类型C# 使用上下文信息解析谓词,c#,simple-injector,C#,Simple Injector,我有一个服务类型ITestGuard,我想用FooTestGuard或NullTestGuard实现它,具体取决于实例被注入的表达式树。具体来说,我想为所有情况提供FooTestGuard,但解析请求的“祖先”之一为TestController类型时除外 我想我可以通过ExpressionBuilding事件来实现这一点,作为指导,将新的Parent属性添加到DependencyContext并通过递归下降来填充它: [DebuggerDisplay("DependencyContext (Se
ITestGuard
,我想用FooTestGuard
或NullTestGuard
实现它,具体取决于实例被注入的表达式树。具体来说,我想为所有情况提供FooTestGuard
,但解析请求的“祖先”之一为TestController
类型时除外
我想我可以通过ExpressionBuilding
事件来实现这一点,作为指导,将新的Parent
属性添加到DependencyContext
并通过递归下降来填充它:
[DebuggerDisplay("DependencyContext (ServiceType: {ServiceType}, ImplementationType: {ImplementationType})")]
public class DependencyContext
{
public static readonly DependencyContext Root = new DependencyContext();
public DependencyContext(
Type serviceType,
Type implementationType,
ParameterInfo parameter,
DependencyContext parent = null)
{
ServiceType = serviceType;
ImplementationType = implementationType;
Parameter = parameter;
Parent = parent;
}
private DependencyContext() { }
public Type ServiceType { get; private set; }
public Type ImplementationType { get; private set; }
public ParameterInfo Parameter { get; private set; }
public DependencyContext Parent { get; private set; }
}
public static class ContextDependentExtensions
{
public static IEnumerable<DependencyContext> AncestorsAndSelf(this DependencyContext context)
{
while (true)
{
yield return context;
if (context.Parent == null)
yield break;
context = context.Parent;
}
}
public static void RegisterWithContext<TService>(this Container container,
Func<DependencyContext, TService> contextBasedFactory) where TService : class
{
if (contextBasedFactory == null)
throw new ArgumentNullException("contextBasedFactory");
Func<TService> rootFactory = () => contextBasedFactory(DependencyContext.Root);
container.Register(rootFactory, Lifestyle.Transient);
// Allow the Func<DependencyContext, TService> to be injected into parent types.
container.ExpressionBuilding += (sender, e) =>
{
if (e.RegisteredServiceType != typeof(TService))
{
var rewriter = new DependencyContextRewriter(
contextBasedFactory,
rootFactory,
e.RegisteredServiceType,
e.Expression);
e.Expression = rewriter.Visit(e.Expression);
}
};
}
private sealed class DependencyContextRewriter : ExpressionVisitor
{
private readonly object _contextBasedFactory;
private readonly object _rootFactory;
private readonly Type _serviceType;
private readonly Expression _expression;
private readonly DependencyContext _parentContext;
private readonly ParameterInfo _parameter;
public DependencyContextRewriter(object contextBasedFactory,
object rootFactory,
Type serviceType,
Expression expression,
DependencyContext parentContext = null,
ParameterInfo parameter = null)
{
_serviceType = serviceType;
_contextBasedFactory = contextBasedFactory;
_rootFactory = rootFactory;
_expression = expression;
_parentContext = parentContext;
_parameter = parameter;
}
private Type ImplementationType
{
get
{
var expression = _expression as NewExpression;
if (expression == null)
return _serviceType;
return expression.Constructor.DeclaringType;
}
}
protected override Expression VisitNew(NewExpression node)
{
var context = new DependencyContext(_serviceType, ImplementationType, _parameter, _parentContext);
var parameters = node.Constructor.GetParameters();
var rewritten = node.Arguments
.Select((x, i) => new DependencyContextRewriter(_contextBasedFactory, _rootFactory, x.Type, x, context, parameters[i]).Visit(x));
return node.Update(rewritten);
}
protected override Expression VisitInvocation(InvocationExpression node)
{
if (IsRootedContextBasedFactory(node))
return Expression.Invoke(
Expression.Constant(_contextBasedFactory),
Expression.Constant(
new DependencyContext(
_serviceType,
ImplementationType,
_parameter,
new DependencyContext(_serviceType, ImplementationType, _parameter, _parentContext))));
return base.VisitInvocation(node);
}
private bool IsRootedContextBasedFactory(InvocationExpression node)
{
var expression = node.Expression as ConstantExpression;
if (expression == null)
return false;
return ReferenceEquals(expression.Value, _rootFactory);
}
}
}
[DebuggerDisplay(“DependencyContext(ServiceType:{ServiceType},ImplementationType:{ImplementationType})”)]
公共类依赖上下文
{
公共静态只读DependencyContext根=新DependencyContext();
公共依赖语境(
类型serviceType,
类型实现类型,
ParameterInfo参数,
DependencyContext父项=空)
{
服务类型=服务类型;
ImplementationType=ImplementationType;
参数=参数;
父母=父母;
}
私有依赖上下文(){}
公共类型ServiceType{get;private set;}
公共类型实现类型{get;private set;}
公共参数信息参数{get;private set;}
public DependencyContext父项{get;private set;}
}
公共静态类contextDependentTextensions
{
公共静态IEnumerable AnteStorsandSelf(此DependencyContext上下文)
{
while(true)
{
屈服-返回语境;
if(context.Parent==null)
屈服断裂;
context=context.Parent;
}
}
公共静态无效注册表WithContext(此容器,
Func contextBasedFactory),其中TService:class
{
if(contextBasedFactory==null)
抛出新ArgumentNullException(“contextBasedFactory”);
Func rootFactory=()=>contextBasedFactory(DependencyContext.Root);
容器。注册(rootFactory,lifesture.Transient);
//允许将Func注入父类型。
container.ExpressionBuilding+=(发送方,e)=>
{
if(例如RegisteredServiceType!=typeof(TService))
{
var rewriter=新的DependencyContextRewriter(
基于上下文的工厂,
根工厂,
e、 RegisteredServiceType,
e、 表情);
e、 表达式=重写器访问(e.Expression);
}
};
}
私有密封类DependencyContextRewriter:ExpressionVisitor
{
私有只读对象\u contextBasedFactory;
私有只读对象_rootFactory;
私有只读类型_serviceType;
私有只读表达式\u表达式;
私有只读DependencyContext\u parentContext;
私有只读参数INFO_参数;
公共依赖性ContextRewriter(对象contextBasedFactory,
对象根工厂,
类型serviceType,
表情表情,
DependencyContext parentContext=null,
ParameterInfo参数=空)
{
_服务类型=服务类型;
_contextBasedFactory=contextBasedFactory;
_rootFactory=rootFactory;
_表达式=表达式;
_parentContext=parentContext;
_参数=参数;
}
私有类型实现类型
{
得到
{
var表达式=_表达式作为NewExpression;
if(表达式==null)
返回_serviceType;
返回表达式.Constructor.DeclaringType;
}
}
受保护的重写表达式VisitNew(新建表达式节点)
{
var context=新的DependencyContext(\u serviceType,ImplementationType,\u参数,\u parentContext);
var parameters=node.Constructor.GetParameters();
var rewrited=node.Arguments
.Select((x,i)=>newDependencyContextRewriter(_-contextBasedFactory,_-rootFactory,x.Type,x,context,parameters[i])。访问(x));
返回节点。更新(重写);
}
受保护的重写表达式VisitInvocation(调用表达式节点)
{
if(IsRootedContextBasedFactory(节点))
返回表达式.Invoke(
表达式.常量(_contextBasedFactory),
表达式.常数(
新依赖上下文(
_服务类型,
实现类型,
_参数,
新的DependencyContext(_serviceType,ImplementationType,_参数,_parentContext));
返回基地。访问职业(节点);
}
私有bool IsRootedContextBasedFactory(调用表达式节点)
{
var表达式=节点。表达式为常量表达式;
if(表达式==null)
返回false;
返回ReferenceEquals(expression.Value,_rootFactory);
}
}
}
但是,我看到的是,上下文
层次结构在传递给委托时没有完全填充。我在请求一个TestController
时调试了访问者,然后继续执行ITestGuard
步骤。但是,IsRootedContextBasedFactory
检查返回false,跳过了委托替换。我认为这是因为它在先前调用expressionbuild
时已经被替换,这意味着注册的表达式不再是rootFactory
,因此检查失败
public class TestGuardSelector : ITestGuard
{
private readonly Func<bool> selector;
private readonly ITestGuard trueGuard;
private readonly ITestGuard falseGuard;
public TestGuardSelector(Func<bool> selector, ITestGuard trueGuard,
ITestGuard falseGuard) {
this.selector = selector;
this.trueGuard = trueGuard;
this.falseGuard = falseGuard;
}
public object TestGuardMethod(object value) {
// Forward the call
return this.CurrentGuard.TestGuardMethod(value);
}
private ITestGuard CurrentGuard {
get { return this.selector() ? this.trueGuard : this.falseGuard; }
}
}
container.RegisterSingle<ITestGuard>(new TestGuardSelector(
() => HttpContext.Current.Request.Url.Contains(@"\Test\"),
new FooTestGuard(),
new NullTestGuard());