<NME> ReadOnlyBase.cs
<BEF> //-----------------------------------------------------------------------
// <copyright file="ReadOnlyBase.cs" company="Marimer LLC">
//     Copyright (c) Marimer LLC. All rights reserved.
//     Website: https://cslanet.com
// </copyright>
// <summary>This is a base class from which readonly business classes</summary>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Csla.Core;
using Csla.Core.FieldManager;
using Csla.Core.LoadManager;
using Csla.Properties;
using Csla.Reflection;
using Csla.Rules;
using Csla.Security;
using Csla.Serialization.Mobile;
using Csla.Server;
using System.Collections.Concurrent;

namespace Csla
{
  /// <summary>
  /// This is a base class from which readonly business classes
  /// can be derived.
  /// </summary>
  /// <remarks>
  /// This base class only supports data retrieve, not updating or
  /// deleting. Any business classes derived from this base class
  /// should only implement readonly properties.
  /// </remarks>
  /// <typeparam name="T">Type of the business object.</typeparam>
  [Serializable()]
  public abstract class ReadOnlyBase<T> : BindableBase,
    ICloneable,
    IReadOnlyObject,
    ISerializationNotification,
    IAuthorizeReadWrite,
    IDataPortalTarget,
    IManageProperties,
    INotifyBusy,
    IHostRules,
    IReadOnlyBase,
    IUseApplicationContext,
    IUseFieldManager,
    IUseBusinessRules
    where T : ReadOnlyBase<T>
  {
    #region Object ID Value

    /// <summary>
    /// Override this method to return a unique identifying
    /// value for this object.
    /// </summary>
    protected virtual object GetIdValue()
    {
      return null;
    }

    #endregion

    #region System.Object Overrides

    /// <summary>
    /// Returns a text representation of this object by
    /// returning the <see cref="GetIdValue"/> value
    /// in text form.
    /// </summary>
    public override string ToString()
    {
      object id = GetIdValue();
      if (id == null)
        return base.ToString();
      else
        return id.ToString();
    }

    #endregion

    /// <summary>
    /// Gets or sets the current ApplicationContext object.
    /// </summary>
    protected ApplicationContext ApplicationContext { get; set; }
    ApplicationContext IUseApplicationContext.ApplicationContext 
    { 
      get => ApplicationContext;
      set
      {
        ApplicationContext = value;
        Initialize();
        InitializeBusinessRules();
      }
    }

    /// <summary>
    /// Creates an instance of the type.
    /// </summary>
    protected ReadOnlyBase()
    {
    }

    #region Initialize

    /// <summary>
    /// Override this method to set up event handlers so user
    /// code in a partial class can respond to events raised by
    /// generated code.
    /// </summary>
    protected virtual void Initialize()
    { /* allows subclass to initialize events before any other activity occurs */ }

    #endregion

    #region Identity

    int IBusinessObject.Identity
    {
      get { return 0; }
    }

    #endregion

    #region Authorization

    [NotUndoable()]
    [NonSerialized()]
    private ConcurrentDictionary<string, bool> _readResultCache;
    [NotUndoable()]
    [NonSerialized()]
    private ConcurrentDictionary<string, bool> _executeResultCache;
    [NotUndoable()]
    [NonSerialized()]
    private System.Security.Principal.IPrincipal _lastPrincipal;

    private void InitializeBusinessRules()
    {
      var rules = BusinessRuleManager.GetRulesForType(this.GetType());
      if (!rules.Initialized)
        lock (rules)
          if (!rules.Initialized)
          {
            try
            {
              AddBusinessRules();
              rules.Initialized = true;
            }
            catch (Exception)
            {
              BusinessRuleManager.CleanupRulesForType(this.GetType());
              throw;  // and rethrow exception
            }
          }
    }

    private Csla.Rules.BusinessRules _businessRules;

    /// <summary>
    /// Provides access to the broken rules functionality.
    /// </summary>
    /// <remarks>
    /// This property is used within your business logic so you can
    /// easily call the AddRule() method to associate business
    /// rules with your object's properties.
    /// </remarks>
    protected BusinessRules BusinessRules
    {
      get
      {
        if (_businessRules == null)
          _businessRules = ApplicationContext.CreateInstanceDI<BusinessRules>(ApplicationContext, this);
        else if (_businessRules.Target == null)
          _businessRules.SetTarget(this);
        return _businessRules;
      }
    }

    BusinessRules IUseBusinessRules.BusinessRules => BusinessRules;

    void IHostRules.RuleStart(IPropertyInfo property)
    { }

    void IHostRules.RuleComplete(IPropertyInfo property)
    { }

    void IHostRules.RuleComplete(string property)
    { }

    void Rules.IHostRules.AllRulesComplete()
    { }

    /// <summary>
    /// Override this method to add per-type
    /// authorization rules for your type's properties.
    /// </summary>
    /// <remarks>
    /// AddSharedAuthorizationRules is automatically called by CSLA .NET
    /// when your object should associate per-type authorization roles
    /// with its properties.
    /// </remarks>
    protected virtual void AddBusinessRules()
    { }

    /// <summary>
    /// Returns true if the user is allowed to read the
    /// calling property.
    /// </summary>
    /// <param name="property">Property to check.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)
    {
      bool result = true;

      VerifyAuthorizationCache();

      if (!_readResultCache.TryGetValue(property.Name, out result))
      {
        result = BusinessRules.HasPermission(ApplicationContext, AuthorizationActions.ReadProperty, property);
        // store value in cache
        _readResultCache.AddOrUpdate(property.Name, result, (a, b) => { return result; });
      }
      return result;
    }

    /// <summary>
    /// Returns true if the user is allowed to read the
    /// calling property.
    /// </summary>
    /// <returns>true if read is allowed.</returns>
    /// <param name="property">Property to read.</param>
    /// <param name="throwOnFalse">Indicates whether a negative
    /// result should cause an exception.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)
    {
      bool result = CanReadProperty(property);
      if (throwOnFalse && result == false)
      {
        Csla.Security.SecurityException ex = new Csla.Security.SecurityException(
          String.Format("{0} ({1})",
          Resources.PropertyGetNotAllowed, property.Name));
        throw ex;
      }
      return result;
    }

    /// <summary>
    /// Returns true if the user is allowed to read the
    /// specified property.
    /// </summary>
    /// <param name="propertyName">Name of the property to read.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public bool CanReadProperty(string propertyName)
    {
      return CanReadProperty(propertyName, false);
    }

    /// <summary>
    /// Returns true if the user is allowed to read the
    /// specified property.
    /// </summary>
    /// <param name="propertyName">Name of the property to read.</param>
    /// <param name="throwOnFalse">Indicates whether a negative
    /// result should cause an exception.</param>
    private bool CanReadProperty(string propertyName, bool throwOnFalse)
    {
      var propertyInfo = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Name == propertyName);
      if (propertyInfo == null)
      {
#if NETFX_CORE || (ANDROID || IOS)
#else
        Trace.TraceError("CanReadProperty: {0} is not a registered property of {1}.{2}", propertyName, this.GetType().Namespace, this.GetType().Name);
#endif
        return true;
      }
      return CanReadProperty(propertyInfo, throwOnFalse);
    }

    bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(string propertyName)
    {
      return false;
    }

    bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(IPropertyInfo property)
    {
      return false;
    }

    private void VerifyAuthorizationCache()
    {
      if (_readResultCache == null)
        _readResultCache = new ConcurrentDictionary<string, bool>();
      if (_executeResultCache == null)
        _executeResultCache = new ConcurrentDictionary<string, bool>();
      if (!ReferenceEquals(ApplicationContext.User, _lastPrincipal))
      {
        // the principal has changed - reset the cache
        _readResultCache.Clear();
        _executeResultCache.Clear();
        _lastPrincipal = ApplicationContext.User;
      }
    }

    /// <summary>
    /// Returns true if the user is allowed to execute
    /// the specified method.
    /// </summary>
    /// <param name="method">Method to execute.</param>
    /// <returns>true if execute is allowed.</returns>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)
    {
      bool result = true;

      VerifyAuthorizationCache();

      if (!_executeResultCache.TryGetValue(method.Name, out result))
      {
        result = BusinessRules.HasPermission(ApplicationContext, AuthorizationActions.ExecuteMethod, method);
        _executeResultCache.AddOrUpdate(method.Name, result, (a, b) => { return result; });
      }
      return result;
    }

    /// <summary>
    /// Returns true if the user is allowed to execute
    /// the specified method.
    /// </summary>
    /// <returns>true if execute is allowed.</returns>
    /// <param name="method">Method to execute.</param>
    /// <param name="throwOnFalse">Indicates whether a negative
    /// result should cause an exception.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)
    {

      bool result = CanExecuteMethod(method);
      if (throwOnFalse && result == false)
      {
        Csla.Security.SecurityException ex =
          new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, method.Name));
        throw ex;
      }
      return result;

    }


    /// <summary>
    /// Returns true if the user is allowed to execute
    /// the specified method.
    /// </summary>
    /// <param name="methodName">Name of the method to execute.</param>
    /// <returns>true if execute is allowed.</returns>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public virtual bool CanExecuteMethod(string methodName)
    {
      return CanExecuteMethod(methodName, false);
    }

    private bool CanExecuteMethod(string methodName, bool throwOnFalse)
    {

      bool result = CanExecuteMethod(new MethodInfo(methodName));
      if (throwOnFalse && result == false)
      {
        Csla.Security.SecurityException ex = new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, methodName));
        throw ex;
      }
      return result;
    }

#endregion

#region IClonable

    object ICloneable.Clone()
    {
      return GetClone();
    }

    /// <summary>
    /// Creates a clone of the object.
    /// </summary>
    /// <returns>A new object containing the exact data of the original object.</returns>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public virtual object GetClone()
    {
      return Core.ObjectCloner.GetInstance(ApplicationContext).Clone(this);
    }

    /// <summary>
    /// Creates a clone of the object.
    /// </summary>
    /// <returns>
    /// A new object containing the exact data of the original object.
    /// </returns>
    public T Clone()
    {
      return (T)GetClone();
    }
    #endregion

    #region Data Access

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
    private void DataPortal_Create(object criteria)
    {
      throw new NotSupportedException(Resources.CreateNotSupportedException);
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
    private void DataPortal_Update()
    {
      throw new NotSupportedException(Resources.UpdateNotSupportedException);
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
    [Delete]
    private void DataPortal_Delete(object criteria)
    {
      throw new NotSupportedException(Resources.DeleteNotSupportedException);
    }

    /// <summary>
    /// Called by the server-side DataPortal prior to calling the 
    /// requested DataPortal_xyz method.
    /// </summary>
    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
    {

    }

    /// <summary>
    /// Called by the server-side DataPortal after calling the 
    /// requested DataPortal_xyz method.
    /// </summary>
    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
    {

    }

    /// <summary>
    /// Called by the server-side DataPortal if an exception
    /// occurs during data access.
    /// </summary>
    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
    /// <param name="ex">The Exception thrown during data access.</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
    {

    }

    /// <summary>
    /// Called by the server-side DataPortal prior to calling the 
    /// requested DataPortal_XYZ method.
    /// </summary>
    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)
    {
    }

    /// <summary>
    /// Called by the server-side DataPortal after calling the 
    /// requested DataPortal_XYZ method.
    /// </summary>
    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
    {
    }

    /// <summary>
    /// Called by the server-side DataPortal if an exception
    /// occurs during data access.
    /// </summary>
    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>
    /// <param name="ex">The Exception thrown during data access.</param>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
    {
    }

#endregion

#region Serialization Notification

    void ISerializationNotification.Deserialized()
    {
      OnDeserializedHandler(new System.Runtime.Serialization.StreamingContext());
    }

    [System.Runtime.Serialization.OnDeserialized()]
    private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)
    {
      if (_fieldManager != null)
        FieldManager.SetPropertyList(this.GetType());
      InitializeBusinessRules();
      OnDeserialized(context);
    }

    /// <summary>
    /// This method is called on a newly deserialized object
    /// after deserialization is complete.
    /// </summary>
    /// <param name="context">Serialization context object.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
    {
      // do nothing - this is here so a subclass
      // could override if needed
    }

#endregion

#region  Register Properties

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the type.
    /// </summary>
    /// <typeparam name="P">
    /// Type of property.
    /// </typeparam>
    /// <param name="objectType">
    /// Type of object to which the property belongs.
    /// </param>
    /// <param name="info">
    /// PropertyInfo object for the property.
    /// </param>
    /// <returns>
    /// The provided IPropertyInfo object.
    /// </returns>
    protected static PropertyInfo<P> RegisterProperty<P>(Type objectType, PropertyInfo<P> info)
    {
      return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(objectType, info);
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">
    /// Type of property.
    /// </typeparam>
    /// <param name="info">
    /// PropertyInfo object for the property.
    /// </param>
    /// <returns>
    /// The provided IPropertyInfo object.
    /// </returns>
    protected static PropertyInfo<P> RegisterProperty<P>(PropertyInfo<P> info)
    {
      return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(typeof(T), info);
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">Type of property</typeparam>
    /// <param name="propertyName">Property name from nameof()</param>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName));
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">Type of property</typeparam>
    /// <param name="propertyLambdaExpression">Property Expression</param>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)
    {
      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
      return RegisterProperty<P>(reflectedPropertyInfo.Name);

    #endregion

    #region  Get Properties

    /// <summary>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue)
    {
      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
      return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue);
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">Type of property</typeparam>
    /// <param name="propertyName">Property name from nameof()</param>
    /// <param name="relationship">Relationship with property value.</param>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, RelationshipTypes relationship)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, string.Empty, relationship));
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">Type of property</typeparam>
    /// <param name="propertyLambdaExpression">Property Expression</param>
    /// <param name="relationship">Relationship with property value.</param>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, RelationshipTypes relationship)
    {
      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
      return RegisterProperty<P>(reflectedPropertyInfo.Name, relationship);
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">Type of property</typeparam>
    /// <param name="propertyName">Property name from nameof()</param>
    /// <param name="friendlyName">Friendly description for a property to be used in databinding</param>
    /// <param name="defaultValue">Default Value for the property</param>
    /// <param name="relationship">Relationship with property value.</param>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue, RelationshipTypes relationship)
    {
      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue, relationship));
    }

    /// <summary>
    /// Indicates that the specified property belongs
    /// to the business object type.
    /// </summary>
    /// <typeparam name="P">Type of property</typeparam>
    /// <param name="propertyLambdaExpression">Property Expression</param>
    /// <param name="friendlyName">Friendly description for a property to be used in databinding</param>
    /// <param name="defaultValue">Default Value for the property</param>
    /// <param name="relationship">Relationship with property value.</param>
    /// <returns></returns>
    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue, RelationshipTypes relationship)
    {
      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);
      return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue, relationship);
    }
    #endregion

    #region Register Methods

    /// <summary>
    /// Indicates that the specified method belongs
    /// to the type.
    /// </summary>
    /// <param name="objectType">
    /// Type of object to which the method belongs.
    /// </param>
    /// <param name="info">
    /// IMemberInfo object for the property.
    /// </param>
    /// <returns>
    /// The provided IMemberInfo object.
    /// </returns>
    protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
    {
      var reflected = objectType.GetMethod(info.Name);
      if (reflected == null)
        throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");
      return info;
    }

    /// <summary>
    /// Indicates that the specified method belongs
    /// to the type.
    /// </summary>
    /// <param name="objectType">
    /// Type of object to which the method belongs.
    /// </param>
    /// <param name="methodName">
    /// Name of the method.
    /// </param>
    /// <returns>
    /// The provided IMemberInfo object.
    /// </returns>
    protected static MethodInfo RegisterMethod(Type objectType, string methodName)
    {
      var info = new MethodInfo(methodName);
      RegisterMethod(objectType, info);
      return info;
    }

    /// <summary>
    /// Registers a method for use in Authorization.
    /// </summary>
    /// <param name="methodName">Method name from nameof()</param>
    /// <returns></returns>
    protected static MethodInfo RegisterMethod(string methodName)
    {
      return RegisterMethod(typeof(T), methodName);
    }

    /// <summary>
    /// Registers the method.
    /// </summary>
    /// <param name="methodLambdaExpression">The method lambda expression.</param>
    /// <returns></returns>
    protected static MethodInfo RegisterMethod(Expression<Action<T>> methodLambdaExpression)
    {
      System.Reflection.MethodInfo reflectedMethodInfo = Reflect<T>.GetMethod(methodLambdaExpression);
      return RegisterMethod(reflectedMethodInfo.Name);
    }

#endregion

#region  Get Properties

    /// <summary>
    /// Gets a property's value, first checking authorization.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="field">
    /// The backing field for the property.</param>
    /// <param name="propertyName">
    /// The name of the property.</param>
    /// <param name="defaultValue">
    /// Value to be returned if the user is not
    /// authorized to read the property.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetProperty<P>(string propertyName, P field, P defaultValue)
    {
      return GetProperty<P>(propertyName, field, defaultValue, Security.NoAccessBehavior.SuppressException);
    }

    /// <summary>
    /// Gets a property's value, first checking authorization.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="field">
    /// The backing field for the property.</param>
    /// <param name="propertyName">
    /// The name of the property.</param>
    /// <param name="defaultValue">
    /// Value to be returned if the user is not
    /// authorized to read the property.</param>
    /// <param name="noAccess">
    /// True if an exception should be thrown when the
    /// user is not authorized to read this property.</param>
    protected P GetProperty<P>(string propertyName, P field, P defaultValue, Security.NoAccessBehavior noAccess)
    {
#region Check to see if the property is marked with RelationshipTypes.PrivateField

      var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);

      if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)
        throw new InvalidOperationException(Resources.PrivateFieldException);

#endregion

      if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))
        return field;

      return defaultValue;
    }

    /// <summary>
    /// Gets a property's value, first checking authorization.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="field">
    /// The backing field for the property.</param>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)
    {
      return GetProperty<P>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException);
    }

    /// <summary>
    /// Gets a property's value, first checking authorization.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="field">
    /// The backing field for the property.</param>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="defaultValue">
    /// Value to be returned if the user is not
    /// authorized to read the property.</param>
    /// <param name="noAccess">
    /// True if an exception should be thrown when the
    /// user is not authorized to read this property.</param>
    protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field, P defaultValue, Security.NoAccessBehavior noAccess)
    {
      return GetProperty<P>(propertyInfo.Name, field, defaultValue, noAccess);
    }

    /// <summary>
    /// Lazily initializes a property and returns
    /// the resulting value.
    /// </summary>
    /// <typeparam name="P">Type of the property.</typeparam>
    /// <param name="property">PropertyInfo object containing property metadata.</param>
    /// <param name="valueGenerator">Method returning the new value.</param>
    /// <returns></returns>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P LazyGetProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
    {
      if (!(FieldManager.FieldExists(property)))
      {
        var result = valueGenerator();
        LoadProperty(property, result);
      }
      return GetProperty<P>(property);
    }

    /// <summary>
    /// Gets a value indicating whether a lazy loaded 
    /// property is currently being retrieved.
    /// </summary>
    /// <param name="propertyInfo">Property to check.</param>
    /// <returns></returns>
    protected bool PropertyIsLoading(IPropertyInfo propertyInfo)
    {
      return LoadManager.IsLoadingProperty(propertyInfo);
    }

    /// <summary>
    /// Lazily initializes a property and returns
    /// the resulting value.
    /// </summary>
    /// <typeparam name="P">Type of the property.</typeparam>
    /// <param name="property">PropertyInfo object containing property metadata.</param>
    /// <param name="factory">Async method returning the new value.</param>
    /// <returns></returns>
    /// <remarks>
    /// <para>
    /// Note that the first value returned is almost certainly
    /// the defaultValue because the value is initialized asynchronously.
    /// The real value is provided later along with a PropertyChanged
    /// event to indicate the value has changed.
    /// </para><para>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </para>
    /// </remarks>
    protected P LazyGetPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
    {
      if (!(FieldManager.FieldExists(property)) && !PropertyIsLoading(property))
      {
        LoadPropertyAsync(property, factory);
      }
      return GetProperty<P>(property);
    }

    /// <summary>
    /// Gets a property's value as 
    /// a specified type, first checking authorization.
    /// </summary>
    /// <typeparam name="F">
    /// Type of the field.
    /// </typeparam>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="field">
    /// The backing field for the property.</param>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field)
    {
      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException));
    }

    /// <summary>
    /// Gets a property's value as a specified type, 
    /// first checking authorization.
    /// </summary>
    /// <typeparam name="F">
    /// Type of the field.
    /// </typeparam>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="field">
    /// The backing field for the property.</param>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="noAccess">
    /// True if an exception should be thrown when the
    /// user is not authorized to read this property.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field, Security.NoAccessBehavior noAccess)
    {
      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, noAccess));
    }

    /// <summary>
    /// Gets a property's managed field value, 
    /// first checking authorization.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetProperty<P>(PropertyInfo<P> propertyInfo)
    {
      return GetProperty<P>(propertyInfo, Security.NoAccessBehavior.SuppressException);
    }

    /// <summary>
    /// Gets a property's value from the list of 
    /// managed field values, first checking authorization,
    /// and converting the value to an appropriate type.
    /// </summary>
    /// <typeparam name="F">
    /// Type of the field.
    /// </typeparam>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo)
    {
      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, Security.NoAccessBehavior.SuppressException));
    }

    /// <summary>
    /// Gets a property's value from the list of 
    /// managed field values, first checking authorization,
    /// and converting the value to an appropriate type.
    /// </summary>
    /// <typeparam name="F">
    /// Type of the field.
    /// </typeparam>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="noAccess">
    /// True if an exception should be thrown when the
    /// user is not authorized to read this property.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, Security.NoAccessBehavior noAccess)
    {
      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, noAccess));
    }

    /// <summary>
    /// Gets a property's value as a specified type, 
    /// first checking authorization.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="noAccess">
    /// True if an exception should be thrown when the
    /// user is not authorized to read this property.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected P GetProperty<P>(PropertyInfo<P> propertyInfo, Security.NoAccessBehavior noAccess)
    {
      if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
      {
        if (PropertyIsLoading(propertyInfo))
          return propertyInfo.DefaultValue;
        throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
      }

      P result = default(P);
      if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))
        result = ReadProperty<P>(propertyInfo);
      else
        result = propertyInfo.DefaultValue;
      return result;
    }

    /// <summary>
    /// Gets a property's value as a specified type.
    /// </summary>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <remarks>
    /// If the user is not authorized to read the property
    /// value, the defaultValue value is returned as a
    /// result.
    /// </remarks>
    protected object GetProperty(IPropertyInfo propertyInfo)
    {
      object result = null;
      if (CanReadProperty(propertyInfo, false))
      {
        // call ReadProperty (may be overloaded in actual class)
        result = ReadProperty(propertyInfo);
      }
      else
      {
        result = propertyInfo.DefaultValue;
      }
      return result;
    }

#endregion

#region  Read Properties

    /// <summary>
    /// Gets a property's value from the list of 
    /// managed field values, converting the 
    /// value to an appropriate type.
    /// </summary>
    /// <typeparam name="F">
    /// Type of the field.
    /// </typeparam>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    protected P ReadPropertyConvert<F, P>(PropertyInfo<F> propertyInfo)
    {
      return Utilities.CoerceValue<P>(typeof(F), null, ReadProperty<F>(propertyInfo));
    }

    /// <summary>
    /// Gets a property's value as a specified type.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    protected P ReadProperty<P>(PropertyInfo<P> propertyInfo)
    {
      if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))
      {
        if (PropertyIsLoading(propertyInfo))
          return default;
        throw new InvalidOperationException(Resources.PropertyGetNotAllowed);
      }

      P result = default(P);
      IFieldData data = FieldManager.GetFieldData(propertyInfo);
      if (data != null)
      {
        IFieldData<P> fd = data as IFieldData<P>;
        if (fd != null)
          result = fd.Value;
        else
          result = (P)data.Value;
      }
      else
      {
        result = propertyInfo.DefaultValue;
        FieldManager.LoadFieldData<P>(propertyInfo, result);
      }
      return result;
    }

    /// <summary>
    /// Gets a property's value as a specified type.
    /// </summary>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    protected virtual object ReadProperty(IPropertyInfo propertyInfo)
    {
      if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)
      {
        return MethodCaller.CallPropertyGetter(this, propertyInfo.Name);
      }

      object result = null;
      var info = FieldManager.GetFieldData(propertyInfo);
      if (info != null)
      {
        result = info.Value;
      }
      else
      {
        result = propertyInfo.DefaultValue;
        FieldManager.LoadFieldData(propertyInfo, result);
      }
      return result;
    }

    /// <summary>
    /// Gets a property's value as a specified type.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="property">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="valueGenerator">Method returning the new value.</param>
    protected P LazyReadProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)
    {
      if (!(FieldManager.FieldExists(property)))
      {
        var result = valueGenerator();
        LoadProperty(property, result);
      }
      return ReadProperty<P>(property);
    }

    /// <summary>
    /// Gets a property's value as a specified type.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="property">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="factory">Async method returning the new value.</param>
    protected P LazyReadPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)
    {
      if (!(FieldManager.FieldExists(property)) && !PropertyIsLoading(property))
      {
        LoadPropertyAsync(property, factory);
      }
      return ReadProperty<P>(property);
    }

    P IManageProperties.LazyReadProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
    {
      return LazyReadProperty(propertyInfo, valueGenerator);
    }

    P IManageProperties.LazyReadPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
    {
      return LazyReadPropertyAsync(propertyInfo, factory);
    }

#endregion

#region  Load Properties

    /// <summary>
    /// Loads a property's managed field with the 
    /// supplied value calling PropertyHasChanged 
    /// if the value does change.
    /// </summary>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="newValue">
    /// The new value for the property.</param>
    /// <remarks>
    /// No authorization checks occur when this method is called,
    /// and no PropertyChanging or PropertyChanged events are raised.
    /// Loading values does not cause validation rules to be
    /// invoked.
    /// </remarks>
    protected void LoadPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue)
    {
      try
      {
        P oldValue = default(P);
        var fieldData = FieldManager.GetFieldData(propertyInfo);
        if (fieldData == null)
        {
          oldValue = propertyInfo.DefaultValue;
          fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);
        }
        else
        {
          oldValue = (P)fieldData.Value;
        }

        if (oldValue == null)
        {
          if (newValue != null)
            FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));
        }
        else if (!(oldValue.Equals(newValue)))
        {
          FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));
        }
      }
      catch (Exception ex)
      {
        throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));
      }
    }

    void Core.IManageProperties.LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
    {
      LoadProperty<P>(propertyInfo, newValue);
    }

    bool Core.IManageProperties.FieldExists(Core.IPropertyInfo property)
    {
      return FieldManager.FieldExists(property);
    }

    /// <summary>
    /// Loads a property's managed field with the 
    /// supplied value calling PropertyHasChanged 
    /// if the value does change.
    /// </summary>
    /// <typeparam name="P">
    /// Type of the property.
    /// </typeparam>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="newValue">
    /// The new value for the property.</param>
    /// <remarks>
    /// No authorization checks occur when this method is called,
    /// and no PropertyChanging or PropertyChanged events are raised.
    /// Loading values does not cause validation rules to be
    /// invoked.
    /// </remarks>
    protected void LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)
    {
      try
      {
        P oldValue = default(P);
        var fieldData = FieldManager.GetFieldData(propertyInfo);
        if (fieldData == null)
        {
          oldValue = propertyInfo.DefaultValue;
          fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);
        }
        else
        {
          oldValue = (P)fieldData.Value;
        }

        if (oldValue == null)
        {
          if (newValue != null)
            FieldManager.LoadFieldData(propertyInfo, newValue);
        }
        else if (!(oldValue.Equals(newValue)))
        {
          FieldManager.LoadFieldData(propertyInfo, newValue);
        }
      }
      catch (Exception ex)
      {
        throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));
      }
    }

    /// <summary>
    /// Loads a property's managed field with the 
    /// supplied value calling PropertyHasChanged 
    /// if the value does change.
    /// </summary>
    /// <param name="propertyInfo">
    /// PropertyInfo object containing property metadata.</param>
    /// <param name="newValue">
    /// The new value for the property.</param>
    /// <remarks>
    /// No authorization checks occur when this method is called,
    /// and no PropertyChanging or PropertyChanged events are raised.
    /// Loading values does not cause validation rules to be
    /// invoked.
    /// </remarks>
    protected virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)
    {
      var t = this.GetType();
      var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
      var method = t.GetMethods(flags).Where(c => c.Name == "LoadProperty" && c.IsGenericMethod).FirstOrDefault();
      var gm = method.MakeGenericMethod(propertyInfo.Type);
      var p = new object[] { propertyInfo, newValue };
      gm.Invoke(this, p);
    }

    //private AsyncLoadManager
    [NonSerialized]
    private AsyncLoadManager _loadManager;
    internal AsyncLoadManager LoadManager
    {
      get
      {
        if (_loadManager == null)
        {
          _loadManager = new AsyncLoadManager(this, OnPropertyChanged);
          _loadManager.BusyChanged += loadManager_BusyChanged;
          _loadManager.UnhandledAsyncException += loadManager_UnhandledAsyncException;
        }
        return _loadManager;
      }
    }

    void loadManager_UnhandledAsyncException(object sender, Csla.Core.ErrorEventArgs e)
    {
      OnUnhandledAsyncException(e);
    }

    void loadManager_BusyChanged(object sender, BusyChangedEventArgs e)
    {
      OnBusyChanged(e);
    }
    /*
    /// <summary>
    /// Loads a property value asynchronously.
    /// </summary>
    /// <typeparam name="R">Type of the property</typeparam>
    /// <typeparam name="P">Type of the parameter.</typeparam>
    /// <param name="property">Property to load.</param>
    /// <param name="factory">AsyncFactory delegate.</param>
    //protected void LoadPropertyAsync<R>(PropertyInfo<R> property, AsyncFactoryDelegate<R> factory)
    //{
    //  LoadManager.BeginLoad(new AsyncLoader<R>(property, factory));
    //}

    /// <summary>
    /// Loads a property value asynchronously.
    /// </summary>
    /// <typeparam name="R">Type of the property</typeparam>
    /// <typeparam name="P">Type of the parameter.</typeparam>
    /// <param name="property">Property to load.</param>
    /// <param name="factory">AsyncFactory delegate.</param>
    /// <param name="parameter">Parameter value.</param>
    //protected void LoadPropertyAsync<R, P>(PropertyInfo<R> property, AsyncFactoryDelegate<R, P> factory, P parameter)
    //{
    //  LoadManager.BeginLoad(new AsyncLoader<R>(property, factory, parameter));
    //}
    */

    /// <summary>
    /// Load a property from an async method. 
    /// </summary>
    /// <typeparam name="R"></typeparam>
    /// <param name="property"></param>
    /// <param name="factory"></param>
    protected void LoadPropertyAsync<R>(PropertyInfo<R> property, Task<R> factory)
    {
      LoadManager.BeginLoad(new TaskLoader<R>(property, factory));
    }
#endregion

#region  Field Manager

    [NotUndoable()]
    private FieldDataManager _fieldManager;

    /// <summary>
    /// Gets the PropertyManager object for this
    /// business object.
    /// </summary>
    protected FieldDataManager FieldManager
    {
      get
      {
        if (_fieldManager == null)
        {
          _fieldManager = new FieldDataManager(ApplicationContext, this.GetType());
        }
        return _fieldManager;
      }
    }

    FieldDataManager IUseFieldManager.FieldManager => FieldManager;

#endregion

#region IsBusy / IsIdle

    [NonSerialized]
    [NotUndoable]
    private bool _isBusy;

    /// <summary>
    /// Marks the object as being busy (it is
    /// running an async operation).
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected void MarkBusy()
    {
      if (_isBusy)
        throw new InvalidOperationException(Resources.BusyObjectsMayNotBeMarkedBusy);

      _isBusy = true;
      OnBusyChanged(new BusyChangedEventArgs("", true));
    }

    /// <summary>
    /// Marks the object as being not busy
    /// (it is not running an async operation).
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected void MarkIdle()
    {
      _isBusy = false;
      OnBusyChanged(new BusyChangedEventArgs("", false));
    }

    /// <summary>
    /// Gets a value indicating whether this
    /// object or any of its child objects are
    /// running an async operation.
    /// </summary>
    [Browsable(false)]
    [Display(AutoGenerateField = false)]
    [ScaffoldColumn(false)]
    public virtual bool IsBusy
    {
      get { return IsSelfBusy || (_fieldManager != null && FieldManager.IsBusy()); }
    }

    /// <summary>
    /// Gets a value indicating whether this
    /// object is
    /// running an async operation.
    /// </summary>
    [Browsable(false)]
    [Display(AutoGenerateField = false)]
    [ScaffoldColumn(false)]
    public virtual bool IsSelfBusy
    {
      get { return _isBusy || LoadManager.IsLoading; }
    }

    void Child_PropertyBusy(object sender, BusyChangedEventArgs e)
    {
      OnBusyChanged(e);
    }

    [NotUndoable]
    [NonSerialized]
    private BusyChangedEventHandler _propertyBusy;

    /// <summary>
    /// Event raised when the IsBusy property value
    /// has changed.
    /// </summary>
    public event BusyChangedEventHandler BusyChanged
    {
      add { _propertyBusy = (BusyChangedEventHandler)Delegate.Combine(_propertyBusy, value); }
      remove { _propertyBusy = (BusyChangedEventHandler)Delegate.Remove(_propertyBusy, value); }
    }

    /// <summary>
    /// Raises the BusyChanged event.
    /// </summary>
    /// <param name="propertyName">Name of the property
    /// that has changed.</param>
    /// <param name="busy">New busy value.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected void OnBusyChanged(string propertyName, bool busy)
    {
      OnBusyChanged(new BusyChangedEventArgs(propertyName, busy));
    }

    /// <summary>
    /// Raises the BusyChanged event.
    /// </summary>
    /// <param name="args">Event arguments.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnBusyChanged(BusyChangedEventArgs args)
    {
      if (_propertyBusy != null)
        _propertyBusy(this, args);
    }

#endregion

#region IDataPortalTarget Members

    void Csla.Server.IDataPortalTarget.CheckRules()
    { }

    void Csla.Server.IDataPortalTarget.MarkAsChild()
    { }

    void Csla.Server.IDataPortalTarget.MarkNew()
    { }

    void Csla.Server.IDataPortalTarget.MarkOld()
    { }

    void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
    {
      this.DataPortal_OnDataPortalInvoke(e);
    }

    void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
    {
      this.DataPortal_OnDataPortalInvokeComplete(e);
    }

    void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)
    {
      this.DataPortal_OnDataPortalException(e, ex);
    }

    void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)
    {
      this.Child_OnDataPortalInvoke(e);
    }

    void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)
    {
      this.Child_OnDataPortalInvokeComplete(e);
    }

    void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
    {
      this.Child_OnDataPortalException(e, ex);
    }

#endregion

#region IManageProperties Members

    bool IManageProperties.HasManagedProperties
    {
      get { return (_fieldManager != null && _fieldManager.HasFields); }
    }

    List<IPropertyInfo> IManageProperties.GetManagedProperties()
    {
      return FieldManager.GetRegisteredProperties();
    }

    object IManageProperties.GetProperty(IPropertyInfo propertyInfo)
    {
      return GetProperty(propertyInfo);
    }

    object IManageProperties.LazyGetProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)
    {
      return LazyGetProperty(propertyInfo, valueGenerator);
    }

    object IManageProperties.LazyGetPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)
    {
      return LazyGetPropertyAsync(propertyInfo, factory);
    }

    object IManageProperties.ReadProperty(IPropertyInfo propertyInfo)
    {
      return ReadProperty(propertyInfo);
    }

    P IManageProperties.ReadProperty<P>(PropertyInfo<P> propertyInfo)
    {
      return ReadProperty<P>(propertyInfo);
    }

    void IManageProperties.SetProperty(IPropertyInfo propertyInfo, object newValue)
    {
      throw new NotImplementedException("IManageProperties.SetProperty");
    }

    void IManageProperties.LoadProperty(IPropertyInfo propertyInfo, object newValue)
    {
      LoadProperty(propertyInfo, newValue);
    }

    bool IManageProperties.LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)
    {
      LoadProperty(propertyInfo, newValue);
      return false;
    }

    List<object> IManageProperties.GetChildren()
    {
      return FieldManager.GetChildren();
    }
#endregion

#region MobileFormatter

    /// <summary>
    /// Override this method to insert your child object
    /// references into the MobileFormatter serialzation stream.
    /// </summary>
    /// <param name="info">
    /// Object containing the data to serialize.
    /// </param>
    /// <param name="formatter">
    /// Reference to MobileFormatter instance. Use this to
    /// convert child references to/from reference id values.
    /// </param>
    protected override void OnGetChildren(
      Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)
    {
      base.OnGetChildren(info, formatter);
      if (_fieldManager != null)
      {
        var fieldManagerInfo = formatter.SerializeObject(_fieldManager);
        info.AddChild("_fieldManager", fieldManagerInfo.ReferenceId);
      }
    }

    /// <summary>
    /// Override this method to retrieve your child object
    /// references from the MobileFormatter serialzation stream.
    /// </summary>
    /// <param name="info">
    /// Object containing the data to serialize.
    /// </param>
    /// <param name="formatter">
    /// Reference to MobileFormatter instance. Use this to
    /// convert child references to/from reference id values.
    /// </param>
    protected override void OnSetChildren(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)
    {
      if (info.Children.ContainsKey("_fieldManager"))
      {
        var childData = info.Children["_fieldManager"];
        _fieldManager = (FieldDataManager)formatter.GetObject(childData.ReferenceId);
      }
      base.OnSetChildren(info, formatter);
    }

#endregion

#region INotifyUnhandledAsyncException Members

    [NotUndoable]
    [NonSerialized]
    private EventHandler<Csla.Core.ErrorEventArgs> _unhandledAsyncException;

    /// <summary>
    /// Event raised when an exception occurs on a background
    /// thread during an asynchronous operation.
    /// </summary>
    public event EventHandler<Csla.Core.ErrorEventArgs> UnhandledAsyncException
    {
      add { _unhandledAsyncException = (EventHandler<Csla.Core.ErrorEventArgs>)Delegate.Combine(_unhandledAsyncException, value); }
      remove { _unhandledAsyncException = (EventHandler<Csla.Core.ErrorEventArgs>)Delegate.Remove(_unhandledAsyncException, value); }
    }

    /// <summary>
    /// Raises the UnhandledAsyncException event.
    /// </summary>
    /// <param name="error">Error arguments.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected virtual void OnUnhandledAsyncException(Csla.Core.ErrorEventArgs error)
    {
      if (_unhandledAsyncException != null)
        _unhandledAsyncException(this, error);
    }

    /// <summary>
    /// Raises the UnhandledAsyncException event.
    /// </summary>
    /// <param name="originalSender">Original sender of the
    /// event.</param>
    /// <param name="error">Execption that occurred.</param>
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    protected void OnUnhandledAsyncException(object originalSender, Exception error)
    {
      OnUnhandledAsyncException(new Csla.Core.ErrorEventArgs(originalSender, error));
    }

#endregion
  }
}
<MSG> Fix RegisterMethod implementation.
bugid: 13


<DFF> @@ -603,6 +603,51 @@ protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>>
 
     #endregion
 
+    #region Register Methods
+
+    /// <summary>
+    /// Indicates that the specified method belongs
+    /// to the type.
+    /// </summary>
+    /// <param name="objectType">
+    /// Type of object to which the method belongs.
+    /// </param>
+    /// <param name="info">
+    /// IMemberInfo object for the property.
+    /// </param>
+    /// <returns>
+    /// The provided IMemberInfo object.
+    /// </returns>
+    protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)
+    {
+      var reflected = objectType.GetMethod(info.Name);
+      if (reflected == null)
+        throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");
+      return info;
+    }
+
+    /// <summary>
+    /// Indicates that the specified method belongs
+    /// to the type.
+    /// </summary>
+    /// <param name="objectType">
+    /// Type of object to which the method belongs.
+    /// </param>
+    /// <param name="methodName">
+    /// Name of the method.
+    /// </param>
+    /// <returns>
+    /// The provided IMemberInfo object.
+    /// </returns>
+    protected static MethodInfo RegisterMethod(Type objectType, string methodName)
+    {
+      var info = new MethodInfo(methodName);
+      RegisterMethod(objectType, info);
+      return info;
+    }
+
+    #endregion
+
     #region  Get Properties
 
     /// <summary>

{'commit': 'diff --git a/Source/Csla/Core/BusinessBase.cs b/Source/Csla/Core/BusinessBase.cs\nindex b6fb1c4aa..50fc9e270 100644\n--- a/Source/Csla/Core/BusinessBase.cs\n+++ b/Source/Csla/Core/BusinessBase.cs\n@@ -1464,7 +1464,7 @@ protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberIn\n     {\n       var reflected = objectType.GetMethod(info.Name);\n       if (reflected == null)\n-        throw new ArgumentException("No such method " + info.Name, "info");\n+        throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");\n       return info;\n     }\n \n@@ -1481,9 +1481,11 @@ protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberIn\n     /// <returns>\n     /// The provided IMemberInfo object.\n     /// </returns>\n-    protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, string methodName)\n+    protected static MethodInfo RegisterMethod(Type objectType, string methodName)\n     {\n-      return RegisterMethod(objectType, new MethodInfo(methodName));\n+      var info = new MethodInfo(methodName);\n+      RegisterMethod(objectType, info);\n+      return info;\n     }\n \n     #endregion\ndiff --git a/Source/Csla/Properties/Resources.Designer.cs b/Source/Csla/Properties/Resources.Designer.cs\nindex 6036e72ba..055c93f42 100644\n--- a/Source/Csla/Properties/Resources.Designer.cs\n+++ b/Source/Csla/Properties/Resources.Designer.cs\n@@ -1,7 +1,7 @@\n \ufeff//------------------------------------------------------------------------------\n // <auto-generated>\n //     This code was generated by a tool.\n-//     Runtime Version:4.0.30128.1\n+//     Runtime Version:4.0.30319.1\n //\n //     Changes to this file may cause incorrect behavior and will be lost if\n //     the code is regenerated.\n@@ -699,6 +699,15 @@ public class Resources {\n             }\n         }\n         \n+        /// <summary>\n+        ///   Looks up a localized string similar to No such method {0}.\n+        /// </summary>\n+        public static string NoSuchMethod {\n+            get {\n+                return ResourceManager.GetString("NoSuchMethod", resourceCulture);\n+            }\n+        }\n+        \n         /// <summary>\n         ///   Looks up a localized string similar to No such value exists:.\n         /// </summary>\ndiff --git a/Source/Csla/Properties/Resources.resx b/Source/Csla/Properties/Resources.resx\nindex 2027c11a7..b0f5d60ec 100644\n--- a/Source/Csla/Properties/Resources.resx\n+++ b/Source/Csla/Properties/Resources.resx\n@@ -455,4 +455,7 @@\n     <value>This property requires {0} index arguments, {1} were provided</value>\r\n     <comment>Csla.Silverlight</comment>\r\n   </data>\r\n+  <data name="NoSuchMethod" xml:space="preserve">\r\n+    <value>No such method {0}</value>\r\n+  </data>\r\n </root>\n\\ No newline at end of file\ndiff --git a/Source/Csla/ReadOnlyBase.cs b/Source/Csla/ReadOnlyBase.cs\nindex 8a7fa40f0..a0d76b293 100644\n--- a/Source/Csla/ReadOnlyBase.cs\n+++ b/Source/Csla/ReadOnlyBase.cs\n@@ -603,6 +603,51 @@ protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>>\n \n     #endregion\n \n+    #region Register Methods\n+\n+    /// <summary>\n+    /// Indicates that the specified method belongs\n+    /// to the type.\n+    /// </summary>\n+    /// <param name="objectType">\n+    /// Type of object to which the method belongs.\n+    /// </param>\n+    /// <param name="info">\n+    /// IMemberInfo object for the property.\n+    /// </param>\n+    /// <returns>\n+    /// The provided IMemberInfo object.\n+    /// </returns>\n+    protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)\n+    {\n+      var reflected = objectType.GetMethod(info.Name);\n+      if (reflected == null)\n+        throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");\n+      return info;\n+    }\n+\n+    /// <summary>\n+    /// Indicates that the specified method belongs\n+    /// to the type.\n+    /// </summary>\n+    /// <param name="objectType">\n+    /// Type of object to which the method belongs.\n+    /// </param>\n+    /// <param name="methodName">\n+    /// Name of the method.\n+    /// </param>\n+    /// <returns>\n+    /// The provided IMemberInfo object.\n+    /// </returns>\n+    protected static MethodInfo RegisterMethod(Type objectType, string methodName)\n+    {\n+      var info = new MethodInfo(methodName);\n+      RegisterMethod(objectType, info);\n+      return info;\n+    }\n+\n+    #endregion\n+\n     #region  Get Properties\n \n     /// <summary>\n', 'commit_subject': 'Fix RegisterMethod implementation. bugid: 13', 'repo_name': 'MarimerLLC/csla', 'committer': {'name': 'rocky@lhotka.net', 'email': '97d1c8e71df7104d35e31cdbf1b52cb0bc6240b8@fa5919ed-4f44-5740-a13a-40f41935fe31', 'time_sec': '1272314695', 'tz_offset': '0', 'date': {'seconds': '1272314695'}}, 'commit_tree': 'c552d6f3f518cd595fd5e3408ccfbcc0136d37bc', 'commit_message': 'Fix RegisterMethod implementation.\nbugid: 13\n\n', 'language_name': 'Shell', 'license': 'mit', 'hunks': '@@ -603,6 +603,51 @@ protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>>\n \n     #endregion\n \n+    #region Register Methods\n+\n+    /// <summary>\n+    /// Indicates that the specified method belongs\n+    /// to the type.\n+    /// </summary>\n+    /// <param name="objectType">\n+    /// Type of object to which the method belongs.\n+    /// </param>\n+    /// <param name="info">\n+    /// IMemberInfo object for the property.\n+    /// </param>\n+    /// <returns>\n+    /// The provided IMemberInfo object.\n+    /// </returns>\n+    protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)\n+    {\n+      var reflected = objectType.GetMethod(info.Name);\n+      if (reflected == null)\n+        throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");\n+      return info;\n+    }\n+\n+    /// <summary>\n+    /// Indicates that the specified method belongs\n+    /// to the type.\n+    /// </summary>\n+    /// <param name="objectType">\n+    /// Type of object to which the method belongs.\n+    /// </param>\n+    /// <param name="methodName">\n+    /// Name of the method.\n+    /// </param>\n+    /// <returns>\n+    /// The provided IMemberInfo object.\n+    /// </returns>\n+    protected static MethodInfo RegisterMethod(Type objectType, string methodName)\n+    {\n+      var info = new MethodInfo(methodName);\n+      RegisterMethod(objectType, info);\n+      return info;\n+    }\n+\n+    #endregion\n+\n     #region  Get Properties\n \n     /// <summary>\n', 'addition_count': 45, 'deletion_count': 0, 'src_file': 'a/Source/Csla/ReadOnlyBase.cs', 'tgt_file': 'b/Source/Csla/ReadOnlyBase.cs', 'file_extension': '.cs', 'before_file': '//-----------------------------------------------------------------------\n// <copyright file="ReadOnlyBase.cs" company="Marimer LLC">\n//     Copyright (c) Marimer LLC. All rights reserved.\n//     Website: https://cslanet.com\n// </copyright>\n// <summary>This is a base class from which readonly business classes</summary>\n//-----------------------------------------------------------------------\nusing System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.ComponentModel.DataAnnotations;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing System.Threading.Tasks;\nusing Csla.Core;\nusing Csla.Core.FieldManager;\nusing Csla.Core.LoadManager;\nusing Csla.Properties;\nusing Csla.Reflection;\nusing Csla.Rules;\nusing Csla.Security;\nusing Csla.Serialization.Mobile;\nusing Csla.Server;\nusing System.Collections.Concurrent;\n\nnamespace Csla\n{\n  /// <summary>\n  /// This is a base class from which readonly business classes\n  /// can be derived.\n  /// </summary>\n  /// <remarks>\n  /// This base class only supports data retrieve, not updating or\n  /// deleting. Any business classes derived from this base class\n  /// should only implement readonly properties.\n  /// </remarks>\n  /// <typeparam name="T">Type of the business object.</typeparam>\n  [Serializable()]\n  public abstract class ReadOnlyBase<T> : BindableBase,\n    ICloneable,\n    IReadOnlyObject,\n    ISerializationNotification,\n    IAuthorizeReadWrite,\n    IDataPortalTarget,\n    IManageProperties,\n    INotifyBusy,\n    IHostRules,\n    IReadOnlyBase,\n    IUseApplicationContext,\n    IUseFieldManager,\n    IUseBusinessRules\n    where T : ReadOnlyBase<T>\n  {\n    #region Object ID Value\n\n    /// <summary>\n    /// Override this method to return a unique identifying\n    /// value for this object.\n    /// </summary>\n    protected virtual object GetIdValue()\n    {\n      return null;\n    }\n\n    #endregion\n\n    #region System.Object Overrides\n\n    /// <summary>\n    /// Returns a text representation of this object by\n    /// returning the <see cref="GetIdValue"/> value\n    /// in text form.\n    /// </summary>\n    public override string ToString()\n    {\n      object id = GetIdValue();\n      if (id == null)\n        return base.ToString();\n      else\n        return id.ToString();\n    }\n\n    #endregion\n\n    /// <summary>\n    /// Gets or sets the current ApplicationContext object.\n    /// </summary>\n    protected ApplicationContext ApplicationContext { get; set; }\n    ApplicationContext IUseApplicationContext.ApplicationContext \n    { \n      get => ApplicationContext;\n      set\n      {\n        ApplicationContext = value;\n        Initialize();\n        InitializeBusinessRules();\n      }\n    }\n\n    /// <summary>\n    /// Creates an instance of the type.\n    /// </summary>\n    protected ReadOnlyBase()\n    {\n    }\n\n    #region Initialize\n\n    /// <summary>\n    /// Override this method to set up event handlers so user\n    /// code in a partial class can respond to events raised by\n    /// generated code.\n    /// </summary>\n    protected virtual void Initialize()\n    { /* allows subclass to initialize events before any other activity occurs */ }\n\n    #endregion\n\n    #region Identity\n\n    int IBusinessObject.Identity\n    {\n      get { return 0; }\n    }\n\n    #endregion\n\n    #region Authorization\n\n    [NotUndoable()]\n    [NonSerialized()]\n    private ConcurrentDictionary<string, bool> _readResultCache;\n    [NotUndoable()]\n    [NonSerialized()]\n    private ConcurrentDictionary<string, bool> _executeResultCache;\n    [NotUndoable()]\n    [NonSerialized()]\n    private System.Security.Principal.IPrincipal _lastPrincipal;\n\n    private void InitializeBusinessRules()\n    {\n      var rules = BusinessRuleManager.GetRulesForType(this.GetType());\n      if (!rules.Initialized)\n        lock (rules)\n          if (!rules.Initialized)\n          {\n            try\n            {\n              AddBusinessRules();\n              rules.Initialized = true;\n            }\n            catch (Exception)\n            {\n              BusinessRuleManager.CleanupRulesForType(this.GetType());\n              throw;  // and rethrow exception\n            }\n          }\n    }\n\n    private Csla.Rules.BusinessRules _businessRules;\n\n    /// <summary>\n    /// Provides access to the broken rules functionality.\n    /// </summary>\n    /// <remarks>\n    /// This property is used within your business logic so you can\n    /// easily call the AddRule() method to associate business\n    /// rules with your object\'s properties.\n    /// </remarks>\n    protected BusinessRules BusinessRules\n    {\n      get\n      {\n        if (_businessRules == null)\n          _businessRules = ApplicationContext.CreateInstanceDI<BusinessRules>(ApplicationContext, this);\n        else if (_businessRules.Target == null)\n          _businessRules.SetTarget(this);\n        return _businessRules;\n      }\n    }\n\n    BusinessRules IUseBusinessRules.BusinessRules => BusinessRules;\n\n    void IHostRules.RuleStart(IPropertyInfo property)\n    { }\n\n    void IHostRules.RuleComplete(IPropertyInfo property)\n    { }\n\n    void IHostRules.RuleComplete(string property)\n    { }\n\n    void Rules.IHostRules.AllRulesComplete()\n    { }\n\n    /// <summary>\n    /// Override this method to add per-type\n    /// authorization rules for your type\'s properties.\n    /// </summary>\n    /// <remarks>\n    /// AddSharedAuthorizationRules is automatically called by CSLA .NET\n    /// when your object should associate per-type authorization roles\n    /// with its properties.\n    /// </remarks>\n    protected virtual void AddBusinessRules()\n    { }\n\n    /// <summary>\n    /// Returns true if the user is allowed to read the\n    /// calling property.\n    /// </summary>\n    /// <param name="property">Property to check.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public virtual bool CanReadProperty(Csla.Core.IPropertyInfo property)\n    {\n      bool result = true;\n\n      VerifyAuthorizationCache();\n\n      if (!_readResultCache.TryGetValue(property.Name, out result))\n      {\n        result = BusinessRules.HasPermission(ApplicationContext, AuthorizationActions.ReadProperty, property);\n        // store value in cache\n        _readResultCache.AddOrUpdate(property.Name, result, (a, b) => { return result; });\n      }\n      return result;\n    }\n\n    /// <summary>\n    /// Returns true if the user is allowed to read the\n    /// calling property.\n    /// </summary>\n    /// <returns>true if read is allowed.</returns>\n    /// <param name="property">Property to read.</param>\n    /// <param name="throwOnFalse">Indicates whether a negative\n    /// result should cause an exception.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public bool CanReadProperty(Csla.Core.IPropertyInfo property, bool throwOnFalse)\n    {\n      bool result = CanReadProperty(property);\n      if (throwOnFalse && result == false)\n      {\n        Csla.Security.SecurityException ex = new Csla.Security.SecurityException(\n          String.Format("{0} ({1})",\n          Resources.PropertyGetNotAllowed, property.Name));\n        throw ex;\n      }\n      return result;\n    }\n\n    /// <summary>\n    /// Returns true if the user is allowed to read the\n    /// specified property.\n    /// </summary>\n    /// <param name="propertyName">Name of the property to read.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public bool CanReadProperty(string propertyName)\n    {\n      return CanReadProperty(propertyName, false);\n    }\n\n    /// <summary>\n    /// Returns true if the user is allowed to read the\n    /// specified property.\n    /// </summary>\n    /// <param name="propertyName">Name of the property to read.</param>\n    /// <param name="throwOnFalse">Indicates whether a negative\n    /// result should cause an exception.</param>\n    private bool CanReadProperty(string propertyName, bool throwOnFalse)\n    {\n      var propertyInfo = FieldManager.GetRegisteredProperties().FirstOrDefault(p => p.Name == propertyName);\n      if (propertyInfo == null)\n      {\n#if NETFX_CORE || (ANDROID || IOS)\n#else\n        Trace.TraceError("CanReadProperty: {0} is not a registered property of {1}.{2}", propertyName, this.GetType().Namespace, this.GetType().Name);\n#endif\n        return true;\n      }\n      return CanReadProperty(propertyInfo, throwOnFalse);\n    }\n\n    bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(string propertyName)\n    {\n      return false;\n    }\n\n    bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(IPropertyInfo property)\n    {\n      return false;\n    }\n\n    private void VerifyAuthorizationCache()\n    {\n      if (_readResultCache == null)\n        _readResultCache = new ConcurrentDictionary<string, bool>();\n      if (_executeResultCache == null)\n        _executeResultCache = new ConcurrentDictionary<string, bool>();\n      if (!ReferenceEquals(ApplicationContext.User, _lastPrincipal))\n      {\n        // the principal has changed - reset the cache\n        _readResultCache.Clear();\n        _executeResultCache.Clear();\n        _lastPrincipal = ApplicationContext.User;\n      }\n    }\n\n    /// <summary>\n    /// Returns true if the user is allowed to execute\n    /// the specified method.\n    /// </summary>\n    /// <param name="method">Method to execute.</param>\n    /// <returns>true if execute is allowed.</returns>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public virtual bool CanExecuteMethod(Csla.Core.IMemberInfo method)\n    {\n      bool result = true;\n\n      VerifyAuthorizationCache();\n\n      if (!_executeResultCache.TryGetValue(method.Name, out result))\n      {\n        result = BusinessRules.HasPermission(ApplicationContext, AuthorizationActions.ExecuteMethod, method);\n        _executeResultCache.AddOrUpdate(method.Name, result, (a, b) => { return result; });\n      }\n      return result;\n    }\n\n    /// <summary>\n    /// Returns true if the user is allowed to execute\n    /// the specified method.\n    /// </summary>\n    /// <returns>true if execute is allowed.</returns>\n    /// <param name="method">Method to execute.</param>\n    /// <param name="throwOnFalse">Indicates whether a negative\n    /// result should cause an exception.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public bool CanExecuteMethod(Csla.Core.IMemberInfo method, bool throwOnFalse)\n    {\n\n      bool result = CanExecuteMethod(method);\n      if (throwOnFalse && result == false)\n      {\n        Csla.Security.SecurityException ex =\n          new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, method.Name));\n        throw ex;\n      }\n      return result;\n\n    }\n\n\n    /// <summary>\n    /// Returns true if the user is allowed to execute\n    /// the specified method.\n    /// </summary>\n    /// <param name="methodName">Name of the method to execute.</param>\n    /// <returns>true if execute is allowed.</returns>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public virtual bool CanExecuteMethod(string methodName)\n    {\n      return CanExecuteMethod(methodName, false);\n    }\n\n    private bool CanExecuteMethod(string methodName, bool throwOnFalse)\n    {\n\n      bool result = CanExecuteMethod(new MethodInfo(methodName));\n      if (throwOnFalse && result == false)\n      {\n        Csla.Security.SecurityException ex = new Csla.Security.SecurityException(string.Format("{0} ({1})", Properties.Resources.MethodExecuteNotAllowed, methodName));\n        throw ex;\n      }\n      return result;\n    }\n\n#endregion\n\n#region IClonable\n\n    object ICloneable.Clone()\n    {\n      return GetClone();\n    }\n\n    /// <summary>\n    /// Creates a clone of the object.\n    /// </summary>\n    /// <returns>A new object containing the exact data of the original object.</returns>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    public virtual object GetClone()\n    {\n      return Core.ObjectCloner.GetInstance(ApplicationContext).Clone(this);\n    }\n\n    /// <summary>\n    /// Creates a clone of the object.\n    /// </summary>\n    /// <returns>\n    /// A new object containing the exact data of the original object.\n    /// </returns>\n    public T Clone()\n    {\n      return (T)GetClone();\n    }\n    #endregion\n\n    #region Data Access\n\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]\n    private void DataPortal_Create(object criteria)\n    {\n      throw new NotSupportedException(Resources.CreateNotSupportedException);\n    }\n\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]\n    private void DataPortal_Update()\n    {\n      throw new NotSupportedException(Resources.UpdateNotSupportedException);\n    }\n\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "criteria")]\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]\n    [Delete]\n    private void DataPortal_Delete(object criteria)\n    {\n      throw new NotSupportedException(Resources.DeleteNotSupportedException);\n    }\n\n    /// <summary>\n    /// Called by the server-side DataPortal prior to calling the \n    /// requested DataPortal_xyz method.\n    /// </summary>\n    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)\n    {\n\n    }\n\n    /// <summary>\n    /// Called by the server-side DataPortal after calling the \n    /// requested DataPortal_xyz method.\n    /// </summary>\n    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)\n    {\n\n    }\n\n    /// <summary>\n    /// Called by the server-side DataPortal if an exception\n    /// occurs during data access.\n    /// </summary>\n    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>\n    /// <param name="ex">The Exception thrown during data access.</param>\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)\n    {\n\n    }\n\n    /// <summary>\n    /// Called by the server-side DataPortal prior to calling the \n    /// requested DataPortal_XYZ method.\n    /// </summary>\n    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void Child_OnDataPortalInvoke(DataPortalEventArgs e)\n    {\n    }\n\n    /// <summary>\n    /// Called by the server-side DataPortal after calling the \n    /// requested DataPortal_XYZ method.\n    /// </summary>\n    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)\n    {\n    }\n\n    /// <summary>\n    /// Called by the server-side DataPortal if an exception\n    /// occurs during data access.\n    /// </summary>\n    /// <param name="e">The DataPortalContext object passed to the DataPortal.</param>\n    /// <param name="ex">The Exception thrown during data access.</param>\n    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")]\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)\n    {\n    }\n\n#endregion\n\n#region Serialization Notification\n\n    void ISerializationNotification.Deserialized()\n    {\n      OnDeserializedHandler(new System.Runtime.Serialization.StreamingContext());\n    }\n\n    [System.Runtime.Serialization.OnDeserialized()]\n    private void OnDeserializedHandler(System.Runtime.Serialization.StreamingContext context)\n    {\n      if (_fieldManager != null)\n        FieldManager.SetPropertyList(this.GetType());\n      InitializeBusinessRules();\n      OnDeserialized(context);\n    }\n\n    /// <summary>\n    /// This method is called on a newly deserialized object\n    /// after deserialization is complete.\n    /// </summary>\n    /// <param name="context">Serialization context object.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void OnDeserialized(System.Runtime.Serialization.StreamingContext context)\n    {\n      // do nothing - this is here so a subclass\n      // could override if needed\n    }\n\n#endregion\n\n#region  Register Properties\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the type.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of property.\n    /// </typeparam>\n    /// <param name="objectType">\n    /// Type of object to which the property belongs.\n    /// </param>\n    /// <param name="info">\n    /// PropertyInfo object for the property.\n    /// </param>\n    /// <returns>\n    /// The provided IPropertyInfo object.\n    /// </returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(Type objectType, PropertyInfo<P> info)\n    {\n      return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(objectType, info);\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of property.\n    /// </typeparam>\n    /// <param name="info">\n    /// PropertyInfo object for the property.\n    /// </param>\n    /// <returns>\n    /// The provided IPropertyInfo object.\n    /// </returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(PropertyInfo<P> info)\n    {\n      return Core.FieldManager.PropertyInfoManager.RegisterProperty<P>(typeof(T), info);\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">Type of property</typeparam>\n    /// <param name="propertyName">Property name from nameof()</param>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName)\n    {\n      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName));\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">Type of property</typeparam>\n    /// <param name="propertyLambdaExpression">Property Expression</param>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression)\n    {\n      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);\n      return RegisterProperty<P>(reflectedPropertyInfo.Name);\n\n    #endregion\n\n    #region  Get Properties\n\n    /// <summary>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue)\n    {\n      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);\n      return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue);\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">Type of property</typeparam>\n    /// <param name="propertyName">Property name from nameof()</param>\n    /// <param name="relationship">Relationship with property value.</param>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, RelationshipTypes relationship)\n    {\n      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, string.Empty, relationship));\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">Type of property</typeparam>\n    /// <param name="propertyLambdaExpression">Property Expression</param>\n    /// <param name="relationship">Relationship with property value.</param>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, RelationshipTypes relationship)\n    {\n      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);\n      return RegisterProperty<P>(reflectedPropertyInfo.Name, relationship);\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">Type of property</typeparam>\n    /// <param name="propertyName">Property name from nameof()</param>\n    /// <param name="friendlyName">Friendly description for a property to be used in databinding</param>\n    /// <param name="defaultValue">Default Value for the property</param>\n    /// <param name="relationship">Relationship with property value.</param>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(string propertyName, string friendlyName, P defaultValue, RelationshipTypes relationship)\n    {\n      return RegisterProperty(Csla.Core.FieldManager.PropertyInfoFactory.Factory.Create<P>(typeof(T), propertyName, friendlyName, defaultValue, relationship));\n    }\n\n    /// <summary>\n    /// Indicates that the specified property belongs\n    /// to the business object type.\n    /// </summary>\n    /// <typeparam name="P">Type of property</typeparam>\n    /// <param name="propertyLambdaExpression">Property Expression</param>\n    /// <param name="friendlyName">Friendly description for a property to be used in databinding</param>\n    /// <param name="defaultValue">Default Value for the property</param>\n    /// <param name="relationship">Relationship with property value.</param>\n    /// <returns></returns>\n    protected static PropertyInfo<P> RegisterProperty<P>(Expression<Func<T, object>> propertyLambdaExpression, string friendlyName, P defaultValue, RelationshipTypes relationship)\n    {\n      PropertyInfo reflectedPropertyInfo = Reflect<T>.GetProperty(propertyLambdaExpression);\n      return RegisterProperty<P>(reflectedPropertyInfo.Name, friendlyName, defaultValue, relationship);\n    }\n    #endregion\n\n    #region Register Methods\n\n    /// <summary>\n    /// Indicates that the specified method belongs\n    /// to the type.\n    /// </summary>\n    /// <param name="objectType">\n    /// Type of object to which the method belongs.\n    /// </param>\n    /// <param name="info">\n    /// IMemberInfo object for the property.\n    /// </param>\n    /// <returns>\n    /// The provided IMemberInfo object.\n    /// </returns>\n    protected static Csla.Core.IMemberInfo RegisterMethod(Type objectType, IMemberInfo info)\n    {\n      var reflected = objectType.GetMethod(info.Name);\n      if (reflected == null)\n        throw new ArgumentException(string.Format(Resources.NoSuchMethod, info.Name), "info");\n      return info;\n    }\n\n    /// <summary>\n    /// Indicates that the specified method belongs\n    /// to the type.\n    /// </summary>\n    /// <param name="objectType">\n    /// Type of object to which the method belongs.\n    /// </param>\n    /// <param name="methodName">\n    /// Name of the method.\n    /// </param>\n    /// <returns>\n    /// The provided IMemberInfo object.\n    /// </returns>\n    protected static MethodInfo RegisterMethod(Type objectType, string methodName)\n    {\n      var info = new MethodInfo(methodName);\n      RegisterMethod(objectType, info);\n      return info;\n    }\n\n    /// <summary>\n    /// Registers a method for use in Authorization.\n    /// </summary>\n    /// <param name="methodName">Method name from nameof()</param>\n    /// <returns></returns>\n    protected static MethodInfo RegisterMethod(string methodName)\n    {\n      return RegisterMethod(typeof(T), methodName);\n    }\n\n    /// <summary>\n    /// Registers the method.\n    /// </summary>\n    /// <param name="methodLambdaExpression">The method lambda expression.</param>\n    /// <returns></returns>\n    protected static MethodInfo RegisterMethod(Expression<Action<T>> methodLambdaExpression)\n    {\n      System.Reflection.MethodInfo reflectedMethodInfo = Reflect<T>.GetMethod(methodLambdaExpression);\n      return RegisterMethod(reflectedMethodInfo.Name);\n    }\n\n#endregion\n\n#region  Get Properties\n\n    /// <summary>\n    /// Gets a property\'s value, first checking authorization.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="field">\n    /// The backing field for the property.</param>\n    /// <param name="propertyName">\n    /// The name of the property.</param>\n    /// <param name="defaultValue">\n    /// Value to be returned if the user is not\n    /// authorized to read the property.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetProperty<P>(string propertyName, P field, P defaultValue)\n    {\n      return GetProperty<P>(propertyName, field, defaultValue, Security.NoAccessBehavior.SuppressException);\n    }\n\n    /// <summary>\n    /// Gets a property\'s value, first checking authorization.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="field">\n    /// The backing field for the property.</param>\n    /// <param name="propertyName">\n    /// The name of the property.</param>\n    /// <param name="defaultValue">\n    /// Value to be returned if the user is not\n    /// authorized to read the property.</param>\n    /// <param name="noAccess">\n    /// True if an exception should be thrown when the\n    /// user is not authorized to read this property.</param>\n    protected P GetProperty<P>(string propertyName, P field, P defaultValue, Security.NoAccessBehavior noAccess)\n    {\n#region Check to see if the property is marked with RelationshipTypes.PrivateField\n\n      var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);\n\n      if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) != RelationshipTypes.PrivateField)\n        throw new InvalidOperationException(Resources.PrivateFieldException);\n\n#endregion\n\n      if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))\n        return field;\n\n      return defaultValue;\n    }\n\n    /// <summary>\n    /// Gets a property\'s value, first checking authorization.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="field">\n    /// The backing field for the property.</param>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)\n    {\n      return GetProperty<P>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException);\n    }\n\n    /// <summary>\n    /// Gets a property\'s value, first checking authorization.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="field">\n    /// The backing field for the property.</param>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="defaultValue">\n    /// Value to be returned if the user is not\n    /// authorized to read the property.</param>\n    /// <param name="noAccess">\n    /// True if an exception should be thrown when the\n    /// user is not authorized to read this property.</param>\n    protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field, P defaultValue, Security.NoAccessBehavior noAccess)\n    {\n      return GetProperty<P>(propertyInfo.Name, field, defaultValue, noAccess);\n    }\n\n    /// <summary>\n    /// Lazily initializes a property and returns\n    /// the resulting value.\n    /// </summary>\n    /// <typeparam name="P">Type of the property.</typeparam>\n    /// <param name="property">PropertyInfo object containing property metadata.</param>\n    /// <param name="valueGenerator">Method returning the new value.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P LazyGetProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)\n    {\n      if (!(FieldManager.FieldExists(property)))\n      {\n        var result = valueGenerator();\n        LoadProperty(property, result);\n      }\n      return GetProperty<P>(property);\n    }\n\n    /// <summary>\n    /// Gets a value indicating whether a lazy loaded \n    /// property is currently being retrieved.\n    /// </summary>\n    /// <param name="propertyInfo">Property to check.</param>\n    /// <returns></returns>\n    protected bool PropertyIsLoading(IPropertyInfo propertyInfo)\n    {\n      return LoadManager.IsLoadingProperty(propertyInfo);\n    }\n\n    /// <summary>\n    /// Lazily initializes a property and returns\n    /// the resulting value.\n    /// </summary>\n    /// <typeparam name="P">Type of the property.</typeparam>\n    /// <param name="property">PropertyInfo object containing property metadata.</param>\n    /// <param name="factory">Async method returning the new value.</param>\n    /// <returns></returns>\n    /// <remarks>\n    /// <para>\n    /// Note that the first value returned is almost certainly\n    /// the defaultValue because the value is initialized asynchronously.\n    /// The real value is provided later along with a PropertyChanged\n    /// event to indicate the value has changed.\n    /// </para><para>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </para>\n    /// </remarks>\n    protected P LazyGetPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)\n    {\n      if (!(FieldManager.FieldExists(property)) && !PropertyIsLoading(property))\n      {\n        LoadPropertyAsync(property, factory);\n      }\n      return GetProperty<P>(property);\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as \n    /// a specified type, first checking authorization.\n    /// </summary>\n    /// <typeparam name="F">\n    /// Type of the field.\n    /// </typeparam>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="field">\n    /// The backing field for the property.</param>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field)\n    {\n      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, Security.NoAccessBehavior.SuppressException));\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type, \n    /// first checking authorization.\n    /// </summary>\n    /// <typeparam name="F">\n    /// Type of the field.\n    /// </typeparam>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="field">\n    /// The backing field for the property.</param>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="noAccess">\n    /// True if an exception should be thrown when the\n    /// user is not authorized to read this property.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, F field, Security.NoAccessBehavior noAccess)\n    {\n      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo.Name, field, propertyInfo.DefaultValue, noAccess));\n    }\n\n    /// <summary>\n    /// Gets a property\'s managed field value, \n    /// first checking authorization.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetProperty<P>(PropertyInfo<P> propertyInfo)\n    {\n      return GetProperty<P>(propertyInfo, Security.NoAccessBehavior.SuppressException);\n    }\n\n    /// <summary>\n    /// Gets a property\'s value from the list of \n    /// managed field values, first checking authorization,\n    /// and converting the value to an appropriate type.\n    /// </summary>\n    /// <typeparam name="F">\n    /// Type of the field.\n    /// </typeparam>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo)\n    {\n      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, Security.NoAccessBehavior.SuppressException));\n    }\n\n    /// <summary>\n    /// Gets a property\'s value from the list of \n    /// managed field values, first checking authorization,\n    /// and converting the value to an appropriate type.\n    /// </summary>\n    /// <typeparam name="F">\n    /// Type of the field.\n    /// </typeparam>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="noAccess">\n    /// True if an exception should be thrown when the\n    /// user is not authorized to read this property.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetPropertyConvert<F, P>(PropertyInfo<F> propertyInfo, Security.NoAccessBehavior noAccess)\n    {\n      return Utilities.CoerceValue<P>(typeof(F), null, GetProperty<F>(propertyInfo, noAccess));\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type, \n    /// first checking authorization.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="noAccess">\n    /// True if an exception should be thrown when the\n    /// user is not authorized to read this property.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected P GetProperty<P>(PropertyInfo<P> propertyInfo, Security.NoAccessBehavior noAccess)\n    {\n      if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))\n      {\n        if (PropertyIsLoading(propertyInfo))\n          return propertyInfo.DefaultValue;\n        throw new InvalidOperationException(Resources.PropertyGetNotAllowed);\n      }\n\n      P result = default(P);\n      if (CanReadProperty(propertyInfo, noAccess == Csla.Security.NoAccessBehavior.ThrowException))\n        result = ReadProperty<P>(propertyInfo);\n      else\n        result = propertyInfo.DefaultValue;\n      return result;\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type.\n    /// </summary>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <remarks>\n    /// If the user is not authorized to read the property\n    /// value, the defaultValue value is returned as a\n    /// result.\n    /// </remarks>\n    protected object GetProperty(IPropertyInfo propertyInfo)\n    {\n      object result = null;\n      if (CanReadProperty(propertyInfo, false))\n      {\n        // call ReadProperty (may be overloaded in actual class)\n        result = ReadProperty(propertyInfo);\n      }\n      else\n      {\n        result = propertyInfo.DefaultValue;\n      }\n      return result;\n    }\n\n#endregion\n\n#region  Read Properties\n\n    /// <summary>\n    /// Gets a property\'s value from the list of \n    /// managed field values, converting the \n    /// value to an appropriate type.\n    /// </summary>\n    /// <typeparam name="F">\n    /// Type of the field.\n    /// </typeparam>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    protected P ReadPropertyConvert<F, P>(PropertyInfo<F> propertyInfo)\n    {\n      return Utilities.CoerceValue<P>(typeof(F), null, ReadProperty<F>(propertyInfo));\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    protected P ReadProperty<P>(PropertyInfo<P> propertyInfo)\n    {\n      if (((propertyInfo.RelationshipType & RelationshipTypes.LazyLoad) == RelationshipTypes.LazyLoad) && !FieldManager.FieldExists(propertyInfo))\n      {\n        if (PropertyIsLoading(propertyInfo))\n          return default;\n        throw new InvalidOperationException(Resources.PropertyGetNotAllowed);\n      }\n\n      P result = default(P);\n      IFieldData data = FieldManager.GetFieldData(propertyInfo);\n      if (data != null)\n      {\n        IFieldData<P> fd = data as IFieldData<P>;\n        if (fd != null)\n          result = fd.Value;\n        else\n          result = (P)data.Value;\n      }\n      else\n      {\n        result = propertyInfo.DefaultValue;\n        FieldManager.LoadFieldData<P>(propertyInfo, result);\n      }\n      return result;\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type.\n    /// </summary>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    protected virtual object ReadProperty(IPropertyInfo propertyInfo)\n    {\n      if ((propertyInfo.RelationshipType & RelationshipTypes.PrivateField) == RelationshipTypes.PrivateField)\n      {\n        return MethodCaller.CallPropertyGetter(this, propertyInfo.Name);\n      }\n\n      object result = null;\n      var info = FieldManager.GetFieldData(propertyInfo);\n      if (info != null)\n      {\n        result = info.Value;\n      }\n      else\n      {\n        result = propertyInfo.DefaultValue;\n        FieldManager.LoadFieldData(propertyInfo, result);\n      }\n      return result;\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="property">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="valueGenerator">Method returning the new value.</param>\n    protected P LazyReadProperty<P>(PropertyInfo<P> property, Func<P> valueGenerator)\n    {\n      if (!(FieldManager.FieldExists(property)))\n      {\n        var result = valueGenerator();\n        LoadProperty(property, result);\n      }\n      return ReadProperty<P>(property);\n    }\n\n    /// <summary>\n    /// Gets a property\'s value as a specified type.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="property">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="factory">Async method returning the new value.</param>\n    protected P LazyReadPropertyAsync<P>(PropertyInfo<P> property, Task<P> factory)\n    {\n      if (!(FieldManager.FieldExists(property)) && !PropertyIsLoading(property))\n      {\n        LoadPropertyAsync(property, factory);\n      }\n      return ReadProperty<P>(property);\n    }\n\n    P IManageProperties.LazyReadProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)\n    {\n      return LazyReadProperty(propertyInfo, valueGenerator);\n    }\n\n    P IManageProperties.LazyReadPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)\n    {\n      return LazyReadPropertyAsync(propertyInfo, factory);\n    }\n\n#endregion\n\n#region  Load Properties\n\n    /// <summary>\n    /// Loads a property\'s managed field with the \n    /// supplied value calling PropertyHasChanged \n    /// if the value does change.\n    /// </summary>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="newValue">\n    /// The new value for the property.</param>\n    /// <remarks>\n    /// No authorization checks occur when this method is called,\n    /// and no PropertyChanging or PropertyChanged events are raised.\n    /// Loading values does not cause validation rules to be\n    /// invoked.\n    /// </remarks>\n    protected void LoadPropertyConvert<P, F>(PropertyInfo<P> propertyInfo, F newValue)\n    {\n      try\n      {\n        P oldValue = default(P);\n        var fieldData = FieldManager.GetFieldData(propertyInfo);\n        if (fieldData == null)\n        {\n          oldValue = propertyInfo.DefaultValue;\n          fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);\n        }\n        else\n        {\n          oldValue = (P)fieldData.Value;\n        }\n\n        if (oldValue == null)\n        {\n          if (newValue != null)\n            FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));\n        }\n        else if (!(oldValue.Equals(newValue)))\n        {\n          FieldManager.LoadFieldData(propertyInfo, Utilities.CoerceValue<P>(typeof(F), oldValue, newValue));\n        }\n      }\n      catch (Exception ex)\n      {\n        throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));\n      }\n    }\n\n    void Core.IManageProperties.LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)\n    {\n      LoadProperty<P>(propertyInfo, newValue);\n    }\n\n    bool Core.IManageProperties.FieldExists(Core.IPropertyInfo property)\n    {\n      return FieldManager.FieldExists(property);\n    }\n\n    /// <summary>\n    /// Loads a property\'s managed field with the \n    /// supplied value calling PropertyHasChanged \n    /// if the value does change.\n    /// </summary>\n    /// <typeparam name="P">\n    /// Type of the property.\n    /// </typeparam>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="newValue">\n    /// The new value for the property.</param>\n    /// <remarks>\n    /// No authorization checks occur when this method is called,\n    /// and no PropertyChanging or PropertyChanged events are raised.\n    /// Loading values does not cause validation rules to be\n    /// invoked.\n    /// </remarks>\n    protected void LoadProperty<P>(PropertyInfo<P> propertyInfo, P newValue)\n    {\n      try\n      {\n        P oldValue = default(P);\n        var fieldData = FieldManager.GetFieldData(propertyInfo);\n        if (fieldData == null)\n        {\n          oldValue = propertyInfo.DefaultValue;\n          fieldData = FieldManager.LoadFieldData(propertyInfo, oldValue);\n        }\n        else\n        {\n          oldValue = (P)fieldData.Value;\n        }\n\n        if (oldValue == null)\n        {\n          if (newValue != null)\n            FieldManager.LoadFieldData(propertyInfo, newValue);\n        }\n        else if (!(oldValue.Equals(newValue)))\n        {\n          FieldManager.LoadFieldData(propertyInfo, newValue);\n        }\n      }\n      catch (Exception ex)\n      {\n        throw new PropertyLoadException(string.Format(Properties.Resources.PropertyLoadException, propertyInfo.Name, ex.Message));\n      }\n    }\n\n    /// <summary>\n    /// Loads a property\'s managed field with the \n    /// supplied value calling PropertyHasChanged \n    /// if the value does change.\n    /// </summary>\n    /// <param name="propertyInfo">\n    /// PropertyInfo object containing property metadata.</param>\n    /// <param name="newValue">\n    /// The new value for the property.</param>\n    /// <remarks>\n    /// No authorization checks occur when this method is called,\n    /// and no PropertyChanging or PropertyChanged events are raised.\n    /// Loading values does not cause validation rules to be\n    /// invoked.\n    /// </remarks>\n    protected virtual void LoadProperty(IPropertyInfo propertyInfo, object newValue)\n    {\n      var t = this.GetType();\n      var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;\n      var method = t.GetMethods(flags).Where(c => c.Name == "LoadProperty" && c.IsGenericMethod).FirstOrDefault();\n      var gm = method.MakeGenericMethod(propertyInfo.Type);\n      var p = new object[] { propertyInfo, newValue };\n      gm.Invoke(this, p);\n    }\n\n    //private AsyncLoadManager\n    [NonSerialized]\n    private AsyncLoadManager _loadManager;\n    internal AsyncLoadManager LoadManager\n    {\n      get\n      {\n        if (_loadManager == null)\n        {\n          _loadManager = new AsyncLoadManager(this, OnPropertyChanged);\n          _loadManager.BusyChanged += loadManager_BusyChanged;\n          _loadManager.UnhandledAsyncException += loadManager_UnhandledAsyncException;\n        }\n        return _loadManager;\n      }\n    }\n\n    void loadManager_UnhandledAsyncException(object sender, Csla.Core.ErrorEventArgs e)\n    {\n      OnUnhandledAsyncException(e);\n    }\n\n    void loadManager_BusyChanged(object sender, BusyChangedEventArgs e)\n    {\n      OnBusyChanged(e);\n    }\n    /*\n    /// <summary>\n    /// Loads a property value asynchronously.\n    /// </summary>\n    /// <typeparam name="R">Type of the property</typeparam>\n    /// <typeparam name="P">Type of the parameter.</typeparam>\n    /// <param name="property">Property to load.</param>\n    /// <param name="factory">AsyncFactory delegate.</param>\n    //protected void LoadPropertyAsync<R>(PropertyInfo<R> property, AsyncFactoryDelegate<R> factory)\n    //{\n    //  LoadManager.BeginLoad(new AsyncLoader<R>(property, factory));\n    //}\n\n    /// <summary>\n    /// Loads a property value asynchronously.\n    /// </summary>\n    /// <typeparam name="R">Type of the property</typeparam>\n    /// <typeparam name="P">Type of the parameter.</typeparam>\n    /// <param name="property">Property to load.</param>\n    /// <param name="factory">AsyncFactory delegate.</param>\n    /// <param name="parameter">Parameter value.</param>\n    //protected void LoadPropertyAsync<R, P>(PropertyInfo<R> property, AsyncFactoryDelegate<R, P> factory, P parameter)\n    //{\n    //  LoadManager.BeginLoad(new AsyncLoader<R>(property, factory, parameter));\n    //}\n    */\n\n    /// <summary>\n    /// Load a property from an async method. \n    /// </summary>\n    /// <typeparam name="R"></typeparam>\n    /// <param name="property"></param>\n    /// <param name="factory"></param>\n    protected void LoadPropertyAsync<R>(PropertyInfo<R> property, Task<R> factory)\n    {\n      LoadManager.BeginLoad(new TaskLoader<R>(property, factory));\n    }\n#endregion\n\n#region  Field Manager\n\n    [NotUndoable()]\n    private FieldDataManager _fieldManager;\n\n    /// <summary>\n    /// Gets the PropertyManager object for this\n    /// business object.\n    /// </summary>\n    protected FieldDataManager FieldManager\n    {\n      get\n      {\n        if (_fieldManager == null)\n        {\n          _fieldManager = new FieldDataManager(ApplicationContext, this.GetType());\n        }\n        return _fieldManager;\n      }\n    }\n\n    FieldDataManager IUseFieldManager.FieldManager => FieldManager;\n\n#endregion\n\n#region IsBusy / IsIdle\n\n    [NonSerialized]\n    [NotUndoable]\n    private bool _isBusy;\n\n    /// <summary>\n    /// Marks the object as being busy (it is\n    /// running an async operation).\n    /// </summary>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected void MarkBusy()\n    {\n      if (_isBusy)\n        throw new InvalidOperationException(Resources.BusyObjectsMayNotBeMarkedBusy);\n\n      _isBusy = true;\n      OnBusyChanged(new BusyChangedEventArgs("", true));\n    }\n\n    /// <summary>\n    /// Marks the object as being not busy\n    /// (it is not running an async operation).\n    /// </summary>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected void MarkIdle()\n    {\n      _isBusy = false;\n      OnBusyChanged(new BusyChangedEventArgs("", false));\n    }\n\n    /// <summary>\n    /// Gets a value indicating whether this\n    /// object or any of its child objects are\n    /// running an async operation.\n    /// </summary>\n    [Browsable(false)]\n    [Display(AutoGenerateField = false)]\n    [ScaffoldColumn(false)]\n    public virtual bool IsBusy\n    {\n      get { return IsSelfBusy || (_fieldManager != null && FieldManager.IsBusy()); }\n    }\n\n    /// <summary>\n    /// Gets a value indicating whether this\n    /// object is\n    /// running an async operation.\n    /// </summary>\n    [Browsable(false)]\n    [Display(AutoGenerateField = false)]\n    [ScaffoldColumn(false)]\n    public virtual bool IsSelfBusy\n    {\n      get { return _isBusy || LoadManager.IsLoading; }\n    }\n\n    void Child_PropertyBusy(object sender, BusyChangedEventArgs e)\n    {\n      OnBusyChanged(e);\n    }\n\n    [NotUndoable]\n    [NonSerialized]\n    private BusyChangedEventHandler _propertyBusy;\n\n    /// <summary>\n    /// Event raised when the IsBusy property value\n    /// has changed.\n    /// </summary>\n    public event BusyChangedEventHandler BusyChanged\n    {\n      add { _propertyBusy = (BusyChangedEventHandler)Delegate.Combine(_propertyBusy, value); }\n      remove { _propertyBusy = (BusyChangedEventHandler)Delegate.Remove(_propertyBusy, value); }\n    }\n\n    /// <summary>\n    /// Raises the BusyChanged event.\n    /// </summary>\n    /// <param name="propertyName">Name of the property\n    /// that has changed.</param>\n    /// <param name="busy">New busy value.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected void OnBusyChanged(string propertyName, bool busy)\n    {\n      OnBusyChanged(new BusyChangedEventArgs(propertyName, busy));\n    }\n\n    /// <summary>\n    /// Raises the BusyChanged event.\n    /// </summary>\n    /// <param name="args">Event arguments.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void OnBusyChanged(BusyChangedEventArgs args)\n    {\n      if (_propertyBusy != null)\n        _propertyBusy(this, args);\n    }\n\n#endregion\n\n#region IDataPortalTarget Members\n\n    void Csla.Server.IDataPortalTarget.CheckRules()\n    { }\n\n    void Csla.Server.IDataPortalTarget.MarkAsChild()\n    { }\n\n    void Csla.Server.IDataPortalTarget.MarkNew()\n    { }\n\n    void Csla.Server.IDataPortalTarget.MarkOld()\n    { }\n\n    void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)\n    {\n      this.DataPortal_OnDataPortalInvoke(e);\n    }\n\n    void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)\n    {\n      this.DataPortal_OnDataPortalInvokeComplete(e);\n    }\n\n    void Csla.Server.IDataPortalTarget.DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex)\n    {\n      this.DataPortal_OnDataPortalException(e, ex);\n    }\n\n    void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvoke(DataPortalEventArgs e)\n    {\n      this.Child_OnDataPortalInvoke(e);\n    }\n\n    void Csla.Server.IDataPortalTarget.Child_OnDataPortalInvokeComplete(DataPortalEventArgs e)\n    {\n      this.Child_OnDataPortalInvokeComplete(e);\n    }\n\n    void Csla.Server.IDataPortalTarget.Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)\n    {\n      this.Child_OnDataPortalException(e, ex);\n    }\n\n#endregion\n\n#region IManageProperties Members\n\n    bool IManageProperties.HasManagedProperties\n    {\n      get { return (_fieldManager != null && _fieldManager.HasFields); }\n    }\n\n    List<IPropertyInfo> IManageProperties.GetManagedProperties()\n    {\n      return FieldManager.GetRegisteredProperties();\n    }\n\n    object IManageProperties.GetProperty(IPropertyInfo propertyInfo)\n    {\n      return GetProperty(propertyInfo);\n    }\n\n    object IManageProperties.LazyGetProperty<P>(PropertyInfo<P> propertyInfo, Func<P> valueGenerator)\n    {\n      return LazyGetProperty(propertyInfo, valueGenerator);\n    }\n\n    object IManageProperties.LazyGetPropertyAsync<P>(PropertyInfo<P> propertyInfo, Task<P> factory)\n    {\n      return LazyGetPropertyAsync(propertyInfo, factory);\n    }\n\n    object IManageProperties.ReadProperty(IPropertyInfo propertyInfo)\n    {\n      return ReadProperty(propertyInfo);\n    }\n\n    P IManageProperties.ReadProperty<P>(PropertyInfo<P> propertyInfo)\n    {\n      return ReadProperty<P>(propertyInfo);\n    }\n\n    void IManageProperties.SetProperty(IPropertyInfo propertyInfo, object newValue)\n    {\n      throw new NotImplementedException("IManageProperties.SetProperty");\n    }\n\n    void IManageProperties.LoadProperty(IPropertyInfo propertyInfo, object newValue)\n    {\n      LoadProperty(propertyInfo, newValue);\n    }\n\n    bool IManageProperties.LoadPropertyMarkDirty(IPropertyInfo propertyInfo, object newValue)\n    {\n      LoadProperty(propertyInfo, newValue);\n      return false;\n    }\n\n    List<object> IManageProperties.GetChildren()\n    {\n      return FieldManager.GetChildren();\n    }\n#endregion\n\n#region MobileFormatter\n\n    /// <summary>\n    /// Override this method to insert your child object\n    /// references into the MobileFormatter serialzation stream.\n    /// </summary>\n    /// <param name="info">\n    /// Object containing the data to serialize.\n    /// </param>\n    /// <param name="formatter">\n    /// Reference to MobileFormatter instance. Use this to\n    /// convert child references to/from reference id values.\n    /// </param>\n    protected override void OnGetChildren(\n      Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)\n    {\n      base.OnGetChildren(info, formatter);\n      if (_fieldManager != null)\n      {\n        var fieldManagerInfo = formatter.SerializeObject(_fieldManager);\n        info.AddChild("_fieldManager", fieldManagerInfo.ReferenceId);\n      }\n    }\n\n    /// <summary>\n    /// Override this method to retrieve your child object\n    /// references from the MobileFormatter serialzation stream.\n    /// </summary>\n    /// <param name="info">\n    /// Object containing the data to serialize.\n    /// </param>\n    /// <param name="formatter">\n    /// Reference to MobileFormatter instance. Use this to\n    /// convert child references to/from reference id values.\n    /// </param>\n    protected override void OnSetChildren(Csla.Serialization.Mobile.SerializationInfo info, Csla.Serialization.Mobile.MobileFormatter formatter)\n    {\n      if (info.Children.ContainsKey("_fieldManager"))\n      {\n        var childData = info.Children["_fieldManager"];\n        _fieldManager = (FieldDataManager)formatter.GetObject(childData.ReferenceId);\n      }\n      base.OnSetChildren(info, formatter);\n    }\n\n#endregion\n\n#region INotifyUnhandledAsyncException Members\n\n    [NotUndoable]\n    [NonSerialized]\n    private EventHandler<Csla.Core.ErrorEventArgs> _unhandledAsyncException;\n\n    /// <summary>\n    /// Event raised when an exception occurs on a background\n    /// thread during an asynchronous operation.\n    /// </summary>\n    public event EventHandler<Csla.Core.ErrorEventArgs> UnhandledAsyncException\n    {\n      add { _unhandledAsyncException = (EventHandler<Csla.Core.ErrorEventArgs>)Delegate.Combine(_unhandledAsyncException, value); }\n      remove { _unhandledAsyncException = (EventHandler<Csla.Core.ErrorEventArgs>)Delegate.Remove(_unhandledAsyncException, value); }\n    }\n\n    /// <summary>\n    /// Raises the UnhandledAsyncException event.\n    /// </summary>\n    /// <param name="error">Error arguments.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected virtual void OnUnhandledAsyncException(Csla.Core.ErrorEventArgs error)\n    {\n      if (_unhandledAsyncException != null)\n        _unhandledAsyncException(this, error);\n    }\n\n    /// <summary>\n    /// Raises the UnhandledAsyncException event.\n    /// </summary>\n    /// <param name="originalSender">Original sender of the\n    /// event.</param>\n    /// <param name="error">Execption that occurred.</param>\n    [EditorBrowsable(EditorBrowsableState.Advanced)]\n    protected void OnUnhandledAsyncException(object originalSender, Exception error)\n    {\n      OnUnhandledAsyncException(new Csla.Core.ErrorEventArgs(originalSender, error));\n    }\n\n#endregion\n  }\n}', 'message': 'Fix RegisterMethod implementation.\nbugid: 13\n\n', 'author_name': 'rocky@lhotka.net', 'lang': 'cs'}