简体   繁体   中英

Autofac generic decorator linking

I have a generic RepositoryDecorator<T> decorator. MyRepositoryDecoratorBase<T> and NoteRepository<Note> are inheriting from it.

IRepository<T> is an interface and Repository<T> is an implementation of it. This is also registered using Autofac as shown in code sample.

Trying to use autofac to generate instance of MyRepositoryDecoratorBase every time an instance of NoteRepository is asked for.

That way I can link the decorators for cross cutting concerns like logging.

Abstract Decorator

    public abstract class RepositoryDecorator<TAggregate>:IRepository<TAggregate> 
    where TAggregate:AggregateRoot, new() 
{
    protected readonly IRepository<TAggregate> Repository;

    protected RepositoryDecorator(IRepository<TAggregate>  repository)
    {
        Repository = repository;
    }

    public virtual TAggregate GetById(Guid Id)
    {
        return Repository.GetById(Id);
    }

    public virtual void Save(TAggregate aggregate)
    {
        Repository.Save(aggregate);
    }

}

Generic LoggingDecorator

    public class MyRepositoryDecoratorBase<T>:RepositoryDecorator<T> where T : AggregateRoot, new()
{
    private DateTime _commitStartTime;

    public MyRepositoryDecoratorBase(IRepository<T> repository) : base(repository)
    {
    }

    public override T GetById(Guid Id)
    {
        BeforeLoadAggregate(Id);
        var result =  base.GetById(Id);
        AfterLoadingAggregate(result);
        return result;
    }

    public override void Save(T aggregate)
    {
        BeforeSaveAggregate(aggregate);
        base.Save(aggregate);
        AfterSavingAggregate(aggregate);
    }

    protected void BeforeLoadAggregate(Guid id)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine($"Loading {id} ...");
        Console.ForegroundColor = ConsoleColor.White;
    }

    protected void AfterLoadingAggregate(T aggregate)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine($"Loaded {aggregate.GetType()} ...");
        Console.ForegroundColor = ConsoleColor.White;
    }

    protected void BeforeSaveAggregate(T aggregate)
    {
        _commitStartTime = DateTime.Now;
        Console.WriteLine($"Trying to commit {aggregate.GetUncommittedChanges().Count()} events to storage.");
    }

    protected void AfterSavingAggregate(T aggregate)
    {
        Console.WriteLine($"Committed in {DateTime.Now.Subtract(_commitStartTime).TotalMilliseconds} ms.");
    }
}

Note Decorator

public class NoteRepository:RepositoryDecorator<Note>
{
    public NoteRepository(IRepository<Note> repository) : base(repository)
    {

    }

    public override void Save(Note aggregate)
    {
        LogManager.Log("Saving Note...", LogSeverity.Information);
        base.Save(aggregate);
        LogManager.Log("Note Saved...", LogSeverity.Information);
    }
}

Note: I'm using this to Register a base Repository implementation for IRepository

            //This will resolve and bind storage types to a concrete repository of <T> as needed
        builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).SingleInstance();

I've looked at the solution in Autofac - Register multiple decorators

But couldn't get it working. I have a feeling my Generic registration of Repository is getting in the way.

The following works but I want to link multiple Decorators automatically without hardcoding it.

 NoteRepository rep = new NoteRepository(new MyRepositoryDecoratorBase<Note>(container.Resolve<IRepository<Note>>())); 

I got it working as follows

        //This will resolve and bind storage types to a concrete repository of <T> as needed
        builder.RegisterGeneric(typeof(Repository<>))
        .Named("handler",typeof(IRepository<>))
        .SingleInstance();

        //This will bind the decorator
        builder.RegisterGenericDecorator(
        typeof(MyRepositoryDecorator<>),typeof(IRepository<>),fromKey: "handler");

        //Register NoteRepository
        builder.RegisterType<NoteRepository>();

And using it

        //Get ioc container to create our repository
        NoteRepository rep = resolver.Resolve<NoteRepository>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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