2015-04-20 2 views
1

Я использую следующий интерфейс в своем логическом слое, чтобы обеспечить единоличную ответственность (можно сломать, но вам нужно перепрыгнуть через обручи и дать себе сильную головную боль для достижения этого).Autofac и перечисления с HasFlag

public interface ILogic<in TContext, out TOutput> 
{ 
    #region Execute 

    TOutput Execute(TContext context); 

    #endregion 
} 

Давайте предположим, что с иметь следующее:

[DataContract] 
public class CompanyRequest : ExtensibleDataObject 
{ 
    #region Properties 

    [DataMember(IsRequired = true)] 
    public string Number { get; set; } 

    [DataMember(IsRequired = true)] 
    public Entity Entity { get; set; } 

    [DataMember(IsRequired = true)] 
    public CompanyOptions Options { get; set; } 

    #endregion 
} 

и

[DataContract] 
public class CompanyResponse : ExtensibleDataObject 
{ 
    [DataMember] 
    public Company Company { get; set; } 

    // TODO: Store any errors occurred for graceful handling 

    //.. 

    //.. 
} 

Компания DataContract будет содержать данные, запрошенные через перечисление CompanyOptions, в конечном счете, будет 30 - 50 таких свойства.

Я понимаю, что Aufofac не может вводить список только логических экземпляров, необходимых при строительстве, но я знаю через IIndex, что можно заключить контракт с компанией или другое имя (для обсуждения сейчас) IIndex, хранящийся во время построения, либо с помощью метаданных, либо в противном случае он может, например, выполнить команду Where (registration => context.Flags.HasFlag (logic.Metadata.Flag), оставляя список логических реализаций, отвечающих за выполнение вызова. объяснение, вероятно, неправильное и полное отверстий)

Мой вопрос - это предпочтительный способ передачи этого типа поведения. В идеале я бы полностью избегал метаданных, поскольку я являюсь частью команды, задачей которой является введение пользовательский сервер nuget, через который мы рассматриваем и контролировать, какие пакеты команд разрешено использовать, поэтому для меня было бы иронично продолжать добавлять новые пакеты, такие как пакет Aufofac.Extras.Metadata.

Logic регистрация автоматическая/отказ в с помощью атрибута:

[Logic(Entity.Uk, CompanyDetail.PaymentTrends)] 
public class PaymentTrends : ILogic<CompanyRequest, NullLogicResponse> 
{ 
    public NullLogicResponse Execute(CompanyRequest request) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Каждых сборок, которое регистрируется с Autofac делает это через модуль, как так:

public class LogicAutofacModule : Module 
{ 
    #region Load 

    protected override void Load(ContainerBuilder builder) 
    { 
     // ReSharper disable once IteratorMethodResultIsIgnored 
     builder.RegisterTypesWithAttribute<LogicAttribute>(typeof(ILogic<,>)); 

     builder.RegisterAssemblyModules<DataAutofacModule>(); 
    } 

    #endregion Load 
} 

Где RegiserTypesWithAttribute выглядит следующим образом:

public static class ContainerBuilderRegisterTypesWithAttribute 
{ 
    #region RegisterTypesWithAttribute 

    public static IEnumerable<IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle>> RegisterTypesWithAttribute<TAttribute>(this ContainerBuilder builder, Type typeBeingRegistered) where TAttribute : Attribute 
    { 
     var assembly = typeof(TAttribute).Assembly; 

     // ReSharper disable once LoopCanBeConvertedToQuery ... no thanks! 
     foreach (var type in assembly 
         .GetTypes() 
         .Where(type => type.HasCustomAttribute<TAttribute>())) 
     { 
      var registration = builder.RegisterType(type) 
        .As(type.GetInterfaces() 
        .First(i => 
          i.IsGenericType && 
          i.GetGenericTypeDefinition() == typeBeingRegistered)); 

      yield return registration; 
     } 
    } 

    #endregion 
} 

Я еще не могу получить свою область головы вокруг наилучшего способа зарегистрируйте тип и его метаданные. LogicAttribute предоставляет свойство Metadata, состоящее из Entity и Flag. Ключ можно догадаться, что его можно исключить только для строк? так что я иду с IIndex <>, а затем обеспечить параметр моего конструктора выглядит примерно так:

public LogicDispatcher(IEnumerable>Lazy<Meta<LogicMetadata, ILogic<NullLogicResponse, CompanyRequest>>> logicEnumerable) 
{ 
    _logicEnumerable = logicEnumerable; 
} 

, а затем в пределах его Execute метода:

public NullLogicResponse Execute(CompanyRequest request) 
{ 
    var applicableLogic = 
     _logicEnumerable.Where(metadata => metadata.HasFlag(request.Flag); 

    foreach (var logic in applicableLogic) 
    { 
     logic.Execute(request) 
    } 
} 

Любая помощь по улучшению выше и/или лучший подход к решению этой проблемы будет с благодарностью оценен. Спасибо.

P.S.

Было бы 30 и растущих интерфейсов ILogic с одинаковыми типами. Каждый из них был бы/может быть запущен через TPL, например, поэтому я рад получить X-регистрацию сразу.

+0

Ребята, я сформулировал это слишком плохо для вас, чтобы понять проблему? –

ответ

0

То, как я сейчас справлялся с этим, заключается в следующем. Я не очень доволен этим, но он работает. Причина, по которой я не счастлив, заключается в том, что это не особенно AutoFac-ish.

Я добавил следующий метод расширения, чтобы перечислять все типы в сборке, которые имеют необходимый атрибут. Когда тип обнаруживается действие, называется позволяя разработчику делать все, что он хочет регистрации мудрое:

public static class ContainerBuilderEnumerateAttributedTypes 
{ 
    #region Properties 

    public static void EnumerateAttributedTypes<TAttribute>(this ContainerBuilder builder, 
     Action<Type, TAttribute> action) where TAttribute : Attribute 
    { 
     var typesAndAttributes = Assembly 
      .GetExecutingAssembly() 
      .GetTypes() 
      .Where(type => type.GetCustomAttributes(typeof(TAttribute), false).Length != 0) 
      .Select(type => new { Type = type, Attribute = (TAttribute)type.GetCustomAttributes(typeof(TAttribute), false)[0] }); 

     foreach (var typeAndAtttribute in typesAndAttributes) 
     { 
      action(typeAndAtttribute.Type, typeAndAtttribute.Attribute); 
     } 
    } 

    #endregion 
} 

А потом в модуле я делаю следующее:

public class LogicAutofacModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.EnumerateAttributedTypes<LogicAttribute>((type, attribute) => 
     { 
      // ReSharper disable once ConvertToLambdaExpression 
      builder 
       .RegisterType(type) 
       .Keyed(attribute.Metadata.LoginState, typeof (ILogic<,>)) 
       .As(typeof (ILogic<,>)); 
     });   
    } 
} 

ее работ на данный момент и является то, что я могу использовать, когда позволяет время. Дайте мне знать, что вы думаете ... спасибо!

+0

Примечания: контекст изменился из-за моей текущей задачи, требующей этой функции. Я улучшу решение для работы с предыдущим требованием. –

+0

Глупая ошибка с моей стороны re. Метаданные. LoignState необходим в каждом случае. Заряда нет. Обычно рассказ о том, что он торопится и омерзителен. Также хотелось избегать слишком большого количества nuget-зависимостей, которые теперь являются частью нового технического руководящего комитета, и мы ограничиваем их как можно больше. Больше всего RUSHING. –

Смежные вопросы