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/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,
51 where T : ReadOnlyBase<T>
52 {
53 #region Object ID Value
54
59 protected virtual object GetIdValue()
60 {
61 return null;
62 }
63
64 #endregion
65
66 #region System.Object Overrides
67
73 public override string ToString()
74 {
75 object id = GetIdValue();
76 if (id == null)
77 return base.ToString();
78 else
79 return id.ToString();
80 }
81
82 #endregion
83
87 protected ReadOnlyBase()
88 {
89 Initialize();
90 InitializeBusinessRules();
91 }
92
93 #region Initialize
94
100 protected virtual void Initialize()
101 { /* allows subclass to initialize events before any other activity occurs */ }
102
103 #endregion
104
105 #region Identity
106
108 {
109 get { return 0; }
110 }
111
112 #endregion
113
114 #region Authorization
115
116 [NotUndoable()]
117 [NonSerialized()]
118 private ConcurrentDictionary<string, bool> _readResultCache;
119 [NotUndoable()]
120 [NonSerialized()]
121 private ConcurrentDictionary<string, bool> _executeResultCache;
122 [NotUndoable()]
123 [NonSerialized()]
124 private System.Security.Principal.IPrincipal _lastPrincipal;
125
126 private void InitializeBusinessRules()
127 {
128 var rules = BusinessRuleManager.GetRulesForType(this.GetType());
129 if (!rules.Initialized)
130 lock (rules)
131 if (!rules.Initialized)
132 {
133 try
134 {
136 rules.Initialized = true;
137 }
138 catch (Exception)
139 {
140 BusinessRuleManager.CleanupRulesForType(this.GetType());
141 throw; // and rethrow exception
142 }
143 }
144 }
145
146 private Csla.Rules.BusinessRules _businessRules;
147
157 {
158 get
159 {
160 if (_businessRules == null)
161 _businessRules = new BusinessRules(this);
162 else if (_businessRules.Target == null)
163 _businessRules.SetTarget(this);
164 return _businessRules;
165 }
166 }
167
168 void IHostRules.RuleStart(IPropertyInfo property)
169 { }
170
172 { }
173
174 void IHostRules.RuleComplete(string property)
175 { }
176
177 void Rules.IHostRules.AllRulesComplete()
178 { }
179
189 protected virtual void AddBusinessRules()
190 { }
191
197 [EditorBrowsable(EditorBrowsableState.Advanced)]
198 public virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)
199 {
200 bool result = true;
201
202 VerifyAuthorizationCache();
203
204 if (!_readResultCache.TryGetValue(property.Name, out result))
205 {
206 result = BusinessRules.HasPermission(AuthorizationActions.ReadProperty, property);
207 // store value in cache
208 _readResultCache.AddOrUpdate(property.Name, result, (a, b) => { return result; });
209 }
210 return result;
211 }
212
221 [EditorBrowsable(EditorBrowsableState.Advanced)]
222 public bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
223 {
224 bool result = CanReadProperty(property);
225 if (throwOnFalse && result == false)
226 {
228 String.Format("{0} ({1})",
229 Resources.PropertyGetNotAllowed, property.Name));
230 throw ex;
231 }
232 return result;
233 }
234
240 [EditorBrowsable(EditorBrowsableState.Advanced)]
241 public bool CanReadProperty(string propertyName)
242 {
243 return CanReadProperty(propertyName, false);
244 }
245
253 private bool CanReadProperty(string propertyName, bool throwOnFalse)
254 {
255 var propertyInfo = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Name == propertyName);
256 if (propertyInfo == null)
257 {
258#if NETFX_CORE || (ANDROID || IOS)
259#else
260 Trace.TraceError("CanReadProperty: {0} is not a registered property of {1}.{2}", propertyName, this.GetType().Namespace, this.GetType().Name);
261#endif
262 return true;
263 }
264 return CanReadProperty(propertyInfo, throwOnFalse);
265 }
266
267 bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(string propertyName)
268 {
269 return false;
270 }
271
273 {
274 return false;
275 }
276
277 private void VerifyAuthorizationCache()
278 {
279 if (_readResultCache == null)
280 _readResultCache = new ConcurrentDictionary<string, bool>();
281 if (_executeResultCache == null)
282 _executeResultCache = new ConcurrentDictionary<string, bool>();
283 if (!ReferenceEquals(Csla.ApplicationContext.User, _lastPrincipal))
284 {
285 // the principal has changed - reset the cache
286 _readResultCache.Clear();
287 _executeResultCache.Clear();
288 _lastPrincipal = Csla.ApplicationContext.User;
289 }
290 }
291
298 [EditorBrowsable(EditorBrowsableState.Advanced)]
299 public virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)
300 {
301 bool result = true;
302
303 VerifyAuthorizationCache();
304
305 if (!_executeResultCache.TryGetValue(method.Name, out result))
306 {
307 result = BusinessRules.HasPermission(AuthorizationActions.ExecuteMethod, method);
308 _executeResultCache.AddOrUpdate(method.Name, result, (a, b) => { return result; });
309 }
310 return result;
311 }
312
321 [EditorBrowsable(EditorBrowsableState.Advanced)]
322 public bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)
323 {
324
325 bool result = CanExecuteMethod(method);
326 if (throwOnFalse && result == false)
327 {
329 new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, method.Name));
330 throw ex;
331 }
332 return result;
333
334 }
335
336
343 [EditorBrowsable(EditorBrowsableState.Advanced)]
344 public virtual bool CanExecuteMethod(string methodName)
345 {
346 return CanExecuteMethod(methodName, false);
347 }
348
349 private bool CanExecuteMethod(string methodName, bool throwOnFalse)
350 {
351
352 bool result = CanExecuteMethod(new MethodInfo(methodName));
353 if (throwOnFalse && result == false)
354 {
355 Csla.Security.SecurityException ex = new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, methodName));
356 throw ex;
357 }
358 return result;
359 }
360
361#endregion
362
363#region IClonable
364
365 object ICloneable.Clone()
366 {
367 return GetClone();
368 }
369
374 [EditorBrowsable(EditorBrowsableState.Advanced)]
375 public virtual object GetClone()
376 {
377 return Core.ObjectCloner.Clone(this);
378 }
379
386 public T Clone()
387 {
388 return (T)GetClone();
389 }
390#endregion
391
392#region Data Access
393
394 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
395 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
396 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
397 private void DataPortal_Create(object criteria)
398 {
399 throw new NotSupportedException(Resources.CreateNotSupportedException);
400 }
401
402 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
403 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
404 private void DataPortal_Update()
405 {
406 throw new NotSupportedException(Resources.UpdateNotSupportedException);
407 }
408
409 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
410 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
411 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
412 [Delete]
413 private void DataPortal_Delete(object criteria)
414 {
415 throw new NotSupportedException(Resources.DeleteNotSupportedException);
416 }
417
423 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
424 [EditorBrowsable(EditorBrowsableState.Advanced)]
426 {
427
428 }
429
435 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
436 [EditorBrowsable(EditorBrowsableState.Advanced)]
438 {
439
440 }
441
448 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
449 [EditorBrowsable(EditorBrowsableState.Advanced)]
450 protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
451 {
452
453 }
454
460 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
461 [EditorBrowsable(EditorBrowsableState.Advanced)]
463 {
464 }
465
471 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
472 [EditorBrowsable(EditorBrowsableState.Advanced)]
474 {
475 }
476
483 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
484 [EditorBrowsable(EditorBrowsableState.Advanced)]
485 protected virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
486 {
487 }
488
489#endregion
490
491#region Serialization Notification
492
494 {
495 OnDeserializedHandler(new System.Runtime.Serialization.StreamingContext());
496 }
497
498 [System.Runtime.Serialization.OnDeserialized()]
499 private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)
500 {
501 if (_fieldManager != null)
502 FieldManager.SetPropertyList(this.GetType());
503 InitializeBusinessRules();
504 OnDeserialized(context);
505 }
506
512 [EditorBrowsable(EditorBrowsableState.Advanced)]
513 protected virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
514 {
515 // do nothing - this is here so a subclass
516 // could override if needed
517 }
518
519#endregion
520
521#region Register Properties
522
539 protected static PropertyInfo<P> RegisterProperty<P>(Type objectType, PropertyInfo<P> info)
540 {
541 return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(objectType, info);
542 }
543
558 {
559 return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(typeof(T), info);
560 }
561
569 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName)
570 {
571 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName));
572 }
573
581 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)
582 {
583 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
584 return RegisterProperty<P>(reflectedPropertyInfo.Name);
585 }
586
595 [Obsolete]
596 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, P defaultValue)
597 {
598 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
599
600 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), reflectedPropertyInfo.Name, reflectedPropertyInfo.Name, defaultValue));
601 }
602
611 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName)
612 {
613 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName));
614 }
615
624 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName)
625 {
626 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
627 return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName);
628 }
629
639 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue)
640 {
641 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue));
642 }
643
653 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue)
654 {
655 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
656 return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue);
657 }
658
667 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, RelationshipTypes relationship)
668 {
669 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, string.Empty, relationship));
670 }
671
680 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, RelationshipTypes relationship)
681 {
682 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
683 return RegisterProperty<P>(reflectedPropertyInfo.Name, relationship);
684 }
685
695 [Obsolete]
696 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, RelationshipTypes relationship)
697 {
698 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
699
700 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), reflectedPropertyInfo.Name, friendlyName, relationship));
701 }
702
713 protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue, RelationshipTypes relationship)
714 {
715 return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue, relationship));
716 }
717
728 protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue, RelationshipTypes relationship)
729 {
730 PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
731 return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue, relationship);
732 }
733 #endregion
734
735 #region Register Methods
736
750 protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
751 {
752 var reflected = objectType.GetMethod(info.Name);
753 if (reflected == null)
754 throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");
755 return info;
756 }
757
771 protected static MethodInfo RegisterMethod(Type objectType, string methodName)
772 {
773 var info = new MethodInfo(methodName);
774 RegisterMethod(objectType, info);
775 return info;
776 }
777
783 protected static MethodInfo RegisterMethod(string methodName)
784 {
785 return RegisterMethod(typeof(T), methodName);
786 }
787
793 protected static MethodInfo RegisterMethod(Expression<Action<T>> methodLambdaExpression)
794 {
795 System.Reflection.MethodInfo reflectedMethodInfo = Reflect<T>.GetMethod(methodLambdaExpression);
796 return RegisterMethod(reflectedMethodInfo.Name);
797 }
798
799#endregion
800
801#region Get Properties
802
821 protected P GetProperty<P>(string propertyName, P field, P defaultValue)
822 {
823 return GetProperty<P>(propertyName, field, defaultValue, Security.NoAccessBehavior.SuppressException);
824 }
825
842 protected P GetProperty<P>(string propertyName, P field, P defaultValue, Security.NoAccessBehavior noAccess)
843 {
844#region Check to see if the property is marked with RelationshipTypes.PrivateField
845
846 var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
847
848 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)
849 throw new InvalidOperationException(Resources.PrivateFieldException);
850
851#endregion
852
853 if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))
854 return field;
855
856 return defaultValue;
857 }
858
874 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)
875 {
876 return GetProperty<P>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException);
877 }
878
895 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field, P defaultValue, Security.NoAccessBehavior noAccess)
896 {
897 return GetProperty<P>(propertyInfo.Name, field, defaultValue, noAccess);
898 }
899
913 protected P LazyGetProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
914 {
915 if (!(FieldManager.FieldExists(property)))
916 {
917 var result = valueGenerator();
918 LoadProperty(property, result);
919 }
920 return GetProperty<P>(property);
921 }
922
923 private List<Csla.Core.IPropertyInfo> _lazyLoadingProperties = new List<Csla.Core.IPropertyInfo>();
924
945 protected P LazyGetPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
946 {
947 if (!(FieldManager.FieldExists(property)) && !_lazyLoadingProperties.Contains(property))
948 {
949 _lazyLoadingProperties.Add(property);
950 LoadPropertyAsync(property, factory);
951 }
952 return GetProperty<P>(property);
953 }
954
974 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field)
975 {
976 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException));
977 }
978
1001 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field, Security.NoAccessBehavior noAccess)
1002 {
1003 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, noAccess));
1004 }
1005
1020 protected P GetProperty<P>(PropertyInfo<P> propertyInfo)
1021 {
1022 return GetProperty<P>(propertyInfo, Security.NoAccessBehavior.SuppressException);
1023 }
1024
1044 {
1045 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, Security.NoAccessBehavior.SuppressException));
1046 }
1047
1069 protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, Security.NoAccessBehavior noAccess)
1070 {
1071 return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, noAccess));
1072 }
1073
1091 protected P GetProperty<P>(PropertyInfo<P> propertyInfo, Security.NoAccessBehavior noAccess)
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 P result = default(P);
1159 IFieldData data = FieldManager.GetFieldData(propertyInfo);
1160 if (data != null)
1161 {
1162 IFieldData<P> fd = data as IFieldData<P>;
1163 if (fd != null)
1164 result = fd.Value;
1165 else
1166 result = (P)data.Value;
1167 }
1168 else
1169 {
1170 result = propertyInfo.DefaultValue;
1171 FieldManager.LoadFieldData<P>(propertyInfo, result);
1172 }
1173 return result;
1174 }
1175
1181 protected virtual object ReadProperty(IPropertyInfo propertyInfo)
1182 {
1183 if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)
1184 {
1185 return MethodCaller.CallPropertyGetter(this, propertyInfo.Name);
1186 }
1187
1188 object result = null;
1189 var info = FieldManager.GetFieldData(propertyInfo);
1190 if (info != null)
1191 {
1192 result = info.Value;
1193 }
1194 else
1195 {
1196 result = propertyInfo.DefaultValue;
1197 FieldManager.LoadFieldData(propertyInfo, result);
1198 }
1199 return result;
1200 }
1201
1211 protected P LazyReadProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
1212 {
1213 if (!(FieldManager.FieldExists(property)))
1214 {
1215 var result = valueGenerator();
1216 LoadProperty(property, result);
1217 }
1218 return ReadProperty<P>(property);
1219 }
1220
1230 protected P LazyReadPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
1231 {
1232 if (!(FieldManager.FieldExists(property)) && !_lazyLoadingProperties.Contains(property))
1233 {
1234 _lazyLoadingProperties.Add(property);
1235 LoadPropertyAsync(property, factory);
1236 }
1237 return ReadProperty<P>(property);
1238 }
1239
1240 P IManageProperties.LazyReadProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
1241 {
1242 return LazyReadProperty(propertyInfo, valueGenerator);
1243 }
1244
1245 P IManageProperties.LazyReadPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
1246 {
1247 return LazyReadPropertyAsync(propertyInfo, factory);
1248 }
1249
1250#endregion
1251
1252#region Load Properties
1253
1269 protected void LoadPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue)
1270 {
1271 try
1272 {
1273 P oldValue = default(P);
1274 var fieldData = FieldManager.GetFieldData(propertyInfo);
1275 if (fieldData == null)
1276 {
1277 oldValue = propertyInfo.DefaultValue;
1278 fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);
1279 }
1280 else
1281 {
1282 oldValue = (P)fieldData.Value;
1283 }
1284
1285 if (oldValue == null)
1286 {
1287 if (newValue != null)
1288 FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));
1289 }
1290 else if (!(oldValue.Equals(newValue)))
1291 {
1292 FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));
1293 }
1294 }
1295 catch (Exception ex)
1296 {
1297 throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));
1298 }
1299 }
1300
1301 void Core.IManageProperties.LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
1302 {
1303 LoadProperty<P>(propertyInfo, newValue);
1304 }
1305
1306 bool Core.IManageProperties.FieldExists(Core.IPropertyInfo property)
1307 {
1308 return FieldManager.FieldExists(property);
1309 }
1310
1329 protected void LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
1330 {
1331 try
1332 {
1333 P oldValue = default(P);
1334 var fieldData = FieldManager.GetFieldData(propertyInfo);
1335 if (fieldData == null)
1336 {
1337 oldValue = propertyInfo.DefaultValue;
1338 fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);
1339 }
1340 else
1341 {
1342 oldValue = (P)fieldData.Value;
1343 }
1344
1345 if (oldValue == null)
1346 {
1347 if (newValue != null)
1348 FieldManager.LoadFieldData(propertyInfo, newValue);
1349 }
1350 else if (!(oldValue.Equals(newValue)))
1351 {
1352 FieldManager.LoadFieldData(propertyInfo, newValue);
1353 }
1354 }
1355 catch (Exception ex)
1356 {
1357 throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));
1358 }
1359 }
1360
1376 protected virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)
1377 {
1378 var t = this.GetType();
1379 var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
1380 var method = t.GetMethods(flags).Where(c => c.Name == "LoadProperty" && c.IsGenericMethod).FirstOrDefault();
1381 var gm = method.MakeGenericMethod(propertyInfo.Type);
1382 var p = new object[] { propertyInfo, newValue };
1383 gm.Invoke(this, p);
1384 }
1385
1386 //private AsyncLoadManager
1387 [NonSerialized]
1388 private AsyncLoadManager _loadManager;
1389 internal AsyncLoadManager LoadManager
1390 {
1391 get
1392 {
1393 if (_loadManager == null)
1394 {
1395 _loadManager = new AsyncLoadManager(this, OnPropertyChanged);
1396 _loadManager.BusyChanged += loadManager_BusyChanged;
1397 _loadManager.UnhandledAsyncException += loadManager_UnhandledAsyncException;
1398 }
1399 return _loadManager;
1400 }
1401 }
1402
1403 void loadManager_UnhandledAsyncException(object sender, ErrorEventArgs e)
1404 {
1406 }
1407
1408 void loadManager_BusyChanged(object sender, BusyChangedEventArgs e)
1409 {
1410 OnBusyChanged(e);
1411 }
1412 /*
1420 //protected void LoadPropertyAsync<R>(PropertyInfo<R> property, AsyncFactoryDelegate<R> factory)
1421 //{
1422 // LoadManager.BeginLoad(new AsyncLoader<R>(property, factory));
1423 //}
1424
1433 //protected void LoadPropertyAsync<R, P>(PropertyInfo<R> property, AsyncFactoryDelegate<R, P> factory, P parameter)
1434 //{
1435 // LoadManager.BeginLoad(new AsyncLoader<R>(property, factory, parameter));
1436 //}
1437 */
1438
1445 protected void LoadPropertyAsync<R>(PropertyInfo<R> property, Task<R> factory)
1446 {
1447 LoadManager.BeginLoad(new TaskLoader<R>(property, factory));
1448 }
1449#endregion
1450
1451#region Field Manager
1452
1453 [NotUndoable()]
1454 private FieldDataManager _fieldManager;
1455
1461 {
1462 get
1463 {
1464 if (_fieldManager == null)
1465 {
1466 _fieldManager = new FieldDataManager(this.GetType());
1467 }
1468 return _fieldManager;
1469 }
1470 }
1471
1472#endregion
1473
1474#region IsBusy / IsIdle
1475
1476 [NonSerialized]
1477 [NotUndoable]
1478 private bool _isBusy;
1479
1484 [EditorBrowsable(EditorBrowsableState.Advanced)]
1485 protected void MarkBusy()
1486 {
1487 if (_isBusy)
1488 throw new InvalidOperationException(Resources.BusyObjectsMayNotBeMarkedBusy);
1489
1490 _isBusy = true;
1491 OnBusyChanged(new BusyChangedEventArgs("", true));
1492 }
1493
1498 [EditorBrowsable(EditorBrowsableState.Advanced)]
1499 protected void MarkIdle()
1500 {
1501 _isBusy = false;
1502 OnBusyChanged(new BusyChangedEventArgs("", false));
1503 }
1504
1510 [Browsable(false)]
1511 [Display(AutoGenerateField = false)]
1512 [ScaffoldColumn(false)]
1513 public virtual bool IsBusy
1514 {
1515 get { return IsSelfBusy || (_fieldManager != null && FieldManager.IsBusy()); }
1516 }
1517
1523 [Browsable(false)]
1524 [Display(AutoGenerateField = false)]
1525 [ScaffoldColumn(false)]
1526 public virtual bool IsSelfBusy
1527 {
1528 get { return _isBusy || LoadManager.IsLoading; }
1529 }
1530
1531 void Child_PropertyBusy(object sender, BusyChangedEventArgs e)
1532 {
1533 OnBusyChanged(e);
1534 }
1535
1536 [NotUndoable]
1537 [NonSerialized]
1538 private BusyChangedEventHandler _propertyBusy;
1539
1545 {
1546 add { _propertyBusy = (BusyChangedEventHandler)Delegate.Combine(_propertyBusy, value); }
1547 remove { _propertyBusy = (BusyChangedEventHandler)Delegate.Remove(_propertyBusy, value); }
1548 }
1549
1556 [EditorBrowsable(EditorBrowsableState.Advanced)]
1557 protected void OnBusyChanged(string propertyName, bool busy)
1558 {
1559 OnBusyChanged(new BusyChangedEventArgs(propertyName, busy));
1560 }
1561
1566 [EditorBrowsable(EditorBrowsableState.Advanced)]
1567 protected virtual void OnBusyChanged(BusyChangedEventArgs args)
1568 {
1569 if (_propertyBusy != null)
1570 _propertyBusy(this, args);
1571 }
1572
1573#endregion
1574
1575#region IDataPortalTarget Members
1576
1577 void Csla.Server.IDataPortalTarget.CheckRules()
1578 { }
1579
1580 void Csla.Server.IDataPortalTarget.MarkAsChild()
1581 { }
1582
1583 void Csla.Server.IDataPortalTarget.MarkNew()
1584 { }
1585
1586 void Csla.Server.IDataPortalTarget.MarkOld()
1587 { }
1588
1589 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
1590 {
1592 }
1593
1594 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
1595 {
1597 }
1598
1599 void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
1600 {
1602 }
1603
1604 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)
1605 {
1607 }
1608
1609 void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
1610 {
1612 }
1613
1614 void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
1615 {
1616 this.Child_OnDataPortalException(e, ex);
1617 }
1618
1619#endregion
1620
1621#region IManageProperties Members
1622
1623 bool IManageProperties.HasManagedProperties
1624 {
1625 get { return (_fieldManager != null && _fieldManager.HasFields); }
1626 }
1627
1628 List<IPropertyInfo> IManageProperties.GetManagedProperties()
1629 {
1631 }
1632
1633 object IManageProperties.GetProperty(IPropertyInfo propertyInfo)
1634 {
1635 return GetProperty(propertyInfo);
1636 }
1637
1638 object IManageProperties.LazyGetProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
1639 {
1640 return LazyGetProperty(propertyInfo, valueGenerator);
1641 }
1642
1643 object IManageProperties.LazyGetPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
1644 {
1645 return LazyGetPropertyAsync(propertyInfo, factory);
1646 }
1647
1648 object IManageProperties.ReadProperty(IPropertyInfo propertyInfo)
1649 {
1650 return ReadProperty(propertyInfo);
1651 }
1652
1653 P IManageProperties.ReadProperty<P>(PropertyInfo<P> propertyInfo)
1654 {
1655 return ReadProperty<P>(propertyInfo);
1656 }
1657
1658 void IManageProperties.SetProperty(IPropertyInfo propertyInfo, object newValue)
1659 {
1660 throw new NotImplementedException("IManageProperties.SetProperty");
1661 }
1662
1663 void IManageProperties.LoadProperty(IPropertyInfo propertyInfo, object newValue)
1664 {
1665 LoadProperty(propertyInfo, newValue);
1666 }
1667
1668 bool IManageProperties.LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)
1669 {
1670 LoadProperty(propertyInfo, newValue);
1671 return false;
1672 }
1673
1674 List<object> IManageProperties.GetChildren()
1675 {
1676 return FieldManager.GetChildren();
1677 }
1678#endregion
1679
1680#region MobileFormatter
1681
1693 protected override void OnGetChildren(
1695 {
1696 base.OnGetChildren(info, formatter);
1697 if (_fieldManager != null)
1698 {
1699 var fieldManagerInfo = formatter.SerializeObject(_fieldManager);
1700 info.AddChild("_fieldManager", fieldManagerInfo.ReferenceId);
1701 }
1702 }
1703
1716 {
1717 if (info.Children.ContainsKey("_fieldManager"))
1718 {
1719 var childData = info.Children["_fieldManager"];
1720 _fieldManager = (FieldDataManager)formatter.GetObject(childData.ReferenceId);
1721 }
1722 base.OnSetChildren(info, formatter);
1723 }
1724
1725#endregion
1726
1727#region INotifyUnhandledAsyncException Members
1728
1729 [NotUndoable]
1730 [NonSerialized]
1731 private EventHandler<ErrorEventArgs> _unhandledAsyncException;
1732
1737 public event EventHandler<ErrorEventArgs> UnhandledAsyncException
1738 {
1739 add { _unhandledAsyncException = (EventHandler<ErrorEventArgs>)Delegate.Combine(_unhandledAsyncException, value); }
1740 remove { _unhandledAsyncException = (EventHandler<ErrorEventArgs>)Delegate.Remove(_unhandledAsyncException, value); }
1741 }
1742
1747 [EditorBrowsable(EditorBrowsableState.Advanced)]
1748 protected virtual void OnUnhandledAsyncException(ErrorEventArgs error)
1749 {
1750 if (_unhandledAsyncException != null)
1751 _unhandledAsyncException(this, error);
1752 }
1753
1760 [EditorBrowsable(EditorBrowsableState.Advanced)]
1761 protected void OnUnhandledAsyncException(object originalSender, Exception error)
1762 {
1763 OnUnhandledAsyncException(new ErrorEventArgs(originalSender, error));
1764 }
1765
1766#endregion
1767 }
1768}
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 object.
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.
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.
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...
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...
override string ToString()
Returns a text representation of this object by returning the GetIdValue value in text form.
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.
virtual void OnUnhandledAsyncException(ErrorEventArgs error)
Raises the UnhandledAsyncException event.
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.
EventHandler< ErrorEventArgs > UnhandledAsyncException
Event raised when an exception occurs on a background thread during an asynchronous operation.
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.
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 object.
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.
static bool HasPermission(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.
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.