I am developing a WPF Application using MVVM Architecture. I am an amateur in WPF so bear with me..
I have two model classes. Parent class has an object of another (child) class as its property. (i mean nested objects and not inherited objects)
For instance, consider the following scenario.
public class Company
{
public string CompanyName {get; set;}
public Employee EmployeeObj {get; set;}
}
public class Employee
{
public string FirstName {get; set;}
public string LastName {get; set;}
}
I want to validate the properties of Employee entity using Enterprise Library Validation Block.
I was able to do it by implementing IDataErroInfo interface in employee class as shown below
public class Employee : IDataErrorInfo
{
[NotNullValidator(MessageTemplate="First Name is mandatory"]
public string FirstName {get; set;}
[StringLengthValidator(0,20,MessageTemplate="Invalid")]
public string LastName {get; set;}
public string Error
{
get
{
StringBuilder error = new StringBuilder();
ValidationResults results = Validation.ValidateFromAttributes<Employee>(this);
foreach (ValidationResult result in results)
{
error.AppendLine(result.Message);
}
return error.ToString();
}
}
public string this[string propertyName]
{
get
{
ValidationResults results = Validation.ValidateFromAttributes<Employee>(this);
foreach (ValidationResult result in results)
{
if (result.Key == propertyName)
{
return result.Message;
}
}
return string.Empty;
}
}
}
I dont want to implement IDataErroInfo for every child model i create.
Is there any way to validate the Employee object by implementing IDataErrorInfo on the parent (Company) class ?
And also is there any triggers to start validation of objects. I would like to validate the objects only when i want to and not all the time.
You can absolutely implement IDataErrorInfo on a base class using Validation Application Block. Here is an article that describes how to. The code basically comes down to this:
public abstract class DataErrorInfo : IDataErrorInfo
{
string IDataErrorInfo.Error
{
get { return string.Empty; }
}
string IDataErrorInfo.this[string columnName]
{
get
{
var prop = this.GetType().GetProperty(columnName);
return this.GetErrorInfo(prop);
}
}
private string GetErrorInfo(PropertyInfo prop)
{
var validator = this.GetPropertyValidator(prop);
if (validator != null)
{
var results = validator.Validate(this);
if (!results.IsValid)
{
return string.Join(" ",
results.Select(r => r.Message).ToArray());
}
}
return string.Empty;
}
private Validator GetPropertyValidator(PropertyInfo prop)
{
string ruleset = string.Empty;
var source = ValidationSpecificationSource.All;
var builder = new ReflectionMemberValueAccessBuilder();
return PropertyValidationFactory.GetPropertyValidator(
this.GetType(), prop, ruleset, source, builder);
}
}
You can use this abstract class add validation behavior to your entities by inheriting from it:
public partial class Customer : DataErrorInfo
{
}
Related
I have classes something like this:
public class foo{
public string FooProp1 {get; set;}
public Bar Bar{get; set;}
}
public class Bar{
public string BarProp1 {get; set;}
public string BarProp2 {get; set;}
}
I have some audit setup where If I Update Foo then I can get that property Name and value for all the property apart from the 'Bar'. Is there a way to get property name and value of 'BarProp1'.
private void ProcessModifiedEntries(Guid transactionId) {
foreach (DbEntityEntry entry in ChangeTracker.Entries().Where(t => t.State == EntityState.Modified).ToList()) {
Track audit = CreateAudit(entry, transactionId, "U");
foreach (var propertyName in entry.CurrentValues.PropertyNames) {
string newValue = entry.CurrentValues[propertyName]?.ToString();
string originalValue = entry.OriginalValues[propertyName]?.ToString();
SetAuditProperty(entry, propertyName, originalValue, audit, newValue);
}
}
}
I want to audit BarProp1 when Foo got changed.
You want classes to report additional information to your auditing system. I think the best place to do that is in your CreateAudit method. The question is how.
You could have code in there that does something special for each incoming entry:
var foo = entry.Entity as Foo;
if (foo != null)
{
// do something with foo.Bar
}
var boo = entry.Entity as Boo;
if (boo != null)
{
// do something with boo.Far
}
etc.
Of course that isn't very pretty.
If you have multiple classes that need to report additional info to the auditor I would define an interface and tack that to each of these classes:
public interface IAuditable
{
string AuditInfo { get; }
}
public class Foo : IAuditable
{
public string FooProp1 { get; set; }
public Bar Bar { get; set; }
[NotMapped]
public string AuditInfo
{
get { return Bar?.BarProp1; }
}
}
And then in CreateAudit:
var auditable = entry.Entity as IAuditable;
if (auditable != null)
{
// do something with auditable.AuditInfo
}
And even if there's only one class that needs this behavior I would still use the interface because it makes your code self-explanatory.
I have a Person class which contains a property that lazy loads (custom made lazy loading) the person address data through accessing the Item property. I would want it to be mapped to a POCO class. How could it be done?
In addition, is it possible to be mapped only if it has data (checking the HasData property) and mapped as null if there isn’t data?.
These are the source classes:
public class SourcePerson
{
public string Name { get; set; }
public MyLazyLoadingObject<SourceAddress> Address;
}
public class SourceAddress
{
public string City { get; set; }
public string Country { get; set; }
}
This is the custom lazy loading class (simplified):
public class MyLazyLoadingObject<T>
{
private int? _id;
private T _object;
public T Item
{
get
{
if (!_object.IsReaded)
{
_object.Read();
}
return _object;
}
}
public bool HasData
{
get
{
return _id.HasValue;
}
}
// Other non-relevant properties and methods
}
These are the destination classes:
public class DestinationPerson
{
public string Name { get; set; }
public DestinationAddress Address;
}
public class DestinationAddress
{
public string City { get; set; }
public string Country { get; set; }
}
Couldn't find conventional way of setting up conversion from MyLazyLoadingObject<T> to T and then T to some TDestination without code repetition.
But custom IObjectMapper implementation with some manual expression building does the job.
Here is the class that builds the mapping expression:
public class MyLazyLoadingObjectMapper : IObjectMapper
{
public bool IsMatch(TypePair context)
{
return context.SourceType.IsGenericType && context.SourceType.GetGenericTypeDefinition() == typeof(MyLazyLoadingObject<>);
}
public Expression MapExpression(TypeMapRegistry typeMapRegistry, IConfigurationProvider configurationProvider, PropertyMap propertyMap, Expression sourceExpression, Expression destExpression, Expression contextExpression)
{
var item = Expression.Property(sourceExpression, "Item");
Expression result = item;
if (item.Type != destExpression.Type)
{
var typeMap = configurationProvider.ResolveTypeMap(item.Type, destExpression.Type);
result = Expression.Invoke(typeMap.MapExpression, item, destExpression, contextExpression);
}
// source != null && source.HasData ? result : default(TDestination)
return Expression.Condition(
Expression.AndAlso(
Expression.NotEqual(sourceExpression, Expression.Constant(null)),
Expression.Property(sourceExpression, "HasData")
),
result,
Expression.Default(destExpression.Type)
);
}
}
All you need is to register it to the MapperRegistry:
AutoMapper.Mappers.MapperRegistry.Mappers.Add(new MyLazyLoadingObjectMapper());
and of course create the regular type maps (which I guess you already did):
cfg.CreateMap<SourceAddress, DestinationAddress>();
cfg.CreateMap<SourcePerson, DestinationPerson>();
I've achieved it this way:
cfg.CreateMap<SourcePerson, DestinationPerson>().ForMember(t => t.Address, o => o.MapFrom(s => (s.Address.HasData)? s.Address.Item : null));
I set ServiceStack.Text.JsConfig.IncludePublicFields = true; in AppHost.Configure but public fields are still not deserializing in JSON format.
Here is a simplified example:
[DataContract(Name = "RspItems")]
public class RspItems<T1>
{
[DataMember]
public int ItemCount { get { return Items == null ? 0 : Items.Count; } set { } }
[DataMember]
public IList<T1> Items;
public void SetItems(T1 item)
{
if (item != null)
{
Items = new List<T1>(1);
Items.Add(item);
}
}
public void SetItems(IList<T1> items)
{
Items = items;
}
}
[DataContract(Name="UserInfo")]
public class UserInfo
{
[DataMember]
public int UserID;
[DataMember]
public string LoginName;
[DataMember]
public string FirstName;
[DataMember]
public string LastName;
[DataMember]
public string Comment;
}
public class UserInfoReq<T> : IReturn<RspItems<T>>
{
public int? UserID { get; set; }
}
[Route("/app/user/list", "GET")]
public class UserInfoGetReq : UserInfoReq<UserInfo> { }
public class UserList : Service
{
public RspItems<UserInfo> Get(UserInfoGetReq req)
{
RspItems<UserInfo> rsp = new RspItems<UserInfo>();
UserInfo u = new UserInfo();
u.UserID = 3418;
u.LoginName = "jsmith";
u.FirstName = "John";
u.LastName = "Smith";
u.Comment = req.UserID.HasValue ? req.UserID.ToString() : "NULL";
rsp.SetItems(u);
return rsp;
}
}
The above example does not deserialize the response object in JSON format, although it works in XML format.
But inexplicably, if I remove the DataContract attributes on the classes, JSON format works.
Is this a bug?
Also, in the request DTO above, if I make UserID a simple public field (instead of being a property), then it is not deserialized from the querystring. Why?
Why does ServiceStack not include public fields by default anyway? Aren't DTOs supposed to be just "flat" structures used as a container for serializing/deserializing inputs and outputs (ie: the simpler, the better)? Public fields are also smaller and faster (no generated hidden private fields and getter/setter functions).
Note: Please don't suggest to just turn all public fields into properties because there are already tons of serialization structures that exist in the project. With many coming from different teams.
I have an abstract class that looks like so:
public abstract class PageObjectsBase
{
public abstract string FriendlyName { get; }
public abstract string PageObjectKeyPrefix { get; }
public abstract string CollectionProperty { get; }
}
And a class that derives from PageObjectsBase:
public class PageRatingList : PageObjectsBase
{
public IList<PageRating> PageRatings { get; set; }
public PageRatingList()
{
this.PageRatings = new List<PageRating>();
}
public override string CollectionProperty
{
get
{
var collectionProperty = typeof(PageRatingList).GetProperties().FirstOrDefault(p => p.Name == "PageRatings");
return (collectionProperty != null) ? collectionProperty.Name : string.Empty;
}
}
public override string FriendlyName
{
get
{
return "Page feedback/rating";
}
}
public override string PageObjectKeyPrefix
{
get
{
return "pagerating-";
}
}
}
And a PageRating class which PageRatingList.PageRatings is holding a collection of:
public class PageRating : PageObjectBase
{
public int Score { get; set; }
public string Comment { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
The PageRatingList is being stored in a database (EPiServer's Dynamic Data Store, more specifically using the Page Object Manager). I need to create some reporting functionality and am essentially loading all reports that derive from PageObjectBase. When it comes to returning the data, the code will never know at compile time what type of data it is to load, so I am using Reflection. In my reporting class I have:
//this gives me the right type
var type = Type.GetType("MyNameSpace.PageRatingList", true);
var startPageData = this._contentRepository.Get<PageData>(startPage);
PageObjectManager pageObjectManager = new PageObjectManager(startPageData);
//this loads the instances from the DB
var props = pageObjectManager.LoadAllMetaObjects()
.FirstOrDefault(o => o.StoreName == "Sigma.CitizensAdvice.Web.Business.CustomEntity.PageRatingList");
//this gives me 4 PropertyInfo objects (IList: PageRatings, string : CollectionProperty, string :FriendlyName, string : PageObjectKeyPrefix)
var properties = props.Value.GetType().GetProperties();
I can then iterate through the PropertyInfo objects using:
foreach (var property in properties)
{
//extract property value here
}
The issue I am having is that I cannot figure out how to get the value of each of the propertyinfo objects. In addition, one of those properties is type List and again we wont know the type of T until runtime. So I also need some logic that checks if one of the PropertyInfo objects is of type List and then provides access to each of the properties in the List - the List being of type PageRating.
Can anyone help here? I've not really used reflection in the past so I am winging my way through it, rightly or wrongly!
Many thanks
Al
I may be missunderstanding the problem, but i think you may use something like this:
var props = new PageRatingList(); /*actual instanse of the object, in your case, i think "props.Value" */
var properties = typeof(PageRatingList).GetProperties();
foreach (var property in properties)
{
if (property.PropertyType == typeof(IList<PageRating>))
{
IList<PageRating> list = (IList<PageRating>)property.GetValue(props);
/* do */
}
else
{
object val = property.GetValue(props);
}
}
Hope this helps to find your solution.
i've got 3 classes (all deriving from the same base class) and i have to dynamicly fill a ListBox with the Property-Names.
I've tried like this
class Test : TestBase {
[NameAttribute("Name of the Person")]
public string PersonName { get; set; }
private DateTime Birthday { get; set; }
[NameAttribute("Birthday of the Person")]
public string PersonBDay {
get {
return this.bDay.ToShortDateString();
}
}
}
...
[AttributeUsage(AttributeTargets.Property)]
public class NameAttribute : Attribute {
public string Name { get; private set; }
public NameAttribute(string name) {
this.Name = name;
}
}
Is there a possibility to look in my object for all properties which has the attribute NameAttribute and get the string form the Name property of NameAttribute?
You can inspect each property from Type.GetProperties and then filter the ones that have the required attribute with the MemberInfo.GetCustomAttributes method.
With a little bit of LINQ, this would look like:
var propNameTuples = from property in typeof(Test).GetProperties()
let nameAttribute = (NameAttribute)property.GetCustomAttributes
(typeof(NameAttribute), false).SingleOrDefault()
where nameAttribute != null
select new { Property = property, nameAttribute.Name };
foreach (var propNameTuple in propNameTuples)
{
Console.WriteLine("Property: {0} Name: {1}",
propNameTuple.Property.Name, propNameTuple.Name);
}
By the way, I also recommend declaring the attribute to be single-use only with AllowMultiple = false in the AttributeUsage decoration.