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.
BusinessRules.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="BusinessRules.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Tracks the business rules for a business object.</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections;
10using System.ComponentModel;
11using System.Linq;
13using Csla.Reflection;
14using System.Collections.Generic;
16using Csla.Core;
17using System.Collections.ObjectModel;
18using System.Threading.Tasks;
19using Csla.Threading;
20
21namespace Csla.Rules
22{
27 public class BusinessRules :
29 {
30 [NonSerialized]
31 private object SyncRoot = new object();
32
33 // list of broken rules for this business object.
34 private BrokenRulesCollection _brokenRules;
35 private BrokenRulesCollection BrokenRules
36 {
37 get
38 {
39 if (_brokenRules == null)
40 _brokenRules = new BrokenRulesCollection(true);
41 return _brokenRules;
42 }
43 }
44
45 private bool _suppressRuleChecking;
53 {
54 get { return _suppressRuleChecking; }
55 set { _suppressRuleChecking = value; }
56 }
57
58 private int _processThroughPriority;
64 {
65 get { return _processThroughPriority; }
66 set { _processThroughPriority = value; }
67 }
68
69 private string _ruleSet = null;
74 public string RuleSet
75 {
76 get { return string.IsNullOrEmpty(_ruleSet) ? ApplicationContext.DefaultRuleSet : _ruleSet; }
77 set
78 {
79 _typeRules = null;
80 _typeAuthRules = null;
81 _ruleSet = value == ApplicationContext.DefaultRuleSet ? null : value;
82 if (BrokenRules.Count > 0)
83 {
84 BrokenRules.ClearRules();
85 }
86 }
87 }
88
96 {
97 get { return _cascadeOnDirtyProperties; }
98 set { _cascadeOnDirtyProperties = value; }
99 }
100
101
102 [NonSerialized]
103 private BusinessRuleManager _typeRules;
104 internal BusinessRuleManager TypeRules
105 {
106 get
107 {
108 if (_typeRules == null && _target != null)
109 _typeRules = BusinessRuleManager.GetRulesForType(_target.GetType(), _ruleSet);
110 return _typeRules;
111 }
112 }
113
114 [NonSerialized]
115 private AuthorizationRuleManager _typeAuthRules;
116 internal AuthorizationRuleManager TypeAuthRules
117 {
118 get
119 {
120 if (_typeAuthRules == null && _target != null)
121 _typeAuthRules = AuthorizationRuleManager.GetRulesForType(_target.GetType(), _ruleSet);
122 return _typeAuthRules;
123 }
124 }
125
131 public string[] GetRuleDescriptions()
132 {
133 var result = new List<string>();
134 foreach (var item in TypeRules.Rules)
135 result.Add(item.RuleName);
136 return result.ToArray();
137 }
138
139 // reference to current business object
140 [NonSerialized]
141 private IHostRules _target;
142
143 internal void SetTarget(IHostRules target)
144 {
145 _target = target;
146 }
147
148 internal object Target
149 {
150 get { return _target; }
151 }
152
157 { }
158
163 internal BusinessRules(IHostRules target)
164 {
165 SetTarget(target);
166 }
167
172 public void AddRule(IBusinessRuleBase rule)
173 {
174 TypeRules.Rules.Add(rule);
175 }
176
182 public void AddRule(IBusinessRuleBase rule, string ruleSet)
183 {
184 var typeRules = BusinessRuleManager.GetRulesForType(_target.GetType(), ruleSet);
185 typeRules.Rules.Add(rule);
186 }
187
192 public void AddRule(IAuthorizationRule rule)
193 {
194 EnsureUniqueRule(TypeAuthRules, rule);
195 TypeAuthRules.Rules.Add(rule);
196 }
197
204 public static void AddRule(Type objectType, IAuthorizationRule rule)
205 {
206 AddRule(objectType, rule, ApplicationContext.RuleSet);
207 }
208
216 public static void AddRule(Type objectType, IAuthorizationRule rule, string ruleSet)
217 {
218 var typeRules = AuthorizationRuleManager.GetRulesForType(objectType, ruleSet);
219 EnsureUniqueRule(typeRules, rule);
220 typeRules.Rules.Add(rule);
221 }
222
223 private static void EnsureUniqueRule(AuthorizationRuleManager mgr, IAuthorizationRule rule)
224 {
225 IAuthorizationRule oldRule = null;
226 if (rule.Element != null)
227 oldRule = mgr.Rules.FirstOrDefault(c => c.Element != null && c.Element.Name == rule.Element.Name && c.Action == rule.Action);
228 else
229 oldRule = mgr.Rules.FirstOrDefault(c => c.Element == null && c.Action == rule.Action);
230 if (oldRule != null)
231 throw new ArgumentException("rule");
232 }
233
239 public bool IsValid
240 {
241 get { return BrokenRules.ErrorCount == 0; }
242 }
243
248 {
249 return BrokenRules;
250 }
251
252 [NonSerialized]
253 private bool _runningRules;
258 public bool RunningRules
259 {
260 get { return _runningRules; }
261 private set { _runningRules = value; }
262 }
263
264 [NonSerialized]
265 private bool _isBusy;
266
267 [NonSerialized]
268 private AsyncManualResetEvent _busyChanged;
269 private AsyncManualResetEvent BusyChanged
270 {
271 get
272 {
273 if (_busyChanged == null)
274 _busyChanged = new AsyncManualResetEvent();
275 return _busyChanged;
276 }
277 }
278
284 {
285 get { return _isBusy; }
286 set
287 {
288 _isBusy = value;
289 if (_isBusy)
290 BusyChanged.Reset();
291 else
292 BusyChanged.Set();
293 }
294 }
295
302 {
303 return BusyProperties.Contains(property);
304 }
305
311 public static bool HasPermission(AuthorizationActions action, Type objectType)
312 {
313 objectType = ApplicationContext.DataPortalActivator.ResolveType(objectType);
314 // no object specified so must use RuleSet from ApplicationContext
315 return HasPermission(action, null, objectType, null, ApplicationContext.RuleSet);
316 }
317
324 public static bool HasPermission(AuthorizationActions action, Type objectType, object[] criteria)
325 {
326 objectType = ApplicationContext.DataPortalActivator.ResolveType(objectType);
327 // no object specified so must use RuleSet from ApplicationContext
328 return HasPermission(action, null, objectType, criteria, ApplicationContext.RuleSet);
329 }
330
340 public static bool HasPermission(AuthorizationActions action, Type objectType, string ruleSet)
341 {
342 return HasPermission(action, null, objectType, null, ruleSet);
343 }
344
350 public static bool HasPermission(AuthorizationActions action, object obj)
351 {
352 return HasPermission(action, obj, obj.GetType(), null, ApplicationContext.RuleSet);
353 }
354
364 public static bool HasPermission(AuthorizationActions action, object obj, string ruleSet)
365 {
366 return HasPermission(action, obj, obj.GetType(), null, ruleSet);
367 }
368
369 private static bool HasPermission(AuthorizationActions action, object obj, Type objType, object[] criteria, string ruleSet)
370 {
371
372 if (action == AuthorizationActions.ReadProperty ||
373 action == AuthorizationActions.WriteProperty ||
374 action == AuthorizationActions.ExecuteMethod)
375 throw new ArgumentOutOfRangeException(nameof(action));
376
377 bool result = true;
378 var rule =
379 AuthorizationRuleManager.GetRulesForType(objType, ruleSet).Rules.FirstOrDefault(c => c.Element == null && c.Action == action);
380 if (rule != null)
381 {
382 var context = new AuthorizationContext { Rule = rule, Target = obj, TargetType = objType, Criteria = criteria };
383 rule.Execute(context);
384 result = context.HasPermission;
385 }
386 return result;
387 }
388
395 {
396 if (_suppressRuleChecking)
397 return true;
398
399 if (action == AuthorizationActions.CreateObject ||
400 action == AuthorizationActions.DeleteObject ||
401 action == AuthorizationActions.GetObject ||
402 action == AuthorizationActions.EditObject)
403 throw new ArgumentOutOfRangeException(nameof(action));
404
405 bool result = true;
406 var rule =
407 TypeAuthRules.Rules.FirstOrDefault(c => c.Element != null && c.Element.Name == element.Name && c.Action == action);
408 if (rule != null)
409 {
410 var context = new AuthorizationContext { Rule = rule, Target = this.Target, TargetType = this.Target.GetType() };
411 rule.Execute(context);
412 result = context.HasPermission;
413 }
414 return result;
415 }
416
424 {
425 // cannot cache result when suppressRuleChecking as HasPermission is then short circuited to return true.
426 if (_suppressRuleChecking)
427 return false;
428
429 bool result = true;
430 var rule =
431 TypeAuthRules.Rules.FirstOrDefault(c => c.Element != null && c.Element.Name == element.Name && c.Action == action);
432 if (rule != null)
433 result = rule.CacheResult;
434 return result;
435 }
436
446 public async Task<List<string>> CheckRulesAsync(int timeout)
447 {
448 var result = CheckRules();
450 {
451 var tasks = new Task[] { BusyChanged.WaitAsync(), Task.Delay(timeout) };
452 var final = await Task.WhenAny(tasks);
453 if (final == tasks[1])
454 throw new TimeoutException(nameof(CheckRulesAsync));
455 }
456 return result;
457 }
458
467 public async Task<List<string>> CheckRulesAsync()
468 {
469 return await CheckRulesAsync(int.MaxValue);
470 }
471
480 public List<string> CheckRules()
481 {
482 if (_suppressRuleChecking)
483 return new List<string>();
484
485 RunningRules = true;
486 var affectedProperties = CheckObjectRules(RuleContextModes.CheckRules, false);
487 var properties = TypeRules.Rules.Where(p => p.PrimaryProperty != null)
488 .Select(p => p.PrimaryProperty)
489 .Distinct();
490 foreach (var property in properties)
491 affectedProperties.AddRange(CheckRules(property, RuleContextModes.CheckRules));
492 RunningRules = false;
494 _target.AllRulesComplete();
495 return affectedProperties.Distinct().ToList();
496 }
497
507 public List<string> CheckObjectRules()
508 {
509 return CheckObjectRules(RuleContextModes.CheckObjectRules, true);
510 }
511
512
522 private List<string> CheckObjectRules(RuleContextModes executionContext, bool cascade)
523 {
524 if (_suppressRuleChecking)
525 return new List<string>();
526
527 var oldRR = RunningRules;
528 RunningRules = true;
529 var rules = from r in TypeRules.Rules
530 where r.PrimaryProperty == null
531 && CanRunRule(r, executionContext)
532 orderby r.Priority
533 select r;
534 BrokenRules.ClearRules(null);
535 // Changed to cascade propertyrule to make async ObjectLevel rules rerun PropertLevel rules.
536 var firstResult = RunRules(rules, false, executionContext);
537
538 // rerun property level rules for affected properties
539 if (cascade)
540 {
541 var propertiesToRun = new List<Csla.Core.IPropertyInfo>();
542 foreach (var item in rules)
543 if (!item.IsAsync)
544 {
545 foreach (var p in item.AffectedProperties)
546 propertiesToRun.Add(p);
547 }
548 // run rules for affected properties
549 foreach (var item in propertiesToRun.Distinct())
550 {
551 var doCascade = false;
553 doCascade = firstResult.DirtyProperties.Any(p => p == item.Name);
554 firstResult.AffectedProperties.AddRange(CheckRulesForProperty(item, doCascade,
555 executionContext | RuleContextModes.AsAffectedPoperty));
556 }
557 }
558
559 RunningRules = oldRR;
561 _target.AllRulesComplete();
562 return firstResult.AffectedProperties.Distinct().ToList();
563 }
564
575 public List<string> CheckRules(Csla.Core.IPropertyInfo property)
576 {
577 return CheckRules(property, RuleContextModes.PropertyChanged);
578 }
579
580 private List<string> CheckRules(Csla.Core.IPropertyInfo property, RuleContextModes executionContext)
581 {
582 if (property == null)
583 throw new ArgumentNullException("property");
584
585 if (_suppressRuleChecking)
586 return new List<string>();
587
588 var oldRR = RunningRules;
589 RunningRules = true;
590
591 var affectedProperties = new List<string>();
592 affectedProperties.AddRange(CheckRulesForProperty(property, true, executionContext));
593
594 RunningRules = oldRR;
596 _target.AllRulesComplete();
597 return affectedProperties.Distinct().ToList();
598 }
599
608 internal static bool CanRunRule(IBusinessRuleBase rule, RuleContextModes contextMode)
609 {
610 // default then just return true
611 if (rule.RunMode == RunModes.Default) return true;
612
613 bool canRun = true;
614
615 if ((contextMode & RuleContextModes.AsAffectedPoperty) > 0)
616 canRun &= (rule.RunMode & RunModes.DenyAsAffectedProperty) == 0;
617
618 if ((rule.RunMode & RunModes.DenyOnServerSidePortal) > 0)
619 canRun &= ApplicationContext.LogicalExecutionLocation != ApplicationContext.LogicalExecutionLocations.Server;
620
621 if ((contextMode & RuleContextModes.CheckRules) > 0)
622 canRun &= (rule.RunMode & RunModes.DenyCheckRules) == 0;
623
624 return canRun;
625 }
626
634 private List<string> CheckRulesForProperty(Csla.Core.IPropertyInfo property, bool cascade, RuleContextModes executionContext)
635 {
636 var rules = from r in TypeRules.Rules
637 where ReferenceEquals(r.PrimaryProperty, property)
638 && CanRunRule(r, executionContext)
639 orderby r.Priority
640 select r;
641
642 BrokenRules.ClearRules(property);
643 var firstResult = RunRules(rules, cascade, executionContext);
645 cascade = cascade || firstResult.DirtyProperties.Any();
646 if (cascade)
647 {
648 // get properties affected by all rules
649 var propertiesToRun = new List<Csla.Core.IPropertyInfo>();
650 foreach (var item in rules)
651 if (!item.IsAsync)
652 {
653 foreach (var p in item.AffectedProperties)
654 if (!ReferenceEquals(property, p))
655 propertiesToRun.Add(p);
656 }
657
658 // add PrimaryProperty where property is in InputProperties
659 var input = from r in TypeRules.Rules
660 where !ReferenceEquals(r.PrimaryProperty, property)
661 && r.PrimaryProperty != null
662 && r.InputProperties != null
663 && r.InputProperties.Contains(property)
664 select r.PrimaryProperty;
665
666 foreach (var p in input)
667 {
668 if (!ReferenceEquals(property, p))
669 propertiesToRun.Add(p);
670 }
671 // run rules for affected properties
672 foreach (var item in propertiesToRun.Distinct())
673 {
674 var doCascade = false;
676 doCascade = firstResult.DirtyProperties.Any(p => p == item.Name);
677 firstResult.AffectedProperties.AddRange(CheckRulesForProperty(item, doCascade,
678 executionContext | RuleContextModes.AsAffectedPoperty));
679 }
680 }
681
682 // always make sure to add PrimaryProperty
683 firstResult.AffectedProperties.Add(property.Name);
684 return firstResult.AffectedProperties.Distinct().ToList();
685 }
686
687 [NonSerialized]
688 private List<Csla.Core.IPropertyInfo> _busyProperties;
689
690 private bool _cascadeOnDirtyProperties;
691
692 private List<Csla.Core.IPropertyInfo> BusyProperties
693 {
694 get
695 {
696 if (_busyProperties == null)
697 _busyProperties = new List<Csla.Core.IPropertyInfo>();
698 return _busyProperties;
699 }
700 }
701
709 private RunRulesResult RunRules(IEnumerable<IBusinessRuleBase> rules, bool cascade, RuleContextModes executionContext)
710 {
711 var affectedProperties = new List<string>();
712 var dirtyProperties = new List<string>();
713 bool anyRuleBroken = false;
714 foreach (var rule in rules)
715 {
716 // implicit short-circuiting
717 if (anyRuleBroken && rule.Priority > ProcessThroughPriority)
718 break;
719 bool complete = false;
720 // set up context
721 var context = new RuleContext((r) =>
722 {
723 if (r.Rule.IsAsync)
724 {
725 lock (SyncRoot)
726 {
727 // update output values
728 if (r.OutputPropertyValues != null)
729 foreach (var item in r.OutputPropertyValues)
730 {
731 // value is changed add to dirtyValues
732 if (((IManageProperties)_target).LoadPropertyMarkDirty(item.Key, item.Value))
733 r.AddDirtyProperty(item.Key);
734 }
735 // update broken rules list
736 BrokenRules.SetBrokenRules(r.Results, r.OriginPropertyName);
737
738 // run rules on affected properties for this async rule
739 var affected = new List<string>();
740 if (cascade)
741 foreach (var item in r.Rule.AffectedProperties.Distinct())
742 if (!ReferenceEquals(r.Rule.PrimaryProperty, item))
743 {
744 var doCascade = false;
745 if (CascadeOnDirtyProperties && (r.DirtyProperties != null))
746 doCascade = r.DirtyProperties.Any(p => p.Name == item.Name);
747 affected.AddRange(CheckRulesForProperty(item, doCascade, r.ExecuteContext | RuleContextModes.AsAffectedPoperty));
748 }
749
750 // mark each property as not busy
751 foreach (var item in r.Rule.AffectedProperties)
752 {
753 BusyProperties.Remove(item);
754 RunningAsyncRules = BusyProperties.Count > 0;
755 if (!BusyProperties.Contains(item))
756 _target.RuleComplete(item);
757 }
758
759 foreach (var property in affected.Distinct())
760 {
761 // property is not in AffectedProperties (already signalled to UI)
762 if (!r.Rule.AffectedProperties.Any(p => p.Name == property))
763 _target.RuleComplete(property);
764 }
765
766 if (!RunningRules && !RunningAsyncRules)
767 _target.AllRulesComplete();
768 }
769 }
770 else // Rule is Sync
771 {
772 // update output values
773 if (r.OutputPropertyValues != null)
774 foreach (var item in r.OutputPropertyValues)
775 {
776 // value is changed add to dirtyValues
777 if (((IManageProperties)_target).LoadPropertyMarkDirty(item.Key, item.Value))
778 r.AddDirtyProperty(item.Key);
779 }
780
781 // update broken rules list
782 if (r.Results != null)
783 {
784 BrokenRules.SetBrokenRules(r.Results, r.OriginPropertyName);
785
786 // is any rules here broken with severity Error
787 if (r.Results.Any(p => !p.Success && p.Severity == RuleSeverity.Error))
788 anyRuleBroken = true;
789 }
790
791 complete = true;
792 }
793 })
794 {
795 Rule = rule
796 };
797 if (rule.PrimaryProperty != null)
798 context.OriginPropertyName = rule.PrimaryProperty.Name;
799 context.ExecuteContext = executionContext;
800 if (!rule.IsAsync || rule.ProvideTargetWhenAsync)
801 context.Target = _target;
802
803 // get input properties
804 if (rule.InputProperties != null)
805 {
806 var target = (IManageProperties) _target;
807 context.InputPropertyValues = new Dictionary<IPropertyInfo, object>();
808 foreach (var item in rule.InputProperties)
809 {
810 // do not add lazy loaded fields that have no field data.
811 if ((item.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad)
812 {
813 if (target.FieldExists(item))
814 context.InputPropertyValues.Add(item, target.ReadProperty(item));
815 }
816 else
817 context.InputPropertyValues.Add(item, target.ReadProperty(item));
818 }
819 }
820
821 // mark properties busy
822 if (rule.IsAsync)
823 {
824 lock (SyncRoot)
825 {
826 // mark each property as busy
827 foreach (var item in rule.AffectedProperties)
828 {
829 var alreadyBusy = BusyProperties.Contains(item);
830 BusyProperties.Add(item);
831 RunningAsyncRules = true;
832 if (!alreadyBusy)
833 _target.RuleStart(item);
834 }
835 }
836 }
837
838 // execute (or start executing) rule
839 try
840 {
841 if (rule is IBusinessRule syncRule)
842 syncRule.Execute(context);
843 else if (rule is IBusinessRuleAsync asyncRule)
844 RunAsyncRule(asyncRule, context);
845 else
846 throw new ArgumentOutOfRangeException(rule.GetType().FullName);
847 }
848 catch (Exception ex)
849 {
850 context.AddErrorResult(string.Format("{0}:{1}", rule.RuleName, ex.Message));
851 if (rule.IsAsync)
852 context.Complete();
853 }
854
855 if (!rule.IsAsync)
856 {
857 // process results
858 if (!complete)
859 context.Complete();
860 // copy affected property names
861 affectedProperties.AddRange(rule.AffectedProperties.Select(c => c.Name));
862 // copy output property names
863 if (context.OutputPropertyValues != null)
864 affectedProperties.AddRange(context.OutputPropertyValues.Select(c =>c.Key.Name));
865 // copy dirty properties
866 if (context.DirtyProperties != null)
867 dirtyProperties.AddRange(context.DirtyProperties.Select(c => c.Name));
868
869 if (context.Results != null)
870 {
871 // explicit short-circuiting
872 if (context.Results.Any(r => r.StopProcessing))
873 break;
874 }
875 }
876 }
877 // return any synchronous results
878 return new RunRulesResult(affectedProperties, dirtyProperties);
879 }
880
881 private async void RunAsyncRule(IBusinessRuleAsync asyncRule, IRuleContext context)
882 {
883 try
884 {
885 await asyncRule.ExecuteAsync(context);
886 }
887 finally
888 {
889 context.Complete();
890 }
891 }
892
893 #region DataAnnotations
894
899 [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
900 public void AddDataAnnotations()
901 {
902 Type metadataType;
903#if !NETSTANDARD2_0 && !NET5_0
904 // add data annotations from metadata class if specified
905 var classAttList = _target.GetType().GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.MetadataTypeAttribute), true);
906 if (classAttList.Length > 0)
907 {
908 metadataType = ((System.ComponentModel.DataAnnotations.MetadataTypeAttribute)classAttList[0]).MetadataClassType;
909 AddDataAnnotationsFromType(metadataType);
910 }
911#endif
912
913 // attributes on class
914 metadataType = _target.GetType();
915 AddDataAnnotationsFromType(metadataType);
916 }
917
922 private void AddDataAnnotationsFromType(Type metadataType)
923 {
924 var attList = metadataType.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute), true);
925 foreach (var att in attList)
926 AddRule(new CommonRules.DataAnnotation(null, (System.ComponentModel.DataAnnotations.ValidationAttribute)att));
927
928 // attributes on properties
929 var propList = metadataType.GetProperties();
930 foreach (var prop in propList)
931 {
932 attList = prop.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute), true);
933 foreach (var att in attList)
934 {
935 var target = (IManageProperties)_target;
936 var pi = target.GetManagedProperties().First(c => c.Name == prop.Name);
937 AddRule(new CommonRules.DataAnnotation(pi, (System.ComponentModel.DataAnnotations.ValidationAttribute)att));
938 }
939 }
940 }
941
942 #endregion
943
944 #region MobileObject overrides
945
956 protected override void OnGetState(SerializationInfo info, StateMode mode)
957 {
958 info.AddValue("_processThroughPriority", _processThroughPriority);
959 info.AddValue("_ruleSet", _ruleSet);
960 info.AddValue("_cascadeWhenChanged", _cascadeOnDirtyProperties);
961 base.OnGetState(info, mode);
962 }
963
974 protected override void OnSetState(SerializationInfo info, StateMode mode)
975 {
976 _processThroughPriority = info.GetValue<int>("_processThroughPriority");
977 _ruleSet = info.GetValue<string>("_ruleSet");
978 _cascadeOnDirtyProperties = info.GetValue<bool>("_cascadeWhenChanged");
979 base.OnSetState(info, mode);
980 }
981
993 protected override void OnGetChildren(SerializationInfo info, MobileFormatter formatter)
994 {
995 if (_brokenRules != null && _brokenRules.Count > 0)
996 {
997 SerializationInfo brInfo = formatter.SerializeObject(_brokenRules);
998 info.AddChild("_brokenRules", brInfo.ReferenceId);
999 }
1000
1001 base.OnGetChildren(info, formatter);
1002 }
1003
1015 protected override void OnSetChildren(SerializationInfo info, MobileFormatter formatter)
1016 {
1017 if (info.Children.ContainsKey("_brokenRules"))
1018 {
1019 int referenceId = info.Children["_brokenRules"].ReferenceId;
1020 _brokenRules = (BrokenRulesCollection)formatter.GetObject(referenceId);
1021 }
1022
1023 base.OnSetChildren(info, formatter);
1024 }
1025 #endregion
1026
1027 #region Serialization Notification
1028
1030 {
1031 OnDeserializedHandler(new System.Runtime.Serialization.StreamingContext());
1032 }
1033
1034 [System.Runtime.Serialization.OnDeserialized]
1035 private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)
1036 {
1037 SyncRoot = new object();
1038 }
1039
1040 #endregion
1041
1042 #region Get All Broken Rules (tree)
1043
1049 public static BrokenRulesTree GetAllBrokenRules(object root)
1050 {
1051 return GetAllBrokenRules(root, true);
1052 }
1059 public static BrokenRulesTree GetAllBrokenRules(object root, bool errorsOnly)
1060 {
1061 var list = new BrokenRulesTree();
1062 long counter = 1;
1063 long childBrokenRuleCount = 0;
1064 AddNodeToBrukenRules(ref list, ref counter, null, root, errorsOnly, ref childBrokenRuleCount);
1065
1066 return list;
1067 }
1068
1069 private static void AddNodeToBrukenRules(ref BrokenRulesTree list, ref long counter, object parentKey, object obj, bool errorsOnly, ref long childBrokenRuleCount)
1070 {
1071 // is this a single editable object
1072 if (obj is Csla.Core.BusinessBase)
1073 {
1074 var nodeKey = counter++;
1075 var bo = (Csla.Core.BusinessBase)obj;
1076 long myChildBrokenRuleCount = bo.BrokenRulesCollection.Count;
1077 var node = new BrokenRulesNode() { Parent = parentKey, Node = nodeKey, BrokenRules = bo.BrokenRulesCollection, Object = obj };
1078 list.Add(node);
1079
1080 // get managed child properties
1081 foreach (var child in ((IManageProperties)bo).GetChildren())
1082 {
1083 AddNodeToBrukenRules(ref list, ref counter, nodeKey, child, errorsOnly, ref myChildBrokenRuleCount);
1084 }
1085
1086 // remove node if it has no child with broken rules.
1087 if (!errorsOnly && myChildBrokenRuleCount == 0)
1088 {
1089 list.Remove(node);
1090 }
1091 if (errorsOnly && bo.IsValid)
1092 {
1093 list.Remove(node);
1094 }
1095 childBrokenRuleCount += myChildBrokenRuleCount;
1096 }
1097
1098 // or a list of EditableObject (both BindingList and ObservableCollection)
1099 else if (obj is IEditableCollection)
1100 {
1101 var nodeKey = counter++;
1102 var isValid = ((ITrackStatus)obj).IsValid;
1103 var node = new BrokenRulesNode() { Parent = parentKey, Node = nodeKey, Object = obj, BrokenRules = new BrokenRulesCollection(true) };
1104 long myChildBrokenRuleCount = 0;
1105
1106 list.Add(node);
1107
1108 foreach (var child in (IEnumerable)obj)
1109 {
1110 AddNodeToBrukenRules(ref list, ref counter, nodeKey, child, errorsOnly, ref myChildBrokenRuleCount);
1111 }
1112
1113 // remove node if it has no child with broken rules.
1114 if (!errorsOnly && myChildBrokenRuleCount == 0)
1115 {
1116 list.Remove(node);
1117 }
1118 if (errorsOnly && isValid)
1119 {
1120 list.Remove(node);
1121 }
1122 childBrokenRuleCount += myChildBrokenRuleCount;
1123 }
1124 return;
1125 }
1126
1127 #endregion
1128
1129
1130 internal class RunRulesResult
1131 {
1132 public RunRulesResult(List<string> affectedProperties, List<string> dirtyProperties)
1133 {
1134 AffectedProperties = affectedProperties;
1135 DirtyProperties = dirtyProperties;
1136 }
1137
1138 public List<string> AffectedProperties { get; set; }
1139 public List<string> DirtyProperties { get; set; }
1140 }
1141
1142 object IBusinessRules.Target
1143 {
1144 get { return Target; }
1145 }
1146 }
1147}
This is the non-generic base class from which most business objects will be derived.
Inherit from this base class to easily create a serializable class.
Definition: MobileObject.cs:20
Context information provided to an authorization rule when it is invoked.
Manages the list of authorization rules for a business type.
List< IAuthorizationRule > Rules
Gets the list of rule objects for the business type.
A collection of currently broken rules.
int ErrorCount
Gets the number of broken rules in the collection that have a severity of Error.
Holds broken rules for an Node in the BrokenRulesTree.
Holds a list of broken rules tree list
Manages the list of rules for a business type.
List< IBusinessRuleBase > Rules
Gets the list of rule objects for the business type.
Tracks the business rules for a business object.
BusinessRules()
Creates an instance of the object.
static bool HasPermission(AuthorizationActions action, Type objectType)
Checks per-type authorization rules.
string?? RuleSet
Gets or sets the rule set to use for this business object instance.
async Task< List< string > > CheckRulesAsync()
Invokes all rules for the business type.
int ProcessThroughPriority
Gets or sets the priority through which all rules will be processed.
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...
static BrokenRulesTree GetAllBrokenRules(object root, bool errorsOnly)
Gets all nodes in tree that have broken rules.
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...
static bool HasPermission(AuthorizationActions action, Type objectType, object[] criteria)
Checks per-type authorization rules.
bool IsValid
Gets a value indicating whether there are any currently broken rules, which would mean the object is ...
void AddRule(IAuthorizationRule rule)
Associates an authorization rule with the business object.
bool CachePermissionResult(AuthorizationActions action, Csla.Core.IMemberInfo element)
Gets a value indicating whether the permission result can be cached.
static bool HasPermission(AuthorizationActions action, object obj, string ruleSet)
Checks per-instance authorization rules.
void AddRule(IBusinessRuleBase rule, string ruleSet)
Associates a business rule with the business object.
bool RunningRules
Gets a value indicating whether a CheckRules operation is in progress.
bool HasPermission(AuthorizationActions action, Csla.Core.IMemberInfo element)
Checks per-property authorization rules.
bool CascadeOnDirtyProperties
Gets or sets a value indicating whether rule engine should cacade n-leves when property value is chan...
List< string > CheckObjectRules()
Invokes all rules attached at the class level of the business type.
static void AddRule(Type objectType, IAuthorizationRule rule, string ruleSet)
Associates a per-type authorization rule with the business type.
static BrokenRulesTree GetAllBrokenRules(object root)
Gets all nodes in tree that have IsValid = false (and all parents)
void AddDataAnnotations()
Adds validation rules corresponding to property data annotation attributes.
override void OnGetState(SerializationInfo info, StateMode mode)
Override this method to insert your field values into the MobileFormatter serialzation stream.
List< string > CheckRules(Csla.Core.IPropertyInfo property)
Invokes all rules for a specific property of the business type.
bool GetPropertyBusy(Csla.Core.IPropertyInfo property)
Gets a value indicating whether a specific property has any async rules running.
void AddRule(IBusinessRuleBase rule)
Associates a business rule with the business object.
bool RunningAsyncRules
Gets a value indicating whether any async rules are currently executing.
override void OnSetState(SerializationInfo info, StateMode mode)
Override this method to retrieve your field values from the MobileFormatter serialzation stream.
static void AddRule(Type objectType, IAuthorizationRule rule)
Associates a per-type authorization rule with the business type in the default rule set.
static bool HasPermission(AuthorizationActions action, Type objectType, string ruleSet)
Checks per-type authorization rules.
BrokenRulesCollection GetBrokenRules()
Gets the broken rules list.
string[] GetRuleDescriptions()
Gets a list of rule:// URI values for the rules defined in the object.
static bool HasPermission(AuthorizationActions action, object obj)
Checks per-instance authorization rules.
override void OnGetChildren(SerializationInfo info, MobileFormatter formatter)
Override this method to insert your child object references into the MobileFormatter serialzation str...
Serializes and deserializes objects at the field level.
IMobileObject GetObject(int referenceId)
Gets a deserialized object based on the object's reference id within the serialization stream.
SerializationInfo SerializeObject(object obj)
Serializes an object into a SerializationInfo object.
Object containing the serialization data for a specific object.
int ReferenceId
Reference number for this object.
Dictionary< string, ChildData > Children
Dictionary containing child reference data.
void AddChild(string name, int referenceId)
Adds a child to the list of child references.
void AddValue(string name, object value)
Adds a value to the serialization stream.
Async/await implementation of a ManualResetEvent
void Reset()
Reset the event, preparing it for reuse
Task WaitAsync()
Get awaitable task for the event
void Set()
Set the event, unblocking any code awaiting the event
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
Maintains metadata about a property.
Defines the common properties required objects that track their own status.
Definition: ITrackStatus.cs:17
Interface defining an authorization rule implementation.
Csla.Core.IMemberInfo Element
Gets the element (property/method) to which this rule is associated.
AuthorizationActions Action
Gets the authorization action this rule will enforce.
Interface defining a business/validation rule implementation.
Public interfacefor IBusinessRules
Defines the interaction between the rules engine and a business object that hosts the rules.
Definition: IHostRules.cs:20
void RuleStart(Csla.Core.IPropertyInfo property)
Indicates that a rule has started processing.
void AllRulesComplete()
Indicates that all rules have finished processing.
Interface defining callback methods used by the SerializationFormatterFactory.GetFormatter().
void Deserialized()
Method called on an object after deserialization is complete.
StateMode
Indicates the reason the MobileFormatter functionality has been invoked.
Definition: StateMode.cs:20
RunModes
Flags enum to define when rule is allowed or denied to run
AuthorizationActions
Authorization actions.
RuleContextModes
RuleContext mode flags
Definition: RuleContext.cs:24
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.