【问题标题】:Autofac and enums with HasFlag带有 HasFlag 的 Autofac 和枚举
【发布时间】:2015-04-20 08:43:56
【问题描述】:

我在我的逻辑层中使用以下接口来强制执行单一职责(可能会被破坏,但你必须跳过障碍,让自己非常头疼才能实现这一点)。

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

    //..

    //..
}

Company DataContract 将包含通过 CompanyOptions 枚举请求的数据,最终会有 30 - 50 个此类属性。

我意识到 Aufofac 不可能注入仅包含构造所需的逻辑实例的列表,但我确实通过 IIndex 知道,公司运营合同或其他名称(目前尚待讨论)可以获得IIndex 在构造期间存储并通过元数据或其他方式存储,例如它可以执行 Where(registration => context.Flags.HasFlag(logic.Metadata.Flag) 留下负责满足调用的逻辑实现列表。(我的解释可能是错误的,而且漏洞百出)

我的问题是处理这种行为的首选方法是哪种。理想情况下,我会完全避免元数据,因为我是一个团队的一员,该团队的工作是引入一个自定义 nuget 服务器,我们通过该服务器审查和控制允许团队使用哪些包,所以对我来说继续开始有点讽刺添加新的包,例如 Aufofac.Extras.Metadata 包。

逻辑注册是通过属性自动/选择加入的:

[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 公开了一个由实体和标志组成的元数据属性。我猜可以将键控排除在字符串之外吗?我也应该使用 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)
     }
}

对于改进上述内容和/或处理手头问题的更好方法的任何帮助将不胜感激。谢谢。

附言

将有 30 个具有相同类型的 ILogic 接口并且不断增长。例如,每个都将/可能通过 TPL 被解雇,所以我很高兴一次收到 X 个注册。

【问题讨论】:

  • 各位,我是不是措辞太差,让你们无法理解这个问题?

标签: c# wcf enums autofac


【解决方案1】:

我现在处理的方式如下。我对它不是特别满意,但它确实有效。我不高兴的原因是它不是特别像 AutoFac-ish。

我添加了以下扩展方法来枚举程序集中具有所需属性的所有类型。当找到一个类型时,一个 Action 被调用,允许开发者做他想做的任何事情。

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<,>));
        });         
    }
}

它现在有效,是我可以在时间允许的情况下建立的东西。让我知道你的想法...谢谢!

【讨论】:

  • 请注意,由于我当前的任务需要此功能,因此上下文已更改。我将改进解决方案以满足之前的要求。
  • 我的愚蠢错误。元数据。每个实例都需要 LoignState。收费不是。通常是匆忙和过度的故事。还希望避免引入过多的 nuget 依赖项,因为现在作为新技术指导委员会的一部分,我们正在尽可能地限制这些。最重要的是 RUSHING。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多