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.
AuthorizationRuleManager.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="AuthorizationRuleManager.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Manages the list of authorization </summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Generic;
10using System.Linq;
11using System.Reflection;
12#if NET5_0_OR_GREATER
13using System.Runtime.Loader;
14
15using Csla.Runtime;
16#endif
17
18namespace Csla.Rules
19{
25 {
26#if NET5_0_OR_GREATER
27 private static Lazy<System.Collections.Concurrent.ConcurrentDictionary<RuleSetKey, Tuple<string, AuthorizationRuleManager>>> _perTypeRules =
28 new Lazy<System.Collections.Concurrent.ConcurrentDictionary<RuleSetKey, Tuple<string, AuthorizationRuleManager>>>();
29#else
30 private static Lazy<System.Collections.Concurrent.ConcurrentDictionary<RuleSetKey, AuthorizationRuleManager>> _perTypeRules =
31 new Lazy<System.Collections.Concurrent.ConcurrentDictionary<RuleSetKey, AuthorizationRuleManager>>();
32#endif
33
34 internal static AuthorizationRuleManager GetRulesForType(ApplicationContext applicationContext, Type type, string ruleSet)
35 {
37 ruleSet = null;
38
39 var key = new RuleSetKey { Type = type, RuleSet = ruleSet };
40
41#if NET5_0_OR_GREATER
42 var rulesInfo = _perTypeRules.Value
43 .GetOrAdd(
44 key,
45 (t) => AssemblyLoadContextManager.CreateCacheInstance(type, new AuthorizationRuleManager(), OnAssemblyLoadContextUnload)
46 );
47
48 var result = rulesInfo.Item2;
49#else
50 var result = _perTypeRules.Value.GetOrAdd(key, (t) => { return new AuthorizationRuleManager(); });
51#endif
52
53 InitializePerTypeRules(applicationContext, result, type);
54
55 return result;
56 }
57
58 private bool InitializingPerType { get; set; }
59
60 private static void InitializePerTypeRules(ApplicationContext applicationContext, AuthorizationRuleManager mgr, Type type)
61 {
62 if (!mgr.InitializedPerType)
63 lock (mgr)
64 if (!mgr.InitializedPerType && !mgr.InitializingPerType)
65 {
66 // Only call AddObjectAuthorizationRules when there are no rules for this type
67 if (RulesExistForType(type))
68 {
69 mgr.InitializedPerType = true;
70 return;
71 }
72
73 try
74 {
75 mgr.InitializingPerType = true;
76
77 // invoke method to add auth roles
78 System.Reflection.MethodInfo method = FindObjectAuthorizationRulesMethod(type);
79 if (method != null)
80 {
81 if (method.GetParameters().Length == 0)
82 method.Invoke(null, null);
83 else if (applicationContext != null)
84 method.Invoke(null, new object[] { new AddObjectAuthorizationRulesContext(applicationContext) });
85 else
86 throw new InvalidOperationException(
87 $"{nameof(InitializePerTypeRules)} {nameof(applicationContext)} == null");
88 }
89 mgr.InitializedPerType = true;
90 }
91 catch (Exception)
92 {
93 // remove all loaded rules for this type
94 CleanupRulesForType(type);
95 throw; // and rethrow the exception
96 }
97 finally
98 {
99 mgr.InitializingPerType = false;
100 }
101 }
102 }
103
104 private static System.Reflection.MethodInfo FindObjectAuthorizationRulesMethod(Type type)
105 {
106 System.Reflection.MethodInfo method;
107 method = type.GetMethods().Where(
108 m => m.IsStatic && m.CustomAttributes.Where(
109 a => a.AttributeType == typeof(ObjectAuthorizationRulesAttribute)).Any()).
110 FirstOrDefault();
111 if (method == null)
112 {
113 const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
114 method = type.GetMethod("AddObjectAuthorizationRules", flags);
115 }
116 return method;
117 }
118
119 private static bool RulesExistForType(Type type)
120 {
121 lock (_perTypeRules)
122 {
123 // the first RuleSet is already added to list when this check is executed so so if count > 1 then we have already initialized type rules.
124 return _perTypeRules.Value.Count(value => value.Key.Type == type) > 1;
125 }
126
127 }
128
129 private static void CleanupRulesForType(Type type)
130 {
131 lock (_perTypeRules)
132 {
133
134 // the first RuleSet is already added to list when this check is executed so so if count > 1 then we have already initialized type rules.
135 var typeRules = _perTypeRules.Value.Where(value => value.Key.Type == type);
136 foreach (var key in typeRules)
137 {
138 _perTypeRules.Value.TryRemove(key.Key, out _);
139 }
140 }
141 }
142
143 private class RuleSetKey
144 {
145 public Type Type { get; set; }
146 public string RuleSet { get; set; }
147
148 public override bool Equals(object obj)
149 {
150 var other = obj as RuleSetKey;
151 if (other == null)
152 return false;
153 else
154 return this.Type.Equals(other.Type) && RuleSet == other.RuleSet;
155 }
156
157 public override int GetHashCode()
158 {
159 return (this.Type.FullName + RuleSet).GetHashCode();
160 }
161 }
162
166 public List<IAuthorizationRule> Rules { get; private set; }
167
172 public bool Initialized { get; internal set; }
177 public bool InitializedPerType { get; internal set; }
178
180 {
181 Rules = new List<IAuthorizationRule>();
182 }
183#if NET5_0_OR_GREATER
184
185 private static void OnAssemblyLoadContextUnload(AssemblyLoadContext context)
186 {
187 lock (_perTypeRules)
188 AssemblyLoadContextManager.RemoveFromCache(_perTypeRules.Value, context, true);
189 }
190#endif
191 }
192}
Provides consistent context information between the client and server DataPortal objects.
const string DefaultRuleSet
The default RuleSet name
Attribute identifying static method invoked to add object authorization rules for type.
Context for the AddObjectAuthorizationRulesContext method.
Manages the list of authorization rules for a business type.
bool Initialized
Gets or sets a value indicating whether the rules have been initialized.
bool InitializedPerType
Gets or sets a value indicating whether the rules have been initialized.
List< IAuthorizationRule > Rules
Gets the list of rule objects for the business type.
@ Any
Default value, rule can run in any context