I use FluentValidation and PostSharp in my business layer.
My database has an Admin table, and the UserName column in this table is unique.
I want to check the uniqueness with an "Aspect".
My codes are as follows.
AdminValidator
public class AdminValidator : AbstractValidator<Admin>
{
public AdminValidator(IEnumerable<Admin> admins)
{
RuleFor(x => x.Fullname).MaximumLength(50);
RuleFor(x => x.Username).Matches(#"^\S{3,15}$").IsUnique(admins);
RuleFor(x => x.Password).Matches(#"^\S{5,20}$");
}
}
IsUnique extension method
public static class Extensions
{
public static IRuleBuilderOptions<TItem, TProperty> IsUnique<TItem, TProperty>(
this IRuleBuilder<TItem, TProperty> ruleBuilder, IEnumerable<TItem> items)
where TItem : class
{
return ruleBuilder.SetValidator(new UniqueValidator<TItem>(items));
}
}
public class UniqueValidator<T> : PropertyValidator
where T : class
{
private readonly IEnumerable<T> _items;
public UniqueValidator(IEnumerable<T> items)
: base("{PropertyName} must be unique")
{
_items = items;
}
protected override bool IsValid(PropertyValidatorContext context)
{
var editedItem = context.Instance as T;
var newValue = context.PropertyValue as string;
var property = typeof(T).GetTypeInfo().GetDeclaredProperty(context.PropertyName);
return _items.All(item =>
item.Equals(editedItem) || property.GetValue(item).ToString() != newValue);
}
}
FluentValidation aspect
[Serializable]
public class FluentValidationAspect : OnMethodBoundaryAspect
{
private readonly Type _validatorType;
private readonly object[] _parameters;
public FluentValidationAspect(Type validatorType, params object[] parameters)
{
_validatorType = validatorType;
_parameters = parameters;
}
public override void OnEntry(MethodExecutionArgs args)
{
var validator = (IValidator)Activator.CreateInstance(_validatorType, _parameters);
var entityType = _validatorType.BaseType?.GetGenericArguments()[0];
var entities = args.Arguments.Where(x => x.GetType() == entityType);
foreach (var entity in entities)
ValidatorTool.FluentValidate(validator, entity);
}
}
and AdminManager
public class AdminManager : IAdminService
{
private readonly IAdminDal _adminDal;
public AdminManager(IAdminDal adminDal)
{
_adminDal = adminDal;
}
public Admin GetByUsername(string username)
=> string.IsNullOrEmpty(username) ? null : _adminDal.Get(x => x.Username.Equals(username));
[FluentValidationAspect(typeof(AdminValidator))] // I need to pass IEnumerable<Admin> as a second parameter.
public void Add(Admin admin) => _adminDal.Add(admin);
[FluentValidationAspect(typeof(AdminValidator))] //
public void Update(Admin admin) => _adminDal.Update(admin);
public void DeleteById(int id) => _adminDal.Delete(new Admin { Id = id });
}
As I mentioned in the comment line, I need to pass IEnumerable to the FluentValidationAspect.
But, dynamic parameters can not be passed to attributes.
As a result, I'm blocked here.
What is the best way to check for uniqueness?
Thank you in advance for your help?
Best regards...
You can't pass dynamic values in Attributes, so you will have to do the validation in the method body.
public void Add(Admin admin)
{
var admins = GetAll():
var val = new AdminValidator(admins);
validator.ValidateAndThrow(admin);
_adminDal.Add(admin);
}
Related
I'm implementing Interceptor mechanism in .NET with Castle.DynamicProxy (Castle.Core 4.4.0). I'm following this tutorial for selecting which method to intercept: https://kozmic.net/2009/01/17/castle-dynamic-proxy-tutorial-part-iii-selecting-which-methods-to/
It was given an example in this article about "selecting which methods to intercept":
public class FreezableProxyGenerationHook:IProxyGenerationHook
{
public bool ShouldInterceptMethod(Type type, MethodInfo memberInfo)
{
return !memberInfo.Name.StartsWith("get_", StringComparison.Ordinal);
}
//implementing other methods...
}
According to this article, I implemented the ShouldInterceptMethod like below but i can not access the method's custom attributes.
public class ProductServiceProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected()
{
}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
//return methodInfo.CustomAttributes.Any(a => a.GetType() == typeof(UseInterceptorAttribute));
return methodInfo.CustomAttributes.Count() > 0;
}
}
This is the method that i want to intercept:
[UseInterceptor]
public Product AOP_Get(string serialNumber)
{
throw new NotImplementedException();
}
This is my custom attribute:
[System.AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
sealed class UseInterceptorAttribute : Attribute
{
public UseInterceptorAttribute()
{
}
}
When ShouldInterceptMethod invoked for AOP_Get method, there aren't any custom attributes on local variable methodInfo. As a result ShouldInterceptMethod returns false. But when i check from the AOP_Get method body, i can access custom attribute like below:
How can i access custom attributes in ShouldInterceptMethod method?
I solved the problem using UseInterceptorAttribute in the interface methods. Because the interceptor is enabling for interface:
//autofac
var proxyGenerationOptions = new ProxyGenerationOptions(new ProductServiceProxyGenerationHook());
builder.RegisterType<ProductService>()
.As<IProductService>()
.EnableInterfaceInterceptors(proxyGenerationOptions)
.InterceptedBy(typeof(LoggingInterceptor));
The solution:
public interface IProductService
{
Product Get(string productNumber, string serialNumber);
bool Create(string productNumber, string serialNumber);
[UseInterceptor]
Product AOP_Get(string productNumber, string serialNumber);
}
public class ProductService : IProductService
{
public Product AOP_Get(string productNumber, string serialNumber)
{
var m = GetType().GetMethod("AOP_Get");
return null;
}
public bool Create(string productNumber, string serialNumber)
{
return true;
}
public Product Get(string productNumber, string serialNumber)
{
return new Product
{
Id = 5,
ProductNumber = "testPN",
SerialNumber = "testSN"
};
}
}
public class ProductServiceProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected()
{
}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
return methodInfo
.CustomAttributes
.Any(a => a.AttributeType == typeof(UseInterceptorAttribute));
}
}
}
I'm developing a input validation library for my APIs.
interface IValidation<T>{
List<string> Errors();
bool Valid(T input);
}
class GuidValidator: IValidation<Guid> {
bool Valid(Guid input){ ... }
}
class StringLengthValidator: IValidation<String> {
bool Valid(String input){ ... }
}
and am trying to validate
class MyInputToValidate {
public Guid Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
}
from the controller
class MyController {
public ActionResult Post([FromBody] MyInputToValidate body){
ValidatorCollection validators = new ValidatorCollection<MyInputToValidate>();
validators.AddValidator(i => i.Id, new GuidValidator());
validators.AddValidator(i => i.Name, new LengthValidator());
validators.AddValidator(i => i.Description, new LengthValidator());
bool valid = validators.Validate(body);
//...
}
}
But I'm having difficulty saving the validators to a dictionary for later use.
interface IValidatorCollection<T> {
void AddValidator<TProperty>(
Expression<Func<T, TProperty>> property,
IValidator<TProperty> validator
);
bool Validate(T value);
}
class ValidatorCollection: IValidatorCollection<T> {
private IDictionary<string, IValidator<object>> _validators = new Dictionary<string, IValidator<object>>();
public void AddValidator<TProperty>(Expression<Func<T, TProperty>> property, IValidator<TProperty> validator)
{
_validators.Add(property.Name, validator);
}
public bool Validate(T value)
{
foreach(var val in _validators){
bool valid = val.Value.Valid(value);
}
//...
}
}
I receive the error IValidator<TProperty> is not assignable to to IValidator<object> for the line _validators.Add(property.Name, validator);. I've tried typecasting (IValidator<object>validator), but I receive the runtime error Unable to cast object GuidValidator to type IValidator<object>. How can I store a list of validators for the properties of a generic object?
I have created an architecture in my C# code which does exactly what I want, but seems it would be very difficult to maintain in the long-run and am hoping there's a design pattern / better architecture I could be pointed towards.
I have created an object Test which, again, does exactly what I need perfectly which has the following structure:
class Test
{
public static Dictionary<string, Func<Test, object>> MethodDictionary;
public double Var1;
public double Var2;
private Lazy<object> _test1;
public object Test1 { get { return _test1.Value; } }
private Lazy<object> _test2;
public object Test2 { get { return _test2.Value; } }
public Test()
{
_test1 = new Lazy<object>(() => MethodDictionary["Test1"](this), true);
_test2 = new Lazy<object>(() => MethodDictionary["Test2"](this), true);
}
}
What this allows me to do is, at run-time to assign a dictionary of functions to my Test object and the 2 properties Test1 & Test2 will use the functions loaded into it to return values.
The implementation looking somewhat as follows:
class Program
{
static void Main(string[] args)
{
Dictionary<string, Func<Test, object>> MethodDictionary = new Dictionary<string,Func<Test,object>>();
MethodDictionary.Add("Test1", TestMethod1);
MethodDictionary.Add("Test2", TestMethod2);
Test.MethodDictionary = MethodDictionary;
var x = new Test() { Var1 = 20, Var2 = 30 };
Console.WriteLine(x.Test1.ToString());
Console.WriteLine(x.Test2.ToString());
Console.ReadKey();
}
private static object TestMethod1(Test t)
{ return t.Var1 + t.Var2; }
private static object TestMethod2(Test t)
{ return t.Var1 - t.Var2; }
}
And it works great and has proven very efficient for large sets of Test objects.
My challenge is that if I ever want to add in a new method to my Test class, I need to add in the:
private Lazy<object> _myNewMethod;
public object MyNewMethod { get { return _myNewMethod.Value; } }
Update the constuctor with the key to look for in the dictionary
And, although that is pretty simple, I'd love to have a 1-line add-in (maybe some form of custom object) or have the properties read directly form the dictionary without any need for defining them at all.
Any ideas? ANY help would be great!!!
Thanks!!!
One of the ways in which you could achieve your desired behavior, is to use something that resembles a miniature IoC framework for field injection, tuned to your specific use case.
To make things easier, allow less typing in your concrete classes and make things type-safe, we introduce the LazyField type:
public class LazyField<T>
{
private static readonly Lazy<T> Default = new Lazy<T>();
private readonly Lazy<T> _lazy;
public LazyField() : this(Default) { }
public LazyField(Lazy<T> lazy)
{
_lazy = lazy;
}
public override string ToString()
{
return _lazy.Value.ToString();
}
public static implicit operator T(LazyField<T> instance)
{
return instance._lazy.Value;
}
}
Furthermore, we define an abstract base class, that ensures that these fields will be created at construction time:
public abstract class AbstractLazyFieldHolder
{
protected AbstractLazyFieldHolder()
{
LazyFields.BuildUp(this); // ensures fields are populated.
}
}
Skipping for a moment how this is achieved (explained further below), this allows the following way of defining your Test class:
public class Test : AbstractLazyFieldHolder
{
public double Var1;
public double Var2;
public readonly LazyField<double> Test1;
public readonly LazyField<double> Test2;
}
Note that these fields are immutable, initialized in the constructor. Now, for your usage example, the below snippet shows the "new way" of doing this:
LazyFields.Configure<Test>()
// We can use a type-safe lambda
.SetProvider(x => x.Test1, inst => inst.Var1 + inst.Var2)
// Or the field name.
.SetProvider("Test2", TestMethod2);
var x = new Test() { Var1 = 20, Var2 = 30 };
Console.WriteLine(x.Test1);
double test2Val = x.Test2; // type-safe conversion
Console.WriteLine(test2Val);
// Output:
// 50
// -10
The class below provides the services that support the configuration and injection of these field value.
public static class LazyFields
{
private static readonly ConcurrentDictionary<Type, IBuildUp> _registry = new ConcurrentDictionary<Type,IBuildUp>();
public interface IConfigureType<T> where T : class
{
IConfigureType<T> SetProvider<FT>(string fieldName, Func<T, FT> provider);
IConfigureType<T> SetProvider<F, FT>(Expression<Func<T, F>> fieldExpression, Func<T, FT> provider) where F : LazyField<FT>;
}
public static void BuildUp(object instance)
{
System.Diagnostics.Debug.Assert(instance != null);
var builder = _registry.GetOrAdd(instance.GetType(), BuildInitializer);
builder.BuildUp(instance);
}
public static IConfigureType<T> Configure<T>() where T : class
{
return (IConfigureType<T>)_registry.GetOrAdd(typeof(T), BuildInitializer);
}
private interface IBuildUp
{
void BuildUp(object instance);
}
private class TypeCfg<T> : IBuildUp, IConfigureType<T> where T : class
{
private readonly List<FieldInfo> _fields;
private readonly Dictionary<string, Action<T>> _initializers;
public TypeCfg()
{
_fields = typeof(T)
.GetFields(BindingFlags.Instance | BindingFlags.Public)
.Where(IsLazyField)
.ToList();
_initializers = _fields.ToDictionary(x => x.Name, BuildDefaultSetter);
}
public IConfigureType<T> SetProvider<FT>(string fieldName, Func<T,FT> provider)
{
var pi = _fields.First(x => x.Name == fieldName);
_initializers[fieldName] = BuildSetter<FT>(pi, provider);
return this;
}
public IConfigureType<T> SetProvider<F,FT>(Expression<Func<T,F>> fieldExpression, Func<T,FT> provider)
where F : LazyField<FT>
{
return SetProvider((fieldExpression.Body as MemberExpression).Member.Name, provider);
}
public void BuildUp(object instance)
{
var typedInstance = (T)instance;
foreach (var initializer in _initializers.Values)
initializer(typedInstance);
}
private bool IsLazyField(FieldInfo fi)
{
return fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(LazyField<>);
}
private Action<T> BuildDefaultSetter(FieldInfo fi)
{
var itemType = fi.FieldType.GetGenericArguments()[0];
var defValue = Activator.CreateInstance(typeof(LazyField<>).MakeGenericType(itemType));
return (inst) => fi.SetValue(inst, defValue);
}
private Action<T> BuildSetter<FT>(FieldInfo fi, Func<T, FT> provider)
{
return (inst) => fi.SetValue(inst, new LazyField<FT>(new Lazy<FT>(() => provider(inst))));
}
}
private static IBuildUp BuildInitializer(Type targetType)
{
return (IBuildUp)Activator.CreateInstance(typeof(TypeCfg<>).MakeGenericType(targetType));
}
}
Look at library https://github.com/ekonbenefits/impromptu-interface.
With it and using DynamicObject i wrote sample code that shows how to simplify adding new methods:
public class Methods
{
public Methods()
{
MethodDictionary = new Dictionary<string, Func<ITest, object>>();
LazyObjects = new Dictionary<string, Lazy<object>>();
}
public Dictionary<string, Func<ITest, object>> MethodDictionary { get; private set; }
public Dictionary<string, Lazy<object>> LazyObjects { get; private set; }
}
public class Proxy : DynamicObject
{
Methods _methods;
public Proxy()
{
_methods = new Methods();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = _methods.LazyObjects[binder.Name].Value;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_methods.MethodDictionary[binder.Name] = (Func<ITest, object>)value;
_methods.LazyObjects[binder.Name] = new Lazy<object>(() => _methods.MethodDictionary[binder.Name](this.ActLike<ITest>()), true);
return true;
}
}
//now you can add new methods by add single method to interface
public interface ITest
{
object Test1 { get; set; }
object Test2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var x = new Proxy().ActLike<ITest>();
x.Test1 = new Func<ITest, object>((y) => "Test1");
x.Test2 = new Func<ITest, object>((y) => "Test2");
Console.WriteLine(x.Test1);
Console.WriteLine(x.Test2);
}
}
I don't know what you are trying to do, but I think you can use a simpler approach like this:
class Test
{
public static Dictionary<string, Func<Test, object>> MethodDictionary;
public double Var1;
public double Var2;
}
Calling the function is simple:
static void Main(string[] args)
{
Dictionary<string, Func<Test, object>> MethodDictionary = new Dictionary<string,Func<Test,object>>();
MethodDictionary.Add("Test1", TestMethod1);
MethodDictionary.Add("Test2", TestMethod2);
Test.MethodDictionary = MethodDictionary;
var x = new Test() { Var1 = 20, Var2 = 30 };
Console.WriteLine(Test.MethodDictionary["Test1"](x).ToString());
Console.WriteLine(Test.MethodDictionary["Test2"](x).ToString());
Console.ReadKey();
}
I have these open-generics:
public interface IQuery<out TResult> {}
public interface ICacheableQuery<out TResult> : IQuery<TResult> {
string CacheKey { get; }
}
public interface IQueryHandler<in TQuery, out TResult>
where TQuery : IQuery<TResult> {
TResult Handle(TQuery query);
}
and this single decorator:
public class CacheableQueryHandlerDecorator<TQuery, TResult>
: IQueryHandler<TQuery, TResult>
where TQuery : ICacheableQuery<TResult> {
public TResult Handle(TQuery query) {
// doing stuffs....
}
}
What I want is to register decorator only for queries which are implementing ICacheableQuery<out TResult>. I'm registering components like this:
builder.RegisterAssemblyTypes(assemblies)
.AsClosedTypesOf(typeof (IQueryHandler<,>))
.AsImplementedInterfaces()
.Named("queryHandler",typeof(IQueryHandler<,>));
builder.RegisterGenericDecorator(
typeof(CacheableQueryHandlerDecorator<,>),
typeof(IQueryHandler<,>),
fromKey: "queryHandler");
But it registers the decorator for all types. Any idea? Thanks in advance.
Unfortunately, Autofac hasn't got this feature out-of-the-box. However, it can be achieved implementing a RegistrationSource:
public interface IGenericDecoratorRegistrationBuilder : IHideObjectMembers
{
IGenericDecoratorRegistrationBuilder Decorator(Type decoratorType, Func<Type, bool> filter = null, Func<Type, IEnumerable<Parameter>> paramsGetter = null);
}
public static class GenericDecorators
{
public class GenericDecoratorRegistration
{
public Type Type;
public Func<Type, bool> Filter;
public Func<Type, IEnumerable<Parameter>> ParamsGetter;
}
class GenericDecoratorRegistrationBuilder : IGenericDecoratorRegistrationBuilder
{
readonly List<GenericDecoratorRegistration> decorators = new List<GenericDecoratorRegistration>();
public IEnumerable<GenericDecoratorRegistration> Decorators
{
get { return decorators; }
}
public IGenericDecoratorRegistrationBuilder Decorator(Type decoratorType, Func<Type, bool> filter, Func<Type, IEnumerable<Parameter>> paramsGetter)
{
if (decoratorType == null)
throw new ArgumentNullException("decoratorType");
if (!decoratorType.IsGenericTypeDefinition)
throw new ArgumentException(null, "decoratorType");
var decorator = new GenericDecoratorRegistration
{
Type = decoratorType,
Filter = filter,
ParamsGetter = paramsGetter
};
decorators.Add(decorator);
return this;
}
}
class GenericDecoratorRegistrationSource : IRegistrationSource
{
readonly Type decoratedType;
readonly IEnumerable<GenericDecoratorRegistration> decorators;
readonly object fromKey;
readonly object toKey;
public GenericDecoratorRegistrationSource(Type decoratedType, IEnumerable<GenericDecoratorRegistration> decorators, object fromKey, object toKey)
{
this.decoratedType = decoratedType;
this.decorators = decorators;
this.fromKey = fromKey;
this.toKey = toKey;
}
public bool IsAdapterForIndividualComponents
{
get { return true; }
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
KeyedService ks;
if (swt == null ||
(ks = new KeyedService(fromKey, swt.ServiceType)) == service ||
!swt.ServiceType.IsGenericType || swt.ServiceType.GetGenericTypeDefinition() != decoratedType)
return Enumerable.Empty<IComponentRegistration>();
return registrationAccessor(ks).Select(cr => new ComponentRegistration(
Guid.NewGuid(),
BuildActivator(cr, swt),
cr.Lifetime,
cr.Sharing,
cr.Ownership,
new[] { toKey != null ? (Service)new KeyedService(toKey, swt.ServiceType) : new TypedService(swt.ServiceType) },
cr.Metadata,
cr));
}
DelegateActivator BuildActivator(IComponentRegistration cr, IServiceWithType swt)
{
var limitType = cr.Activator.LimitType;
var actualDecorators = decorators
.Where(d => d.Filter != null ? d.Filter(limitType) : true)
.Select(d => new { Type = d.Type, Parameters = d.ParamsGetter != null ? d.ParamsGetter(limitType) : Enumerable.Empty<Parameter>() })
.ToArray();
return new DelegateActivator(cr.Activator.LimitType, (ctx, p) =>
{
var typeArgs = swt.ServiceType.GetGenericArguments();
var service = ctx.ResolveKeyed(fromKey, swt.ServiceType);
foreach (var decorator in actualDecorators)
{
var decoratorType = decorator.Type.MakeGenericType(typeArgs);
var #params = decorator.Parameters.Concat(new[] { new TypedParameter(swt.ServiceType, service) });
var activator = new ReflectionActivator(decoratorType, new DefaultConstructorFinder(), new MostParametersConstructorSelector(),
#params, Enumerable.Empty<Parameter>());
service = activator.ActivateInstance(ctx, #params);
}
return service;
});
}
}
public static IGenericDecoratorRegistrationBuilder RegisterGenericDecorators(this ContainerBuilder builder, Type decoratedServiceType, object fromKey, object toKey = null)
{
if (builder == null)
throw new ArgumentNullException("builder");
if (decoratedServiceType == null)
throw new ArgumentNullException("decoratedServiceType");
if (!decoratedServiceType.IsGenericTypeDefinition)
throw new ArgumentException(null, "decoratedServiceType");
var rb = new GenericDecoratorRegistrationBuilder();
builder.RegisterCallback(cr => cr.AddRegistrationSource(new GenericDecoratorRegistrationSource(decoratedServiceType, rb.Decorators, fromKey, toKey)));
return rb;
}
}
Sample usage:
public interface IGeneric<T>
{
void SomeMethod();
}
class IntImpl : IGeneric<int>
{
public void SomeMethod() { }
}
class StringImpl : IGeneric<string>
{
public void SomeMethod() { }
}
class GenericDecorator<T> : IGeneric<T>
{
IGeneric<T> target;
public GenericDecorator(IGeneric<T> target)
{
this.target = target;
}
public void SomeMethod()
{
target.SomeMethod();
}
}
static void Configure(ContainerBuilder builder)
{
builder.RegisterType<IntImpl>().Named<IGeneric<int>>("generic");
builder.RegisterType<StringImpl>().Named<IGeneric<string>>("generic");
builder.RegisterGenericDecorators(typeof(IGeneric<>), "generic")
// applying decorator to IGeneric<string> only
.Decorator(typeof(GenericDecorator<>), t => typeof(IGeneric<string>).IsAssignableFrom(t));
}
Please note
You must key the registrations of decorated components because (as far as I know) there's no way to override these with dynamic registrations provided by the RegistrationSource.
In this solution the decorated component inherits the configuration of the decorated one (scoping, sharing, ownership, etc)
I've just started to use AutoFixture.AutoMoq in my unit tests and I'm finding it very helpful for creating objects where I don't care about the specific value. After all, anonymous object creation is what it is all about.
What I'm struggling with is when I care about one or more of the constructor parameters. Take ExampleComponent below:
public class ExampleComponent
{
public ExampleComponent(IService service, string someValue)
{
}
}
I want to write a test where I supply a specific value for someValue but leave IService to be created automatically by AutoFixture.AutoMoq.
I know how to use Freeze on my IFixture to keep hold of a known value that will be injected into a component but I can't quite see how to supply a known value of my own.
Here is what I would ideally like to do:
[TestMethod]
public void Create_ExampleComponent_With_Known_SomeValue()
{
// create a fixture that supports automocking
IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
// supply a known value for someValue (this method doesn't exist)
string knownValue = fixture.Freeze<string>("My known value");
// create an ExampleComponent with my known value injected
// but without bothering about the IService parameter
ExampleComponent component = this.fixture.Create<ExampleComponent>();
// exercise component knowning it has my known value injected
...
}
I know I could do this by calling the constructor directly but this would no longer be anonymous object creation. Is there a way to use AutoFixture.AutoMock like this or do I need to incorporate a DI container into my tests to be able to do what I want?
EDIT:
I probably should have been less absract in my original question so here is my specific scenario.
I have an ICache interface which has generic TryRead<T> and Write<T> methods:
public interface ICache
{
bool TryRead<T>(string key, out T value);
void Write<T>(string key, T value);
// other methods not shown...
}
I'm implementing a CookieCache where ITypeConverter handles converting objects to and from strings and lifespan is used to set the expiry date of a cookie.
public class CookieCache : ICache
{
public CookieCache(ITypeConverter converter, TimeSpan lifespan)
{
// usual storing of parameters
}
public bool TryRead<T>(string key, out T result)
{
// read the cookie value as string and convert it to the target type
}
public void Write<T>(string key, T value)
{
// write the value to a cookie, converted to a string
// set the expiry date of the cookie using the lifespan
}
// other methods not shown...
}
So when writing a test for the expiry date of a cookie, I care about the lifespan but not so much about the converter.
So I'm sure people could work out the generalized implementation of Mark's suggestion but I thought I'd post it for comments.
I've created a generic ParameterNameSpecimenBuilder based on Mark's LifeSpanArg:
public class ParameterNameSpecimenBuilder<T> : ISpecimenBuilder
{
private readonly string name;
private readonly T value;
public ParameterNameSpecimenBuilder(string name, T value)
{
// we don't want a null name but we might want a null value
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("name");
}
this.name = name;
this.value = value;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
{
return new NoSpecimen(request);
}
if (pi.ParameterType != typeof(T) ||
!string.Equals(
pi.Name,
this.name,
StringComparison.CurrentCultureIgnoreCase))
{
return new NoSpecimen(request);
}
return this.value;
}
}
I've then defined a generic FreezeByName extension method on IFixture which sets the customization:
public static class FreezeByNameExtension
{
public static void FreezeByName<T>(this IFixture fixture, string name, T value)
{
fixture.Customizations.Add(new ParameterNameSpecimenBuilder<T>(name, value));
}
}
The following test will now pass:
[TestMethod]
public void FreezeByName_Sets_Value1_And_Value2_Independently()
{
//// Arrange
IFixture arrangeFixture = new Fixture();
string myValue1 = arrangeFixture.Create<string>();
string myValue2 = arrangeFixture.Create<string>();
IFixture sutFixture = new Fixture();
sutFixture.FreezeByName("value1", myValue1);
sutFixture.FreezeByName("value2", myValue2);
//// Act
TestClass<string> result = sutFixture.Create<TestClass<string>>();
//// Assert
Assert.AreEqual(myValue1, result.Value1);
Assert.AreEqual(myValue2, result.Value2);
}
public class TestClass<T>
{
public TestClass(T value1, T value2)
{
this.Value1 = value1;
this.Value2 = value2;
}
public T Value1 { get; private set; }
public T Value2 { get; private set; }
}
You have to replace:
string knownValue = fixture.Freeze<string>("My known value");
with:
fixture.Inject("My known value");
You can read more about Inject here.
Actually the Freeze extension method does:
var value = fixture.Create<T>();
fixture.Inject(value);
return value;
Which means that the overload you used in the test actually called Create<T> with a seed: My known value resulting in "My known value4d41f94f-1fc9-4115-9f29-e50bc2b4ba5e".
You could do something like this. Imagine that you want to assign a particular value to the TimeSpan argument called lifespan.
public class LifespanArg : ISpecimenBuilder
{
private readonly TimeSpan lifespan;
public LifespanArg(TimeSpan lifespan)
{
this.lifespan = lifespan;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
return new NoSpecimen(request);
if (pi.ParameterType != typeof(TimeSpan) ||
pi.Name != "lifespan")
return new NoSpecimen(request);
return this.lifespan;
}
}
Imperatively, it could be used like this:
var fixture = new Fixture();
fixture.Customizations.Add(new LifespanArg(mySpecialLifespanValue));
var sut = fixture.Create<CookieCache>();
This approach can be generalized to some degree, but in the end, we're limited by the lack of a strongly typed way to extract a ParameterInfo from a particular constructor or method argument.
I fee like #Nick was almost there. When overriding the constructor argument, it needs to be for the given type and have it limited to that type only.
First we create a new ISpecimenBuilder that looks at the "Member.DeclaringType" to keep the correct scope.
public class ConstructorArgumentRelay<TTarget,TValueType> : ISpecimenBuilder
{
private readonly string _paramName;
private readonly TValueType _value;
public ConstructorArgumentRelay(string ParamName, TValueType value)
{
_paramName = ParamName;
_value = value;
}
public object Create(object request, ISpecimenContext context)
{
if (context == null)
throw new ArgumentNullException("context");
ParameterInfo parameter = request as ParameterInfo;
if (parameter == null)
return (object)new NoSpecimen(request);
if (parameter.Member.DeclaringType != typeof(TTarget) ||
parameter.Member.MemberType != MemberTypes.Constructor ||
parameter.ParameterType != typeof(TValueType) ||
parameter.Name != _paramName)
return (object)new NoSpecimen(request);
return _value;
}
}
Next we create an extension method to allow us to easily wire it up with AutoFixture.
public static class AutoFixtureExtensions
{
public static IFixture ConstructorArgumentFor<TTargetType, TValueType>(
this IFixture fixture,
string paramName,
TValueType value)
{
fixture.Customizations.Add(
new ConstructorArgumentRelay<TTargetType, TValueType>(paramName, value)
);
return fixture;
}
}
Now we create two similar classes to test with.
public class TestClass<T>
{
public TestClass(T value1, T value2)
{
Value1 = value1;
Value2 = value2;
}
public T Value1 { get; private set; }
public T Value2 { get; private set; }
}
public class SimilarClass<T>
{
public SimilarClass(T value1, T value2)
{
Value1 = value1;
Value2 = value2;
}
public T Value1 { get; private set; }
public T Value2 { get; private set; }
}
Finally we test it with an extension of the original test to see that it will not override similarly named and typed constructor arguments.
[TestFixture]
public class AutoFixtureTests
{
[Test]
public void Can_Create_Class_With_Specific_Parameter_Value()
{
string wanted = "This is the first string";
string wanted2 = "This is the second string";
Fixture fixture = new Fixture();
fixture.ConstructorArgumentFor<TestClass<string>, string>("value1", wanted)
.ConstructorArgumentFor<TestClass<string>, string>("value2", wanted2);
TestClass<string> t = fixture.Create<TestClass<string>>();
SimilarClass<string> s = fixture.Create<SimilarClass<string>>();
Assert.AreEqual(wanted,t.Value1);
Assert.AreEqual(wanted2,t.Value2);
Assert.AreNotEqual(wanted,s.Value1);
Assert.AreNotEqual(wanted2,s.Value2);
}
}
This seems to be the most comprehensive solution set here. So I'm going to add mine:
The first thing to create ISpecimenBuilder that can handle multiple constructor parameters
internal sealed class CustomConstructorBuilder<T> : ISpecimenBuilder
{
private readonly Dictionary<string, object> _ctorParameters = new Dictionary<string, object>();
public object Create(object request, ISpecimenContext context)
{
var type = typeof (T);
var sr = request as SeededRequest;
if (sr == null || !sr.Request.Equals(type))
{
return new NoSpecimen(request);
}
var ctor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault();
if (ctor == null)
{
return new NoSpecimen(request);
}
var values = new List<object>();
foreach (var parameter in ctor.GetParameters())
{
if (_ctorParameters.ContainsKey(parameter.Name))
{
values.Add(_ctorParameters[parameter.Name]);
}
else
{
values.Add(context.Resolve(parameter.ParameterType));
}
}
return ctor.Invoke(BindingFlags.CreateInstance, null, values.ToArray(), CultureInfo.InvariantCulture);
}
public void Addparameter(string paramName, object val)
{
_ctorParameters.Add(paramName, val);
}
}
Then create extension method that simplifies usage of created builder
public static class AutoFixtureExtensions
{
public static void FreezeActivator<T>(this IFixture fixture, object parameters)
{
var builder = new CustomConstructorBuilder<T>();
foreach (var prop in parameters.GetType().GetProperties())
{
builder.Addparameter(prop.Name, prop.GetValue(parameters));
}
fixture.Customize<T>(x => builder);
}
}
And usage:
var f = new Fixture();
f.FreezeActivator<UserInfo>(new { privateId = 15, parentId = (long?)33 });
Good thread, I added another twist based on many of the aswers already posted:
Usage
Example:
var sut = new Fixture()
.For<AClass>()
.Set("value1").To(aInterface)
.Set("value2").ToEnumerableOf(22, 33)
.Create();
Test classes:
public class AClass
{
public AInterface Value1 { get; private set; }
public IEnumerable<int> Value2 { get; private set; }
public AClass(AInterface value1, IEnumerable<int> value2)
{
Value1 = value1;
Value2 = value2;
}
}
public interface AInterface
{
}
Full test
public class ATest
{
[Theory, AutoNSubstituteData]
public void ATestMethod(AInterface aInterface)
{
var sut = new Fixture()
.For<AClass>()
.Set("value1").To(aInterface)
.Set("value2").ToEnumerableOf(22, 33)
.Create();
Assert.True(ReferenceEquals(aInterface, sut.Value1));
Assert.Equal(2, sut.Value2.Count());
Assert.Equal(22, sut.Value2.ElementAt(0));
Assert.Equal(33, sut.Value2.ElementAt(1));
}
}
Infrastructure
Extension method:
public static class AutoFixtureExtensions
{
public static SetCreateProvider<TTypeToConstruct> For<TTypeToConstruct>(this IFixture fixture)
{
return new SetCreateProvider<TTypeToConstruct>(fixture);
}
}
Classes participating in the fluent style:
public class SetCreateProvider<TTypeToConstruct>
{
private readonly IFixture _fixture;
public SetCreateProvider(IFixture fixture)
{
_fixture = fixture;
}
public SetProvider<TTypeToConstruct> Set(string parameterName)
{
return new SetProvider<TTypeToConstruct>(this, parameterName);
}
public TTypeToConstruct Create()
{
var instance = _fixture.Create<TTypeToConstruct>();
return instance;
}
internal void AddConstructorParameter<TTypeOfParam>(ConstructorParameterRelay<TTypeToConstruct, TTypeOfParam> constructorParameter)
{
_fixture.Customizations.Add(constructorParameter);
}
}
public class SetProvider<TTypeToConstruct>
{
private readonly string _parameterName;
private readonly SetCreateProvider<TTypeToConstruct> _father;
public SetProvider(SetCreateProvider<TTypeToConstruct> father, string parameterName)
{
_parameterName = parameterName;
_father = father;
}
public SetCreateProvider<TTypeToConstruct> To<TTypeOfParam>(TTypeOfParam parameterValue)
{
var constructorParameter = new ConstructorParameterRelay<TTypeToConstruct, TTypeOfParam>(_parameterName, parameterValue);
_father.AddConstructorParameter(constructorParameter);
return _father;
}
public SetCreateProvider<TTypeToConstruct> ToEnumerableOf<TTypeOfParam>(params TTypeOfParam[] parametersValues)
{
IEnumerable<TTypeOfParam> actualParamValue = parametersValues;
var constructorParameter = new ConstructorParameterRelay<TTypeToConstruct, IEnumerable<TTypeOfParam>>(_parameterName, actualParamValue);
_father.AddConstructorParameter(constructorParameter);
return _father;
}
}
Constructor parameter relay from other answers:
public class ConstructorParameterRelay<TTypeToConstruct, TValueType> : ISpecimenBuilder
{
private readonly string _paramName;
private readonly TValueType _paramValue;
public ConstructorParameterRelay(string paramName, TValueType paramValue)
{
_paramName = paramName;
_paramValue = paramValue;
}
public object Create(object request, ISpecimenContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
ParameterInfo parameter = request as ParameterInfo;
if (parameter == null)
return new NoSpecimen();
if (parameter.Member.DeclaringType != typeof(TTypeToConstruct) ||
parameter.Member.MemberType != MemberTypes.Constructor ||
parameter.ParameterType != typeof(TValueType) ||
parameter.Name != _paramName)
return new NoSpecimen();
return _paramValue;
}
}