CSLA.NET 6.0.0
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
ReadOnlyBase.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="ReadOnlyBase.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>This is a base class from which readonly business classes</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Generic;
10using System.ComponentModel;
11using System.ComponentModel.DataAnnotations;
12using System.Diagnostics;
13using System.Linq;
14using System.Linq.Expressions;
15using System.Reflection;
16using System.Threading.Tasks;
17using Csla.Core;
20using Csla.Properties;
21using Csla.Reflection;
22using Csla.Rules;
23using Csla.Security;
25using Csla.Server;
26using System.Collections.Concurrent;
27
28namespace Csla
29{
40 [Serializable()]
41 public abstract class ReadOnlyBase<T> : BindableBase,
42 ICloneable,
46 IDataPortalTarget,
47 IManageProperties,
52 IUseFieldManager,
53 IUseBusinessRules
54 where T : ReadOnlyBase<T>
55 {
56 #region Object ID Value
57
62 protected virtual object GetIdValue()
63 {
64 return null;
65 }
66
67 #endregion
68
69 #region System.Object Overrides
70
76 public override string ToString()
77 {
78 object id = GetIdValue();
79 if (id == null)
80 return base.ToString();
81 else
82 return id.ToString();
83 }
84
85 #endregion
86
90 protected ApplicationContext ApplicationContext { get; set; }
92 {
93 get => ApplicationContext;
94 set
95 {
96 ApplicationContext = value;
97 Initialize();
98 InitializeBusinessRules();
99 }
100 }
101
105 protected ReadOnlyBase()
106 {
107 }
108
109 #region Initialize
110
116 protected virtual void Initialize()
117 { /* allows subclass to initialize events before any other activity occurs */ }
118
119 #endregion
120
121 #region Identity
122
124 {
125 get { return 0; }
126 }
127
128 #endregion
129
130 #region Authorization
131
132 [NotUndoable()]
133 [NonSerialized()]
134 private ConcurrentDictionary<string, bool> _readResultCache;
135 [NotUndoable()]
136 [NonSerialized()]
137 private ConcurrentDictionary<string, bool> _executeResultCache;
138 [NotUndoable()]
139 [NonSerialized()]
140 private System.Security.Principal.IPrincipal _lastPrincipal;
141
142 private void InitializeBusinessRules()
143 {
144 var rules = BusinessRuleManager.GetRulesForType(this.GetType());
145 if (!rules.Initialized)
146 lock (rules)
147 if (!rules.Initialized)
148 {
149 try
150 {
152 rules.Initialized = true;
153 }
154 catch (Exception)
155 {
156 BusinessRuleManager.CleanupRulesForType(this.GetType());
157 throw; // and rethrow exception
158 }
159 }
160 }
161
162 private Csla.Rules.BusinessRules _businessRules;
163
173 {
174 get
175 {
176 if (_businessRules == null)
178 else if (_businessRules.Target == null)
179 _businessRules.SetTarget(this);
180 return _businessRules;
181 }
182 }
183
184 BusinessRules IUseBusinessRules.BusinessRules => BusinessRules;
185
186 void IHostRules.RuleStart(IPropertyInfo property)
187 { }
188
190 { }
191
192 void IHostRules.RuleComplete(string property)
193 { }
194
195 void Rules.IHostRules.AllRulesComplete()
196 { }
197
207 protected virtual void AddBusinessRules()
208 { }
209
215 [EditorBrowsable(EditorBrowsableState.Advanced)]
216 public virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)
217 {
218 bool result = true;
219
220 VerifyAuthorizationCache();
221
222 if (!_readResultCache.TryGetValue(property.Name, out result))
223 {
224 result = BusinessRules.HasPermission(ApplicationContext, AuthorizationActions.ReadProperty, property);
225 // store value in cache
226 _readResultCache.AddOrUpdate(property.Name, result, (a, b) => { return result; });
227 }
228 return result;
229 }
230
239 [EditorBrowsable(EditorBrowsableState.Advanced)]
240 public bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
241 {
242 bool result = CanReadProperty(property);
243 if (throwOnFalse && result == false)
244 {
246 String.Format("{0} ({1})",
247 Resources.PropertyGetNotAllowed, property.Name));
248 throw ex;
249 }
250 return result;
251 }
252
258 [EditorBrowsable(EditorBrowsableState.Advanced)]
259 public bool CanReadProperty(string propertyName)
260 {
261 return CanReadProperty(propertyName, false);
262 }
263
271 private bool CanReadProperty(string propertyName, bool throwOnFalse)
272 {
273 var propertyInfo = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Name == propertyName);
274 if (propertyInfo == null)
275 {
276#if NETFX_CORE || (ANDROID || IOS)
277#else
278 Trace.TraceError("CanReadProperty: {0} is not a registered property of {1}.{2}", propertyName, this.GetType().Namespace, this.GetType().Name);
279#endif
280 return true;
281 }
282 return CanReadProperty(propertyInfo, throwOnFalse);
283 }
284
285 bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(string propertyName)
286 {
287 return false;
288 }
289
291 {
292 return false;
293 }
294
295 private void VerifyAuthorizationCache()
296 {
297 if (_readResultCache == null)
298 _readResultCache = new ConcurrentDictionary<string, bool>();
299 if (_executeResultCache == null)
300 _executeResultCache = new ConcurrentDictionary<string, bool>();
301 if (!ReferenceEquals(ApplicationContext.User, _lastPrincipal))
302 {
303 // the principal has changed - reset the cache
304 _readResultCache.Clear();
305 _executeResultCache.Clear();
306 _lastPrincipal = ApplicationContext.User;
307 }
308 }
309
316 [EditorBrowsable(EditorBrowsableState.Advanced)]
317 public virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)
318 {
319 bool result = true;
320
321 VerifyAuthorizationCache();
322
323 if (!_executeResultCache.TryGetValue(method.Name, out result))
324 {
326 _executeResultCache.AddOrUpdate(method.Name, result, (a, b) => { return result; });
327 }
328 return result;
329 }
330
339 [EditorBrowsable(EditorBrowsableState.Advanced)]
340 public bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)
341 {
342
343 bool result = CanExecuteMethod(method);
344 if (throwOnFalse && result == false)
345 {
347 new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, method.Name));
348 throw ex;
349 }
350 return result;
351
352 }
353
354
361 [EditorBrowsable(EditorBrowsableState.Advanced)]
362 public virtual bool CanExecuteMethod(string methodName)
363 {
364 return CanExecuteMethod(methodName, false);
365 }
366
367 private bool CanExecuteMethod(string methodName, bool throwOnFalse)
368 {
369
370 bool result = CanExecuteMethod(new MethodInfo(methodName));
371 if (throwOnFalse && result == false)
372 {
373 Csla.Security.SecurityException ex = new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, methodName));
374 throw ex;
375 }
376 return result;
377 }
378
379#endregion
380
381#region IClonable
382
383 object ICloneable.Clone()
384 {
385 return GetClone();
386 }
387
392 [EditorBrowsable(EditorBrowsableState.Advanced)]
393 public virtual object GetClone()
394 {
395 return Core.ObjectCloner.GetInstance(ApplicationContext).Clone(this);
396 }
397
404 public T Clone()
405 {
406 return (T)GetClone();
407 }
408 #endregion
409
410 #region Data Access
411
412 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
413 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
414 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
415 private void DataPortal_Create(object criteria)
416 {
417 throw new NotSupportedException(Resources.CreateNotSupportedException);
418 }
419
420 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
421 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
422 private void DataPortal_Update()
423 {
424 throw new NotSupportedException(Resources.UpdateNotSupportedException);
425 }
426
427 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
428 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
429 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
430 [Delete]
431 private void DataPortal_Delete(object criteria)
432 {
433 throw new NotSupportedException(Resources.DeleteNotSupportedException);
434 }
435
441 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
442 [EditorBrowsable(EditorBrowsableState.Advanced)]
444 {
445
446 }
447
453 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
454 [EditorBrowsable(EditorBrowsableState.Advanced)]
456 {
457
458 }
459
466 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
467 [EditorBrowsable(EditorBrowsableState.Advanced)]
468 protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
469 {
470
471 }
472
478 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
479 [EditorBrowsable(EditorBrowsableState.Advanced)]
481 {
482 }
483
489 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
490 [EditorBrowsable(EditorBrowsableState.Advanced)]
492 {
493 }
494
501 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
502 [EditorBrowsable(EditorBrowsableState.Advanced)]
503 protected virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
504 {
505 }
506
507#endregion
508
509#region Serialization Notification
510
512 {
513 OnDeserializedHandler(new System.Runtime.Serialization.StreamingContext());
514 }
515
516 [System.Runtime.Serialization.OnDeserialized()]
517 private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)
518 {
519 if (_fieldManager != null)
520 FieldManager.SetPropertyList(this.GetType());
521 InitializeBusinessRules();
522 OnDeserialized(context);
523 }
524
530 [EditorBrowsable(EditorBrowsableState.Advanced)]
531 protected virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
532 {
533 // do nothing - this is here so a subclass
534 // could override if needed
535 }
536
537#endregion
538
539#region Register Properties
540
557 protected static PropertyInfo<P> RegisterProperty<P>(Type objectType, PropertyInfo<P> info)
558 {
559 return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(objectType, info);
560 }
561
576 {
577 return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(typeof(T), info);
578 }
579
587 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName)
588 {
589 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName));
590 }
591
599 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)
600 {
601 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
602 return RegisterProperty<P>(reflectedPropertyInfo.Name);
603 }
604
613 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName)
614 {
615 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName));
616 }
617
626 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName)
627 {
628 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
629 return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName);
630 }
631
641 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue)
642 {
643 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue));
644 }
645
655 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue)
656 {
657 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
658 return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue);
659 }
660
669 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, RelationshipTypes relationship)
670 {
671 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, string.Empty, relationship));
672 }
673
682 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, RelationshipTypes relationship)
683 {
684 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
685 return RegisterProperty<P>(reflectedPropertyInfo.Name, relationship);
686 }
687
698 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue, RelationshipTypes relationship)
699 {
700 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue, relationship));
701 }
702
713 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue, RelationshipTypes relationship)
714 {
715 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
716 return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue, relationship);
717 }
718 #endregion
719
720 #region Register Methods
721
735 protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
736 {
737 var reflected = objectType.GetMethod(info.Name);
738 if (reflected == null)
739 throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");
740 return info;
741 }
742
756 protected static MethodInfo RegisterMethod(Type objectType, string methodName)
757 {
758 var info = new MethodInfo(methodName);
759 RegisterMethod(objectType, info);
760 return info;
761 }
762
768 protected static MethodInfo RegisterMethod(string methodName)
769 {
770 return RegisterMethod(typeof(T), methodName);
771 }
772
778 protected static MethodInfo RegisterMethod(Expression<Action<T>> methodLambdaExpression)
779 {
780 System.Reflection.MethodInfo reflectedMethodInfo = Reflect<T>.GetMethod(methodLambdaExpression);
781 return RegisterMethod(reflectedMethodInfo.Name);
782 }
783
784#endregion
785
786#region Get Properties
787
806 protected P GetProperty<P>(string propertyName, P field, P defaultValue)
807 {
808 return GetProperty<P>(propertyName, field, defaultValue, Security.NoAccessBehavior.SuppressException);
809 }
810
827 protected P GetProperty<P>(string propertyName, P field, P defaultValue, Security.NoAccessBehavior noAccess)
828 {
829#region Check to see if the property is marked with RelationshipTypes.PrivateField
830
831 var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
832
833 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)
834 throw new InvalidOperationException(Resources.PrivateFieldException);
835
836#endregion
837
838 if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))
839 return field;
840
841 return defaultValue;
842 }
843
859 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)
860 {
861 return GetProperty<P>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException);
862 }
863
880 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field, P defaultValue, Security.NoAccessBehavior noAccess)
881 {
882 return GetProperty<P>(propertyInfo.Name, field, defaultValue, noAccess);
883 }
884
898 protected P LazyGetProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
899 {
900 if (!(FieldManager.FieldExists(property)))
901 {
902 var result = valueGenerator();
903 LoadProperty(property, result);
904 }
905 return GetProperty<P>(property);
906 }
907
914 protected bool PropertyIsLoading(IPropertyInfo propertyInfo)
915 {
916 return LoadManager.IsLoadingProperty(propertyInfo);
917 }
918
939 protected P LazyGetPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
940 {
941 if (!(FieldManager.FieldExists(property)) && !PropertyIsLoading(property))
942 {
943 LoadPropertyAsync(property, factory);
944 }
945 return GetProperty<P>(property);
946 }
947
967 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field)
968 {
969 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException));
970 }
971
994 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field, Security.NoAccessBehavior noAccess)
995 {
996 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, noAccess));
997 }
998
1013 protected P GetProperty<P>(PropertyInfo<P> propertyInfo)
1014 {
1015 return GetProperty<P>(propertyInfo, Security.NoAccessBehavior.SuppressException);
1016 }
1017
1037 {
1038 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, Security.NoAccessBehavior.SuppressException));
1039 }
1040
1062 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, Security.NoAccessBehavior noAccess)
1063 {
1064 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, noAccess));
1065 }
1066
1084 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, Security.NoAccessBehavior noAccess)
1085 {
1086 if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
1087 {
1088 if (PropertyIsLoading(propertyInfo))
1089 return propertyInfo.DefaultValue;
1090 throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
1091 }
1092
1093 P result = default(P);
1094 if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))
1095 result = ReadProperty<P>(propertyInfo);
1096 else
1097 result = propertyInfo.DefaultValue;
1098 return result;
1099 }
1100
1111 protected object GetProperty(IPropertyInfo propertyInfo)
1112 {
1113 object result = null;
1114 if (CanReadProperty(propertyInfo, false))
1115 {
1116 // call ReadProperty (may be overloaded in actual class)
1117 result = ReadProperty(propertyInfo);
1118 }
1119 else
1120 {
1121 result = propertyInfo.DefaultValue;
1122 }
1123 return result;
1124 }
1125
1126#endregion
1127
1128#region Read Properties
1129
1144 {
1145 return Utilities.CoerceValue<P>(typeof(F), null, ReadProperty<F>(propertyInfo));
1146 }
1147
1156 protected P ReadProperty<P>(PropertyInfo<P> propertyInfo)
1157 {
1158 if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
1159 {
1160 if (PropertyIsLoading(propertyInfo))
1161 return default;
1162 throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
1163 }
1164
1165 P result = default(P);
1166 IFieldData data = FieldManager.GetFieldData(propertyInfo);
1167 if (data != null)
1168 {
1169 IFieldData<P> fd = data as IFieldData<P>;
1170 if (fd != null)
1171 result = fd.Value;
1172 else
1173 result = (P)data.Value;
1174 }
1175 else
1176 {
1177 result = propertyInfo.DefaultValue;
1178 FieldManager.LoadFieldData<P>(propertyInfo, result);
1179 }
1180 return result;
1181 }
1182
1188 protected virtual object ReadProperty(IPropertyInfo propertyInfo)
1189 {
1190 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)
1191 {
1192 return MethodCaller.CallPropertyGetter(this, propertyInfo.Name);
1193 }
1194
1195 object result = null;
1196 var info = FieldManager.GetFieldData(propertyInfo);
1197 if (info != null)
1198 {
1199 result = info.Value;
1200 }
1201 else
1202 {
1203 result = propertyInfo.DefaultValue;
1204 FieldManager.LoadFieldData(propertyInfo, result);
1205 }
1206 return result;
1207 }
1208
1218 protected P LazyReadProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
1219 {
1220 if (!(FieldManager.FieldExists(property)))
1221 {
1222 var result = valueGenerator();
1223 LoadProperty(property, result);
1224 }
1225 return ReadProperty<P>(property);
1226 }
1227
1237 protected P LazyReadPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
1238 {
1239 if (!(FieldManager.FieldExists(property)) && !PropertyIsLoading(property))
1240 {
1241 LoadPropertyAsync(property, factory);
1242 }
1243 return ReadProperty<P>(property);
1244 }
1245
1246 P IManageProperties.LazyReadProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
1247 {
1248 return LazyReadProperty(propertyInfo, valueGenerator);
1249 }
1250
1251 P IManageProperties.LazyReadPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
1252 {
1253 return LazyReadPropertyAsync(propertyInfo, factory);
1254 }
1255
1256#endregion
1257
1258#region Load Properties
1259
1275 protected void LoadPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue)
1276 {
1277 try
1278 {
1279 P oldValue = default(P);
1280 var fieldData = FieldManager.GetFieldData(propertyInfo);
1281 if (fieldData == null)
1282 {
1283 oldValue = propertyInfo.DefaultValue;
1284 fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);
1285 }
1286 else
1287 {
1288 oldValue = (P)fieldData.Value;
1289 }
1290
1291 if (oldValue == null)
1292 {
1293 if (newValue != null)
1294 FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));
1295 }
1296 else if (!(oldValue.Equals(newValue)))
1297 {
1298 FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));
1299 }
1300 }
1301 catch (Exception ex)
1302 {
1303 throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));
1304 }
1305 }
1306
1307 void Core.IManageProperties.LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
1308 {
1309 LoadProperty<P>(propertyInfo, newValue);
1310 }
1311
1312 bool Core.IManageProperties.FieldExists(Core.IPropertyInfo property)
1313 {
1314 return FieldManager.FieldExists(property);
1315 }
1316
1335 protected void LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
1336 {
1337 try
1338 {
1339 P oldValue = default(P);
1340 var fieldData = FieldManager.GetFieldData(propertyInfo);
1341 if (fieldData == null)
1342 {
1343 oldValue = propertyInfo.DefaultValue;
1344 fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);
1345 }
1346 else
1347 {
1348 oldValue = (P)fieldData.Value;
1349 }
1350
1351 if (oldValue == null)
1352 {
1353 if (newValue != null)
1354 FieldManager.LoadFieldData(propertyInfo, newValue);
1355 }
1356 else if (!(oldValue.Equals(newValue)))
1357 {
1358 FieldManager.LoadFieldData(propertyInfo, newValue);
1359 }
1360 }
1361 catch (Exception ex)
1362 {
1363 throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));
1364 }
1365 }
1366
1382 protected virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)
1383 {
1384 var t = this.GetType();
1385 var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1386 var method = t.GetMethods(flags).Where(c => c.Name == "LoadProperty" && c.IsGenericMethod).FirstOrDefault();
1387 var gm = method.MakeGenericMethod(propertyInfo.Type);
1388 var p = new object[] { propertyInfo, newValue };
1389 gm.Invoke(this, p);
1390 }
1391
1392 //private AsyncLoadManager
1393 [NonSerialized]
1394 private AsyncLoadManager _loadManager;
1395 internal AsyncLoadManager LoadManager
1396 {
1397 get
1398 {
1399 if (_loadManager == null)
1400 {
1401 _loadManager = new AsyncLoadManager(this, OnPropertyChanged);
1402 _loadManager.BusyChanged += loadManager_BusyChanged;
1403 _loadManager.UnhandledAsyncException += loadManager_UnhandledAsyncException;
1404 }
1405 return _loadManager;
1406 }
1407 }
1408
1409 void loadManager_UnhandledAsyncException(object sender, Csla.Core.ErrorEventArgs e)
1410 {
1412 }
1413
1414 void loadManager_BusyChanged(object sender, BusyChangedEventArgs e)
1415 {
1416 OnBusyChanged(e);
1417 }
1418 /*
1426 //protected void LoadPropertyAsync<R>(PropertyInfo<R> property, AsyncFactoryDelegate<R> factory)
1427 //{
1428 // LoadManager.BeginLoad(new AsyncLoader<R>(property, factory));
1429 //}
1430
1439 //protected void LoadPropertyAsync<R, P>(PropertyInfo<R> property, AsyncFactoryDelegate<R, P> factory, P parameter)
1440 //{
1441 // LoadManager.BeginLoad(new AsyncLoader<R>(property, factory, parameter));
1442 //}
1443 */
1444
1451 protected void LoadPropertyAsync<R>(PropertyInfo<R> property, Task<R> factory)
1452 {
1453 LoadManager.BeginLoad(new TaskLoader<R>(property, factory));
1454 }
1455#endregion
1456
1457#region Field Manager
1458
1459 [NotUndoable()]
1460 private FieldDataManager _fieldManager;
1461
1467 {
1468 get
1469 {
1470 if (_fieldManager == null)
1471 {
1472 _fieldManager = new FieldDataManager(ApplicationContext, this.GetType());
1473 }
1474 return _fieldManager;
1475 }
1476 }
1477
1478 FieldDataManager IUseFieldManager.FieldManager => FieldManager;
1479
1480#endregion
1481
1482#region IsBusy / IsIdle
1483
1484 [NonSerialized]
1485 [NotUndoable]
1486 private bool _isBusy;
1487
1492 [EditorBrowsable(EditorBrowsableState.Advanced)]
1493 protected void MarkBusy()
1494 {
1495 if (_isBusy)
1496 throw new InvalidOperationException(Resources.BusyObjectsMayNotBeMarkedBusy);
1497
1498 _isBusy = true;
1499 OnBusyChanged(new BusyChangedEventArgs("", true));
1500 }
1501
1506 [EditorBrowsable(EditorBrowsableState.Advanced)]
1507 protected void MarkIdle()
1508 {
1509 _isBusy = false;
1510 OnBusyChanged(new BusyChangedEventArgs("", false));
1511 }
1512
1518 [Browsable(false)]
1519 [Display(AutoGenerateField = false)]
1520 [ScaffoldColumn(false)]
1521 public virtual bool IsBusy
1522 {
1523 get { return IsSelfBusy || (_fieldManager != null && FieldManager.IsBusy()); }
1524 }
1525
1531 [Browsable(false)]
1532 [Display(AutoGenerateField = false)]
1533 [ScaffoldColumn(false)]
1534 public virtual bool IsSelfBusy
1535 {
1536 get { return _isBusy || LoadManager.IsLoading; }
1537 }
1538
1539 void Child_PropertyBusy(object sender, BusyChangedEventArgs e)
1540 {
1541 OnBusyChanged(e);
1542 }
1543
1544 [NotUndoable]
1545 [NonSerialized]
1546 private BusyChangedEventHandler _propertyBusy;
1547
1553 {
1554 add { _propertyBusy = (BusyChangedEventHandler)Delegate.Combine(_propertyBusy, value); }
1555 remove { _propertyBusy = (BusyChangedEventHandler)Delegate.Remove(_propertyBusy, value); }
1556 }
1557
1564 [EditorBrowsable(EditorBrowsableState.Advanced)]
1565 protected void OnBusyChanged(string propertyName, bool busy)
1566 {
1567 OnBusyChanged(new BusyChangedEventArgs(propertyName, busy));
1568 }
1569
1574 [EditorBrowsable(EditorBrowsableState.Advanced)]
1575 protected virtual void OnBusyChanged(BusyChangedEventArgs args)
1576 {
1577 if (_propertyBusy != null)
1578 _propertyBusy(this, args);
1579 }
1580
1581#endregion
1582
1583#region IDataPortalTarget Members
1584
1585 void Csla.Server.IDataPortalTarget.CheckRules()
1586 { }
1587
1588 void Csla.Server.IDataPortalTarget.MarkAsChild()
1589 { }
1590
1591 void Csla.Server.IDataPortalTarget.MarkNew()
1592 { }
1593
1594 void Csla.Server.IDataPortalTarget.MarkOld()
1595 { }
1596
1597 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
1598 {
1600 }
1601
1602 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
1603 {
1605 }
1606
1607 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
1608 {
1610 }
1611
1612 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)
1613 {
1615 }
1616
1617 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
1618 {
1620 }
1621
1622 void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
1623 {
1624 this.Child_OnDataPortalException(e, ex);
1625 }
1626
1627#endregion
1628
1629#region IManageProperties Members
1630
1631 bool IManageProperties.HasManagedProperties
1632 {
1633 get { return (_fieldManager != null && _fieldManager.HasFields); }
1634 }
1635
1636 List<IPropertyInfo> IManageProperties.GetManagedProperties()
1637 {
1639 }
1640
1641 object IManageProperties.GetProperty(IPropertyInfo propertyInfo)
1642 {
1643 return GetProperty(propertyInfo);
1644 }
1645
1646 object IManageProperties.LazyGetProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
1647 {
1648 return LazyGetProperty(propertyInfo, valueGenerator);
1649 }
1650
1651 object IManageProperties.LazyGetPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
1652 {
1653 return LazyGetPropertyAsync(propertyInfo, factory);
1654 }
1655
1656 object IManageProperties.ReadProperty(IPropertyInfo propertyInfo)
1657 {
1658 return ReadProperty(propertyInfo);
1659 }
1660
1661 P IManageProperties.ReadProperty<P>(PropertyInfo<P> propertyInfo)
1662 {
1663 return ReadProperty<P>(propertyInfo);
1664 }
1665
1666 void IManageProperties.SetProperty(IPropertyInfo propertyInfo, object newValue)
1667 {
1668 throw new NotImplementedException("IManageProperties.SetProperty");
1669 }
1670
1671 void IManageProperties.LoadProperty(IPropertyInfo propertyInfo, object newValue)
1672 {
1673 LoadProperty(propertyInfo, newValue);
1674 }
1675
1676 bool IManageProperties.LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)
1677 {
1678 LoadProperty(propertyInfo, newValue);
1679 return false;
1680 }
1681
1682 List<object> IManageProperties.GetChildren()
1683 {
1684 return FieldManager.GetChildren();
1685 }
1686#endregion
1687
1688#region MobileFormatter
1689
1701 protected override void OnGetChildren(
1703 {
1704 base.OnGetChildren(info, formatter);
1705 if (_fieldManager != null)
1706 {
1707 var fieldManagerInfo = formatter.SerializeObject(_fieldManager);
1708 info.AddChild("_fieldManager", fieldManagerInfo.ReferenceId);
1709 }
1710 }
1711
1724 {
1725 if (info.Children.ContainsKey("_fieldManager"))
1726 {
1727 var childData = info.Children["_fieldManager"];
1728 _fieldManager = (FieldDataManager)formatter.GetObject(childData.ReferenceId);
1729 }
1730 base.OnSetChildren(info, formatter);
1731 }
1732
1733#endregion
1734
1735#region INotifyUnhandledAsyncException Members
1736
1737 [NotUndoable]
1738 [NonSerialized]
1739 private EventHandler<Csla.Core.ErrorEventArgs> _unhandledAsyncException;
1740
1746 {
1747 add { _unhandledAsyncException = (EventHandler<Csla.Core.ErrorEventArgs>)Delegate.Combine(_unhandledAsyncException, value); }
1748 remove { _unhandledAsyncException = (EventHandler<Csla.Core.ErrorEventArgs>)Delegate.Remove(_unhandledAsyncException, value); }
1749 }
1750
1755 [EditorBrowsable(EditorBrowsableState.Advanced)]
1757 {
1758 if (_unhandledAsyncException != null)
1759 _unhandledAsyncException(this, error);
1760 }
1761
1768 [EditorBrowsable(EditorBrowsableState.Advanced)]
1769 protected void OnUnhandledAsyncException(object originalSender, Exception error)
1770 {
1771 OnUnhandledAsyncException(new Csla.Core.ErrorEventArgs(originalSender, error));
1772 }
1773
1774#endregion
1775 }
1776}
Provides consistent context information between the client and server DataPortal objects.
object CreateInstanceDI(Type objectType, params object[] parameters)
Creates an object using 'Activator.CreateInstance' using service provider (if one is available) to po...
IPrincipal User
Get or set the current IPrincipal object representing the user's identity.
This class implements INotifyPropertyChanged and INotifyPropertyChanging in a serialization-safe mann...
Definition: BindableBase.cs:23
virtual void OnPropertyChanged(string propertyName)
Call this method to raise the PropertyChanged event for a specific property.
Definition: BindableBase.cs:85
Event arguments for the BusyChanged event.
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.
override void OnSetChildren(SerializationInfo info, MobileFormatter formatter)
Deserializes child objects.
IFieldData GetFieldData(IPropertyInfo propertyInfo)
Gets the IFieldData object for a specific field.
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.
Provides information about the DataPortal call.
Maintains metadata about a method.
Definition: MethodInfo.cs:19
MethodInfo(string name)
Creates an instance of the type.
Definition: MethodInfo.cs:24
A strongly-typed resource class, for looking up localized strings, etc.
static string CreateNotSupportedException
Looks up a localized string similar to Invalid operation - create not allowed.
static string PrivateFieldException
Looks up a localized string similar to Properties with private backing fields must be marked as Relat...
static string DeleteNotSupportedException
Looks up a localized string similar to Invalid operation - delete not allowed.
static string PropertyGetNotAllowed
Looks up a localized string similar to Property get not allowed.
static string UpdateNotSupportedException
Looks up a localized string similar to Invalid operation - update 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.
string Name
Gets the property name value.
Exception indicating a failure to set a property's field.
This is a base class from which readonly business classes can be derived.
Definition: ReadOnlyBase.cs:55
virtual bool IsSelfBusy
Gets a value indicating whether this object is running an async operation.
virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)
Called by the server-side DataPortal prior to calling the requested DataPortal_XYZ method.
virtual void Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
Called by the server-side DataPortal after calling the requested DataPortal_XYZ method.
static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
Indicates that the specified method belongs to the type.
static PropertyInfo< P > RegisterProperty< P >(Type objectType, PropertyInfo< P > info)
Indicates that the specified property belongs to the type.
virtual void OnBusyChanged(BusyChangedEventArgs args)
Raises the BusyChanged event.
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_OnDataPortalInvoke(DataPortalEventArgs e)
Called by the server-side DataPortal prior to calling the requested DataPortal_xyz method.
virtual bool CanExecuteMethod(string methodName)
Returns true if the user is allowed to execute the specified method.
virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)
Returns true if the user is allowed to read the calling property.
virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
Called by the server-side DataPortal if an exception occurs during data access.
void LoadPropertyAsync< R >(PropertyInfo< R > property, Task< R > factory)
Load a property from an async method.
void MarkBusy()
Marks the object as being busy (it is running an async operation).
virtual object GetClone()
Creates a clone of the object.
virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)
Loads a property's managed field with the supplied value calling PropertyHasChanged if the value does...
void OnBusyChanged(string propertyName, bool busy)
Raises the BusyChanged event.
bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
Returns true if the user is allowed to read the calling property.
virtual object ReadProperty(IPropertyInfo propertyInfo)
Gets a property's value as a specified type.
virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
Called by the server-side DataPortal if an exception occurs during data access.
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...
EventHandler< Csla.Core.ErrorEventArgs > UnhandledAsyncException
Event raised when an exception occurs on a background thread during an asynchronous operation.
void LoadPropertyConvert< P, F >(PropertyInfo< P > propertyInfo, F newValue)
Loads a property's managed field with the supplied value calling PropertyHasChanged if the value does...
virtual void OnUnhandledAsyncException(Csla.Core.ErrorEventArgs error)
Raises the UnhandledAsyncException event.
override string ToString()
Returns a text representation of this object by returning the GetIdValue value in text form.
Definition: ReadOnlyBase.cs:76
P LazyGetProperty< P >(PropertyInfo< P > property, Func< P > valueGenerator)
Lazily initializes a property and returns the resulting value.
static MethodInfo RegisterMethod(Type objectType, string methodName)
Indicates that the specified method belongs to the type.
bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)
Returns true if the user is allowed to execute the specified method.
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...
static MethodInfo RegisterMethod(Expression< Action< T > > methodLambdaExpression)
Registers the method.
P LazyReadProperty< P >(PropertyInfo< P > property, Func< P > valueGenerator)
Gets a property's value as a specified type.
BusyChangedEventHandler BusyChanged
Event raised when the IsBusy property value has changed.
object GetProperty(IPropertyInfo propertyInfo)
Gets a property's value as a specified type.
BusinessRules BusinessRules
Provides access to the broken rules functionality.
bool CanReadProperty(string propertyName)
Returns true if the user is allowed to read the specified property.
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...
virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)
Returns true if the user is allowed to execute the specified method.
void MarkIdle()
Marks the object as being not busy (it is not running an async operation).
P LazyReadPropertyAsync< P >(PropertyInfo< P > property, Task< P > factory)
Gets a property's value as a specified type.
virtual object GetIdValue()
Override this method to return a unique identifying value for this object.
Definition: ReadOnlyBase.cs:62
P GetPropertyConvert< F, P >(PropertyInfo< F > propertyInfo, F field)
Gets a property's value as a specified type, first checking authorization.
void OnUnhandledAsyncException(object originalSender, Exception error)
Raises the UnhandledAsyncException event.
P ReadProperty< P >(PropertyInfo< P > propertyInfo)
Gets a property's value as a specified type.
virtual bool IsBusy
Gets a value indicating whether this object or any of its child objects are running an async operatio...
T Clone()
Creates a clone of the object.
FieldDataManager FieldManager
Gets the PropertyManager object for this business object.
virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
Called by the server-side DataPortal after calling the requested DataPortal_xyz method.
static MethodInfo RegisterMethod(string methodName)
Registers a method for use in Authorization.
ApplicationContext ApplicationContext
Gets or sets the current ApplicationContext object.
Definition: ReadOnlyBase.cs:90
bool PropertyIsLoading(IPropertyInfo propertyInfo)
Gets a value indicating whether a lazy loaded property is currently being retrieved.
P LazyGetPropertyAsync< P >(PropertyInfo< P > property, Task< P > factory)
Lazily initializes a property and returns the resulting value.
virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
This method is called on a newly deserialized object after deserialization is complete.
P GetProperty< P >(string propertyName, P field, P defaultValue)
Gets a property's value, first checking authorization.
ReadOnlyBase()
Creates an instance of the type.
virtual void AddBusinessRules()
Override this method to add per-type authorization rules for your type's properties.
Manages the list of rules for a business type.
Tracks the business rules for a business object.
BusinessRules()
Creates an instance of the type.
static bool HasPermission(ApplicationContext applicationContext, AuthorizationActions action, Type objectType)
Checks per-type authorization rules.
Serializes and deserializes objects at the field level.
Object containing the serialization data for a specific object.
Defines the members required by a field data storage object.
Definition: IFieldDataT.cs:15
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...
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
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.
Specifies that the object is a readonly business object.
Implement if a class requires access to the CSLA ApplicationContext type.
ApplicationContext ApplicationContext
Gets or sets the current ApplicationContext object.
This is a base class from which readonly business classes can be derived.
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...
bool CanWriteProperty(string propertyName)
Returns true if the user is allowed to write the to the specified property.
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.
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.
@ Delete
Delete operation.