/// <summary> /// Creates a backup of the object property values. /// </summary> private void CreateBackup() { using (var stream = new MemoryStream()) { var propertiesToIgnore = (from propertyData in PropertyDataManager.GetProperties(_object.GetType()) where !propertyData.Value.IncludeInBackup select propertyData.Value.Name).ToArray(); List <PropertyValue> objectsToSerialize; lock (_object._propertyValuesLock) { objectsToSerialize = _object.ConvertDictionaryToListAndExcludeNonSerializableObjects(_object._propertyBag.GetAllProperties(), propertiesToIgnore); } #if NET var serializer = SerializationHelper.GetBinarySerializer(false); serializer.Serialize(stream, objectsToSerialize); #else // Xml backup, create serializer without using the cache since the dictionary is used for every object, and // we need a "this" object specific dictionary. var serializer = SerializationHelper.GetDataContractSerializer(GetType(), objectsToSerialize.GetType(), "backup", objectsToSerialize, false); serializer.WriteObject(stream, objectsToSerialize); _knownTypesForDeserialization = new List <Type>(); foreach (var objectToSerialize in objectsToSerialize) { if (objectToSerialize.Value != null) { _knownTypesForDeserialization.Add(objectToSerialize.Value.GetType()); } } #endif _propertyValuesBackup = stream.ToByteArray(); } _objectValuesBackup = new Dictionary <string, object>(); _objectValuesBackup.Add(IsDirty, _object.IsDirty); }
/// <summary> /// Initializes the XML property mappings. /// </summary> /// <param name="type">The type for which to initialize the xml mappings.</param> private void InitializeXmlPropertyMappings(Type type) { if (_xmlNameToPropertyNameMappings.ContainsKey(type)) { return; } lock (_xmlMappingsLock) { _xmlNameToPropertyNameMappings.Add(type, new Dictionary <string, string>()); _xmlPropertyNameToXmlNameMappings.Add(type, new Dictionary <string, string>()); foreach (var propertyData in _propertyDataManager.GetProperties(type)) { var propertyInfo = type.GetPropertyEx(propertyData.Key, BindingFlagsHelper.GetFinalBindingFlags(true, false)); // 1st, check if XmlIgnore is used if (AttributeHelper.IsDecoratedWithAttribute <XmlIgnoreAttribute>(propertyInfo)) { continue; } // 2nd, check if XmlAttribute is used XmlAttributeAttribute xmlAttributeAttribute = null; AttributeHelper.TryGetAttribute(propertyInfo, out xmlAttributeAttribute); if (InitializeXmlAttributeAttribute(type, xmlAttributeAttribute, propertyData.Key)) { continue; } // 3rd, check if XmlElement is used XmlElementAttribute xmlElementAttribute = null; AttributeHelper.TryGetAttribute(propertyInfo, out xmlElementAttribute); if (InitializeXmlElementAttribute(type, xmlElementAttribute, propertyData.Key)) { continue; } } } }
/// <summary> /// Deserializes all the properties that are serializable on this object using the specified <see cref="ConformanceLevel"/>. /// </summary> /// <param name="data">The data containing the serialized properties.</param> /// <param name="conformanceLevel">The conformance level.</param> /// <returns>List of deserialized properties.</returns> private List <PropertyValue> DeserializeProperties(byte[] data, ConformanceLevel conformanceLevel) { using (var stream = new MemoryStream(data)) { #if DEBUG long initialStreamPos = stream.Position; var debugReader = new StreamReader(stream); string content = debugReader.ReadToEnd(); stream.Position = initialStreamPos; #endif // Make sure to include all properties of the view model, the types must be known var additionalKnownTypes = new List <Type>(); additionalKnownTypes.Add(GetType()); foreach (var property in PropertyDataManager.GetProperties(GetType())) { if (!additionalKnownTypes.Contains(property.Value.Type)) { additionalKnownTypes.Add(property.Value.Type); } } DataContractSerializer serializer = SerializationHelper.GetDataContractSerializer(GetType(), InternalSerializationType, "internal", additionalKnownTypes, false); // Use a custom reader, required to succeed var settings = new XmlReaderSettings(); settings.ConformanceLevel = conformanceLevel; settings.IgnoreComments = true; settings.IgnoreProcessingInstructions = true; settings.IgnoreWhitespace = true; var reader = XmlReader.Create(stream, settings); return((List <PropertyValue>)serializer.ReadObject(reader, false)); } }
/// <summary> /// Validates the current object for field and business rule errors. /// </summary> /// <param name="force">If set to <c>true</c>, a validation is forced (even if the object knows it is already validated).</param> /// <param name="validateDataAnnotations">If set to <c>true</c>, the data annotations will be checked. This value is only used if <paramref name="force"/> is set to <c>true</c>.</param> /// <remarks> /// To check whether this object contains any errors, use the <see cref="HasErrors"/> property. /// </remarks> internal void Validate(bool force, bool validateDataAnnotations) { if (SuspendValidation) { return; } if (IsValidating) { return; } IsValidating = true; var validationContext = (ValidationContext)ValidationContext; var changes = new List <ValidationContextChange>(); bool hasErrors = HasErrors; bool hasWarnings = HasWarnings; var validator = Validator; if (validator != null) { validator.BeforeValidation(this, validationContext.GetFieldValidations(), validationContext.GetBusinessRuleValidations()); } OnValidating(); CatchUpWithSuspendedAnnotationsValidation(); if (force && validateDataAnnotations) { // In forced mode, validate all registered properties for annotations foreach (var propertyData in PropertyDataManager.GetProperties(GetType())) { var propertyValue = GetValue(propertyData.Value); ValidatePropertyUsingAnnotations(propertyData.Key, propertyValue); } } if (!IsValidated || force) { lock (_validationLock) { var fieldValidationResults = new List <IFieldValidationResult>(); var businessRuleValidationResults = new List <IBusinessRuleValidationResult>(); #region Fields if (validator != null) { validator.BeforeValidateFields(this, validationContext.GetFieldValidations()); } OnValidatingFields(); if (validator != null) { validator.ValidateFields(this, fieldValidationResults); } #if !WINDOWS_PHONE && !NETFX_CORE && !NET35 // Support annotation validation fieldValidationResults.AddRange(from fieldAnnotationValidation in _dataAnnotationValidationResults where !string.IsNullOrEmpty(fieldAnnotationValidation.Value) select(IFieldValidationResult) FieldValidationResult.CreateError(fieldAnnotationValidation.Key, fieldAnnotationValidation.Value)); #endif ValidateFields(fieldValidationResults); // In-between validations, it might be possible that users used the SetFieldValidationResult if (_internalValidationContext != null) { fieldValidationResults.AddRange(_internalValidationContext.GetFieldValidations()); } OnValidatedFields(); if (validator != null) { validator.AfterValidateFields(this, fieldValidationResults); } #endregion #region Business rules if (validator != null) { validator.BeforeValidateBusinessRules(this, validationContext.GetBusinessRuleValidations()); } OnValidatingBusinessRules(); if (validator != null) { validator.ValidateBusinessRules(this, businessRuleValidationResults); } ValidateBusinessRules(businessRuleValidationResults); // In-between validations, it might be possible that users used the SetBusinessRuleValidationResult if (_internalValidationContext != null) { businessRuleValidationResults.AddRange(_internalValidationContext.GetBusinessRuleValidations()); } OnValidatedBusinessRules(); if (validator != null) { validator.AfterValidateBusinessRules(this, businessRuleValidationResults); } #endregion if (validator != null) { validator.Validate(this, validationContext); } IsValidated = true; // Clear internal validation _internalValidationContext = new ValidationContext(); changes = validationContext.SynchronizeWithContext(new ValidationContext(fieldValidationResults, businessRuleValidationResults)); } } OnValidated(); if (validator != null) { validator.AfterValidation(this, validationContext.GetFieldValidations(), validationContext.GetBusinessRuleValidations()); } #region Notify changes bool hasNotifiedBusinessWarningsChanged = false; bool hasNotifiedBusinessErrorsChanged = false; foreach (var change in changes) { var changeAsFieldValidationResult = change.ValidationResult as IFieldValidationResult; var changeAsBusinessRuleValidationResult = change.ValidationResult as IBusinessRuleValidationResult; if (changeAsFieldValidationResult != null) { switch (change.ValidationResult.ValidationResultType) { case ValidationResultType.Warning: NotifyWarningsChanged(changeAsFieldValidationResult.PropertyName, false); break; case ValidationResultType.Error: NotifyErrorsChanged(changeAsFieldValidationResult.PropertyName, false); break; default: throw new ArgumentOutOfRangeException(); } } else if (changeAsBusinessRuleValidationResult != null) { switch (change.ValidationResult.ValidationResultType) { case ValidationResultType.Warning: if (!hasNotifiedBusinessWarningsChanged) { hasNotifiedBusinessWarningsChanged = true; NotifyWarningsChanged(string.Empty, false); } break; case ValidationResultType.Error: if (!hasNotifiedBusinessErrorsChanged) { hasNotifiedBusinessErrorsChanged = true; NotifyErrorsChanged(string.Empty, false); } break; default: throw new ArgumentOutOfRangeException(); } } } if (HasWarnings != hasWarnings) { RaisePropertyChanged("HasWarnings"); } if (HasErrors != hasErrors) { RaisePropertyChanged("HasErrors"); } #endregion IsValidating = false; }