繁体   English   中英

Autofac的不同行为取决于builder.Register或builder.RegisterType的用法

[英]Different behavior of Autofac depending of usage of builder.Register or builder.RegisterType

使用特定的(复杂)类嵌套,当我尝试解析向其注册的类型时,在运行时在Autofac中遇到异常

builder.RegisterType<ClassThatDoesNotWork>().UsingConstructor(expression);

但是相同的注册适用于:

builder.Register<ClassThatDoesNotWork>(func);

添加.As<MyType>似乎没有任何改变。

我不知道是PEBKAC还是bug。 另外,我发现> builder.RegisterType<T>().UsingConstructor(expression); 在其他情况下工作。

我做了一个完整的工作示例(抱歉,它有点长,但是如果我使用过于简单的结构,问题就消失了):

class Program
{
    static void Main(string[] args)
    {
        var a = InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1");
        //var b = InjectionConfig.ResolveNamed<WhateverService>("MyServiceType2");
        var c = InjectionConfig.Resolve<RandomInnerClass>();
        var e = InjectionConfig.Resolve<ClassThatWorks>();

        // This one will fail
        var f = InjectionConfig.Resolve<ClassThatDoesNotWork>();
    }
}

public static class InjectionConfig
{
    private static IContainer Container { get; }

    static InjectionConfig()
    {
        var builder = new ContainerBuilder();

        builder.RegisterModule<InitModule>();

        Container = builder.Build();
    }

    public static TService Resolve<TService>()
    {
        return Container.Resolve<TService>();
    }

    public static TService ResolveNamed<TService>(string dependancy)
    {
        return Container.ResolveNamed<TService>(dependancy);
    }
}

public class InitModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        RegisterTemplateServices(builder);

        RegisterPropertiesGenerationServices(builder);
    }

    private void RegisterTemplateServices(ContainerBuilder builder)
    {
        var myServiceType1 = new WhateverService("MyServiceType1");
        builder.RegisterInstance(myServiceType1).Keyed<WhateverService>("MyServiceType1").SingleInstance();

        //var myServiceType2 = new WhateverService("MyServiceType2");
        //builder.RegisterInstance(myServiceType2).Keyed<WhateverService>("MyServiceType2").SingleInstance();
    }

    private void RegisterPropertiesGenerationServices(ContainerBuilder builder)
    {
        Func<IComponentContext, RandomInnerClass> funCtorRandomInnerClass =
            context => new RandomInnerClass(InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1"));
        builder.Register<RandomInnerClass>(funCtorRandomInnerClass).As<RandomInnerClass>();

        // This kind of initialization works
        Func<IComponentContext, ClassThatWorks> funcWorks = context => new ClassThatWorks(new AnotherClass(InjectionConfig.Resolve<RandomInnerClass>()), InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1"));
        builder.Register<ClassThatWorks>(funcWorks);

        // This one FAILS at runtime
        Expression<Func<ClassThatDoesNotWork>> expressionDoesNotWork = () => new ClassThatDoesNotWork(new AnotherClass(InjectionConfig.Resolve<RandomInnerClass>()), InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1"));
        builder.RegisterType<ClassThatDoesNotWork>().UsingConstructor(expressionDoesNotWork);

        // It would work if instead for registration I used :
        // Func<IComponentContext, ClassThatDoesNotWork> funcExample = context => new ClassThatDoesNotWork(new AnotherClass(InjectionConfig.Resolve<RandomInnerClass>()), InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1"));
        //builder.Register<ClassThatDoesNotWork>(funcExample);
    }
}

internal class AnotherClass
{
    public AnotherClass(RandomInnerClass resolve) { }
}

internal class ClassThatDoesNotWork
{
    public ClassThatDoesNotWork(AnotherClass a, WhateverService b) { }
}

internal class ClassThatWorks
{
    public ClassThatWorks(AnotherClass a, WhateverService b) { }
}

internal class RandomInnerClass
{
    public RandomInnerClass(WhateverService a) { }
}

internal class WhateverService
{
    public WhateverService(string myIdentifier) { }
}

例外:

Autofac.Core.DependencyResolutionException:激活特定注册期间发生错误。 有关详细信息,请参见内部异常。 注册:激活程序= ClassThatDoesNotWork(ReflectionActivator),服务= [ConsoleApp1.ClassThatDoesNotWork],生命周期= Autofac.Core.Lifetime.CurrentScopeLifetime,共享=无,所有权= OwnedByLifetimeScope --->在'Autofac.Core.Activators中找不到的构造函数可以使用可用的服务和参数调用类型为'ConsoleApp1.ClassThatDoesNotWork'的.Reflection.DefaultConstructorFinder:无法解析构造函数'Void .ctor(ConsoleApp1.AnotherClass,ConsoleApp1.WhateverService)'的参数'ConsoleApp1.AnotherClass a'。 (有关详细信息,请参阅内部异常。)---> Autofac.Core.DependencyResolutionException:不能使用可用服务调用类型为'ConsoleApp1.ClassThatDoesNotWork'的'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'的构造函数。参数:无法解析构造函数'Void .ctor(ConsoleApp1.AnotherClass,ConsoleApp1.WhateverService)'的参数'ConsoleApp1.AnotherClass a'。 àAutofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext上下文,IEnumerable 1 parameters) à Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable 1个参数)àAutofac.Core.Activate.InstanceLookup.Activate (IEnumerable 1 parameters) --- Fin de la trace de la pile d'exception interne --- à Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable 1参数)àAutofac.Core.Resolving.InstanceLookup.Execute()à Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope,IComponentRegistration注册,IEnumerable 1 parameters) à Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable 1参数)àAutofac.Core.Lifetime(LifeTimeILifetimeScope.Re注册,IEnumerable 1 parameters) à Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable 1 parameters) à Autofac.Core.Container.ResolveComponent(IComponentRegistration registration, IEnumerable 1参数)àAutofac.ResolutionExtensions.TryResolveService(IComponentContext上下文,服务服务,IEnumerable 1 parameters, Object& instance) à Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable 1参数)àAutofac.ResolutionExtensions.Resolve [ TService](IComponentContext上下文,IEnumerable`1参数)àAutofac.ResolutionExtensions.Resolve [TService](IComponentContext上下文)àConsoleApp1.InjectionConfig.ResolveTService dans T:\\ Temp \\ ConsoleApp1 \\ Program.cs:ligne 55àConsoleApp1.Program.Main (String [] args)dans T:\\ Temp \\ ConsoleApp1 \\ Program.cs:ligne 27

如您在中间看到的那样,使用

Func<IComponentContext, ClassThatDoesNotWork> funcExample = context => new ClassThatDoesNotWork(new AnotherClass(InjectionConfig.Resolve<RandomInnerClass>()), InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1"));
builder.Register<ClassThatDoesNotWork>(funcExample);

代替

Expression<Func<ClassThatDoesNotWork>> expressionDoesNotWork = () => new ClassThatDoesNotWork(new AnotherClass(InjectionConfig.Resolve<RandomInnerClass>()), InjectionConfig.ResolveNamed<WhateverService>("MyServiceType1"));
builder.RegisterType<ClassThatDoesNotWork>().UsingConstructor(expressionDoesNotWork);

解决问题。 对我来说,两个构造都应该做相同的事情,但是不应该。

我在.Net 4.6.2中使用了autofac 4.8.1(last)。

我想知道我是否做错了什么,另外,这两种构造之间最好的是什么(出于性能方面的考虑)。 谢谢

首先,您注册组件的方式看起来没有什么充分的理由过于复杂。 有了这堆new WhateverClass()您似乎正在为它做Autofac的工作,特别是考虑到Autofac抱怨您做的不完全正确。 我认为这可以简单得多。

但是,即使我们对此加以区分,您的代码也会遇到更严重的问题。 使用静态InjectionConfig解决注册中的所有内容,您实际上在打破Autofac的生命周期范围管理。 这正是使用Autofac时不应该执行的操作。 如果您需要解决注册lambda中的问题,则应使用Autofac提供的IComponentContext。

所以,我要做的是下面。 如果由于某种原因该方法不起作用,那么让我们查找一下。

class Program
{
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<InitModule>();
        var container = builder.Build();

        using (var scope = container.BeginLifetimeScope())
        {
            var a = scope.ResolveNamed<WhateverService>("MyServiceType1");
            var c = scope.Resolve<RandomInnerClass>();
            var e = scope.Resolve<ClassThatWorks>();

            // This one now works
            var f = scope.Resolve<ClassThatDoesNotWork>();
        }
    }
}

public class InitModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);

        RegisterTemplateServices(builder);

        RegisterPropertiesGenerationServices(builder);
    }

    private void RegisterTemplateServices(ContainerBuilder builder)
    {
        builder.RegisterType<WhateverService>()
            .WithParameter(new NamedParameter("myIdentifier", "MyServiceType1"))
            .Named<WhateverService>("MyServiceType1")
            .AsSelf()
            .SingleInstance();

        //var myServiceType2 = new WhateverService("MyServiceType2");
        //builder.RegisterInstance(myServiceType2).Keyed<WhateverService>("MyServiceType2").SingleInstance();
    }

    private void RegisterPropertiesGenerationServices(ContainerBuilder builder)
    {
        builder.RegisterType<AnotherClass>().AsSelf().InstancePerLifetimeScope();
        builder.RegisterType<RandomInnerClass>().AsSelf().InstancePerLifetimeScope();
        builder.RegisterType<ClassThatWorks>().AsSelf().InstancePerLifetimeScope();
        builder.RegisterType<ClassThatDoesNotWork>().AsSelf().InstancePerLifetimeScope();
    }
}

internal class AnotherClass
{
    public AnotherClass(RandomInnerClass resolve)
    {
    }
}

internal class ClassThatDoesNotWork
{
    public ClassThatDoesNotWork(AnotherClass a, [KeyFilter("MyServiceType1")] WhateverService b)
    {
    }
}

internal class ClassThatWorks
{
    public ClassThatWorks(AnotherClass a, [KeyFilter("MyServiceType1")] WhateverService b)
    {
    }
}

internal class RandomInnerClass
{
    public RandomInnerClass([KeyFilter("MyServiceType1")] WhateverService a)
    {
    }
}

internal class WhateverService
{
    public WhateverService(string myIdentifier)
    {
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM