The end goal for this post is to override the ToString() method of a concrete implementation of a generic base class while still being able to search the implementation using Linq flattening technique. So if you read this and see a better way let me know. I'm using Telerik controls for Silverlight and they won't change their api to allow some of their control properties to be data-bound and instead rely on the ToString() method of whatever object they are bound to. yea, stupid.. Anyway here is what I've got.
RadTreeView control on my page. The FullPath property of each node in the treeview uses the ToString() method of each item its bound to (so this is what I need to override).
I had to create an "intermediary" class to enhance my base model class so it can be bound as a heirarchy in the tree view and then a concrete implementation of that generic class to override ToString(). Now the problem is I have a Linq extension that explodes because it cannot convert the concrete implementation back to the base generic class. I love generics but this is too much for me. Need help on solving the extension method issue.
Intermediary generic class:
public class HeirarchicalItem<T> : NotifyPropertyChangedBase, INotifyCollectionChanged where T : class
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs ea)
{
if (CollectionChanged != null)
CollectionChanged(this, ea);
}
public HeirarchicalItem() { }
public HeirarchicalItem(T item)
{
Item = item;
}
public HeirarchicalItem(IEnumerable<T> collection)
{
CopyFrom(collection);
}
private T _item;
public T Item
{
get
{
return _item;
}
set
{
_item = value;
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Item);
}
}
private ObservableCollection<HeirarchicalItem<T>> _children = new ObservableCollection<HeirarchicalItem<T>>();
public virtual ObservableCollection<HeirarchicalItem<T>> Children
{
get { return _children; }
set
{
_children = value;
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
private void CopyFrom(IEnumerable<T> collection)
{
if ((collection != null))
{
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
HeirarchicalItem<T> newHeirarchicalItem = new HeirarchicalItem<T>(enumerator.Current);
Children.Add(newHeirarchicalItem);
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
}
}
}
}
Base model class: (data is shuttled to and from WCF Ria service using this class)
public class tbl_Path : EntityBase, IFullPath, IEquatable<tbl_Path>, IEqualityComparer<tbl_Path>
{
public tbl_Path();
public int GetHashCode(tbl_Path obj);
public override string ToString();
public DateTime CreateDate { get; set; }
public short Depth { get; set; }
public string FullPath { get; set; }
public bool IsAuthorized { get; set; }
public bool IsSelected { get; set; }
public string Name { get; set; }
public override IEnumerable<Operation> Operations { get; }
public int? ParentPathID { get; set; }
public int PathID { get; set; }
public Guid SecurityKey { get; set; }
public EntityCollection<tbl_Configuration> tbl_Configuration { get; set; }
public EntityCollection<tbl_Key> tbl_Key { get; set; }
public EntityCollection<tbl_SecurityACL> tbl_SecurityACL { get; set; }
public EntityCollection<tbl_SecurityInheriting> tbl_SecurityInheriting { get; set; }
public EntityCollection<tbl_Variable> tbl_Variable { get; set; }
}
Concrete Implementation so that I can override ToString():
public class HeirarchicalPath : HeirarchicalItem<tbl_Path>
{
public HeirarchicalPath()
{
}
public HeirarchicalPath(tbl_Path item)
: base(item)
{
}
public HeirarchicalPath(IEnumerable<tbl_Path> collection)
: base(collection)
{
}
public override string ToString()
{
return Item.Name; **// we override here so Telerik is happy**
}
}
And finally here is the Linq extension method that explodes during compile time because I introduced a concrete implementation of my generic base class.
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
Actual code that is breaking: (x.Children is highlighted with the error)
Cannot implicitly convert type
'System.Collections.ObjectModel.ObservableCollection<HeirarchicalItem<tbl_Path>>' to
'System.Collections.Generic.IEnumerable<HeirarchicalPath>'. An explicit conversion
exists (are you missing a cast?)
HeirarchicalPath currentItem = this.Paths.Traverse(x => x.Children).Where(x => x.Item.FullPath == "$/MyFolder/Hello").FirstOrDefault();
Figured it out. Been working on this all day and minutes after posting the question I resolve it as always.
Just needed to add this bit to my concrete implementation and no more compiler errors.
private ObservableCollection<HeirarchicalPath> _children = new ObservableCollection<HeirarchicalPath>();
public new ObservableCollection<HeirarchicalPath> Children
{
get
{
return _children;
}
set
{
if (value == null)
return;
_children = value;
RaisePropertyChanged<HeirarchicalPath>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Related
I am validating the content for file import and I have an IsValid property for each line.
public class Header
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public bool IsValid { get; set; }
}
public class Detail
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public bool IsValid { get; set; }
}
public class Trailer
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public bool IsValid { get; set; }
}
public class ImportFile
{
public Header Header { get; set; }
public List<Detail> Details { get; set; }
public Trailer Trailer { get; set; }
}
and my validators look somewhat like:
public class DetailValidator : AbstractValidator<Detail>
{
public DetailValidator()
{
RuleFor(d => d.Property1)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.Length(3)
.WithState(d => d.LineNumber);
RuleFor(d => d.Property2)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.MaximumLength(50)
.WithState(d => d.LineNumber);
...
}
}
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.SetValidator(new HeaderValidator());
RuleForEach(f => f.Details)
.SetValidator(new DetailsValidator());
...
}
}
After I call the validation, I wanted to set the IsValid property of each line of the file (be it header, detail or trailer) base from the result of the validation.
What is possible for now is, since I am using WithState to store the LineNumber, I can match the ValidationResult against the ImportFile instance to set each line's validity like below:
ImportFile file = // parsed file content
var result = new ImportFileValidator().Validate(file);
foreach (var detail in file.Details)
{
var error = result.Errors.FirstOrDefault(e =>
Convert.ToInt32(e.CustomState) == detail.LineNumber);
detail.IsValid = error == null;
}
And I have to check for the header and trailer as well.
Is there a way I can do this inside the validators? I am trying to explore the FluentValidation's documentation, but I can't seem to find what I needed there.
As I was exploring the available methods in FluentValidation, I saw OnFailure and OnAnyFailure methods. This methods might be a good help to what I needed to do, but the problem is they're obsolete as of 10.3.0 and will be removed on version 11. They're suggesting to use a custom validator instead.
The Header, Detail and Trailer Abstract Validators remain as is.
I created custom validator extensions for those 3.
Each extension methods creates an instance of the corresponding validator and executes it. I can make them generic for header, detail and trailer since they will do the same thing, set IsValid property to the validation result.
public static IRuleBuilderOptionsConditions<ImportFile, T> IsHeaderValid<T>(this IRuleBuilder<ImportFile, T> ruleBuilder)
where T : Header
{
return builder.Custom((header, context) =>
{
// Create the Header Abstract Validator Instance
var validator = new HeaderValidator();
var result = validator.Validate(Header);
header.IsValid = result.IsValid;
// Pass the errors to the context
result.Errors.ForEach(context.AddFailure);
}
}
I had to change the ImportFileValidator to call the custom validators, instead of using setvalidator.
The ImportFileValidator looks like this:
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.IsHeaderValid();
RuleForEach(f => f.Details)
.IsDetailValid();
...
}
}
This is pretty much how I was able to set the IsValid property without having to do the matching I initially did in the question.
Im using FluentValidation
I would like to do a range validation using:
InclusiveBetween
RuleFor(x => x.Height)
.InclusiveBetween(x=> x.min, x.max).
I want to be able to get the 'from' and 'to' values dynamically from the model..rather than being hardcoded in the validator
Is this possible?
Thanks
Well, there's nothing in FluentValidation for that.
But you could write your own extension method (and validator), something like that (fast shot, so you'll have to make this better, but you've got the idea).
//the extension method
public static class ValidationExtensions
{
public static IRuleBuilder<T, TProperty> InclusiveBetween<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> fromExpression, Expression<Func<T, TProperty>> toExpression)
{
var fromFunc = leftExpression.Compile();
var toFunc = rightExpression.Compile();
return ruleBuilder.SetValidator(new InclusiveBetweenPropertyValidator(fromFunc.CoerceToNonGeneric(), fromExpression.GetMember(), toFunc.CoerceToNonGeneric(), toExpression.GetMember()));
}
}
Then the Validator class
public class InclusiveBetweenPropertyValidator : PropertyValidator, IBetweenValidator, IPropertyValidator
{
public Func<object, object> FromFunc { get; set; }
public MemberInfo FromMemberInfo { get; set; }
public Func<object, object> ToFunc { get; set; }
public MemberInfo ToMemberInfo { get; set; }
public IComparable From { get; private set; }
public IComparable To { get; private set; }
public InclusiveBetweenPropertyValidator(Func<object, object> fromFunc, MemberInfo fromMember, Func<object, object> toFunc, MemberInfo toMember)
: base((() => Messages.inclusivebetween_error))
{
FromFunc = fromFunc;
FromMemberInfo = fromMember;
ToFunc = toFunc;
ToMemberInfo = toMember;
}
protected override bool IsValid(PropertyValidatorContext context)
{
var comparable = (IComparable)context.PropertyValue;
From = (IComparable)this.FromFunc(context.Instance);
To = (IComparable)this.ToFunc(context.Instance);
if (comparable == null || FluentValidation.Internal.Comparer.GetComparisonResult(comparable, From) >= 0 && FluentValidation.Internal.Comparer.GetComparisonResult(comparable, To) <= 0)
return true;
context.MessageFormatter.AppendArgument("From", string.Format("{0} ({1})", FromMemberInfo.Name, From)).AppendArgument("To", string.Format("{0} ({1})",ToMemberInfo.Name, To)).AppendArgument("Value", context.PropertyValue);
return false;
}
}
usage :
RuleFor(x => x.Height)
.InclusiveBetween(x=> x.min, x.max)
If you don't want to write an extension you could use the additional overload of the Predicate Validator - which also accepts an instance of the parent object - like this:
RuleFor(x => x.Height)
.Must((model, height) => height >= model.Min && height <= model.Max);
This is similar to Raphaël's answer, but is more of a case-by-case usage as opposed to a general usage extension.
RuleFor(x => x).Must(HeightValidation);
private static bool HeightValidation(Model m)
{
return m.Height >= m.min && m.Height <= m.max;
}
Let's imagine your Model as follow:
public class YourModel
{
public int Height { get; set; }
public int Min { get; set; }
public int Max { get; set; }
}
then Validation will be as follow:
public class YourModelValidation : AbstractValidator<YourModel>
{
public YourModelValidation(int min,int max)
{
RuleFor(x => x.Height).InclusiveBetween(min, max);
}
}
then Validation usage is :
var validation = new YourModelValidation(model.Min,model.Max).Validate(model);
as you can see dynamic parameters are passed in validation's Constructor.
you can pass model or dto as Constructor parameter
I have a model called Foo which has a property called MyProp of type Bar.
When I post this model to the controller I want the model binder to validate MyProp because it has the Required attribute just as it does with a string. I need this to be self-contained within the Bar class or as a separate class. I have tried to use the IValidatableObject on the Bar class but it seems like it's impossible to check if the Foo class has the Required attribute on MyProp? So now I'm out of options and need some help. Below is some sample code for my question.
public class Foo {
[Required]
public Bar MyProp { get; set; }
}
public class Bar {
[ScaffoldColumn(false)]
public int Id { get; set; }
public string Name { get; set; }
}
Here is one solution to my problem where I can use the built in required attribute and still get custom behavior. This is just some proof of concept code.
The model:
public class Page : IPageModel {
[Display(Name = "Page", Prompt = "Specify page name...")]
[Required(ErrorMessage = "You must specify a page name")]
public PageReference PageReference { get; set; }
}
The model binder:
public class PageModelBinder : DefaultModelBinder {
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(bindingContext.ModelType)) {
var attributes = property.Attributes;
if (attributes.Count == 0) continue;
foreach (var attribute in attributes) {
if (attribute.GetType().BaseType == typeof(ValidationAttribute) && property.PropertyType == typeof(PageReference)) {
var pageReference = bindingContext.ModelType.GetProperty(property.Name).GetValue(bindingContext.Model, null) as PageReference;
Type attrType = attribute.GetType();
if (attrType == typeof (RequiredAttribute) && string.IsNullOrEmpty(pageReference.Name)) {
bindingContext.ModelState.AddModelError(property.Name,
((RequiredAttribute) attribute).ErrorMessage);
}
}
}
}
base.OnModelUpdated(controllerContext, bindingContext);
}
}
The model binder provider:
public class InheritanceAwareModelBinderProvider : Dictionary<Type, IModelBinder>, IModelBinderProvider {
public IModelBinder GetBinder(Type modelType) {
var binders = from binder in this
where binder.Key.IsAssignableFrom(modelType)
select binder.Value;
return binders.FirstOrDefault();
}
}
And last the global.asax registration:
var binderProvider = new InheritanceAwareModelBinderProvider {
{
typeof (IPageModel), new PageModelBinder() }
};
ModelBinderProviders.BinderProviders.Add(binderProvider);
The result: http://cl.ly/IjCS
So what do you think about this solution?
The problem is that there is no html field called MyProp and MVC doesn't fire any validation for this property.
One way to achieve your goal is to get rid of Bar and create Bar's properties in Foo. You can use AutoMapper to minimize plumbing code to minimum.
Another solution is to write a custom validation attribute which validates against the null values and use it instead of Required attribute.
Solution 1
Instead of using [Required], try a custom ValidationAttribute
public class Foo {
[RequiredBar]
public Bar MyProp { get; set; }
}
public class Bar {
[ScaffoldColumn(false)]
public int Id { get; set; }
public string Name { get; set; }
}
public class RequiredBar : ValidationAttribute {
public override bool IsValid(object value)
{
Bar bar = (Bar)value;
// validate. For example
if (bar == null)
{
return false;
}
return bar.Name != null;
}
}
Solution Two:
Simply put Required on the corresponding required properties of Bar, For example
public class Foo {
//[RequiredBar]
public Bar MyProp { get; set; }
}
public class Bar {
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
I am developing in ASP.NET MVC3 and EntityFramework.
I want my model to follow an interface :
public class Account : IAccount
{
public string Id { get; set; }
public DateTime Date { get; set; }
public string Language { get; set; }
}
public interface IAccount
{
string Id { get; set; }
DateTime Date { get; set; }
string Language { get; set; }
}
Here's my Context
public class EFContext : DbContext, IContext
{
public DbSet<Account> Accounts { get; set; }
}
And here's the repository :
public interface IRepository<T> where T : class
{
IQueryable<T> All { get; }
int Count { get; }
bool Contains(Expression<Func<T, bool>> predicate);
void Create(T item);
void Update(T item);
void Delete(Expression<Func<T, bool>> predicate);
void Delete(T item);
}
public class EFRepository<T> : IRepository<T> where T : class
{
private EFContext _context;
public EFRepository(IUnitOfWork uow)
{
this._context = (EFContext)uow.Context;
}
protected DbSet<T> DbSet
{
get
{
return _context.Set<T>();
}
}
public IQueryable<T> All
{
get
{
return DbSet.AsQueryable();
}
}
public virtual int Count
{
get
{
return DbSet.Count();
}
}
public bool Contains(Expression<Func<T, bool>> predicate)
{
return DbSet.Count(predicate) > 0;
}
public virtual void Create(T item)
{
DbSet.Add(item);
}
public virtual void Update(T TObject)
{
var item = DbSet.Attach(TObject);
_context.SetItemState(TObject, EntityState.Modified);
}
public virtual void Delete(Expression<Func<T, bool>> predicate)
{
var objects = DbSet.Where(predicate);
foreach (var obj in objects)
{
DbSet.Remove(obj);
}
}
public virtual void Delete(T TObject)
{
DbSet.Remove(TObject);
}
}
Now, I want to use IRepository<IAccount> but this will ask the context for DbSet<IAccount>. This leads to an error since the Context contains a DbSet<Account>.
I then tried the solution proposed here for Linq2Sql : http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx
So I added this function to my EFContext
public new DbSet<T> Set<T>() where T : class
{
var ciccio = TableMaps[typeof(T)];
return (DbSet<T>)base.Set(ciccio).Cast<T>();
}
But it doesn't work.
Do anyone have a suggestion?
Thx
What benefit are you receiving from using an interface for your entities? I don't see any value here. Typically, you use Interfaces to remove dependencies upon the implementation, but that's not what you're achieving here because you're returning a concrete DbSet of objects.
Your entities are already Poco's. They don't have dependencies on other implemntations, and they have no code in them other than a getter/setter. Using an interface is redundant and pointless.
I've found a workaround. I kind of like it so I want to share it.
I rewritten my EFRepository :
public class EFRepository<T, W> :
IRepository<T> where T : class
where W : class, T
{
private EFContext _context;
public EFRepository(IUnitOfWork uow)
{
this._context = (EFContext)uow.Context;
}
protected DbSet<W> DbSet
{
get
{
return _context.Set<W>();
}
}
public IQueryable<T> All
{
get
{
return DbSet.AsQueryable<T>();
}
}
public virtual int Count
{
get
{
return DbSet.Count();
}
}
public bool Contains(Expression<Func<T, bool>> predicate)
{
return All.Count(predicate) > 0;
}
public virtual void Create(T item)
{
DbSet.Add(item as W);
}
public virtual void Update(T TObject)
{
var item = DbSet.Attach(TObject as W);
_context.SetItemState(TObject, EntityState.Modified);
}
public virtual void Delete(Expression<Func<T, bool>> predicate)
{
var objects = All.Where(predicate);
foreach (var obj in objects)
{
DbSet.Remove(obj as W);
}
}
public virtual void Delete(T TObject)
{
DbSet.Remove(TObject as W);
}
}
So now basically all I need to do now is
IRepository<IAccount>> accRepository = new EFRepository<IAccount, Account>(uow);
I am happy with this solution, but still I'm not sure it is the best one, so any comments will be appreciated.
Thanks
I am reading up on ASP.NET MVC and all of it's fun uses and I just found out about DataTemplates.
In my hurry to test this thing out, I converted one of my simpler models over to using #Html.DisplayForModel() and #Html.EditForModel() and it worked like a lucky charm that it is :)
One thing that I immediately found out though was that I could not easily define a field to show up on display views but not be present at all for editing...
You can make use of IMetadataAware interface an create attribute which will set ShowForEdit and ShowForDislay in Metadata:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TemplatesVisibilityAttribute : Attribute, IMetadataAware
{
public bool ShowForDisplay { get; set; }
public bool ShowForEdit { get; set; }
public TemplatesVisibilityAttribut()
{
this.ShowForDisplay = true;
this.ShowForEdit = true;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
if (metadata == null)
{
throw new ArgumentNullException("metadata");
}
metadata.ShowForDisplay = this.ShowForDisplay;
metadata.ShowForEdit = this.ShowForEdit;
}
}
Then you can attach it to your property like this:
public class TemplateViewModel
{
[TemplatesVisibility(ShowForEdit = false)]
public string ShowForDisplayProperty { get; set; }
public string ShowAlwaysProperty { get; set; }
}
And this is all you need.
You could write a custom metadata provider and set the ShowForEdit metadata property. So start with a custom attribute:
public class ShowForEditAttribute : Attribute
{
public ShowForEditAttribute(bool show)
{
Show = show;
}
public bool Show { get; private set; }
}
then a custom model metadata provider:
public class MyModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName
)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var sfea = attributes.OfType<ShowForEditAttribute>().FirstOrDefault();
if (sfea != null)
{
metadata.ShowForEdit = sfea.Show;
}
return metadata;
}
}
then register this provider in Application_Start:
ModelMetadataProviders.Current = new MyModelMetadataProvider();
and finally decorate:
public class MyViewModel
{
[ShowForEdit(false)]
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
Now if in your view you have:
#model MyViewModel
<h2>Editor</h2>
#Html.EditorForModel()
<h2>Display</h2>
#Html.DisplayForModel()
the Prop1 property won't be included in the editor template.
Remark: you could do the same with the ShowForDisplay metadata property.
Can you display each of the fields you want using Html.DisplayTextbox or one of the other options? That way you can also customize the appearance and labels referring to the field.