使用 EnableClassInterceptors 和 WithParameter 注册一个类型

Registering a type with both EnableClassInterceptors and WithParameter

我在使用 Autofac 时遇到问题,似乎 EnableClassInterceptors 干扰了我使用 .WithParameter(...) 的能力。当使用下面的代码在 Service 上调用构造函数时,不会填充 someString。备注:

我的注册码片段如下所示:

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:

  • 使用 TypedParamterstring 作为类型:

    .WithParameter(new TypedParameter(typeof(string), "TEST"))
    

    但是,如果您有多个相同类型的参数,这将不起作用

  • 在这种情况下使用 PositionalParameter 如果类型被代理,您需要添加 1

    .WithParameter(new PositionalParameter(2, "TEST"))
    

另一种选择是不使用原始字符串类型,而是创建一个包装器,例如MyServiceParameter 或创建另一个服务,它可以向您的其他服务提供这些 string 配置值。