11using System.Collections.Generic;
12using System.Reflection;
14using System.Runtime.Loader;
21using System.Threading.Tasks;
31 [System.Diagnostics.DebuggerStepThrough]
36 private string _businessObjectType;
40 private List<IPropertyInfo> _propertyList;
54 SetPropertyList(businessObjectType);
55 _fieldData =
new IFieldData[_propertyList.Count];
62 internal void SetPropertyList(Type businessObjectType)
64 _businessObjectType = businessObjectType.AssemblyQualifiedName;
65 _propertyList = GetConsolidatedList(businessObjectType);
84 return new List<IPropertyInfo>(_propertyList);
109 get {
return _propertyList.Count > 0; }
112 #region ConsolidatedPropertyList
115 private static Dictionary<Type, Tuple<string, List<IPropertyInfo>>> _consolidatedLists =
new Dictionary<Type, Tuple<string, List<IPropertyInfo>>>();
117 private static readonly Dictionary<Type, List<IPropertyInfo>> _consolidatedLists =
new();
120 private static List<IPropertyInfo> GetConsolidatedList(Type type)
122 List<IPropertyInfo> result =
null;
129 found = _consolidatedLists.TryGetValue(type, out var consolidatedListsInfo);
131 result = consolidatedListsInfo?.Item2;
133 result = _consolidatedLists[type];
141 lock (_consolidatedLists)
144 if (_consolidatedLists.ContainsKey(type))
146 result = _consolidatedLists[type].Item2;
150 result = CreateConsolidatedList(type);
157 var cacheInstance = AssemblyLoadContextManager.CreateCacheInstance(type, result, OnAssemblyLoadContextUnload,
true);
159 _consolidatedLists.Add(type, cacheInstance);
162 if (_consolidatedLists.ContainsKey(type))
164 result = _consolidatedLists[type];
168 result = CreateConsolidatedList(type);
170 _consolidatedLists.Add(type, result);
179 private static List<IPropertyInfo> CreateConsolidatedList(Type type)
182 List<IPropertyInfo> result =
new List<IPropertyInfo>();
186 List<Type> hierarchy =
new List<Type>();
189 hierarchy.Add(current);
190 current = current.BaseType;
191 }
while (current !=
null && !current.Equals(typeof(BusinessBase)));
194 for (
int index = hierarchy.Count - 1; index >= 0; index--)
196 var source = PropertyInfoManager.GetPropertyListCache(hierarchy[index]);
197 source.IsLocked =
true;
198 result.AddRange(source);
203 foreach (var item
in result)
205 if (item.Index == -1)
221#region Get/Set/Find fields
230 [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
238 return _fieldData[propertyInfo.
Index];
240 catch (IndexOutOfRangeException ex)
250 var field = _fieldData[prop.
Index];
254 _fieldData[prop.
Index] = field;
258 catch (IndexOutOfRangeException ex)
264 internal IPropertyInfo FindProperty(
object value)
267 foreach (var item
in _fieldData)
269 if (item !=
null && item.Value !=
null && item.Value.Equals(value))
270 return _propertyList[index];
285 internal void SetFieldData(IPropertyInfo prop,
object value)
289 valueType = value.GetType();
291 valueType = prop.Type;
292 value = Utilities.CoerceValue(prop.Type, valueType,
null, value);
293 var field = GetOrCreateFieldData(prop);
309 internal void SetFieldData<P>(IPropertyInfo prop, P value)
311 var field = GetOrCreateFieldData(prop);
312 if (field is IFieldData<P> fd)
328 internal IFieldData LoadFieldData(IPropertyInfo prop,
object value)
332 valueType = value.GetType();
334 valueType = prop.Type;
335 value = Utilities.CoerceValue(prop.Type, valueType,
null, value);
336 var field = GetOrCreateFieldData(prop);
355 internal IFieldData LoadFieldData<P>(IPropertyInfo prop, P value)
357 var field = GetOrCreateFieldData(prop);
358 if (field is IFieldData<P> fd)
374 internal void RemoveField(IPropertyInfo prop)
378 var field = _fieldData[prop.Index];
382 catch (IndexOutOfRangeException ex)
400 return _fieldData[propertyInfo.
Index] !=
null;
402 catch (IndexOutOfRangeException ex)
421 var field = _fieldData[propertyInfo.
Index];
423 result = field.IsDirty;
429 catch (IndexOutOfRangeException ex)
431 throw new InvalidOperationException(Properties.Resources.PropertyNotRegistered, ex);
437#region IsValid/IsDirty/IsBusy
445 foreach (var item
in _fieldData)
446 if (item !=
null && !item.IsValid)
457 foreach (var item
in _fieldData)
458 if (item !=
null && item.IsDirty)
467 internal void MarkClean()
469 foreach (var item
in _fieldData)
470 if (item !=
null && item.IsDirty)
474 internal bool IsBusy()
476 foreach (var item
in _fieldData)
477 if (item !=
null && item.IsBusy)
484#region IUndoableObject
486 private readonly Stack<byte[]> _stateStack =
new();
493 get {
return _stateStack.Count; }
496 void Core.IUndoableObject.CopyState(
int parentEditLevel,
bool parentBindingEdit)
498 if (this.
EditLevel + 1 > parentEditLevel)
502 _parent?.GetType().Name,
this.EditLevel, parentEditLevel - 1);
506 for (var index = 0; index < _fieldData.Length; index++)
508 var item = _fieldData[index];
514 child.CopyState(parentEditLevel, parentBindingEdit);
527 using MemoryStream buffer =
new MemoryStream();
528 var formatter = SerializationFormatterFactory.GetFormatter(ApplicationContext);
529 var stateList =
new MobileList<IFieldData>(state.ToList());
530 formatter.Serialize(buffer, stateList);
531 _stateStack.Push(buffer.ToArray());
534 void Core.IUndoableObject.UndoChanges(
int parentEditLevel,
bool parentBindingEdit)
538 if (this.
EditLevel - 1 != parentEditLevel)
539 throw new UndoException(
541 this.GetType().Name, _parent?.GetType().Name,
this.EditLevel, parentEditLevel + 1);
543 IFieldData[] state =
null;
544 using (MemoryStream buffer =
new MemoryStream(_stateStack.Pop()))
547 var formatter = SerializationFormatterFactory.GetFormatter(ApplicationContext);
548 state = ((MobileList<IFieldData>)(formatter.Deserialize(buffer))).ToArray();
551 for (var index = 0; index < _fieldData.Length; index++)
553 var oldItem = state[index];
554 var item = _fieldData[index];
557 if (item.Value is IUndoableObject undoable)
560 var doUndo = (oldItem !=
null);
563 var propInfo = _propertyList.Where(r => r.Index == index).First();
567 undoable.UndoChanges(parentEditLevel, parentBindingEdit);
569 _fieldData[index] =
null;
574 _fieldData[index] = oldItem;
579 void Core.IUndoableObject.AcceptChanges(
int parentEditLevel,
bool parentBindingEdit)
581 if (this.
EditLevel - 1 != parentEditLevel)
582 throw new UndoException(
584 this.GetType().Name, _parent?.GetType().Name,
this.EditLevel, parentEditLevel + 1);
591 foreach (var item
in _fieldData)
595 if (item.Value is IUndoableObject child)
598 child.AcceptChanges(parentEditLevel, parentBindingEdit);
620 List<object> result =
new List<object>();
621 foreach (var item
in _fieldData)
623 result.Add(item.Value);
636 foreach (var item
in _fieldData)
640 object obj = item.Value;
656 foreach (var item
in _fieldData)
660 object obj = item.Value;
662 portal.UpdateAll(obj, parameters);
675 foreach (var item
in _fieldData)
679 object obj = item.Value;
681 await portal.UpdateAsync(obj, parameters).ConfigureAwait(
false);
695 foreach (var item
in _fieldData)
699 object obj = item.Value;
701 await portal.UpdateAllAsync(obj, parameters).ConfigureAwait(
false);
708 #region IMobileObject Members
722 info.
AddValue(
"_businessObjectType", _businessObjectType);
724 if (mode ==
StateMode.Serialization && _stateStack.Count > 0)
725 info.
AddValue(
"_stateStack", _stateStack.ToArray());
732 info.AddValue(
"child_" + data.
Name,
true,
false);
739 base.OnGetState(info, mode);
760 base.OnGetChildren(info, formatter);
775 string type = (string)info.
Values[
"_businessObjectType"].Value;
777 SetPropertyList(businessObjecType);
782 if (info.
Values.ContainsKey(
"_stateStack"))
784 var stackArray = info.GetValue<
byte[][]>(
"_stateStack");
785 foreach (var item
in stackArray.Reverse())
786 _stateStack.Push(item);
789 _fieldData =
new IFieldData[_propertyList.Count];
794 if (info.Values.ContainsKey(property.
Name))
798 IFieldData data = GetOrCreateFieldData(property);
799 if (value.Value !=
null &&
801 typeof(
IMobileObject).IsAssignableFrom(Nullable.GetUnderlyingType(property.
Type) ?? property.
Type) &&
806 else data.
Value = value.Value;
816 if (!info.Values.ContainsKey(
"child_" + property.
Name) || !info.GetValue<
bool>(
"child_" + property.
Name))
817 _fieldData[
property.Index] =
null;
821 data.
Value =
property.DefaultValue;
825 base.OnSetState(info, mode);
837 if (info.Children.ContainsKey(property.
Name))
841 IFieldData data = GetOrCreateFieldData(property);
842 data.
Value = formatter.GetObject(childData.ReferenceId);
843 if (!childData.IsDirty)
847 base.OnSetChildren(info, formatter);
859 const BindingFlags attr =
860 BindingFlags.Static |
861 BindingFlags.Public |
862 BindingFlags.DeclaredOnly |
863 BindingFlags.NonPublic;
869 var fields = t.GetFields(attr);
870 if (fields.Length > 0)
871 fields[0].GetValue(
null);
878 private static void OnAssemblyLoadContextUnload(AssemblyLoadContext context)
880 lock (_consolidatedLists)
881 AssemblyLoadContextManager.RemoveFromCache(_consolidatedLists, context);
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...
This is the base class from which most business objects will be derived.
This is the non-generic base class from which most business objects will be derived.
Contains a field value and related metadata.
Manages properties and property data for a business object.
override void OnGetState(SerializationInfo info, StateMode mode)
Override this method to insert your field values into the MobileFormatter serialzation stream.
bool HasFields
Gets a value indicating whether there are any managed fields available.
bool IsFieldDirty(IPropertyInfo propertyInfo)
Gets a value indicating whether the specified field has been changed.
int EditLevel
Gets the current edit level of the object.
override void OnSetState(SerializationInfo info, StateMode mode)
Override this method to retrieve your field values from the MobileFormatter serialzation stream.
List< IPropertyInfo > GetRegisteredProperties()
Returns a copy of the property list for the business object.
FieldDataManager()
Creates an instance of the type.
bool IsDirty()
Returns a value indicating whether any fields are dirty.
override void OnSetChildren(SerializationInfo info, MobileFormatter formatter)
Deserializes child objects.
IFieldData GetFieldData(IPropertyInfo propertyInfo)
Gets the IFieldData object for a specific field.
void UpdateChildren(params object[] parameters)
Invokes the data portal to update all child objects contained in the list of fields.
static void ForceStaticFieldInit(Type type)
Forces initialization of the static fields declared by a type, and any of its base class types.
async Task UpdateAllChildrenAsync(params object[] parameters)
Asynchronously invokes the data portal to update all child objects, including those which are not dir...
bool IsValid()
Returns a value indicating whether all fields are valid.
bool FieldExists(IPropertyInfo propertyInfo)
Returns a value indicating whether an IFieldData entry exists for the specified property.
void UpdateAllChildren(params object[] parameters)
Invokes the data portal to update all child objects, including those which are not dirty,...
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.
async Task UpdateChildrenAsync(params object[] parameters)
Asynchronously invokes the data portal to update all child objects contained in the list of fields.
override void OnGetChildren(SerializationInfo info, MobileFormatter formatter)
Serializes child objects.
Inherit from this base class to easily create a serializable class.
Exception indicating a problem with the use of the n-level undo feature in CSLA .NET.
Client side data portal used for making asynchronous data portal calls in .NET.
void UpdateChild(T child)
Inserts, updates or deletes an existing child business object.
A strongly-typed resource class, for looking up localized strings, etc.
static string PropertyIsPrivateField
Looks up a localized string similar to Attempt to read/load private field property in managed propert...
static string PropertyNotRegistered
Looks up a localized string similar to One or more properties are not registered for this type.
static string EditLevelMismatchException
Looks up a localized string similar to Edit level mismatch in {0}.
static string PropertyNameNotRegisteredException
Looks up a localized string similar to Property '{0}' not registered.
Object that contains information about a single child reference.
Object that contains information about a single field.
Object containing the serialization data for a specific object.
Dictionary< string, FieldData > Values
Dictionary containg field data.
int ReferenceId
Reference number for this object.
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.
Defines the members required by a field data storage object.
object Value
Gets or sets the field value.
void MarkClean()
Marks the field as unchanged.
string Name
Gets the name of the field.
Defines the common methods required by all editable CSLA single objects.
Defines the common methods required by all editable CSLA collection objects.
string Name
Gets the member name value.
Maintains metadata about a property.
int Index
Gets or sets the index position for the managed field storage behind the property.
RelationshipTypes RelationshipType
Gets the relationship between the declaring object and the object reference in the property.
Type Type
Gets the type of the property.
Core.FieldManager.IFieldData NewFieldData(string name)
Gets a new field data container for the property.
bool IsDirty
Returns true if this object's data, or any of its fields or child objects data, has been changed.
Defines the methods required to participate in n-level undo within the CSLA .NET framework.
Implement if a class requires access to the CSLA ApplicationContext type.
ApplicationContext ApplicationContext
Gets or sets the current ApplicationContext object.
Interface to be implemented by any object that supports serialization by the SerializationFormatterFa...
StateMode
Indicates the reason the MobileFormatter functionality has been invoked.
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.