我在我的逻辑层中使用以下界面来强制执行单一责任(可能会被破坏,但你必须跳过困境并让自己为此而烦恼)。
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个注册号。
答案 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<,>));
});
}
}
它现在起作用,是我可以在时间允许的基础上建立起来的。让我知道你的想法......谢谢!