Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Autofac单例激活解析_C#_Design Patterns_Inversion Of Control_Autofac - Fatal编程技术网

C# Autofac单例激活解析

C# Autofac单例激活解析,c#,design-patterns,inversion-of-control,autofac,C#,Design Patterns,Inversion Of Control,Autofac,我误解的症结在于,我想直接解析()一个嵌套方法中的一个类型,该方法是由于OnActivating事件调用的,用于同一个单例类型,而autofac正试图创建该单例的第二个实例 长得多的版本: 首先是一个完整的示例,然后我将总结: public static class AutofacTest { public static void Test() { var builder = new ContainerBuilder(); // Register

我误解的症结在于,我想直接解析()一个嵌套方法中的一个类型,该方法是由于OnActivating事件调用的,用于同一个单例类型,而autofac正试图创建该单例的第二个实例

长得多的版本:

首先是一个完整的示例,然后我将总结:

public static class AutofacTest
{
    public static void Test()
    {
        var builder = new ContainerBuilder();

        // Register the environment as a singleton, and call Initialize when created
        builder.RegisterType<Environment>().AsSelf().As<IEnvironment>().SingleInstance().OnActivating(e => e.Instance.Initialize());

        // Register the simulator, also a singleton and dependent on 
        builder.RegisterType<Simulator>().AsSelf().As<ISimulator>().SingleInstance();

        // Register a simple class, that needs an initialized environment
        builder.RegisterType<IndependentClass>();

        // Build/scope
        var context = builder.Build();
        var scope = context.BeginLifetimeScope();

        // Register the service locator
        ServiceLocator.GlobalScope = scope;

        //var childScope = scope.BeginLifetimeScope(cb =>
        //{
        //    cb.RegisterType<IndependentClass>();
        //});

        // Now resolve the independent class, which will trigger the environment/simulator instantiation
        var inst = scope.Resolve<IndependentClass>();
    }
}

public static class ServiceLocator
{
    public static ILifetimeScope GlobalScope { get; set; }
}

public interface IEnvironment 
{
    bool IsInitialized { get; }
}

public class Environment : IEnvironment
{
    private static Environment Instance;

    private SampleComponent _component;
    private bool _isInitialized;

    public bool IsInitialized
    {
        get { return _isInitialized; }
    }

    public void Initialize()
    {
        if (Instance != null) throw new InvalidOperationException();
        Instance = this;

        // Canonical complex code which forces me into what I think is a tricky situation...

        _component = new SampleComponent(SampleServiceType.SimulatedThing);

        _component.Initialize();

        _isInitialized = true;
    }
}

public interface ISimulator { }

public class Simulator : ISimulator
{
    private static Simulator Instance;

    private readonly IEnvironment _environment;

    public Simulator(IEnvironment environment)
    {
        if (Instance != null) throw new InvalidOperationException();
        Instance = this;

        _environment = environment;
    }
}

public enum SampleServiceType
{
    None = 0,
    RealThing,
    SimulatedThing,
}

public class SampleComponent
{
    private readonly SampleServiceType _serviceType;

    public SampleComponent(SampleServiceType serviceType)
    {
        _serviceType = serviceType;
    }

    public void Initialize()
    {
        // Sample component that has different types of repositories
        switch (_serviceType)
        {
            case SampleServiceType.SimulatedThing:
                var sim = ServiceLocator.GlobalScope.Resolve<ISimulator>();
                // Create a repositiry object or something requriing the simulator
                break;
        }
    }
}

public class IndependentClass
{
    public IndependentClass(IEnvironment env)
    {
        if (!env.IsInitialized) throw new InvalidOperationException();
    }
}
不过,这是可行的:1<仍然会为每个“新”实例调用code>on激活。2.只是感觉太粗糙了——最终我现在正在管理实例和构造,这就是容器的用途。(当您实际想要使用容器解析参数时,这也有点烦人,但同样可以很容易地解决。)

所以说了这么多(我非常感谢你能做到这一点),似乎我在这里有一个基本的误解。(我猜它与
SampleComponent
中的服务定位器模式和/或偶然工厂有关,但我不再猜测。)


我想真正的问题是:我遗漏了什么?

试图运行示例中的确切代码,我无法解析
独立类,因为我(正确地)得到了一个异常。异常堆栈看起来像一个循环依赖项,它嵌套和嵌套同一个异常,就像堆栈溢出:

Autofac.Core.DependencyResolutionException was unhandled
  _HResult=-2146233088
  _message=An exception was thrown while executing a resolve operation. See the InnerException for details.
  HResult=-2146233088
  IsTransient=false
  Message=An exception was thrown while executing a resolve operation. See the InnerException for details. ---> Operation is not valid due to the current state of the object. (See inner exception for details.)
  Source=Autofac
  StackTrace:
       at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
       at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
       at SingletonRepro.SampleComponent.Initialize() in e:\dev\spike\SingletonRepro\SingletonRepro\Program.cs:line 120
       at SingletonRepro.Environment.Initialize() in e:\dev\spike\SingletonRepro\SingletonRepro\Program.cs:line 75
       at SingletonRepro.Program.<Main>b__0(IActivatingEventArgs`1 e) in e:\dev\spike\SingletonRepro\SingletonRepro\Program.cs:line 17
       at Autofac.Builder.RegistrationBuilder`3.<>c__DisplayClass6.<OnActivating>b__5(Object s, ActivatingEventArgs`1 e)
       at Autofac.Core.Registration.ComponentRegistration.RaiseActivating(IComponentContext context, IEnumerable`1 parameters, Object& instance)
       at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
       at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
       at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
       at Autofac.Core.Resolving.InstanceLookup.Execute()
       at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()
       at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
       at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
       at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
       at Autofac.Core.Resolving.InstanceLookup.Execute()
       at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
       at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
       at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
       at SingletonRepro.Program.Main(String[] args) in e:\dev\spike\SingletonRepro\SingletonRepro\Program.cs:line 38
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.InvalidOperationException
       _HResult=-2146233079
       _message=Operation is not valid due to the current state of the object.
       HResult=-2146233079
       IsTransient=false
       Message=Operation is not valid due to the current state of the object.
       Source=SingletonRepro
       StackTrace:
            at SingletonRepro.Environment.Initialize() in e:\dev\spike\SingletonRepro\SingletonRepro\Program.cs:line 68
            at SingletonRepro.Program.<Main>b__0(IActivatingEventArgs`1 e) in e:\dev\spike\SingletonRepro\SingletonRepro\Program.cs:line 17
            at Autofac.Builder.RegistrationBuilder`3.<>c__DisplayClass6.<OnActivating>b__5(Object s, ActivatingEventArgs`1 e)
            at Autofac.Core.Registration.ComponentRegistration.RaiseActivating(IComponentContext context, IEnumerable`1 parameters, Object& instance)
            at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
            at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
            at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
            at Autofac.Core.Resolving.InstanceLookup.Execute()
            at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
            at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
            at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass2.<CanSupplyValue>b__0()
            at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
            at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)
            at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)
            at Autofac.Core.Resolving.InstanceLookup.<Execute>b__0()
            at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)
            at Autofac.Core.Resolving.InstanceLookup.Execute()
            at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)
            at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)
            at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
       InnerException: ...
如果您创建的存储库需要
i模拟器
,请尝试将该存储库的构造函数更改为使用
Lazy
,并且仅在最后一刻调用
Lazy.Value
。这将延迟
环境的解析操作
足够长的时间,使整个链第一次正确完成,并使您摆脱循环解析问题

一个更好的选择是重构以一直使用DI。现在,您可以通过代码混合依赖注入、服务定位和手动实例构造<代码>环境
手动创建一个
采样组件
SampleComponent
使用服务位置获取一个
ISimulator
ISimulator
使用DI获取
IEnvironment
。像这样的混合和匹配会让你陷入各种各样的麻烦,就像你现在看到的那样

事实上,一直使用DI意味着您实际上不需要在任何地方实现singleton模式,只需使用构造函数并根据需要注册东西
SingleInstance

这是您的代码的更新版本(在控制台应用程序表单中),其中显示了一些可能的操作方法。显然,您真正的代码可能更复杂,因此我无法确切地向您展示每个边缘情况的所有可能解决方案,但这是一种打破链条的方法。你可以利用这里和其他地方的想法来找出应对挑战的方法

using System;
using Autofac;
using Autofac.Features.Indexed;

namespace SingletonRepro
{
  class Program
  {
    static void Main()
    {
      var builder = new ContainerBuilder();

      // You can still keep the Initialize call if you want.
      builder.RegisterType<Environment>().As<IEnvironment>().SingleInstance().OnActivated(args => args.Instance.Initialize());

      // Everything's in DI now, not just some things.
      builder.RegisterType<Simulator>().As<ISimulator>().SingleInstance();
      builder.RegisterType<IndependentClass>();

      // Using keyed services to choose the repository rather than newing things up.
      builder.RegisterType<RealRepository>().Keyed<IRepository>(SampleServiceType.RealThing);
      builder.RegisterType<SimulatedRepository>().Keyed<IRepository>(SampleServiceType.SimulatedThing);
      builder.RegisterType<SampleComponent>().WithParameter("serviceType", SampleServiceType.SimulatedThing);

      var context = builder.Build();
      using (var scope = context.BeginLifetimeScope())
      {
        // Using Lazy<T> in the IndependentClass to defer the need for
        // IEnvironment right away - breaks the dependency circle.
        var inst = scope.Resolve<IndependentClass>();
        inst.DoWork();
        Console.WriteLine("Instance: {0}", inst);
      }
    }
  }

  public interface IEnvironment
  {
    bool IsInitialized { get; }
  }

  public class Environment : IEnvironment
  {
    public SampleComponent _component;

    public Environment(SampleComponent component)
    {
      this._component = component;
    }

    public void Initialize()
    {
      this._component.DoSomethingWithRepo();
      this.IsInitialized = true;
    }

    public bool IsInitialized { get; private set; }
  }

  public interface ISimulator
  {
  }

  public class Simulator : ISimulator
  {
    public Simulator(IEnvironment environment)
    {
      this.Environment = environment;
    }
    public IEnvironment Environment { get; private set; }
  }

  public enum SampleServiceType
  {
    None = 0,
    RealThing,
    SimulatedThing,
  }

  public class SampleComponent
  {
    private IIndex<SampleServiceType, IRepository> _repositories;

    private SampleServiceType _serviceType;

    // Use indexed/keyed services to pick the right one from a dictionary
    // rather than newing up the repository (or whatever) manually.
    public SampleComponent(IIndex<SampleServiceType, IRepository> repositories, SampleServiceType serviceType)
    {
      this._repositories = repositories;
      this._serviceType = serviceType;
    }

    public void DoSomethingWithRepo()
    {
      // You could always take the service type parameter in this function
      // rather than as a constructor param.
      var repo = this._repositories[this._serviceType];
      repo.DoWork();
    }
  }

  public interface IRepository
  {
    void DoWork();
  }

  public class SimulatedRepository : IRepository
  {
    private ISimulator _simulator;

    public SimulatedRepository(ISimulator simulator)
    {
      this._simulator = simulator;
    }

    public void DoWork()
    {
    }
  }

  public class RealRepository : IRepository
  {
    public void DoWork()
    {
    }
  }

  public class IndependentClass
  {
    private Lazy<IEnvironment> _env;

    // Delaying the need for the IEnvironment in the constructor
    // can help break the circular dependency chain, as well as not
    // immediately checking that it's initialized. (Can you just
    // TRUST that it's initialized and call it good?)
    public IndependentClass(Lazy<IEnvironment> env)
    {
      this._env = env;
    }

    public void DoWork()
    {
      if (!this._env.Value.IsInitialized)
        throw new InvalidOperationException();
    }
  }
}
使用系统;
使用Autofac;
使用Autofac.Features.index;
名称空间单音复制
{
班级计划
{
静态void Main()
{
var builder=new ContainerBuilder();
//如果需要,您仍然可以保留初始化调用。
已激活(args=>args.Instance.Initialize());
//现在一切都在DI中,不仅仅是一些东西。
builder.RegisterType().As().SingleInstance();
RegisterType();
//使用键控服务选择存储库,而不是更新内容。
builder.RegisterType().Keyed(SampleServiceType.RealThing);
已键入builder.RegisterType().Keyed(SampleServiceType.SimulatedThing);
builder.RegisterType().WithParameter(“serviceType”,SampleServiceType.SimulatedThing);
var context=builder.Build();
使用(var scope=context.BeginLifetimeScope())
{
//在独立类中使用Lazy延迟
//即时环境-打破依赖循环。
var inst=scope.Resolve();
安装道工();
WriteLine(“实例:{0}”,inst);
}
}
}
公共接口环境
{
布尔已初始化{get;}
}
公共类环境:IEnEnvironment
{
公共样本组件_组件;
公共环境(采样组件)
{
这个._组件=组件;
}
公共无效初始化()
{
此._component.DoSomethingWithRepo();
this.IsInitialized=真;
}
公共布尔值已初始化{get;private set;}
}
公共接口模拟器
{
}
公共类模拟器:ISimulator
{
公共模拟器(IEN环境)
{
这个。环境=环境;
}
公共IEnEnvironment环境{get;private set;}
}
公共枚举SampleServiceType
{
无=0,
房地产,
模拟,,
}
公共类采样组件
{
私有IIndex_存储库;
私有SampleServiceType_serviceType;
//使用索引/键控服务从字典中选择正确的服务
//而不是手动更新存储库(或其他)。
公共SampleComponent(IIndex存储库,SampleServiceType服务类型)
{
这是。_repositories=repositories;
此.\u serviceType=serviceType;
}
公共无效DoSomethingWithRepo()
{
//您可以始终在此函数中使用服务类型参数
//而不是作为构造函数参数。
var repo=this.\u存储库[this.\u服务类型];
回购协议;
}
}
公共接口假定
{
无效销钉();
}
公共类模拟存储:IRepository
{
专用ISimulator_模拟器;
公共模拟存储库(ISimulator模拟器)
{
这个._模拟器=模拟器;
}
公共工作
{
}
}
公共类RealRepository:IRepository
{
公共工作
{
}
}
公共类独立类
{
var sim = ServiceLocator.GlobalScope.Resolve<Lazy<ISimulator>>();
using System;
using Autofac;
using Autofac.Features.Indexed;

namespace SingletonRepro
{
  class Program
  {
    static void Main()
    {
      var builder = new ContainerBuilder();

      // You can still keep the Initialize call if you want.
      builder.RegisterType<Environment>().As<IEnvironment>().SingleInstance().OnActivated(args => args.Instance.Initialize());

      // Everything's in DI now, not just some things.
      builder.RegisterType<Simulator>().As<ISimulator>().SingleInstance();
      builder.RegisterType<IndependentClass>();

      // Using keyed services to choose the repository rather than newing things up.
      builder.RegisterType<RealRepository>().Keyed<IRepository>(SampleServiceType.RealThing);
      builder.RegisterType<SimulatedRepository>().Keyed<IRepository>(SampleServiceType.SimulatedThing);
      builder.RegisterType<SampleComponent>().WithParameter("serviceType", SampleServiceType.SimulatedThing);

      var context = builder.Build();
      using (var scope = context.BeginLifetimeScope())
      {
        // Using Lazy<T> in the IndependentClass to defer the need for
        // IEnvironment right away - breaks the dependency circle.
        var inst = scope.Resolve<IndependentClass>();
        inst.DoWork();
        Console.WriteLine("Instance: {0}", inst);
      }
    }
  }

  public interface IEnvironment
  {
    bool IsInitialized { get; }
  }

  public class Environment : IEnvironment
  {
    public SampleComponent _component;

    public Environment(SampleComponent component)
    {
      this._component = component;
    }

    public void Initialize()
    {
      this._component.DoSomethingWithRepo();
      this.IsInitialized = true;
    }

    public bool IsInitialized { get; private set; }
  }

  public interface ISimulator
  {
  }

  public class Simulator : ISimulator
  {
    public Simulator(IEnvironment environment)
    {
      this.Environment = environment;
    }
    public IEnvironment Environment { get; private set; }
  }

  public enum SampleServiceType
  {
    None = 0,
    RealThing,
    SimulatedThing,
  }

  public class SampleComponent
  {
    private IIndex<SampleServiceType, IRepository> _repositories;

    private SampleServiceType _serviceType;

    // Use indexed/keyed services to pick the right one from a dictionary
    // rather than newing up the repository (or whatever) manually.
    public SampleComponent(IIndex<SampleServiceType, IRepository> repositories, SampleServiceType serviceType)
    {
      this._repositories = repositories;
      this._serviceType = serviceType;
    }

    public void DoSomethingWithRepo()
    {
      // You could always take the service type parameter in this function
      // rather than as a constructor param.
      var repo = this._repositories[this._serviceType];
      repo.DoWork();
    }
  }

  public interface IRepository
  {
    void DoWork();
  }

  public class SimulatedRepository : IRepository
  {
    private ISimulator _simulator;

    public SimulatedRepository(ISimulator simulator)
    {
      this._simulator = simulator;
    }

    public void DoWork()
    {
    }
  }

  public class RealRepository : IRepository
  {
    public void DoWork()
    {
    }
  }

  public class IndependentClass
  {
    private Lazy<IEnvironment> _env;

    // Delaying the need for the IEnvironment in the constructor
    // can help break the circular dependency chain, as well as not
    // immediately checking that it's initialized. (Can you just
    // TRUST that it's initialized and call it good?)
    public IndependentClass(Lazy<IEnvironment> env)
    {
      this._env = env;
    }

    public void DoWork()
    {
      if (!this._env.Value.IsInitialized)
        throw new InvalidOperationException();
    }
  }
}