Как я могу создать регистрацию с ключом, которая игнорирует декораторы в Autofac? - PullRequest
1 голос
/ 14 марта 2019

Я создал простой декоратор кэша (ServiceDecorator), который украшает реализации IService, зарегистрированные в RegisterDecorator.В некоторых случаях я не хочу украшенный экземпляр.(Фактический сценарий - это REST API, в котором ServiceA иногда должен кэшироваться, а иногда нет.)

Внедрение по умолчанию всегда должно разрешаться для декоратора службы, но в некоторых особых случаях я хотел бы использовать метаданные,атрибуты или другие, чтобы сигнализировать, что ServiceA должен использоваться.

Возможно ли этого добиться?Использование Autofac 4.9.1 в .NET 4.7.2.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using Autofac.Core;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var cb = new ContainerBuilder();
            cb.RegisterType<ServiceA>().As<IService>();
            var context = cb.Build();
            var service = context.Resolve<IService>();
            //Output: "ServiceA"
            Console.WriteLine(service.DoStuff());

            cb = new ContainerBuilder();
            cb.RegisterType<ServiceA>().As<IService>();
            cb.RegisterDecorator<ServiceDecorator, IService>();
            context = cb.Build();
            service = context.Resolve<IService>();
            //Output: "ServiceDecorator"
            Console.WriteLine(service.DoStuff());

            cb = new ContainerBuilder();
            cb.RegisterType<ServiceA>().As<IService>();
            cb.RegisterDecorator<ServiceDecorator, IService>();
            cb.RegisterType<ServiceA>().Keyed<IService>("notdecorated");
            context = cb.Build();
            service = context.ResolveKeyed<IService>("notdecorated");
            //Output: "ServiceDecorator", but hoped for "ServiceA"
            Console.WriteLine(service.DoStuff());

            Console.ReadKey();
        }
    }


    public interface IService
    {
        string DoStuff();
    }

    public class ServiceA : IService
    {
        public string DoStuff()
        {
            return "ServiceA";
        }
    }

    public class ServiceDecorator : IService
    {
        private readonly IService _decoratedService;
        public ServiceDecorator(IService decoratedService)
        {
            _decoratedService = decoratedService;
        }
        public string DoStuff()
        {
            return "ServiceDecorator";
        }
    }

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Внедрение по умолчанию всегда должно разрешаться для декоратора службы, но в некоторых особых случаях я хотел бы использовать метаданные, атрибуты или другое, чтобы сигнализировать о необходимости использования ServiceA.

Я бы не пошел по этому маршруту, потому что это означает, что во время построения ваших графов объектов требуются данные времени выполнения. Это кодовый запах , если не сказать больше.

Вместо этого, предпочтите, чтобы структура ваших графов объектов оставалась неизменной во время выполнения вашего приложения. Вместо этого, если какое-то поведение необходимо применить для некоторых запросов, в то время как его следует опускать во время других запросов того же приложения, предпочтите создание этого поведения в самом декораторе или создайте дополнительный сервис, который позволяет переключаться между op и фактическое поведение во время выполнения, основанное на существующих данных времени выполнения.

Однако правильным подходом было бы применение условного декоратора на основе сервисов, которые он декоратор, и других статических метаданных. Например, вы можете пометить ServiceA атрибутом [Cache] и ServiceB атрибутом [NoCache] и соответственно применить декоратор. Обратите внимание, что в этом случае структура графика не изменится во время выполнения, потому что ServiceA всегда будет украшен, а ServiceB никогда не будет. Однако я не уверен, что условно применить декоратор в Autofac.

1 голос
/ 14 марта 2019

Конечно, это не самый чистый способ, и в более сложном примере я не уверен, насколько хорошо это будет работать - но есть возможность добавить переменную flag по существу

public class ServiceA : IService
    {
        public bool withDecs { get; set; } = true;
        public string DoStuff()
        {
            return "ServiceA";
        }
    }

это означает, что выможет сделать что-то вроде:

cb.RegisterType<ServiceA>().As<IService>();
cb.RegisterDecorator<ServiceDecorator, IService>(x=> ((ServiceA)x.CurrentInstance).withDecs);
cb.RegisterType<ServiceA>().Keyed<IService>("notdecorated").WithProperty("withDecs",false);

это не совсем элегантно, хотя он устанавливает декоратор как условный для withDecs, который является свойством, установленным на ключе, поэтому не будет запускать декоратор

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...