Suppose I defined some validation logic like this:
public class Rule1 : IValidator<SomethingValidatable>
{
public IList<Error> Validate(SomethingValidatable item)
{
// apply validation logic to item
}
}
Somewhere in code I bind IValidator<SomethingValidatable>
to one or more concrete Rule
:
protected override void ConfigureContainer(IUnityContainer container)
{
container
.RegisterType<IValidator<SomethingValidatable>, Rule1>("a")
.RegisterType<IValidator<SomethingValidatable>, Rule2>("b");
}
and where I need this validation occurs I have somethin like:
public class HereIValidateClass
{
private readonly IValidator<SomethingValidatable>[] validators;
public HereIValidateClass(IValidator<SomethingValidatable>[] validators)
{
this.validators = validators;
}
public IList<Error> DoSomething()
{
foreach (var validator in validators)
{
var errors = validator.Validate(something);
// append to IList<Error>
}
return errors;
}
}
This do the job. But I would avoid to register explicitely one by one each rules. I really like to say: Dear Unity, register each class in a given namespace that implements IValidator<SomethingValidatable>
.
How about an extension method for IUnityContainer:
public static class UnityExtensions
{
public static void RegisterValidators(this IUnityContainer container)
{
var types = AllClasses.FromLoadedAssemblies().GetValidators();
foreach (var type in types)
{
var interfaces = WithMappings.FromAllInterfaces(type);
foreach (var @interface in interfaces)
{
container.RegisterType(@interface, type);
}
}
}
public static IEnumerable<Type> GetValidators(this IEnumerable<Type> types)
{
var wantedType = typeof(IValidator<>);
return from type in types
from interfaceType in type.GetInterfaces()
where interfaceType.IsGenericType
&& !interfaceType.ContainsGenericParameters
&& wantedType.IsAssignableFrom(interfaceType.GetGenericTypeDefinition())
select type;
}
}
And if you need more info about the specific registrations you can use an attribute.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class MyValidationAttribute : Attribute
{
public string RegistrationName { get; set; }
public MyValidationAttribute(string name)
{
RegistrationName = name;
}
}
And then change the extension method to something like this:
public static void RegisterValidators(this IUnityContainer container)
{
var types = AllClasses.FromLoadedAssemblies().GetValidators();
foreach (var type in types)
{
var interfaces = WithMappings.FromAllInterfaces(type);
foreach (var @interface in interfaces)
{
var myAttr = type.GetCustomAttributes<MyValidationAttribute>(false);
foreach (var attr in myAttr)
{
// Register with specific name.
container.RegisterType(@interface, type, attr.RegistrationName);
}
}
}
}
And change your registration:
protected override void ConfigureContainer(IUnityContainer container)
{
container.RegisterValidators();
}
It will register each implementation for IValidator
, regardless of T.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.