Domanda

I am trying to evaluate the scoping of Autofac and as I understand it, when an instance has been declared as InstancePerLifetimeScope, then within the using(container.BeginLifetimeScope()) block, we should get the same instance. But in another such block, we should get a different instance. But my code (in linqpad) gives me the same instance. Windsor's lifestylescope however works as I think it should.

Code:

static IContainer glkernel;
void Main()
{
  var builder = new ContainerBuilder();
  builder.RegisterType<Controller>();
  builder.RegisterType<A>().As<IInterface>().InstancePerLifetimeScope();
  glkernel = builder.Build();

  using (glkernel.BeginLifetimeScope()){
    Controller c1 = glkernel.Resolve<Controller>();
    c1.GetA();//should get instance 1
    c1.GetA();//should get instance 1
  }

  using (glkernel.BeginLifetimeScope()){
    Controller d = glkernel.Resolve<Controller>();
    d.GetA();//should get instance 2
    d.GetA();//should get instance 2
  }
}

public interface IInterface
{
  void DoWork(string s);
}

public class A : IInterface
{
  public A()
  {
    ID = "AAA-"+Guid.NewGuid().ToString().Substring(1,4);
  }
  public string ID { get; set; }
  public string Name { get; set; }
  public void DoWork(string s)
  {
    Display(ID,"working...."+s);
  }
}

public static void Display(string id, string mesg)
{
  mesg.Dump(id);
}

public class Controller 
{
  public Controller()
  {
    ("controller ins").Dump();
  }

  public void GetA()
  {
    //IInterface a = _kernel.Resolve<IInterface>();
    foreach(IInterface a in glkernel.Resolve<IEnumerable<IInterface>>())
    {
      a.DoWork("from A");
    }
  }
}

The output is:

controller ins

AAA-04a0 
working....from A 

AAA-04a0 
working....from A 

controller ins

AAA-04a0 
working....from A 

AAA-04a0 
working....from A 

Perhaps my understanding of scoping is wrong. If so, can you please explain.

What do I have to do to get a different instance in the second block?

È stato utile?

Soluzione

The problem is you're resolving things out of the container - the glkernel instead of out of the lifetime scope. A container is a lifetime scope - the root lifetime scope.

Resolve out of the lifetime scope instead. That may mean you need to change up your controller to pass in the list of components rather than using service location.

public class Controller 
{
  private IEnumerable<IInterface> _interfaces;
  public Controller(IEnumerable<IInterface> interfaces)
  {
    this._interfaces = interfaces;
    ("controller ins").Dump();
  }

  public void GetA()
  {
    foreach(IInterface a in this._interfaces)
    {
      a.DoWork("from A");
    }
  }
}

Then it's easy enough to switch your resolution code.

using (var scope1 = glkernel.BeginLifetimeScope()){
  Controller c1 = scope1.Resolve<Controller>();
  c1.GetA();
  c1.GetA();
}

using (var scope2 = glkernel.BeginLifetimeScope()){
  Controller c2 = scope2.Resolve<Controller>();
  c2.GetA();
  c2.GetA();
}

The Autofac wiki has some good information on lifetime scopes you might want to check out.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top