CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
Csla/Core/BusinessBase.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="BusinessBase.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>This is the non-generic base class from which most</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Concurrent;
10using System.Diagnostics;
11using System.Linq;
12using System.Collections.Generic;
13using System.ComponentModel;
14using System.Threading.Tasks;
15using Csla.Properties;
16using System.Collections.Specialized;
17using System.ComponentModel.DataAnnotations;
18using System.Collections.ObjectModel;
20using Csla.Reflection;
21using Csla.Server;
22using Csla.Security;
24using Csla.Rules;
25using System.Security;
27using System.Reflection;
28
29namespace Csla.Core
30{
31
36#if TESTING
37 [System.Diagnostics.DebuggerStepThrough]
38#endif
40 public abstract class BusinessBase : UndoableBase,
42 IEditableObject,
43 ICloneable,
45 IParent,
46 IDataPortalTarget,
47 IManageProperties,
48 Rules.IHostRules,
53, IDataErrorInfo
54 {
55
59 protected BusinessBase()
60 {
61 InitializeIdentity();
62 Initialize();
63 InitializeBusinessRules();
64 }
65
66 #region Initialize
67
73 protected virtual void Initialize()
74 { /* allows subclass to initialize events before any other activity occurs */ }
75
76 #endregion
77
78 #region Identity
79
80 private int _identity = -1;
81
83 {
84 get { return _identity; }
85 }
86
87 private void InitializeIdentity()
88 {
89 _identity = ((IParent)this).GetNextIdentity(_identity);
90 }
91
92 [NonSerialized]
93 [NotUndoable]
94 private IdentityManager _identityManager;
95
96 int IParent.GetNextIdentity(int current)
97 {
98 if (this.Parent != null)
99 {
100 return this.Parent.GetNextIdentity(current);
101 }
102 else
103 {
104 if (_identityManager == null)
105 _identityManager = new IdentityManager();
106 return _identityManager.GetNextIdentity(current);
107 }
108 }
109
110 #endregion
111
112 #region Parent/Child link
113
114 [NotUndoable]
115 [NonSerialized]
116 private IParent _parent;
117
125 [Browsable(false)]
126 [Display(AutoGenerateField = false)]
127 [ScaffoldColumn(false)]
128 [EditorBrowsable(EditorBrowsableState.Advanced)]
129 public Core.IParent Parent
130 {
131 get { return _parent; }
132 }
133
140 protected virtual void SetParent(Core.IParent parent)
141 {
142 _parent = parent;
143 _identityManager = null;
144 InitializeIdentity();
145 }
146
147 #endregion
148
149 #region IsNew, IsDeleted, IsDirty, IsSavable
150
151 // keep track of whether we are new, deleted or dirty
152 private bool _isNew = true;
153 private bool _isDeleted;
154 private bool _isDirty = true;
155
169 [Browsable(false)]
170 [Display(AutoGenerateField = false)]
171 [ScaffoldColumn(false)]
172 public bool IsNew
173 {
174 get { return _isNew; }
175 }
176
191 [Browsable(false)]
192 [Display(AutoGenerateField = false)]
193 [ScaffoldColumn(false)]
194 public bool IsDeleted
195 {
196 get { return _isDeleted; }
197 }
198
218 [Browsable(false)]
219 [Display(AutoGenerateField = false)]
220 [ScaffoldColumn(false)]
221 public virtual bool IsDirty
222 {
223 get { return IsSelfDirty || (_fieldManager != null && FieldManager.IsDirty()); }
224 }
225
243 [Browsable(false)]
244 [Display(AutoGenerateField = false)]
245 [ScaffoldColumn(false)]
246 public virtual bool IsSelfDirty
247 {
248 get { return _isDirty; }
249 }
250
266 protected virtual void MarkNew()
267 {
268 _isNew = true;
269 _isDeleted = false;
270 MetaPropertyHasChanged("IsNew");
271 MetaPropertyHasChanged("IsDeleted");
272 MarkDirty();
273 }
274
293 protected virtual void MarkOld()
294 {
295 _isNew = false;
296 MetaPropertyHasChanged("IsNew");
297 MarkClean();
298 }
299
309 protected void MarkDeleted()
310 {
311 _isDeleted = true;
312 MetaPropertyHasChanged("IsDeleted");
313 MarkDirty();
314 }
315
333 protected void MarkDirty()
334 {
335 MarkDirty(false);
336 }
337
345 [EditorBrowsable(EditorBrowsableState.Advanced)]
346 protected void MarkDirty(bool suppressEvent)
347 {
348 bool old = _isDirty;
349 _isDirty = true;
350 if (!suppressEvent)
352 if (_isDirty != old)
353 {
354 MetaPropertyHasChanged("IsSelfDirty");
355 MetaPropertyHasChanged("IsDirty");
356 MetaPropertyHasChanged("IsSavable");
357 }
358 }
359
372 protected virtual void PropertyHasChanged(Csla.Core.IPropertyInfo property)
373 {
374 MarkDirty(true);
375 CheckPropertyRules(property);
376 }
377
378 private void PropertyHasChanged(string propertyName)
379 {
381 }
382
387 protected virtual void MetaPropertyHasChanged(string name)
388 {
389 if (ApplicationContext.PropertyChangedMode != ApplicationContext.PropertyChangedModes.Windows)
391 }
392
397 [EditorBrowsable(EditorBrowsableState.Advanced)]
398 protected virtual void CheckPropertyRules(IPropertyInfo property)
399 {
400 var propertyNames = BusinessRules.CheckRules(property);
401 if (ApplicationContext.PropertyChangedMode == ApplicationContext.PropertyChangedModes.Windows)
402 OnPropertyChanged(property);
403 else
404 foreach (var name in propertyNames)
405 OnPropertyChanged(name);
406 }
407
411 protected virtual void CheckObjectRules()
412 {
413 var propertyNames = BusinessRules.CheckObjectRules();
414 if (ApplicationContext.PropertyChangedMode == ApplicationContext.PropertyChangedModes.Windows)
415 {
417 }
418 else
419 foreach (var name in propertyNames)
420 OnPropertyChanged(name);
421 }
422
423
424
432 [EditorBrowsable(EditorBrowsableState.Advanced)]
433 protected void MarkClean()
434 {
435 _isDirty = false;
436 if (_fieldManager != null)
437 FieldManager.MarkClean();
439 MetaPropertyHasChanged("IsSelfDirty");
440 MetaPropertyHasChanged("IsDirty");
441 MetaPropertyHasChanged("IsSavable");
442 }
443
455 [Browsable(false)]
456 [Display(AutoGenerateField = false)]
457 [ScaffoldColumn(false)]
458 public virtual bool IsSavable
459 {
460 get
461 {
462 bool auth;
463 if (IsDeleted)
464 auth = Csla.Rules.BusinessRules.HasPermission(Rules.AuthorizationActions.DeleteObject, this);
465 else if (IsNew)
466 auth = Csla.Rules.BusinessRules.HasPermission(Rules.AuthorizationActions.CreateObject, this);
467 else
468 auth = Csla.Rules.BusinessRules.HasPermission(Rules.AuthorizationActions.EditObject, this);
469 return (auth && IsDirty && IsValid && !IsBusy);
470 }
471 }
472
473 #endregion
474
475 #region Authorization
476
477 [NotUndoable]
478 [NonSerialized]
479 private ConcurrentDictionary<string, bool> _readResultCache;
480 [NotUndoable]
481 [NonSerialized]
482 private ConcurrentDictionary<string, bool> _writeResultCache;
483 [NotUndoable]
484 [NonSerialized]
485 private ConcurrentDictionary<string, bool> _executeResultCache;
486 [NotUndoable]
487 [NonSerialized]
488 private System.Security.Principal.IPrincipal _lastPrincipal;
489
495 [EditorBrowsable(EditorBrowsableState.Advanced)]
496 public virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)
497 {
498 var result = true;
499
500 VerifyAuthorizationCache();
501
502 if (!_readResultCache.TryGetValue(property.Name, out result))
503 {
504 result = BusinessRules.HasPermission(AuthorizationActions.ReadProperty, property);
505 if (BusinessRules.CachePermissionResult(AuthorizationActions.ReadProperty, property))
506 {
507 // store value in cache
508 _readResultCache.AddOrUpdate(property.Name, result, (a,b) => { return result; });
509 }
510 }
511 return result;
512 }
513
522 [EditorBrowsable(EditorBrowsableState.Advanced)]
523 public bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
524 {
525 bool result = CanReadProperty(property);
526 if (throwOnFalse && result == false)
527 {
529 String.Format("{0} ({1})",
530 Resources.PropertyGetNotAllowed, property.Name));
531 throw ex;
532 }
533 return result;
534 }
535
541 [EditorBrowsable(EditorBrowsableState.Advanced)]
542 public bool CanReadProperty(string propertyName)
543 {
544 return CanReadProperty(propertyName, false);
545 }
546
554 private bool CanReadProperty(string propertyName, bool throwOnFalse)
555 {
556 var propertyInfo = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Name == propertyName);
557 if (propertyInfo == null)
558 {
559 Trace.TraceError("CanReadProperty: {0} is not a registered property of {1}.{2}", propertyName, this.GetType().Namespace, this.GetType().Name);
560 return true;
561 }
562 return CanReadProperty(propertyInfo, throwOnFalse);
563 }
564
570 [EditorBrowsable(EditorBrowsableState.Advanced)]
571 public virtual bool CanWriteProperty(Csla.Core.IPropertyInfo property)
572 {
573 bool result = true;
574
575 VerifyAuthorizationCache();
576
577 if (!_writeResultCache.TryGetValue(property.Name, out result))
578 {
579 result = BusinessRules.HasPermission(AuthorizationActions.WriteProperty, property);
580 if (BusinessRules.CachePermissionResult(AuthorizationActions.WriteProperty, property))
581 {
582 // store value in cache
583 _writeResultCache.AddOrUpdate(property.Name, result, (a, b) => { return result; });
584 }
585 }
586 return result;
587 }
588
597 [EditorBrowsable(EditorBrowsableState.Advanced)]
598 public bool CanWriteProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
599 {
600 bool result = CanWriteProperty(property);
601 if (throwOnFalse && result == false)
602 {
604 String.Format("{0} ({1})", Resources.PropertySetNotAllowed, property.Name));
605 throw ex;
606 }
607 return result;
608 }
609
615 [EditorBrowsable(EditorBrowsableState.Advanced)]
616 public bool CanWriteProperty(string propertyName)
617 {
618 return CanWriteProperty(propertyName, false);
619 }
620
628 private bool CanWriteProperty(string propertyName, bool throwOnFalse)
629 {
630 var propertyInfo = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Name == propertyName);
631 if (propertyInfo == null)
632 {
633 Trace.TraceError("CanReadProperty: {0} is not a registered property of {1}.{2}", propertyName, this.GetType().Namespace, this.GetType().Name);
634 return true;
635 }
636 return CanWriteProperty(propertyInfo, throwOnFalse);
637 }
638
639 private void VerifyAuthorizationCache()
640 {
641 if (_readResultCache == null)
642 _readResultCache = new ConcurrentDictionary<string, bool>();
643 if (_writeResultCache == null)
644 _writeResultCache = new ConcurrentDictionary<string, bool>();
645 if (_executeResultCache == null)
646 _executeResultCache = new ConcurrentDictionary<string, bool>();
647 if (!ReferenceEquals(Csla.ApplicationContext.User, _lastPrincipal))
648 {
649 // the principal has changed - reset the cache
650 _readResultCache.Clear();
651 _writeResultCache.Clear();
652 _executeResultCache.Clear();
653 _lastPrincipal = Csla.ApplicationContext.User;
654 }
655 }
656
663 [EditorBrowsable(EditorBrowsableState.Advanced)]
664 public virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)
665 {
666 bool result = true;
667
668 VerifyAuthorizationCache();
669
670 if (!_executeResultCache.TryGetValue(method.Name, out result))
671 {
672 result = BusinessRules.HasPermission(AuthorizationActions.ExecuteMethod, method);
674 {
675 // store value in cache
676 _executeResultCache.AddOrUpdate(method.Name, result, (a, b) => { return result; });
677 }
678 }
679 return result;
680 }
681
690 [EditorBrowsable(EditorBrowsableState.Advanced)]
691 public bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)
692 {
693
694 bool result = CanExecuteMethod(method);
695 if (throwOnFalse && result == false)
696 {
698 new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, method.Name));
699 throw ex;
700 }
701 return result;
702
703 }
704
705
712 [EditorBrowsable(EditorBrowsableState.Advanced)]
713 public virtual bool CanExecuteMethod(string methodName)
714 {
715 return CanExecuteMethod(methodName, false);
716 }
717
718 private bool CanExecuteMethod(string methodName, bool throwOnFalse)
719 {
720
721 bool result = CanExecuteMethod(new MethodInfo(methodName));
722 if (throwOnFalse && result == false)
723 {
724 Csla.Security.SecurityException ex = new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, methodName));
725 throw ex;
726 }
727 return result;
728 }
729
730#endregion
731
732#region System.ComponentModel.IEditableObject
733
734 private bool _neverCommitted = true;
735 [NotUndoable]
736 private bool _disableIEditableObject;
737
754 [EditorBrowsable(EditorBrowsableState.Advanced)]
756 {
757 get
758 {
759 return _disableIEditableObject;
760 }
761 set
762 {
763 _disableIEditableObject = value;
764 }
765 }
766
775 void System.ComponentModel.IEditableObject.BeginEdit()
776 {
777 if (!_disableIEditableObject && !BindingEdit)
778 {
779 BindingEdit = true;
780 BeginEdit();
781 }
782 }
783
794 void System.ComponentModel.IEditableObject.CancelEdit()
795 {
796 if (!_disableIEditableObject && BindingEdit)
797 {
798 CancelEdit();
799 BindingEdit = false;
800 if (IsNew && _neverCommitted && EditLevel <= EditLevelAdded)
801 {
802 // we're new and no EndEdit or ApplyEdit has ever been
803 // called on us, and now we've been cancelled back to
804 // where we were added so we should have ourselves
805 // removed from the parent collection
806 if (Parent != null)
807 Parent.RemoveChild(this);
808 }
809 }
810 }
811
822 void System.ComponentModel.IEditableObject.EndEdit()
823 {
824 if (!_disableIEditableObject && BindingEdit)
825 {
826 ApplyEdit();
827 BindingEdit = false;
828 }
829 }
830
831#endregion
832
833#region Begin/Cancel/ApplyEdit
834
853 public void BeginEdit()
854 {
855 CopyState(this.EditLevel + 1);
856 }
857
867 public void CancelEdit()
868 {
869 UndoChanges(this.EditLevel - 1);
870 }
871
880 protected override void UndoChangesComplete()
881 {
882 BusinessRules.SetTarget(this);
883 InitializeBusinessRules();
885 base.UndoChangesComplete();
886 }
887
896 public void ApplyEdit()
897 {
898 _neverCommitted = false;
899 AcceptChanges(this.EditLevel - 1);
900 //Next line moved to IEditableObject.ApplyEdit
901 //BindingEdit = false;
902 }
903
908 protected override void AcceptChangesComplete()
909 {
910 BindingEdit = false;
911 base.AcceptChangesComplete();
912
913 // !!!! Will trigger Save here when using DynamicListBase template
914 if (Parent != null)
916 }
917
918#endregion
919
920#region IsChild
921
922 [NotUndoable]
923 private bool _isChild;
924
928 [Browsable(false)]
929 [Display(AutoGenerateField = false)]
930 [ScaffoldColumn(false)]
931 public bool IsChild
932 {
933 get { return _isChild; }
934 }
935
939 protected void MarkAsChild()
940 {
941 _identity = -1;
942 _isChild = true;
943 }
944
945#endregion
946
947#region Delete
948
964 public virtual void Delete()
965 {
966 if (this.IsChild)
967 throw new NotSupportedException(Resources.ChildDeleteException);
968
969 MarkDeleted();
970 }
971
976 internal void DeleteChild()
977 {
978 if (!this.IsChild)
979 throw new NotSupportedException(Resources.NoDeleteRootException);
980
981 BindingEdit = false;
982 MarkDeleted();
983 }
984
985#endregion
986
987#region Edit Level Tracking (child only)
988
989 // we need to keep track of the edit
990 // level when we weere added so if the user
991 // cancels below that level we can be destroyed
992 [NotUndoable]
993 private int _editLevelAdded;
994
1003 internal int EditLevelAdded
1004 {
1005 get { return _editLevelAdded; }
1006 set { _editLevelAdded = value; }
1007 }
1008
1009 int IUndoableObject.EditLevel
1010 {
1011 get
1012 {
1013 return this.EditLevel;
1014 }
1015 }
1016
1017#endregion
1018
1019#region ICloneable
1020
1021 object ICloneable.Clone()
1022 {
1023 return GetClone();
1024 }
1025
1032 [EditorBrowsable(EditorBrowsableState.Advanced)]
1033 protected virtual object GetClone()
1034 {
1035 return ObjectCloner.Clone(this);
1036 }
1037
1038#endregion
1039
1040#region BusinessRules, IsValid
1041
1042 [NonSerialized]
1043 [NotUndoable]
1044 private EventHandler _validationCompleteHandlers;
1045
1049 public event EventHandler ValidationComplete
1050 {
1051 add
1052 {
1053 _validationCompleteHandlers = (EventHandler)
1054 System.Delegate.Combine(_validationCompleteHandlers, value);
1055 }
1056 remove
1057 {
1058 _validationCompleteHandlers = (EventHandler)
1059 System.Delegate.Remove(_validationCompleteHandlers, value);
1060 }
1061 }
1062
1066 [EditorBrowsable(EditorBrowsableState.Never)]
1067 protected virtual void OnValidationComplete()
1068 {
1069 if (_validationCompleteHandlers != null)
1070 _validationCompleteHandlers(this, EventArgs.Empty);
1071 }
1072
1073 private void InitializeBusinessRules()
1074 {
1075 var rules = BusinessRuleManager.GetRulesForType(this.GetType());
1076 if (!rules.Initialized)
1077 lock (rules)
1078 if (!rules.Initialized)
1079 {
1080 try
1081 {
1083 rules.Initialized = true;
1084 }
1085 catch (Exception)
1086 {
1087 BusinessRuleManager.CleanupRulesForType(this.GetType());
1088 throw; // and rethrow exception
1089 }
1090 }
1091 }
1092
1093 private Csla.Rules.BusinessRules _businessRules;
1094
1104 {
1105 get
1106 {
1107 if (_businessRules == null)
1108 _businessRules = new BusinessRules(this);
1109 else if (_businessRules.Target == null)
1110 _businessRules.SetTarget(this);
1111 return _businessRules;
1112 }
1113 }
1114
1119 [EditorBrowsable(EditorBrowsableState.Never)]
1121 {
1122 return BusinessRules.TypeRules;
1123 }
1124
1125 void IHostRules.RuleStart(IPropertyInfo property)
1126 {
1127 OnBusyChanged(new BusyChangedEventArgs(property.Name, true));
1128 }
1129
1130 void IHostRules.RuleComplete(IPropertyInfo property)
1131 {
1132 OnPropertyChanged(property);
1133 OnBusyChanged(new BusyChangedEventArgs(property.Name, false));
1134 MetaPropertyHasChanged("IsSelfValid");
1135 MetaPropertyHasChanged("IsValid");
1136 MetaPropertyHasChanged("IsSavable");
1137 }
1138
1139 void IHostRules.RuleComplete(string property)
1140 {
1141 OnPropertyChanged(property);
1142 MetaPropertyHasChanged("IsSelfValid");
1143 MetaPropertyHasChanged("IsValid");
1144 MetaPropertyHasChanged("IsSavable");
1145 }
1146
1147 void Rules.IHostRules.AllRulesComplete()
1148 {
1150 MetaPropertyHasChanged("IsSelfValid");
1151 MetaPropertyHasChanged("IsValid");
1152 MetaPropertyHasChanged("IsSavable");
1153 }
1154
1165 protected virtual void AddBusinessRules()
1166 {
1168 }
1169
1189 [Browsable(false)]
1190 [Display(AutoGenerateField = false)]
1191 [ScaffoldColumn(false)]
1192 public virtual bool IsValid
1193 {
1194 get { return IsSelfValid && (_fieldManager == null || FieldManager.IsValid()); }
1195 }
1196
1212 [Browsable(false)]
1213 [Display(AutoGenerateField = false)]
1214 [ScaffoldColumn(false)]
1215 public virtual bool IsSelfValid
1216 {
1217 get { return BusinessRules.IsValid; }
1218 }
1219
1224 [Browsable(false)]
1225 [Display(AutoGenerateField = false)]
1226 [ScaffoldColumn(false)]
1227 [System.ComponentModel.DataAnnotations.Schema.NotMapped]
1228 [EditorBrowsable(EditorBrowsableState.Advanced)]
1229 public virtual Rules.BrokenRulesCollection BrokenRulesCollection
1230 {
1231 get { return BusinessRules.GetBrokenRules(); }
1232 }
1233
1234#endregion
1235
1236#region Data Access
1237
1243 [EditorBrowsable(EditorBrowsableState.Advanced)]
1245 { }
1246
1252 [EditorBrowsable(EditorBrowsableState.Advanced)]
1254 { }
1255
1262 [EditorBrowsable(EditorBrowsableState.Advanced)]
1263 protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
1264 { }
1265
1275 protected virtual void Child_Create()
1276 {
1278 }
1279
1285 [EditorBrowsable(EditorBrowsableState.Advanced)]
1287 { }
1288
1294 [EditorBrowsable(EditorBrowsableState.Advanced)]
1296 { }
1297
1304 [EditorBrowsable(EditorBrowsableState.Advanced)]
1305 protected virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
1306 { }
1307
1308#endregion
1309
1310#region IDataErrorInfo
1311
1312 string IDataErrorInfo.Error
1313 {
1314 get
1315 {
1316 if (!IsSelfValid)
1318 Csla.Rules.RuleSeverity.Error);
1319 else
1320 return String.Empty;
1321 }
1322 }
1323
1324 string IDataErrorInfo.this[string columnName]
1325 {
1326 get
1327 {
1328 string result = string.Empty;
1329 if (!IsSelfValid)
1330 {
1331 Rules.BrokenRule rule =
1333 if (rule != null)
1334 result = rule.Description;
1335 }
1336 return result;
1337 }
1338 }
1339
1340#endregion
1341
1342#region Serialization Notification
1343
1345 {
1346 OnDeserializedHandler(new System.Runtime.Serialization.StreamingContext());
1347 }
1348
1349 [System.Runtime.Serialization.OnDeserialized]
1350 private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)
1351 {
1352 BusinessRules.SetTarget(this);
1353 if (_fieldManager != null)
1354 FieldManager.SetPropertyList(this.GetType());
1355 InitializeBusinessRules();
1356 FieldDataDeserialized();
1357
1358 OnDeserialized(context);
1359 }
1360
1366 [EditorBrowsable(EditorBrowsableState.Advanced)]
1367 protected virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
1368 { }
1369
1370#endregion
1371
1372#region Bubbling event Hooks
1373
1378 [EditorBrowsable(EditorBrowsableState.Never)]
1379 protected void AddEventHooks(IBusinessObject child)
1380 {
1381 OnAddEventHooks(child);
1382 }
1383
1388 [EditorBrowsable(EditorBrowsableState.Never)]
1389 protected virtual void OnAddEventHooks(IBusinessObject child)
1390 {
1391 INotifyBusy busy = child as INotifyBusy;
1392 if (busy != null)
1393 busy.BusyChanged += Child_BusyChanged;
1394
1396 if (unhandled != null)
1397 unhandled.UnhandledAsyncException += Child_UnhandledAsyncException;
1398
1399 INotifyPropertyChanged pc = child as INotifyPropertyChanged;
1400 if (pc != null)
1401 pc.PropertyChanged += Child_PropertyChanged;
1402
1403 IBindingList bl = child as IBindingList;
1404 if (bl != null)
1405 bl.ListChanged += Child_ListChanged;
1406
1407 INotifyCollectionChanged ncc = child as INotifyCollectionChanged;
1408 if (ncc != null)
1409 ncc.CollectionChanged += Child_CollectionChanged;
1410
1412 if (cc != null)
1413 cc.ChildChanged += Child_Changed;
1414 }
1415
1420 [EditorBrowsable(EditorBrowsableState.Never)]
1421 protected void RemoveEventHooks(IBusinessObject child)
1422 {
1423 OnRemoveEventHooks(child);
1424 }
1425
1430 [EditorBrowsable(EditorBrowsableState.Never)]
1431 protected virtual void OnRemoveEventHooks(IBusinessObject child)
1432 {
1433 INotifyBusy busy = child as INotifyBusy;
1434 if (busy != null)
1435 busy.BusyChanged -= Child_BusyChanged;
1436
1438 if (unhandled != null)
1439 unhandled.UnhandledAsyncException -= Child_UnhandledAsyncException;
1440
1441 INotifyPropertyChanged pc = child as INotifyPropertyChanged;
1442 if (pc != null)
1443 pc.PropertyChanged -= Child_PropertyChanged;
1444
1445 IBindingList bl = child as IBindingList;
1446 if (bl != null)
1447 bl.ListChanged -= Child_ListChanged;
1448
1449 INotifyCollectionChanged ncc = child as INotifyCollectionChanged;
1450 if (ncc != null)
1451 ncc.CollectionChanged -= Child_CollectionChanged;
1452
1454 if (cc != null)
1455 cc.ChildChanged -= Child_Changed;
1456 }
1457
1458#endregion
1459
1460#region Busy / Unhandled exception bubbling
1461
1462 private void Child_UnhandledAsyncException(object sender, ErrorEventArgs e)
1463 {
1465 }
1466
1467 private void Child_BusyChanged(object sender, BusyChangedEventArgs e)
1468 {
1469 OnBusyChanged(e);
1470 }
1471
1472#endregion
1473
1474#region IEditableBusinessObject Members
1475
1476 int IEditableBusinessObject.EditLevelAdded
1477 {
1478 get
1479 {
1480 return this.EditLevelAdded;
1481 }
1482 set
1483 {
1484 this.EditLevelAdded = value;
1485 }
1486 }
1487
1488 void IEditableBusinessObject.DeleteChild()
1489 {
1490 this.DeleteChild();
1491 }
1492
1493 void IEditableBusinessObject.SetParent(IParent parent)
1494 {
1495 this.SetParent(parent);
1496 }
1497
1498#endregion
1499
1500#region Register Methods
1501
1515 protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
1516 {
1517 var reflected = objectType.GetMethod(info.Name);
1518 if (reflected == null)
1519 throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");
1520 return info;
1521 }
1522
1536 protected static MethodInfo RegisterMethod(Type objectType, string methodName)
1537 {
1538 var info = new MethodInfo(methodName);
1539 RegisterMethod(objectType, info);
1540 return info;
1541 }
1542
1543#endregion
1544
1545#region Register Properties
1546
1563 protected static PropertyInfo<P> RegisterProperty<P>(Type objectType, PropertyInfo<P> info)
1564 {
1565 return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(objectType, info);
1566 }
1567
1568#endregion
1569
1570#region Get Properties
1571
1590 protected P GetProperty<P>(string propertyName, P field, P defaultValue)
1591 {
1592 return GetProperty<P>(propertyName, field, defaultValue, Security.NoAccessBehavior.SuppressException);
1593 }
1594
1611 protected P GetProperty<P>(string propertyName, P field, P defaultValue, Security.NoAccessBehavior noAccess)
1612 {
1613#region Check to see if the property is marked with RelationshipTypes.PrivateField
1614
1615 var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
1616
1617 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)
1618 throw new InvalidOperationException(Resources.PrivateFieldException);
1619
1620#endregion
1621
1622 if (_bypassPropertyChecks || CanReadProperty(propertyInfo, noAccess == Security.NoAccessBehavior.ThrowException))
1623 return field;
1624
1625 return defaultValue;
1626 }
1627
1643 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)
1644 {
1645 return GetProperty<P>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException);
1646 }
1647
1664 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field, P defaultValue, Security.NoAccessBehavior noAccess)
1665 {
1666 return GetProperty<P>(propertyInfo.Name, field, defaultValue, noAccess);
1667 }
1668
1688 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field)
1689 {
1690 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException));
1691 }
1692
1715 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field, Security.NoAccessBehavior noAccess)
1716 {
1717 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, noAccess));
1718 }
1719
1734 protected P GetProperty<P>(PropertyInfo<P> propertyInfo)
1735 {
1736 return GetProperty<P>(propertyInfo, Security.NoAccessBehavior.SuppressException);
1737 }
1738
1758 {
1759 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, Security.NoAccessBehavior.SuppressException));
1760 }
1761
1783 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, Security.NoAccessBehavior noAccess)
1784 {
1785 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, noAccess));
1786 }
1787
1805 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, Security.NoAccessBehavior noAccess)
1806 {
1807 P result = default(P);
1808 if (_bypassPropertyChecks || CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))
1809 result = ReadProperty<P>(propertyInfo);
1810 else
1811 result = propertyInfo.DefaultValue;
1812 return result;
1813 }
1814
1825 protected object GetProperty(IPropertyInfo propertyInfo)
1826 {
1827 object result = null;
1828 if (_bypassPropertyChecks || CanReadProperty(propertyInfo, false))
1829 {
1830 // call ReadProperty (may be overloaded in actual class)
1831 result = ReadProperty(propertyInfo);
1832 }
1833 else
1834 {
1835 result = propertyInfo.DefaultValue;
1836 }
1837 return result;
1838 }
1839
1854 protected P GetProperty<P>(IPropertyInfo propertyInfo)
1855 {
1856 return (P)GetProperty(propertyInfo);
1857 }
1858
1872 protected P LazyGetProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
1873 {
1874 if (!(FieldManager.FieldExists(property)))
1875 {
1876 var result = valueGenerator();
1877 LoadProperty(property, result);
1878 }
1879 return GetProperty<P>(property);
1880 }
1881
1882 [NotUndoable]
1883 [NonSerialized]
1884 private List<Csla.Core.IPropertyInfo> _lazyLoadingProperties = new List<Csla.Core.IPropertyInfo>();
1885
1906 protected P LazyGetPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
1907 {
1908 if (!(FieldManager.FieldExists(property)) && !_lazyLoadingProperties.Contains(property))
1909 {
1910 _lazyLoadingProperties.Add(property);
1911 LoadPropertyAsync(property, factory);
1912 }
1913 return GetProperty<P>(property);
1914 }
1915
1916 object IManageProperties.LazyGetProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
1917 {
1918 return LazyGetProperty(propertyInfo, valueGenerator);
1919 }
1920
1921 object IManageProperties.LazyGetPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
1922 {
1923 return LazyGetPropertyAsync(propertyInfo, factory);
1924 }
1925
1926#endregion
1927
1928#region Read Properties
1929
1944 {
1945 return Utilities.CoerceValue<P>(typeof(F), null, ReadProperty<F>(propertyInfo));
1946 }
1947
1956 protected P ReadProperty<P>(PropertyInfo<P> propertyInfo)
1957 {
1958 if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
1959 throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
1960
1961 P result = default(P);
1962 FieldManager.IFieldData data = FieldManager.GetFieldData(propertyInfo);
1963 if (data != null)
1964 {
1965 FieldManager.IFieldData<P> fd = data as FieldManager.IFieldData<P>;
1966 if (fd != null)
1967 result = fd.Value;
1968 else
1969 result = (P)data.Value;
1970 }
1971 else
1972 {
1973 result = propertyInfo.DefaultValue;
1974 FieldManager.LoadFieldData<P>(propertyInfo, result);
1975 }
1976 return result;
1977 }
1978
1984 protected virtual object ReadProperty(IPropertyInfo propertyInfo)
1985 {
1986 if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
1987 throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
1988
1989 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)
1990 {
1991 using (BypassPropertyChecks)
1992 {
1993 return MethodCaller.CallPropertyGetter(this, propertyInfo.Name);
1994 }
1995 }
1996
1997 object result = null;
1998 var info = FieldManager.GetFieldData(propertyInfo);
1999 if (info != null)
2000 {
2001 result = info.Value;
2002 }
2003 else
2004 {
2005 result = propertyInfo.DefaultValue;
2006 FieldManager.LoadFieldData(propertyInfo, result);
2007 }
2008
2009 return result;
2010 }
2011
2021 protected P LazyReadProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
2022 {
2023 if (!(FieldManager.FieldExists(property)))
2024 {
2025 var result = valueGenerator();
2026 LoadProperty(property, result);
2027 }
2028 return ReadProperty<P>(property);
2029 }
2030
2040 protected P LazyReadPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
2041 {
2042 if (!(FieldManager.FieldExists(property)) && !_lazyLoadingProperties.Contains(property))
2043 {
2044 _lazyLoadingProperties.Add(property);
2045 LoadPropertyAsync(property, factory);
2046 }
2047 return ReadProperty<P>(property);
2048 }
2049
2050 P IManageProperties.LazyReadProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
2051 {
2052 return LazyReadProperty(propertyInfo, valueGenerator);
2053 }
2054
2055 P IManageProperties.LazyReadPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
2056 {
2057 return LazyReadPropertyAsync(propertyInfo, factory);
2058 }
2059
2060#endregion
2061
2062#region Set Properties
2063
2079 protected void SetProperty<P>(PropertyInfo<P> propertyInfo, ref P field, P newValue)
2080 {
2081 SetProperty<P>(propertyInfo.Name, ref field, newValue, Security.NoAccessBehavior.ThrowException);
2082 }
2083
2099 protected void SetProperty<P>(string propertyName, ref P field, P newValue)
2100 {
2101 SetProperty<P>(propertyName, ref field, newValue, Security.NoAccessBehavior.ThrowException);
2102 }
2103
2125 protected void SetPropertyConvert<P, V>(PropertyInfo<P> propertyInfo, ref P field, V newValue)
2126 {
2127 SetPropertyConvert<P, V>(propertyInfo, ref field, newValue, Security.NoAccessBehavior.ThrowException);
2128 }
2129
2154 protected void SetPropertyConvert<P, V>(PropertyInfo<P> propertyInfo, ref P field, V newValue, Security.NoAccessBehavior noAccess)
2155 {
2156 SetPropertyConvert<P, V>(propertyInfo.Name, ref field, newValue, noAccess);
2157 }
2158
2173 protected void SetProperty<P>(string propertyName, ref P field, P newValue, Security.NoAccessBehavior noAccess)
2174 {
2175 try
2176 {
2177#region Check to see if the property is marked with RelationshipTypes.PrivateField
2178
2179 var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
2180
2181 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)
2182 throw new InvalidOperationException(Resources.PrivateFieldException);
2183
2184#endregion
2185
2186 if (_bypassPropertyChecks || CanWriteProperty(propertyInfo, noAccess == Security.NoAccessBehavior.ThrowException))
2187 {
2188 bool doChange = false;
2189 if (field == null)
2190 {
2191 if (newValue != null)
2192 doChange = true;
2193 }
2194 else
2195 {
2196 if (typeof(P) == typeof(string) && newValue == null)
2197 newValue = Utilities.CoerceValue<P>(typeof(string), field, string.Empty);
2198 if (!field.Equals(newValue))
2199 doChange = true;
2200 }
2201 if (doChange)
2202 {
2203 if (!_bypassPropertyChecks) OnPropertyChanging(propertyName);
2204 field = newValue;
2205 if (!_bypassPropertyChecks) PropertyHasChanged(propertyName);
2206 }
2207 }
2208 }
2209 catch (System.Security.SecurityException ex)
2210 {
2211 throw new Csla.Security.SecurityException(ex.Message);
2212 }
2214 {
2215 throw;
2216 }
2217 catch (Exception ex)
2218 {
2219 throw new PropertyLoadException(
2220 string.Format(Resources.PropertyLoadException, propertyName, ex.Message, ex.Message), ex);
2221 }
2222 }
2223
2248 protected void SetPropertyConvert<P, V>(string propertyName, ref P field, V newValue, Security.NoAccessBehavior noAccess)
2249 {
2250 try
2251 {
2252#region Check to see if the property is marked with RelationshipTypes.PrivateField
2253
2254 var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
2255
2256 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)
2257 throw new InvalidOperationException(Resources.PrivateFieldException);
2258
2259#endregion
2260
2261 if (_bypassPropertyChecks || CanWriteProperty(propertyInfo, noAccess == Security.NoAccessBehavior.ThrowException))
2262 {
2263 bool doChange = false;
2264 if (field == null)
2265 {
2266 if (newValue != null)
2267 doChange = true;
2268 }
2269 else
2270 {
2271 if (typeof(V) == typeof(string) && newValue == null)
2272 newValue = Utilities.CoerceValue<V>(typeof(string), null, string.Empty);
2273 if (!field.Equals(newValue))
2274 doChange = true;
2275 }
2276 if (doChange)
2277 {
2278 if (!_bypassPropertyChecks) OnPropertyChanging(propertyName);
2279 field = Utilities.CoerceValue<P>(typeof(V), field, newValue);
2280 if (!_bypassPropertyChecks) PropertyHasChanged(propertyName);
2281 }
2282 }
2283 }
2284 catch (System.Security.SecurityException ex)
2285 {
2286 throw new Csla.Security.SecurityException(ex.Message);
2287 }
2289 {
2290 throw;
2291 }
2292 catch (Exception ex)
2293 {
2294 throw new PropertyLoadException(
2295 string.Format(Properties.Resources.PropertyLoadException, propertyName, ex.Message), ex);
2296 }
2297 }
2298
2313 protected void SetProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
2314 {
2315 SetProperty<P>(propertyInfo, newValue, Security.NoAccessBehavior.ThrowException);
2316 }
2317
2331 protected void SetPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue)
2332 {
2333 SetPropertyConvert<P, F>(propertyInfo, newValue, Security.NoAccessBehavior.ThrowException);
2334 }
2335
2348 protected void SetPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue, Security.NoAccessBehavior noAccess)
2349 {
2350 try
2351 {
2352 if (_bypassPropertyChecks || CanWriteProperty(propertyInfo, noAccess == Security.NoAccessBehavior.ThrowException))
2353 {
2354 P oldValue = default(P);
2355 var fieldData = FieldManager.GetFieldData(propertyInfo);
2356 if (fieldData == null)
2357 {
2358 oldValue = propertyInfo.DefaultValue;
2359 fieldData = FieldManager.LoadFieldData<P>(propertyInfo, oldValue);
2360 }
2361 else
2362 {
2363 var fd = fieldData as FieldManager.IFieldData<P>;
2364 if (fd != null)
2365 oldValue = fd.Value;
2366 else
2367 oldValue = (P)fieldData.Value;
2368 }
2369 if (typeof(F) == typeof(string) && newValue == null)
2370 newValue = Utilities.CoerceValue<F>(typeof(string), null, string.Empty);
2371 LoadPropertyValue<P>(propertyInfo, oldValue, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue), !_bypassPropertyChecks);
2372 }
2373 }
2374 catch (System.Security.SecurityException ex)
2375 {
2376 throw new Csla.Security.SecurityException(ex.Message);
2377 }
2379 {
2380 throw;
2381 }
2382 catch (Exception ex)
2383 {
2384 throw new PropertyLoadException(
2385 string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message), ex);
2386 }
2387 }
2388
2404 protected void SetProperty<P>(PropertyInfo<P> propertyInfo, P newValue, Security.NoAccessBehavior noAccess)
2405 {
2406 if (_bypassPropertyChecks || CanWriteProperty(propertyInfo, noAccess == Security.NoAccessBehavior.ThrowException))
2407 {
2408 try
2409 {
2410 P oldValue = default(P);
2411 var fieldData = FieldManager.GetFieldData(propertyInfo);
2412 if (fieldData == null)
2413 {
2414 oldValue = propertyInfo.DefaultValue;
2415 fieldData = FieldManager.LoadFieldData<P>(propertyInfo, oldValue);
2416 }
2417 else
2418 {
2419 var fd = fieldData as FieldManager.IFieldData<P>;
2420 if (fd != null)
2421 oldValue = fd.Value;
2422 else
2423 oldValue = (P)fieldData.Value;
2424 }
2425 if (typeof(P) == typeof(string) && newValue == null)
2426 newValue = Utilities.CoerceValue<P>(typeof(string), null, string.Empty);
2427 LoadPropertyValue<P>(propertyInfo, oldValue, newValue, !_bypassPropertyChecks);
2428 }
2429 catch (Exception ex)
2430 {
2431 throw new PropertyLoadException(
2432 string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message), ex);
2433 }
2434 }
2435 }
2436
2450 protected void SetProperty(IPropertyInfo propertyInfo, object newValue)
2451 {
2452 try
2453 {
2454 if (_bypassPropertyChecks || CanWriteProperty(propertyInfo, true))
2455 {
2456 if (!_bypassPropertyChecks) OnPropertyChanging(propertyInfo);
2457 FieldManager.SetFieldData(propertyInfo, newValue);
2458 if (!_bypassPropertyChecks) PropertyHasChanged(propertyInfo);
2459 }
2460 }
2461 catch (System.Security.SecurityException ex)
2462 {
2463 throw new Csla.Security.SecurityException(ex.Message);
2464 }
2466 {
2467 throw;
2468 }
2469 catch (Exception ex)
2470 {
2471 throw new PropertyLoadException(
2472 string.Format(Resources.PropertyLoadException, propertyInfo.Name, ex.Message), ex);
2473 }
2474 }
2475
2492 protected void SetProperty<P>(IPropertyInfo propertyInfo, P newValue)
2493 {
2494 SetProperty(propertyInfo, (object)newValue);
2495 }
2496
2497#endregion
2498
2499#region Load Properties
2500
2515 protected void LoadPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue)
2516 {
2517 try
2518 {
2519 P oldValue = default(P);
2520 var fieldData = FieldManager.GetFieldData(propertyInfo);
2521 if (fieldData == null)
2522 {
2523 oldValue = propertyInfo.DefaultValue;
2524 fieldData = FieldManager.LoadFieldData<P>(propertyInfo, oldValue);
2525 }
2526 else
2527 {
2528 var fd = fieldData as FieldManager.IFieldData<P>;
2529 if (fd != null)
2530 oldValue = fd.Value;
2531 else
2532 oldValue = (P)fieldData.Value;
2533 }
2534 LoadPropertyValue<P>(propertyInfo, oldValue, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue), false);
2535 }
2536 catch (Exception ex)
2537 {
2538 throw new PropertyLoadException(
2539 string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message), ex);
2540 }
2541 }
2542
2543 void Core.IManageProperties.LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
2544 {
2545 LoadProperty<P>(propertyInfo, newValue);
2546 }
2547
2548 bool Core.IManageProperties.FieldExists(Core.IPropertyInfo property)
2549 {
2550 return FieldManager.FieldExists(property);
2551 }
2552
2570 protected void LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
2571 {
2572 try
2573 {
2574 P oldValue = default(P);
2575 var fieldData = FieldManager.GetFieldData(propertyInfo);
2576 if (fieldData == null)
2577 {
2578 oldValue = propertyInfo.DefaultValue;
2579 fieldData = FieldManager.LoadFieldData<P>(propertyInfo, oldValue);
2580 }
2581 else
2582 {
2583 var fd = fieldData as FieldManager.IFieldData<P>;
2584 if (fd != null)
2585 oldValue = fd.Value;
2586 else
2587 oldValue = (P)fieldData.Value;
2588 }
2589 LoadPropertyValue<P>(propertyInfo, oldValue, newValue, false);
2590 }
2591 catch (Exception ex)
2592 {
2593 throw new PropertyLoadException(
2594 string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message), ex);
2595 }
2596 }
2597
2615 protected bool LoadPropertyMarkDirty<P>(PropertyInfo<P> propertyInfo, P newValue)
2616 {
2617 try
2618 {
2619 P oldValue = default(P);
2620 var fieldData = FieldManager.GetFieldData(propertyInfo);
2621 if (fieldData == null)
2622 {
2623 oldValue = propertyInfo.DefaultValue;
2624 fieldData = FieldManager.LoadFieldData<P>(propertyInfo, oldValue);
2625 }
2626 else
2627 {
2628 var fd = fieldData as FieldManager.IFieldData<P>;
2629 if (fd != null)
2630 oldValue = fd.Value;
2631 else
2632 oldValue = (P)fieldData.Value;
2633 }
2634
2635 var valuesDiffer = ValuesDiffer(propertyInfo, newValue, oldValue);
2636 if (valuesDiffer)
2637 {
2638
2639 IBusinessObject old = oldValue as IBusinessObject;
2640 if (old != null)
2641 RemoveEventHooks(old);
2642 IBusinessObject @new = newValue as IBusinessObject;
2643 if (@new != null)
2644 AddEventHooks(@new);
2645
2646 if (typeof(IEditableBusinessObject).IsAssignableFrom(propertyInfo.Type))
2647 {
2648 FieldManager.SetFieldData<P>(propertyInfo, newValue);
2649 ResetChildEditLevel(newValue);
2650 }
2651 else if (typeof(IEditableCollection).IsAssignableFrom(propertyInfo.Type))
2652 {
2653 FieldManager.SetFieldData<P>(propertyInfo, newValue);
2654 ResetChildEditLevel(newValue);
2655 }
2656 else
2657 {
2658 FieldManager.SetFieldData<P>(propertyInfo, newValue);
2659 }
2660 }
2661 return valuesDiffer;
2662 }
2663 catch (Exception ex)
2664 {
2665 throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message), ex);
2666 }
2667 }
2668
2677 private static bool ValuesDiffer<P>(PropertyInfo<P> propertyInfo, P newValue, P oldValue)
2678 {
2679 var valuesDiffer = false;
2680 if (oldValue == null)
2681 valuesDiffer = newValue != null;
2682 else
2683 {
2684 // use reference equals for objects that inherit from CSLA base class
2685 if (typeof (IBusinessObject).IsAssignableFrom(propertyInfo.Type))
2686 {
2687 valuesDiffer = !(ReferenceEquals(oldValue, newValue));
2688 }
2689 else
2690 {
2691 valuesDiffer = !(oldValue.Equals(newValue));
2692 }
2693 }
2694 return valuesDiffer;
2695 }
2696
2697 private void LoadPropertyValue<P>(PropertyInfo<P> propertyInfo, P oldValue, P newValue, bool markDirty)
2698 {
2699 var valuesDiffer = ValuesDiffer(propertyInfo, newValue, oldValue);
2700
2701 if (valuesDiffer)
2702 {
2703
2704 IBusinessObject old = oldValue as IBusinessObject;
2705 if (old != null)
2706 RemoveEventHooks(old);
2707 IBusinessObject @new = newValue as IBusinessObject;
2708 if (@new != null)
2709 AddEventHooks(@new);
2710
2711
2712 if (typeof(IEditableBusinessObject).IsAssignableFrom(propertyInfo.Type))
2713 {
2714 if (markDirty)
2715 {
2716 OnPropertyChanging(propertyInfo);
2717 FieldManager.SetFieldData<P>(propertyInfo, newValue);
2718 PropertyHasChanged(propertyInfo);
2719 }
2720 else
2721 {
2722 FieldManager.LoadFieldData<P>(propertyInfo, newValue);
2723 }
2724 ResetChildEditLevel(newValue);
2725 }
2726 else if (typeof(IEditableCollection).IsAssignableFrom(propertyInfo.Type))
2727 {
2728 if (markDirty)
2729 {
2730 OnPropertyChanging(propertyInfo);
2731 FieldManager.SetFieldData<P>(propertyInfo, newValue);
2732 PropertyHasChanged(propertyInfo);
2733 }
2734 else
2735 {
2736 FieldManager.LoadFieldData<P>(propertyInfo, newValue);
2737 }
2738 ResetChildEditLevel(newValue);
2739 }
2740 else
2741 {
2742 if (markDirty)
2743 {
2744 OnPropertyChanging(propertyInfo);
2745 FieldManager.SetFieldData<P>(propertyInfo, newValue);
2746 PropertyHasChanged(propertyInfo);
2747 }
2748 else
2749 {
2750 FieldManager.LoadFieldData<P>(propertyInfo, newValue);
2751 }
2752 }
2753 }
2754 }
2755
2770 protected virtual bool LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)
2771 {
2772 // private field
2773 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)
2774 {
2775 LoadProperty(propertyInfo, newValue);
2776 return false;
2777 }
2778
2779#if IOS
2780 //manually call LoadProperty<T> if the type is nullable otherwise JIT error will occur
2781 if (propertyInfo.Type == typeof(int?))
2782 {
2783 return LoadPropertyMarkDirty((PropertyInfo<int?>)propertyInfo, (int?)newValue);
2784 }
2785 else if (propertyInfo.Type == typeof(bool?))
2786 {
2787 return LoadPropertyMarkDirty((PropertyInfo<bool?>)propertyInfo, (bool?)newValue);
2788 }
2789 else if (propertyInfo.Type == typeof(DateTime?))
2790 {
2791 return LoadPropertyMarkDirty((PropertyInfo<DateTime?>)propertyInfo, (DateTime?)newValue);
2792 }
2793 else if (propertyInfo.Type == typeof(decimal?))
2794 {
2795 return LoadPropertyMarkDirty((PropertyInfo<decimal?>)propertyInfo, (decimal?)newValue);
2796 }
2797 else if (propertyInfo.Type == typeof(double?))
2798 {
2799 return LoadPropertyMarkDirty((PropertyInfo<double?>)propertyInfo, (double?)newValue);
2800 }
2801 else if (propertyInfo.Type == typeof(long?))
2802 {
2803 return LoadPropertyMarkDirty((PropertyInfo<long?>)propertyInfo, (long?)newValue);
2804 }
2805 else if (propertyInfo.Type == typeof(byte?))
2806 {
2807 return LoadPropertyMarkDirty((PropertyInfo<byte?>)propertyInfo, (byte?)newValue);
2808 }
2809 else if (propertyInfo.Type == typeof(char?))
2810 {
2811 return LoadPropertyMarkDirty((PropertyInfo<char?>)propertyInfo, (char?)newValue);
2812 }
2813 else if (propertyInfo.Type == typeof(short?))
2814 {
2815 return LoadPropertyMarkDirty((PropertyInfo<short?>)propertyInfo, (short?)newValue);
2816 }
2817 else if (propertyInfo.Type == typeof(uint?))
2818 {
2819 return LoadPropertyMarkDirty((PropertyInfo<uint?>)propertyInfo, (uint?)newValue);
2820 }
2821 else if (propertyInfo.Type == typeof(ulong?))
2822 {
2823 return LoadPropertyMarkDirty((PropertyInfo<ulong?>)propertyInfo, (ulong?)newValue);
2824 }
2825 else if (propertyInfo.Type == typeof(ushort?))
2826 {
2827 return LoadPropertyMarkDirty((PropertyInfo<ushort?>)propertyInfo, (ushort?)newValue);
2828 }
2829 else
2830 {
2831 return (bool)LoadPropertyByReflection("LoadPropertyMarkDirty", propertyInfo, newValue);
2832 }
2833#else
2834 return (bool)LoadPropertyByReflection("LoadPropertyMarkDirty", propertyInfo, newValue);
2835#endif
2836 }
2837
2838
2853 protected virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)
2854 {
2855#if IOS
2856 //manually call LoadProperty<T> if the type is nullable otherwise JIT error will occur
2857 if (propertyInfo.Type == typeof(int?))
2858 {
2859 LoadProperty((PropertyInfo<int?>)propertyInfo, (int?)newValue);
2860 }
2861 else if (propertyInfo.Type == typeof(bool?))
2862 {
2863 LoadProperty((PropertyInfo<bool?>)propertyInfo, (bool?)newValue);
2864 }
2865 else if (propertyInfo.Type == typeof(DateTime?))
2866 {
2867 LoadProperty((PropertyInfo<DateTime?>)propertyInfo, (DateTime?)newValue);
2868 }
2869 else if (propertyInfo.Type == typeof(decimal?))
2870 {
2871 LoadProperty((PropertyInfo<decimal?>)propertyInfo, (decimal?)newValue);
2872 }
2873 else if (propertyInfo.Type == typeof(double?))
2874 {
2875 LoadProperty((PropertyInfo<double?>)propertyInfo, (double?)newValue);
2876 }
2877 else if (propertyInfo.Type == typeof(long?))
2878 {
2879 LoadProperty((PropertyInfo<long?>)propertyInfo, (long?)newValue);
2880 }
2881 else if (propertyInfo.Type == typeof(byte?))
2882 {
2883 LoadProperty((PropertyInfo<byte?>)propertyInfo, (byte?)newValue);
2884 }
2885 else if (propertyInfo.Type == typeof(char?))
2886 {
2887 LoadProperty((PropertyInfo<char?>)propertyInfo, (char?)newValue);
2888 }
2889 else if (propertyInfo.Type == typeof(short?))
2890 {
2891 LoadProperty((PropertyInfo<short?>)propertyInfo, (short?)newValue);
2892 }
2893 else if (propertyInfo.Type == typeof(uint?))
2894 {
2895 LoadProperty((PropertyInfo<uint?>)propertyInfo, (uint?)newValue);
2896 }
2897 else if (propertyInfo.Type == typeof(ulong?))
2898 {
2899 LoadProperty((PropertyInfo<ulong?>)propertyInfo, (ulong?)newValue);
2900 }
2901 else if (propertyInfo.Type == typeof(ushort?))
2902 {
2903 LoadProperty((PropertyInfo<ushort?>)propertyInfo, (ushort?)newValue);
2904 }
2905 else
2906 {
2907 LoadPropertyByReflection("LoadProperty", propertyInfo, newValue);
2908 }
2909#else
2910 LoadPropertyByReflection("LoadProperty", propertyInfo, newValue);
2911#endif
2912 }
2913
2924 private object LoadPropertyByReflection(string loadPropertyMethodName, IPropertyInfo propertyInfo, object newValue)
2925 {
2926 var t = this.GetType();
2927 var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
2928 var method = t.GetMethods(flags).FirstOrDefault(c => c.Name == loadPropertyMethodName && c.IsGenericMethod);
2929 var gm = method.MakeGenericMethod(propertyInfo.Type);
2930 var p = new object[] { propertyInfo, newValue };
2931 return gm.Invoke(this, p);
2932 }
2933
2939 private void ResetChildEditLevel(object newValue)
2940 {
2941 IEditableBusinessObject child = newValue as IEditableBusinessObject;
2942 if (child != null)
2943 {
2944 child.SetParent(this);
2945 // set child edit level
2946 UndoableBase.ResetChildEditLevel(child, this.EditLevel, this.BindingEdit);
2947 // reset EditLevelAdded
2948 child.EditLevelAdded = this.EditLevel;
2949 }
2950 else
2951 {
2952 IEditableCollection col = newValue as IEditableCollection;
2953 if (col != null)
2954 {
2955 col.SetParent(this);
2956 IUndoableObject undo = col as IUndoableObject;
2957 if (undo != null)
2958 {
2959 // set child edit level
2960 UndoableBase.ResetChildEditLevel(undo, this.EditLevel, this.BindingEdit);
2961 }
2962 }
2963 }
2964 }
2965
2966 //private AsyncLoadManager
2967 [NonSerialized]
2968 [NotUndoable]
2969 private AsyncLoadManager _loadManager;
2970 internal AsyncLoadManager LoadManager
2971 {
2972 get
2973 {
2974 if (_loadManager == null)
2975 {
2976 _loadManager = new AsyncLoadManager(this, OnPropertyChanged);
2977 _loadManager.BusyChanged += loadManager_BusyChanged;
2978 _loadManager.UnhandledAsyncException += loadManager_UnhandledAsyncException;
2979 }
2980 return _loadManager;
2981 }
2982 }
2983
2984 private void loadManager_UnhandledAsyncException(object sender, ErrorEventArgs e)
2985 {
2987 }
2988
2989 private void loadManager_BusyChanged(object sender, BusyChangedEventArgs e)
2990 {
2991 OnBusyChanged(e);
2992 }
2993
3000 protected void LoadPropertyAsync<R>(PropertyInfo<R> property, Task<R> factory)
3001 {
3002 LoadManager.BeginLoad(new TaskLoader<R>(property, factory));
3003 }
3004
3005#endregion
3006
3007#region IsBusy / IsIdle
3008
3009 [NonSerialized]
3010 [NotUndoable]
3011 private bool _isBusy;
3012
3017 [EditorBrowsable(EditorBrowsableState.Advanced)]
3018 protected void MarkBusy()
3019 {
3020 if (_isBusy)
3021 throw new InvalidOperationException(Resources.BusyObjectsMayNotBeMarkedBusy);
3022
3023 _isBusy = true;
3024 OnBusyChanged(new BusyChangedEventArgs("", true));
3025 }
3026
3031 [EditorBrowsable(EditorBrowsableState.Advanced)]
3032 protected void MarkIdle()
3033 {
3034 _isBusy = false;
3035 OnBusyChanged(new BusyChangedEventArgs("", false));
3036 }
3037
3043 [Browsable(false)]
3044 [Display(AutoGenerateField = false)]
3045 [ScaffoldColumn(false)]
3046 public virtual bool IsBusy
3047 {
3048 get { return IsSelfBusy || (_fieldManager != null && FieldManager.IsBusy()); }
3049 }
3050
3055 [Browsable(false)]
3056 [Display(AutoGenerateField = false)]
3057 [ScaffoldColumn(false)]
3058 public virtual bool IsSelfBusy
3059 {
3060 get { return _isBusy || BusinessRules.RunningAsyncRules || LoadManager.IsLoading; }
3061 }
3062
3063 [NotUndoable]
3064 [NonSerialized]
3065 private BusyChangedEventHandler _busyChanged;
3066
3071 {
3072 add { _busyChanged = (BusyChangedEventHandler)Delegate.Combine(_busyChanged, value); }
3073 remove { _busyChanged = (BusyChangedEventHandler)Delegate.Remove(_busyChanged, value); }
3074 }
3075
3080 protected virtual void OnBusyChanged(BusyChangedEventArgs args)
3081 {
3082 if (_busyChanged != null)
3083 _busyChanged(this, args);
3084 MetaPropertyHasChanged("IsSelfBusy");
3085 MetaPropertyHasChanged("IsBusy");
3086 }
3087
3096 public virtual bool IsPropertyBusy(Csla.Core.IPropertyInfo property)
3097 {
3098 return BusinessRules.GetPropertyBusy(property);
3099 }
3100
3109 public bool IsPropertyBusy(string propertyName)
3110 {
3112 }
3113
3114#endregion
3115
3116#region INotifyUnhandledAsyncException Members
3117
3118 [NotUndoable]
3119 [NonSerialized]
3120 private EventHandler<ErrorEventArgs> _unhandledAsyncException;
3121
3126 public event EventHandler<ErrorEventArgs> UnhandledAsyncException
3127 {
3128 add { _unhandledAsyncException = (EventHandler<ErrorEventArgs>)Delegate.Combine(_unhandledAsyncException, value); }
3129 remove { _unhandledAsyncException = (EventHandler<ErrorEventArgs>)Delegate.Remove(_unhandledAsyncException, value); }
3130 }
3131
3136 [EditorBrowsable(EditorBrowsableState.Advanced)]
3137 protected virtual void OnUnhandledAsyncException(ErrorEventArgs error)
3138 {
3139 if (_unhandledAsyncException != null)
3140 _unhandledAsyncException(this, error);
3141 }
3142
3149 [EditorBrowsable(EditorBrowsableState.Advanced)]
3150 protected void OnUnhandledAsyncException(object originalSender, Exception error)
3151 {
3152 OnUnhandledAsyncException(new ErrorEventArgs(originalSender, error));
3153 }
3154
3155#endregion
3156
3157#region Child Change Notification
3158
3159 [NonSerialized]
3160 [NotUndoable]
3161 private EventHandler<Csla.Core.ChildChangedEventArgs> _childChangedHandlers;
3162
3166 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design",
3167 "CA1062:ValidateArgumentsOfPublicMethods")]
3168 public event EventHandler<Csla.Core.ChildChangedEventArgs> ChildChanged
3169 {
3170 add
3171 {
3172 _childChangedHandlers = (EventHandler<Csla.Core.ChildChangedEventArgs>)
3173 System.Delegate.Combine(_childChangedHandlers, value);
3174 }
3175 remove
3176 {
3177 _childChangedHandlers = (EventHandler<Csla.Core.ChildChangedEventArgs>)
3178 System.Delegate.Remove(_childChangedHandlers, value);
3179 }
3180 }
3181
3189 [EditorBrowsable(EditorBrowsableState.Advanced)]
3190 protected virtual void OnChildChanged(ChildChangedEventArgs e)
3191 {
3192 if (_childChangedHandlers != null)
3193 _childChangedHandlers.Invoke(this, e);
3194 MetaPropertyHasChanged("IsDirty");
3195 MetaPropertyHasChanged("IsValid");
3196 MetaPropertyHasChanged("IsSavable");
3197 }
3198
3202 private void RaiseChildChanged(ChildChangedEventArgs e)
3203 {
3204 OnChildChanged(e);
3205 }
3206
3210 private void RaiseChildChanged(
3211 object childObject, PropertyChangedEventArgs propertyArgs)
3212 {
3213 ChildChangedEventArgs args = new ChildChangedEventArgs(childObject, propertyArgs);
3214 OnChildChanged(args);
3215 }
3216
3220 private void RaiseChildChanged(
3221 object childObject, PropertyChangedEventArgs propertyArgs, ListChangedEventArgs listArgs)
3222 {
3223 ChildChangedEventArgs args = new ChildChangedEventArgs(childObject, propertyArgs, listArgs);
3224 OnChildChanged(args);
3225 }
3226
3230 private void RaiseChildChanged(
3231 object childObject, PropertyChangedEventArgs propertyArgs, NotifyCollectionChangedEventArgs listArgs)
3232 {
3233 ChildChangedEventArgs args = new ChildChangedEventArgs(childObject, propertyArgs, listArgs);
3234 OnChildChanged(args);
3235 }
3236
3242 private void Child_PropertyChanged(object sender, PropertyChangedEventArgs e)
3243 {
3244 // Issue 813
3245 // MetaPropertyHasChanged calls in OnChildChanged we're leading to exponential growth in OnChildChanged calls
3246 // Those notifications are for the UI. Ignore them here
3247 if (!(e is MetaPropertyChangedEventArgs))
3248 {
3249 RaiseChildChanged(sender, e);
3250 }
3251 }
3252
3258 private void Child_ListChanged(object sender, ListChangedEventArgs e)
3259 {
3260 if (e.ListChangedType != ListChangedType.ItemChanged)
3261 RaiseChildChanged(sender, null, e);
3262 }
3263
3269 private void Child_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
3270 {
3271 RaiseChildChanged(sender, null, e);
3272 }
3273
3279 private void Child_Changed(object sender, ChildChangedEventArgs e)
3280 {
3281 RaiseChildChanged(e);
3282 }
3283
3284#endregion
3285
3286#region Field Manager
3287
3288 private FieldManager.FieldDataManager _fieldManager;
3289
3295 {
3296 get
3297 {
3298 if (_fieldManager == null)
3299 {
3300 _fieldManager = new FieldDataManager(this.GetType());
3301 UndoableBase.ResetChildEditLevel(_fieldManager, this.EditLevel, this.BindingEdit);
3302 }
3303 return _fieldManager;
3304 }
3305 }
3306
3307 private void FieldDataDeserialized()
3308 {
3309 foreach (object item in FieldManager.GetChildren())
3310 {
3311 if (item is IBusinessObject business)
3312 OnAddEventHooks(business);
3313
3314 if (item is IEditableBusinessObject child)
3315 {
3316 child.SetParent(this);
3317 }
3318 if (item is IEditableCollection childCollection)
3319 {
3320 childCollection.SetParent(this);
3321 }
3322 }
3323 }
3324
3325#endregion
3326
3327#region IParent
3328
3335 [EditorBrowsable(EditorBrowsableState.Advanced)]
3336 protected virtual void EditChildComplete(Core.IEditableBusinessObject child)
3337 {
3338 // do nothing, we don't really care
3339 // when a child has its edits applied
3340 }
3341
3342 void IParent.ApplyEditChild(Core.IEditableBusinessObject child)
3343 {
3344 this.EditChildComplete(child);
3345 }
3346
3347 void IParent.RemoveChild(IEditableBusinessObject child)
3348 {
3349 var info = FieldManager.FindProperty(child);
3350 FieldManager.RemoveField(info);
3351 }
3352
3353 IParent Csla.Core.IParent.Parent
3354 {
3355 get { return this.Parent; }
3356 }
3357
3358#endregion
3359
3360#region IDataPortalTarget Members
3361
3362 void Csla.Server.IDataPortalTarget.CheckRules()
3363 {
3365 }
3366
3367 void Csla.Server.IDataPortalTarget.MarkAsChild()
3368 {
3369 this.MarkAsChild();
3370 }
3371
3372 void Csla.Server.IDataPortalTarget.MarkNew()
3373 {
3374 this.MarkNew();
3375 }
3376
3377 void Csla.Server.IDataPortalTarget.MarkOld()
3378 {
3379 this.MarkOld();
3380 }
3381
3382 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
3383 {
3385 }
3386
3387 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
3388 {
3390 }
3391
3392 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
3393 {
3395 }
3396
3397 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)
3398 {
3400 }
3401
3402 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
3403 {
3405 }
3406
3407 void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
3408 {
3409 this.Child_OnDataPortalException(e, ex);
3410 }
3411
3412#endregion
3413
3414#region IManageProperties Members
3415
3416 bool IManageProperties.HasManagedProperties
3417 {
3418 get { return (_fieldManager != null && _fieldManager.HasFields); }
3419 }
3420
3421 List<IPropertyInfo> IManageProperties.GetManagedProperties()
3422 {
3424 }
3425
3426 object IManageProperties.GetProperty(IPropertyInfo propertyInfo)
3427 {
3428 return GetProperty(propertyInfo);
3429 }
3430
3431 object IManageProperties.ReadProperty(IPropertyInfo propertyInfo)
3432 {
3433 return ReadProperty(propertyInfo);
3434 }
3435
3436 P IManageProperties.ReadProperty<P>(PropertyInfo<P> propertyInfo)
3437 {
3438 return ReadProperty<P>(propertyInfo);
3439 }
3440
3441 void IManageProperties.SetProperty(IPropertyInfo propertyInfo, object newValue)
3442 {
3443 SetProperty(propertyInfo, newValue);
3444 }
3445
3446 void IManageProperties.LoadProperty(IPropertyInfo propertyInfo, object newValue)
3447 {
3448 LoadProperty(propertyInfo, newValue);
3449 }
3450
3451 bool IManageProperties.LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)
3452 {
3453 return LoadPropertyMarkDirty(propertyInfo, newValue);
3454 }
3455
3456 List<object> IManageProperties.GetChildren()
3457 {
3458 return FieldManager.GetChildren();
3459 }
3460#endregion
3461
3462#region MobileFormatter
3463
3474 [EditorBrowsable(EditorBrowsableState.Advanced)]
3476 {
3477 base.OnGetState(info, mode);
3478 info.AddValue("Csla.Core.BusinessBase._isNew", _isNew);
3479 info.AddValue("Csla.Core.BusinessBase._isDeleted", _isDeleted);
3480 info.AddValue("Csla.Core.BusinessBase._isDirty", _isDirty);
3481 info.AddValue("Csla.Core.BusinessBase._neverCommitted", _neverCommitted);
3482 info.AddValue("Csla.Core.BusinessBase._disableIEditableObject", _disableIEditableObject);
3483 info.AddValue("Csla.Core.BusinessBase._isChild", _isChild);
3484 info.AddValue("Csla.Core.BusinessBase._editLevelAdded", _editLevelAdded);
3485 info.AddValue("Csla.Core.BusinessBase._identity", _identity);
3486 }
3487
3498 [EditorBrowsable(EditorBrowsableState.Advanced)]
3500 {
3501 base.OnSetState(info, mode);
3502 _isNew = info.GetValue<bool>("Csla.Core.BusinessBase._isNew");
3503 _isDeleted = info.GetValue<bool>("Csla.Core.BusinessBase._isDeleted");
3504 _isDirty = info.GetValue<bool>("Csla.Core.BusinessBase._isDirty");
3505 _neverCommitted = info.GetValue<bool>("Csla.Core.BusinessBase._neverCommitted");
3506 _disableIEditableObject = info.GetValue<bool>("Csla.Core.BusinessBase._disableIEditableObject");
3507 _isChild = info.GetValue<bool>("Csla.Core.BusinessBase._isChild");
3508 if (mode != StateMode.Undo)
3509 _editLevelAdded = info.GetValue<int>("Csla.Core.BusinessBase._editLevelAdded");
3510 _identity = info.GetValue<int>("Csla.Core.BusinessBase._identity");
3511 }
3512
3524 [EditorBrowsable(EditorBrowsableState.Advanced)]
3525 protected override void OnGetChildren(
3527 {
3528 base.OnGetChildren(info, formatter);
3529
3530 if (_fieldManager != null)
3531 {
3532 var fieldManagerInfo = formatter.SerializeObject(_fieldManager);
3533 info.AddChild("_fieldManager", fieldManagerInfo.ReferenceId);
3534 }
3535
3536 if (_businessRules != null)
3537 {
3538 var vrInfo = formatter.SerializeObject(_businessRules);
3539 info.AddChild("_businessRules", vrInfo.ReferenceId);
3540 }
3541 }
3542
3554 [EditorBrowsable(EditorBrowsableState.Advanced)]
3556 {
3557 if (info.Children.ContainsKey("_fieldManager"))
3558 {
3559 var childData = info.Children["_fieldManager"];
3560 _fieldManager = (FieldManager.FieldDataManager)formatter.GetObject(childData.ReferenceId);
3561 }
3562
3563 if (info.Children.ContainsKey("_businessRules"))
3564 {
3565 int refId = info.Children["_businessRules"].ReferenceId;
3566 _businessRules = (BusinessRules)formatter.GetObject(refId);
3567 }
3568
3569 base.OnSetChildren(info, formatter);
3570 }
3571
3572#endregion
3573
3574#region Property Checks ByPass
3575
3576 [NonSerialized]
3577 [NotUndoable]
3578 private bool _bypassPropertyChecks = false;
3579
3583 protected internal bool IsBypassingPropertyChecks { get { return _bypassPropertyChecks; } }
3584
3585 [NonSerialized]
3586 [NotUndoable]
3587 private BypassPropertyChecksObject _bypassPropertyChecksObject = null;
3588
3595 [DebuggerBrowsable(DebuggerBrowsableState.Never)]
3596 protected internal BypassPropertyChecksObject BypassPropertyChecks
3597 {
3598 get
3599 {
3600 return BypassPropertyChecksObject.GetManager(this);
3601 }
3602 }
3603
3610 [EditorBrowsable(EditorBrowsableState.Never)]
3611 protected internal class BypassPropertyChecksObject : IDisposable
3612 {
3613 private BusinessBase _businessObject;
3614 private static object _lock = new object();
3615
3616 internal BypassPropertyChecksObject(BusinessBase businessObject)
3617 {
3618 _businessObject = businessObject;
3619 _businessObject._bypassPropertyChecks = true;
3620 }
3621
3622#region IDisposable Members
3623
3627 public void Dispose()
3628 {
3629 Dispose(true);
3630 GC.SuppressFinalize(this);
3631 }
3632
3637 protected virtual void Dispose(bool dispose)
3638 {
3639 DeRef();
3640 }
3641
3647 public static BypassPropertyChecksObject GetManager(BusinessBase businessObject)
3648 {
3649 lock (_lock)
3650 {
3651 if (businessObject._bypassPropertyChecksObject == null)
3652 businessObject._bypassPropertyChecksObject = new BypassPropertyChecksObject(businessObject);
3653
3654 businessObject._bypassPropertyChecksObject.AddRef();
3655 }
3656 return businessObject._bypassPropertyChecksObject;
3657 }
3658
3659#region Reference counting
3660
3661 private int _refCount;
3662
3667 public int RefCount
3668 {
3669 get { return _refCount; }
3670 }
3671
3672 private void AddRef()
3673 {
3674 _refCount += 1;
3675 }
3676
3677 private void DeRef()
3678 {
3679
3680 lock (_lock)
3681 {
3682 _refCount -= 1;
3683 if (_refCount == 0)
3684 {
3685 _businessObject._bypassPropertyChecks = false;
3686 _businessObject._bypassPropertyChecksObject = null;
3687 _businessObject = null;
3688 }
3689 }
3690 }
3691
3692#endregion
3693#endregion
3694 }
3695
3696#endregion
3697
3698#region ISuppressRuleChecking Members
3699
3703 void ICheckRules.SuppressRuleChecking()
3704 {
3706 }
3707
3711 void ICheckRules.ResumeRuleChecking()
3712 {
3714 }
3715
3719 void ICheckRules.CheckRules()
3720 {
3722 }
3723
3727 Task ICheckRules.CheckRulesAsync()
3728 {
3730 }
3731
3736 {
3737 return BrokenRulesCollection;
3738 }
3739
3740#endregion
3741 }
3742}
virtual void OnPropertyChanged(string propertyName)
Call this method to raise the PropertyChanged event for a specific property.
Definition: BindableBase.cs:85
virtual void OnMetaPropertyChanged(string propertyName)
virtual void OnUnknownPropertyChanged()
Call this method to raise the PropertyChanged event for all object properties.
virtual void OnPropertyChanging(string propertyName)
Call this method to raise the PropertyChanging event for a specific property.
This is the non-generic base class from which most business objects will be derived.
virtual void CheckObjectRules()
Check object rules and notifies UI of properties that may have changed.
virtual void OnBusyChanged(BusyChangedEventArgs args)
Raise the BusyChanged event.
Core.IParent Parent
Provide access to the parent reference for use in child object code.
void AddEventHooks(IBusinessObject child)
For internal use.
virtual bool IsPropertyBusy(Csla.Core.IPropertyInfo property)
Gets a value indicating whether a specific property is busy (has a currently executing async rule).
virtual bool IsSelfValid
Returns true if the object is currently valid, false if the object has broken rules or is otherwise i...
FieldDataManager FieldManager
Gets the PropertyManager object for this business object.
P LazyReadPropertyAsync< P >(PropertyInfo< P > property, Task< P > factory)
Gets a property's value as a specified type.
virtual bool CanExecuteMethod(string methodName)
Returns true if the user is allowed to execute the specified method.
void RemoveEventHooks(IBusinessObject child)
For internal use only.
virtual void Delete()
Marks the object for deletion.
virtual bool IsBusy
Gets a value indicating if this object or its child objects are busy.
virtual void OnUnhandledAsyncException(ErrorEventArgs error)
Raises the UnhandledAsyncException event.
P LazyGetPropertyAsync< P >(PropertyInfo< P > property, Task< P > factory)
Lazily initializes a property and returns the resulting value.
void ApplyEdit()
Commits the current edit process.
virtual bool IsValid
Returns true if the object and its child objects are currently valid, false if the object or any of i...
virtual void EditChildComplete(Core.IEditableBusinessObject child)
Override this method to be notified when a child object's Core.BusinessBase.ApplyEdit method has comp...
virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)
Called by the server-side DataPortal prior to calling the requested DataPortal_XYZ method.
bool IsDeleted
Returns true if this object is marked for deletion.
object GetProperty(IPropertyInfo propertyInfo)
Gets a property's value as a specified type.
bool IsPropertyBusy(string propertyName)
Gets a value indicating whether a specific property is busy (has a currently executing async rule).
void MarkAsChild()
Marks the object as being a child object.
static MethodInfo RegisterMethod(Type objectType, string methodName)
Indicates that the specified method belongs to the type.
virtual object GetClone()
Creates a clone of the object.
P LazyGetProperty< P >(PropertyInfo< P > property, Func< P > valueGenerator)
Lazily initializes a property and returns the resulting value.
bool DisableIEditableObject
Gets or sets a value indicating whether the IEditableObject interface methods should be disabled for ...
virtual void AddBusinessRules()
Override this method in your business class to be notified when you need to set up shared business ru...
EventHandler ValidationComplete
Event raised when validation is complete.
void SetPropertyConvert< P, V >(PropertyInfo< P > propertyInfo, ref P field, V newValue)
Sets a property's backing field with the supplied value, first checking authorization,...
virtual void OnRemoveEventHooks(IBusinessObject child)
Unhook child object events.
P LazyReadProperty< P >(PropertyInfo< P > property, Func< P > valueGenerator)
Gets a property's value as a specified type.
virtual bool IsSelfBusy
Gets a value indicating if this object is busy.
virtual void OnValidationComplete()
Raises the ValidationComplete event
BusinessRuleManager GetRegisteredRules()
Gets the registered rules.
virtual object ReadProperty(IPropertyInfo propertyInfo)
Gets a property's value.
void SetProperty< P >(PropertyInfo< P > propertyInfo, ref P field, P newValue)
Sets a property's backing field with the supplied value, first checking authorization,...
override void OnSetState(Csla.Serialization.Mobile.SerializationInfo info, StateMode mode)
Override this method to retrieve your field values from the MobileFormatter serialzation stream.
virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
Called by the server-side DataPortal if an exception occurs during data access.
BrokenRulesCollection GetBrokenRules()
Gets the broken rules for this object
BusinessRules BusinessRules
Provides access to the broken rules functionality.
bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)
Returns true if the user is allowed to execute the specified method.
void LoadPropertyAsync< R >(PropertyInfo< R > property, Task< R > factory)
Load a property from an async method.
BusinessBase()
Creates an instance of the object.
virtual void Child_Create()
Override this method to load a new business object with default values from the database.
void MarkDeleted()
Marks an object for deletion.
virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)
Returns true if the user is allowed to execute the specified method.
void SetPropertyConvert< P, F >(PropertyInfo< P > propertyInfo, F newValue)
Sets a property's managed field with the supplied value, first checking authorization,...
void CancelEdit()
Cancels the current edit process, restoring the object's state to its previous values.
virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)
Loads a property's managed field with the supplied value.
virtual void OnChildChanged(ChildChangedEventArgs e)
Raises the ChildChanged event, indicating that a child object has been changed.
virtual bool LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)
Loads a property's managed field with the supplied value.
P ReadPropertyConvert< F, P >(PropertyInfo< F > propertyInfo)
Gets a property's value from the list of managed field values, converting the value to an appropriate...
bool CanReadProperty(string propertyName)
Returns true if the user is allowed to read the specified property.
EventHandler< Csla.Core.ChildChangedEventArgs > ChildChanged
Event raised when a child object has been changed.
bool IsNew
Returns true if this is a new object, false if it is a pre-existing object.
override void OnGetChildren(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)
Override this method to insert your child object references into the MobileFormatter serialzation str...
void MarkDirty(bool suppressEvent)
Marks an object as being dirty, or changed.
virtual bool IsSavable
Returns true if this object is both dirty and valid.
BusyChangedEventHandler BusyChanged
Event indicating that the IsBusy property has changed.
virtual void SetParent(Core.IParent parent)
Used by BusinessListBase as a child object is created to tell the child object about its parent.
virtual void MarkOld()
Marks the object as being an old (not new) object.
virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
This method is called on a newly deserialized object after deserialization is complete.
static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
Indicates that the specified method belongs to the type.
virtual bool IsSelfDirty
Returns true if this object's data has been changed.
EventHandler< ErrorEventArgs > UnhandledAsyncException
Event indicating that an exception occurred during the processing of an async operation.
virtual void PropertyHasChanged(Csla.Core.IPropertyInfo property)
Performs processing required when a property has changed.
virtual bool CanWriteProperty(Csla.Core.IPropertyInfo property)
Returns true if the user is allowed to write the specified property.
virtual Rules.BrokenRulesCollection BrokenRulesCollection
Provides access to the readonly collection of broken business rules for this object.
virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)
Returns true if the user is allowed to read the calling property.
override void UndoChangesComplete()
Called when an undo operation has completed.
void MarkDirty()
Marks an object as being dirty, or changed.
override void AcceptChangesComplete()
Notifies the parent object (if any) that this child object's edits have been accepted.
static PropertyInfo< P > RegisterProperty< P >(Type objectType, PropertyInfo< P > info)
Indicates that the specified property belongs to the type.
virtual void MetaPropertyHasChanged(string name)
Raises OnPropertyChanged for meta properties (IsXYZ) when PropertyChangedMode is not Windows
P GetProperty< P >(string propertyName, P field, P defaultValue)
Gets a property's value, first checking authorization.
virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
Called by the server-side DataPortal prior to calling the requested DataPortal_XYZ method.
void LoadPropertyConvert< P, F >(PropertyInfo< P > propertyInfo, F newValue)
Loads a property's managed field with the supplied value.
virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
Called by the server-side DataPortal after calling the requested DataPortal_XYZ method.
P GetPropertyConvert< F, P >(PropertyInfo< F > propertyInfo, F field)
Gets a property's value as a specified type, first checking authorization.
virtual void OnAddEventHooks(IBusinessObject child)
Hook child object events.
void OnUnhandledAsyncException(object originalSender, Exception error)
Raises the UnhandledAsyncException event.
override void OnGetState(Csla.Serialization.Mobile.SerializationInfo info, StateMode mode)
Override this method to insert your field values into the MobileFormatter serialzation stream.
bool LoadPropertyMarkDirty< P >(PropertyInfo< P > propertyInfo, P newValue)
Loads a property's managed field with the supplied value and mark field as dirty if value is modified...
bool IsChild
Returns true if this is a child (non-root) object.
virtual bool IsDirty
Returns true if this object's data, or any of its fields or child objects data, has been changed.
virtual void CheckPropertyRules(IPropertyInfo property)
Check rules for the property and notifies UI of properties that may have changed.
bool CanWriteProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
Returns true if the user is allowed to write the calling property.
virtual void Initialize()
Override this method to set up event handlers so user code in a partial class can respond to events r...
virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
Called by the server-side DataPortal if an exception occurs during data access.
void MarkClean()
Forces the object's IsDirty flag to false.
void MarkIdle()
Mark the object as not busy (it is not running an async operation).
void MarkBusy()
Mark the object as busy (it is running an async operation).
void BeginEdit()
Starts a nested edit on the object.
void SetProperty(IPropertyInfo propertyInfo, object newValue)
Sets a property's managed field with the supplied value, and then calls PropertyHasChanged if the val...
virtual void Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
Called by the server-side DataPortal after calling the requested DataPortal_XYZ method.
P ReadProperty< P >(PropertyInfo< P > propertyInfo)
Gets a property's value as a specified type.
bool CanWriteProperty(string propertyName)
Returns true if the user is allowed to write the specified property.
virtual void MarkNew()
Marks the object as being a new object.
bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
Returns true if the user is allowed to read the calling property.
override void OnSetChildren(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)
Override this method to retrieve your child object references from the MobileFormatter serialzation s...
Event arguments for the BusyChanged event.
Contains event data about the changed child object.
Event arguments for an unhandled async exception.
Manages properties and property data for a business object.
bool HasFields
Gets a value indicating whether there are any managed fields available.
List< IPropertyInfo > GetRegisteredProperties()
Returns a copy of the property list for the business object.
FieldDataManager()
Creates an instance of the object.
bool IsDirty()
Returns a value indicating whether any fields are dirty.
IFieldData GetFieldData(IPropertyInfo propertyInfo)
Gets the IFieldData object for a specific field.
bool IsValid()
Returns a value indicating whether all fields are valid.
bool FieldExists(IPropertyInfo propertyInfo)
Returns a value indicating whether an IFieldData entry exists for the specified property.
List< object > GetChildren()
Returns a list of all child objects contained in the list of fields.
IPropertyInfo GetRegisteredProperty(string propertyName)
Returns the IPropertyInfo object corresponding to the property name.
Implements n-level undo capabilities as described in Chapters 2 and 3.
Definition: UndoableBase.cs:28
bool BindingEdit
Gets or sets a value indicating whether n-level undo was invoked through IEditableObject.
Definition: UndoableBase.cs:50
UndoableBase()
Creates an instance of the object.
Definition: UndoableBase.cs:38
Provides information about the DataPortal call.
Maintains metadata about a method.
Definition: MethodInfo.cs:19
A strongly-typed resource class, for looking up localized strings, etc.
static string PrivateFieldException
Looks up a localized string similar to Properties with private backing fields must be marked as Relat...
static string NoDeleteRootException
Looks up a localized string similar to Invalid for root objects - use Delete instead.
static string PropertySetNotAllowed
Looks up a localized string similar to Property set not allowed.
static string ChildDeleteException
Looks up a localized string similar to Can not directly mark a child object for deletion - use its pa...
static string PropertyLoadException
Looks up a localized string similar to Property load or set failed for property {0} ({1}).
static string PropertyGetNotAllowed
Looks up a localized string similar to Property get not allowed.
static string BusyObjectsMayNotBeMarkedBusy
Looks up a localized string similar to Objects that are marked busy may not be marked busy again.
static string NoSuchMethod
Looks up a localized string similar to No such method {0}.
Maintains metadata about a property.
virtual T DefaultValue
Gets the default initial value for the property.
RelationshipTypes RelationshipType
Gets the relationship between the declaring object and the object reference in the property.
Type Type
Gets the type of the property.
string Name
Gets the property name value.
Exception indicating a failure to set a property's field.
string Description
Provides access to the description of the broken rule.
Definition: BrokenRule.cs:55
A collection of currently broken rules.
BrokenRule GetFirstBrokenRule(Csla.Core.IPropertyInfo property)
Returns the first BrokenRule object corresponding to the specified property.
override string ToString()
Returns the text of all broken rule descriptions, each separated by a Environment....
Manages the list of rules for a business type.
Tracks the business rules for a business object.
static bool HasPermission(AuthorizationActions action, Type objectType)
Checks per-type authorization rules.
List< string > CheckRules()
Invokes all rules for the business type.
override void OnSetChildren(SerializationInfo info, MobileFormatter formatter)
Override this method to retrieve your child object references from the MobileFormatter serialzation s...
async Task< List< string > > CheckRulesAsync(int timeout)
Invokes all rules for the business type.
bool SuppressRuleChecking
Gets or sets a value indicating whether calling CheckRules should result in rule methods being invoke...
bool IsValid
Gets a value indicating whether there are any currently broken rules, which would mean the object is ...
bool CachePermissionResult(AuthorizationActions action, Csla.Core.IMemberInfo element)
Gets a value indicating whether the permission result can be cached.
List< string > CheckObjectRules()
Invokes all rules attached at the class level of the business type.
void AddDataAnnotations()
Adds validation rules corresponding to property data annotation attributes.
bool GetPropertyBusy(Csla.Core.IPropertyInfo property)
Gets a value indicating whether a specific property has any async rules running.
bool RunningAsyncRules
Gets a value indicating whether any async rules are currently executing.
BrokenRulesCollection GetBrokenRules()
Gets the broken rules list.
Serializes and deserializes objects at the field level.
Object containing the serialization data for a specific object.
object Value
Gets or sets the field value.
Definition: IFieldData.cs:27
This is the core interface implemented by all CSLA .NET base classes.
int Identity
Gets a value representing this object instance's unique identity value within the business object gra...
Defines the common methods for any business object which exposes means to supress and check business ...
Definition: ICheckRules.cs:18
Defines the common methods required by all editable CSLA single objects.
Defines the common methods required by all editable CSLA collection objects.
Maintains metadata about a method or property.
Definition: IMemberInfo.cs:19
string Name
Gets the member name value.
Definition: IMemberInfo.cs:23
Interface defining an object that notifies when it is busy executing an asynchronous operation.
Definition: INotifyBusy.cs:17
BusyChangedEventHandler BusyChanged
Event raised when the object's busy status changes.
Definition: INotifyBusy.cs:22
Implemented by classes that notify when a child object has changed.
EventHandler< ChildChangedEventArgs > ChildChanged
Event indictating that a child object has changed.
Implemented by an object that perfoms asynchronous operations that may raise exceptions.
EventHandler< ErrorEventArgs > UnhandledAsyncException
Event indicating that an exception occurred during an asynchronous operation.
Defines the interface that must be implemented by any business object that contains child objects.
Definition: IParent.cs:18
int GetNextIdentity(int current)
Gets and consumes the next available unique identity value for an object instance in the object graph...
void ApplyEditChild(Core.IEditableBusinessObject child)
Override this method to be notified when a child object's Core.BusinessBase.ApplyEdit method has comp...
void RemoveChild(Core.IEditableBusinessObject child)
This method is called by a child object when it wants to be removed from the collection.
IParent Parent
Provide access to the parent reference for use in child object code.
Definition: IParent.cs:39
Maintains metadata about a property.
RelationshipTypes RelationshipType
Gets the relationship between the declaring object and the object reference in the property.
Type Type
Gets the type of the property.
object DefaultValue
Gets the default initial value for the property.
Defines the interaction between the rules engine and a business object that hosts the rules.
Definition: IHostRules.cs:20
void RuleComplete(Csla.Core.IPropertyInfo property)
Indicates that a rule has finished processing.
void RuleStart(Csla.Core.IPropertyInfo property)
Indicates that a rule has started processing.
Defines the authorization interface through which an object can indicate which properties the current...
Interface defining callback methods used by the SerializationFormatterFactory.GetFormatter().
void Deserialized()
Method called on an object after deserialization is complete.
delegate void BusyChangedEventHandler(object sender, BusyChangedEventArgs e)
Delegate for handling the BusyChanged event.
StateMode
Indicates the reason the MobileFormatter functionality has been invoked.
Definition: StateMode.cs:20
AuthorizationActions
Authorization actions.
RelationshipTypes
List of valid relationship types between a parent object and another object through a managed propert...
@ Serializable
Prevents updating or inserting until the transaction is complete.