Blazor FluentValidation Dynamic Rule Generation C# - c#

I'm trying to create validation rules for Pocos in a generic fashion. I'm fairly confident with Reflection, but I don't really want to pick apart the entire call chain to be able to do what I want.
I came up with the idea of detecting all of the types in use and calling a generic function that could setup the rest of the rule, but I can't find anywhere in the chain that exposes the actual object.
This is a nested structure where panels in my form are based on a property whose type is 'object', I want to know at which point I can get the actual value of the instance. A rule chain for me looks like follows:
RuleForEach(p => p.level1s)
.ChildRules(l1 => {
x.RuleForEach(p => p.level2s)
.ChildRules(l2 => {
//ToDo: Iterate Properties on Type # level1s[].level2s[].poco
//How can I find type of poco for this specific executing of this lambda?
//For each property, I'd have to do reflective code for this kind of thing
//ToDo: l2.RuleFor<~~TProperty~~>(x => x.poco~~property~~).NotEmpty()
// .When(x => x.poco~~property~~ has the RequiredAttribute)
// .WithMessage("{PropertyName} is required");
});
});
So, if you can tell from my pseudo code above, I would need to be able to extract the type of the Poco, and the type of the properties within the last ChildRules expression, but all that I have to hand is an InlineValidator<~~l2type~~, object> - so how/where can the current instance type of that 'object' be determined?
Thanks.
Mark

After looking at this for a while and thinking about it from several angles it occurred to me that I should be able to just pass through a validator for my Poco, but a problem occurred when trying to pick up the validator from my variable.
In my first/outer validator, I ended up with the following code:
//ddeach is just the output of a RuleForEach
ddeach.ChildRules(kvconfig =>
{
//Note - Fluent Validation requires that each rule is stated in full at this point starting with a RuleFor, so it's not
//possible to merge all of these following code blocks
//Chain Child Validator
kvconfig.RuleFor(kv => kv.Value.RefPoco)
.SetValidator(dict => (IValidator<object>)dict.Value.PocoValidator);
});
My property at dict.Value.PocoValidator is just an 'IValidator' but FluentValidation doesn't supply an easy way to use one of those, it has to be a strong type to support the fluent API. You can't give it a IValidator, because you don't know the type and LINQ can't infer it, also it won't automatically cast to IValidator.
Eventually, I found that I could allow my validator class to be used by implementing IValidator. My validator code then looks like:
public class Validator : AbstractValidator<MyPocoType>, IValidator<object>
{
public Validator()
{
RuleFor(x => x.Name).NotEmpty();
}
FluentValidation.Results.ValidationResult IValidator<object>.Validate(object instance)
{
return this.Validate(instance as MyPocoType);
}
async Task<FluentValidation.Results.ValidationResult> IValidator<object>.ValidateAsync(object instance, CancellationToken cancellation)
{
return await this.ValidateAsync(instance as MyPocoType, cancellation);
}
}
Mark

Related

How to use class type in transformer

In my booking object I keep an object reference list with the Type and WorkflowStepTypeId of the corresponding document. I then want to use the type in a Where to find the suitable document, and retrieve it by id. However, when compiling the transformer to RavenDB it says it doesn't know what my type is.
Code:
public class BookingToTrainingTransformer
: RavenTransformerBase<Booking, BookingToTrainingTransformer.Result>
{
public class Result
{
}
public BookingToTrainingTransformer()
{
TransformResults = results =>
from result in results
let trainingWorkflow = LoadDocument<TrainingWorkflow>(result.WorkflowSteps
.FirstOrDefault(a => a.WorkflowStepType == typeof(Trainingworkflow))
.WorkflowStepTypeId)
}
}
To clarify, I know that RavenDB wouldn't know what my type is. On the database side, I simply want it to make a string of both types and compare those strings. However, for refactoring purposes it would be great to know that the type is actually used in said transformer so if it ever gets refactored, the transformer also automatically gets refactored.
Is what I want possible?
You want it to compare actual types so that if you refactor the type later, the transformer will still work?
No, that's not possible.
If I'm understanding your question right, can WorkflowStepType be a type name? If you refactor the type name later, sure, you'd still need to update the WorkflowStepType property in the database. But in your transformer, it'd just look like this:
.FirstOrDefault(a => a.WorkflowStepType == nameof(Trainingworkflow))

What rules does Mongo Bson driver use to automap a type?

When I call this:
BsonClassMap.RegisterClassMap<MyType>();
Under the covers the code calls this:
return RegisterClassMap<TClass>(cm => { cm.AutoMap(); });
And then it's off to mapping land.
I'm trying to figure out what rules are used when reflecting over the type to decide which fields and properties should be serialized/included in the map.
I've tried to reason-thru it by reading the code. I thought someone with more knowledge here could shortcut a full walk-thru in the debugger.
I'd specifically like to know the individual rules used to make a yes/no decision on a type member and the order in which those rules are applied.

LINQ ignore incorrect type being assigned to property

So, I have my own mapper (NOT AutoMapper) which maps models to each other. You give the model you'd like to map to, and with the Map method you push an object in. Beside of this I wrote the Extend method which functions as a override for the Map method to, for example, add properties which are not available in the object being mapped.
Problem:
The problem hereby is that my public Mapper<T> Extend(Func<T, T> func) method doesn't like the different types.
Possible solutions:
There are 2 solutions I'm thinking of:
Ignore the error and map the value within my Extend method. Which isn't possible as far as I know due to the expression being executed immediately.
Create a LINQ method which maps the value for me. Eg; q => q.Ownership = obj.Ownerships.First().Map().
Question:
How can I resolve this error and achieve what I want?

C# casting an object within lambda

I am currently trying to set a field which I need in business logic which in this case is Lazy.
(yes not the property, it is necessary to set the field)
I get the error that Lazy can not be converted to Lazy
as you can see:
Object of type
'BusinessLogic.Lazy1[System.Object]'
cannot be converted to type
'BusinessLogic.Lazy1[BusinessLogic.ArtikelBLL]
I use this line to get a dynamic repository.
dynamic repository = Activator.CreateInstance(typeof(GenericRepository<>).MakeGenericType(typeArgs));
Then I try to set the value of the field but it fails:
fInfo.SetValue(obj, Lazy.From(() => repository.GetDataById(id)));
I have tried to solve it many different ways.
Somehow I have to cast repository.GetDataById(id) to the Entity it is looking for, which in this case is ArtikelBLL (which i can get through pInfo.PropertyType).
But by doing (ArtikelBLL)repository.GetDataById(id) it will not remain object orientated.
Can anybody please help me with this?
The simplest way would be to just use a cast inside the lambda:
fInfo.SetValue(obj, new Lazy<GenericBLL>(
() => (ArtikelBLL) repository.GetDataById(id)));
After all, that's the type the Lazy<T> wants.
EDIT: If you're trying to do this dynamically, I suggest you write a generic method like this:
public Lazy<T> CreateLazyDataFetcher<T>(dynamic repository)
{
return new Lazy<T>(() => (T) repository.GetDataById(id));
}
Then call that method with reflection. (Using MethodInfo.MakeGenericMethod(...).Invoke(...))

c# multiple expression parameteres

I'm trying to create a method signature that takes multiple properties of various type using
I would call it something like this:
AllPropertiesExcept(() => Property1, () => Property2)
This method almost work, except that the type of the properties have to be the same. I'm only going to use the property name, but want to use lambda expression to enable easy refactoring.
public static string MyMethod<T>(params Expression<Func<T>>[] propertyExpression)
I would use AllPropertiesExcept(params Expression<Func<object>>[] properties), you can still get the property names out of it, but it doesn't matter what type the property is.
Edit: However, I would tend to use it the other way round - instead of excluding properties I don't want to see, I would include properties I want to see. The reason is simple - to make your way work, you still need reflection - with my way, you could easily use the Func you get to get the actual data directly.
Edit 2 (getting the property name out of an expression):
Expression<Func<object>> obj = something; // you get this in your method
((obj.Body as UnaryExpression).Operand as MemberExpression).Member.Name
I can really advise you to use LinqPad for such things, you can easily drill down objects via Dump(), which displays the objects very user friendly. Just recreate a small example and experiment.
Does the method AllPropertiesExcept() return anything? Otherwise you could make a fluent interface (using method chaining):
AllPropertiesExcept(() => Property1)
.And(() => Property2)
.And(() => Property3);
Even if the AllPropertiesExcept() method returns something, you can defer the execution until you invoke a method at the end of the method chain:
var foo = AllPropertiesExcept(() => Property1)
.And(() => Property2)
.And(() => Property3)
.DoSomeThing();
I think what you need is to understand the ModelMetadata class documented here:
http://msdn.microsoft.com/en-us/library/system.web.mvc.modelmetadata.aspx
This class is used in ASP.NET MVC in situations like Html.LabelFor(x -> x.Name)
An expression is passed to the ModelMetadata.FromLambdaExpression Method documented here:
http://msdn.microsoft.com/en-us/library/ee428393.aspx
After understanding how it is used in MVC, you could create your own code with some informed knowledge of how it was applied elsewhere.

Categories