Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decorator and ResolveAll<> interaction #141

Closed
eValker opened this issue Aug 7, 2023 · 2 comments
Closed

Decorator and ResolveAll<> interaction #141

eValker opened this issue Aug 7, 2023 · 2 comments

Comments

@eValker
Copy link

eValker commented Aug 7, 2023

Hello,

While working on a project I found weird resolver's behaviour. I ma not sure whether I am doing something wrong or if it is just a bug in the library :)

Here is a code sample to reproduce the issue:

using Stashbox;
using Stashbox.Configuration;

var container = new StashboxContainer(c =>
{
    c.WithRegistrationBehavior(Rules.RegistrationBehavior.PreserveDuplications);
});

container.Register<AnimalRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());
container.Register<CarRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());
container.Register<PhoneRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());
container.Register<HouseRepository>(c => c.WithSingletonLifetime().AsImplementedTypes());

// first try
//container.RegisterDecorator<CachedAnimalRepository>();
//container.RegisterDecorator<CachedCarRepository>();
//container.RegisterDecorator<CachedPhoneRepository>();

// second try
container.RegisterDecorator<CachedAnimalRepository>(c => c.AsServiceAlso<IDataRepository>());
container.RegisterDecorator<CachedCarRepository>(c => c.AsServiceAlso<IDataRepository>());
container.RegisterDecorator<CachedPhoneRepository>(c => c.AsServiceAlso<IDataRepository>());

container.Register<CollectionOfServices>();

var x = container.Resolve<CollectionOfServices>();

Console.ReadKey();

internal interface IDataRepository
{
    void CommonMethod()
    {
    }
}

internal interface IAnimalRepository : IDataRepository
{
}

internal interface ICarRepository : IDataRepository
{
}

internal interface IPhoneRepository : IDataRepository
{
}

internal interface IHouseRepository : IDataRepository
{
}

internal sealed class AnimalRepository : IAnimalRepository
{
}

internal sealed class CarRepository : ICarRepository
{
}

internal sealed class PhoneRepository : IPhoneRepository
{
}

internal sealed class HouseRepository : IHouseRepository
{
}

internal sealed class CachedAnimalRepository : IAnimalRepository
{
    public CachedAnimalRepository(IAnimalRepository service)
    {
        // never called
    }
}

internal sealed class CachedCarRepository : ICarRepository
{
    public CachedCarRepository(ICarRepository service)
    {
        // never called
    }
}

internal sealed class CachedPhoneRepository : IPhoneRepository
{
    public CachedPhoneRepository(IPhoneRepository service)
    {
        //called with PhoneRepository instance
    }
}

internal sealed class CollectionOfServices
{
    public CollectionOfServices(IEnumerable<IDataRepository> services)
    {
        // got array with 4 instances of CachedPhoneRepository (same instance)
    }
}

Expected value

Inside CollectionOfServices constructor, I'm expecting to recieve an array of 3 different data repositories (for animals, cars and phones) wrapped in cached implementations and also HouseRepositry, e.g.

  • CachedAnimalRepository (as decorator of AnimalRepository)
  • CachedCarRepository (as decorator of CarRepository)
  • CachedPhoneRepository (as decorator of PhoneRepository)
  • HouseRepository (not wrapped)

Actual value

CollectionOfServices constructor recieves an array of 4 CachedPhoneRepository instances.
image

I am not sure how can I change the configuration to achive what I need. I little help would be appreciated :)

@eValker
Copy link
Author

eValker commented Aug 7, 2023

Ok, I think I figured this out.

container.RegisterDecorator<IAnimalRepository, CachedAnimalRepository>(c => c.AsServiceAlso<IDataRepository>().When(t => t.Type.IsAssignableTo(typeof(IAnimalRepository))));
container.RegisterDecorator<ICarRepository, CachedCarRepository>(c => c.AsServiceAlso<IDataRepository>().When(t => t.Type.IsAssignableTo(typeof(ICarRepository))));
container.RegisterDecorator<IPhoneRepository, CachedPhoneRepository>(c => c.AsServiceAlso<IDataRepository>().When(t => t.Type.IsAssignableTo(typeof(IPhoneRepository))));

Not sure if this is the best approach, but it is working :)

@eValker eValker closed this as completed Aug 11, 2023
@z4kn4fein
Copy link
Owner

Hi @eValker, thank you for reporting this. I see you found a workaround but I recognised this as a bug. In 5.12.0-preview-821 it's now possible to register your decorators like:

container.RegisterDecorator<CachedAnimalRepository>(c => c.AsServiceAlso<IDataRepository>());
container.RegisterDecorator<CachedCarRepository>(c => c.AsServiceAlso<IDataRepository>());
container.RegisterDecorator<CachedPhoneRepository>(c => c.AsServiceAlso<IDataRepository>());

or:

container.RegisterDecorator<CachedAnimalRepository>(c => c.AsImplementedTypes());
container.RegisterDecorator<CachedCarRepository>(c => c.AsImplementedTypes());
container.RegisterDecorator<CachedPhoneRepository>(c => c.AsImplementedTypes());

The container will now treat your resolution request correctly. Could you please re-check your setup that it works now as expected? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants