使用 EnableClassInterceptors 和 WithParameter 注册一个类型
Registering a type with both EnableClassInterceptors and WithParameter
我在使用 Autofac 时遇到问题,似乎 EnableClassInterceptors 干扰了我使用 .WithParameter(...) 的能力。当使用下面的代码在 Service 上调用构造函数时,不会填充 someString。备注:
- 我试过使用 ResolvedParameter,但没有帮助(注意:我试过时,我的 Resolved 参数仍然包含参数的名称)
- 如果我删除 EnableClassInterceptors 和 InterceptedBy,参数会正确填充。但是,这不是有效的解决方案,因为我需要拦截器。
- 重新排序 WithParameter、EnableClassInterceptors 和 InterceptedBy 没有帮助。
- 查看 Type Interceptors,特别是 "Class Interceptors and UsingConstructor" 部分,在 docs.autofac.org,它提到使用 EnableClassInterceptors 会导致 ConstructUsing 失败。我认为下面的场景可能会发生类似的情况。
我的注册码片段如下所示:
var builder = new ContainerBuilder();
builder.RegisterType<Dependency>.As<IDependency>.InstancePerLifetimeScope();
builder.RegisterType<Service>()
.As<IService>()
.WithParameter(new NamedParameter("someString", "TEST"))
.EnableClassInterceptors()
.InterceptedBy(typeof(LogExceptionsInterceptor));
服务的构造函数看起来像这样:
public class Service : IService
{
public Service(IDependency dependency, string someString)
{
if(dependency == null)
throw ArgumentNullException(nameof(dependency));
if(someString == null)
//**throws here**
throw ArgumentNullException(nameof(someString));
}
}
[猜测] 我在想的是,当调用 EnableClassInterceptors 时,会生成一个代理 class,其构造函数在现有一个,但参数名称不会复制到代理中 class/constructor。
这是个问题吗?有没有一种方法可以形成允许 WithParameter 和 EnableClassInterceptors 一起使用的注册?这是 Autofac 中的错误吗?
您的猜测是正确的:生成的代理 class 不保留构造函数参数名称。
目前没有办法在 DynamicProxy 中影响这一点,所以这不是 Autofac 的错误(尽管 Autofac 文档网站上目前没有记录这种边缘情况)。
这是你原来的 Service
class 参数的样子:
typeof(Service).GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[2]}
[0]: {ConsoleApplication10.IDependency dependency}
[1]: {System.String someString}
但生成的代理不保留名称:
GetType().GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[3]}
[0]: {Castle.DynamicProxy.IInterceptor[] }
[1]: {ConsoleApplication10.IDependency }
[2]: {System.String }
所以你有两个不太可靠的选项来解决这个限制 WithParameter
:
使用 TypedParamter
和 string
作为类型:
.WithParameter(new TypedParameter(typeof(string), "TEST"))
但是,如果您有多个相同类型的参数,这将不起作用
在这种情况下使用 PositionalParameter
如果类型被代理,您需要添加 1
.WithParameter(new PositionalParameter(2, "TEST"))
另一种选择是不使用原始字符串类型,而是创建一个包装器,例如MyServiceParameter
或创建另一个服务,它可以向您的其他服务提供这些 string
配置值。
我在使用 Autofac 时遇到问题,似乎 EnableClassInterceptors 干扰了我使用 .WithParameter(...) 的能力。当使用下面的代码在 Service 上调用构造函数时,不会填充 someString。备注:
- 我试过使用 ResolvedParameter,但没有帮助(注意:我试过时,我的 Resolved 参数仍然包含参数的名称)
- 如果我删除 EnableClassInterceptors 和 InterceptedBy,参数会正确填充。但是,这不是有效的解决方案,因为我需要拦截器。
- 重新排序 WithParameter、EnableClassInterceptors 和 InterceptedBy 没有帮助。
- 查看 Type Interceptors,特别是 "Class Interceptors and UsingConstructor" 部分,在 docs.autofac.org,它提到使用 EnableClassInterceptors 会导致 ConstructUsing 失败。我认为下面的场景可能会发生类似的情况。
我的注册码片段如下所示:
var builder = new ContainerBuilder();
builder.RegisterType<Dependency>.As<IDependency>.InstancePerLifetimeScope();
builder.RegisterType<Service>()
.As<IService>()
.WithParameter(new NamedParameter("someString", "TEST"))
.EnableClassInterceptors()
.InterceptedBy(typeof(LogExceptionsInterceptor));
服务的构造函数看起来像这样:
public class Service : IService
{
public Service(IDependency dependency, string someString)
{
if(dependency == null)
throw ArgumentNullException(nameof(dependency));
if(someString == null)
//**throws here**
throw ArgumentNullException(nameof(someString));
}
}
[猜测] 我在想的是,当调用 EnableClassInterceptors 时,会生成一个代理 class,其构造函数在现有一个,但参数名称不会复制到代理中 class/constructor。
这是个问题吗?有没有一种方法可以形成允许 WithParameter 和 EnableClassInterceptors 一起使用的注册?这是 Autofac 中的错误吗?
您的猜测是正确的:生成的代理 class 不保留构造函数参数名称。
目前没有办法在 DynamicProxy 中影响这一点,所以这不是 Autofac 的错误(尽管 Autofac 文档网站上目前没有记录这种边缘情况)。
这是你原来的 Service
class 参数的样子:
typeof(Service).GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[2]}
[0]: {ConsoleApplication10.IDependency dependency}
[1]: {System.String someString}
但生成的代理不保留名称:
GetType().GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[3]}
[0]: {Castle.DynamicProxy.IInterceptor[] }
[1]: {ConsoleApplication10.IDependency }
[2]: {System.String }
所以你有两个不太可靠的选项来解决这个限制 WithParameter
:
使用
TypedParamter
和string
作为类型:.WithParameter(new TypedParameter(typeof(string), "TEST"))
但是,如果您有多个相同类型的参数,这将不起作用
在这种情况下使用
PositionalParameter
如果类型被代理,您需要添加1
.WithParameter(new PositionalParameter(2, "TEST"))
另一种选择是不使用原始字符串类型,而是创建一个包装器,例如MyServiceParameter
或创建另一个服务,它可以向您的其他服务提供这些 string
配置值。