使用HasFlag进行Autofac和枚举

时间:2015-04-20 08:43:56

标签: c# wcf enums autofac

我在我的逻辑层中使用以下界面来强制执行单一责任(可能会被破坏,但你必须跳过困境并让自己为此而烦恼)。

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 =&gt; context.Flags.HasFlag(logic.Metadata.Flag),留下负责满足调用的逻辑实现的列表。(My解释可能是错误的并且充满漏洞)

我的问题是处理这种行为的首选方法。理想情况下,我完全避免使用元数据,因为我是团队的一员,他们的工作是引入一个自定义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&lt;&gt;然后确保我的构造函数的参数看起来类似于:

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个注册号。

1 个答案:

答案 0 :(得分:0)

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

我添加了以下扩展方法来枚举程序集中具有required属性的所有类型。当找到一个类型时,会调用一个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<,>));
        });         
    }
}

它现在起作用,是我可以在时间允许的基础上建立起来的。让我知道你的想法......谢谢!