using System; using System.Collections.Generic; using System.Reflection; using System.ComponentModel; using System.Runtime.Serialization; using Csla.Properties; namespace Csla { /// /// This is a base class from which readonly business classes /// can be derived. /// /// /// This base class only supports data retrieve, not updating or /// deleting. Any business classes derived from this base class /// should only implement readonly properties. /// /// Type of the business object. [Serializable()] public abstract class ReadOnlyBase : ICloneable, Core.IReadOnlyObject, Csla.Security.IAuthorizeReadWrite where T : ReadOnlyBase { #region Object ID Value /// /// Override this method to return a unique identifying /// vlaue for this object. /// /// /// If you can not provide a unique identifying value, it /// is best if you can generate such a unique value (even /// temporarily). If you can not do that, then return /// and then manually override the /// , and /// methods in your business object. /// protected abstract object GetIdValue(); #endregion #region System.Object Overrides /// /// Compares this object for equality with another object, using /// the results of to determine /// equality. /// /// The object to be compared. public override bool Equals(object obj) { if (obj is T) { object id = GetIdValue(); if (id == null) throw new ArgumentException(Resources.GetIdValueCantBeNull); return id.Equals(((T)obj).GetIdValue()); } else return false; } /// /// Returns a hash code value for this object, based on /// the results of . /// public override int GetHashCode() { object id = GetIdValue(); if (id == null) throw new ArgumentException(Resources.GetIdValueCantBeNull); return id.GetHashCode(); } /// /// Returns a text representation of this object by /// returning the value /// in text form. /// public override string ToString() { object id = GetIdValue(); if (id == null) throw new ArgumentException(Resources.GetIdValueCantBeNull); return id.ToString(); } #endregion #region Constructors /// /// Creates an instance of the object. /// protected ReadOnlyBase() { Initialize(); AddInstanceAuthorizationRules(); if (!Security.SharedAuthorizationRules.RulesExistFor(this.GetType())) { lock (this.GetType()) { if (!Security.SharedAuthorizationRules.RulesExistFor(this.GetType())) AddAuthorizationRules(); } } } #endregion #region Initialize /// /// Override this method to set up event handlers so user /// code in a partial class can respond to events raised by /// generated code. /// protected virtual void Initialize() { /* allows subclass to initialize events before any other activity occurs */ } #endregion #region Authorization [NotUndoable()] [NonSerialized()] private Dictionary _readResultCache; [NotUndoable()] [NonSerialized()] private System.Security.Principal.IPrincipal _lastPrincipal; [NotUndoable()] [NonSerialized()] private Security.AuthorizationRules _authorizationRules; /// /// Override this method to add authorization /// rules for your object's properties. /// protected virtual void AddInstanceAuthorizationRules() { } /// /// Override this method to add per-type /// authorization rules for your type's properties. /// /// /// AddSharedAuthorizationRules is automatically called by CSLA .NET /// when your object should associate per-type authorization roles /// with its properties. /// protected virtual void AddAuthorizationRules() { } /// /// Provides access to the AuthorizationRules object for this /// object. /// /// /// Use this object to add a list of allowed and denied roles for /// reading and writing properties of the object. Typically these /// values are added once when the business object is instantiated. /// protected Security.AuthorizationRules AuthorizationRules { get { if (_authorizationRules == null) _authorizationRules = new Security.AuthorizationRules(this.GetType()); return _authorizationRules; } } /// /// Returns if the user is allowed to read the /// calling property. /// /// if read is allowed. /// Indicates whether a negative /// result should cause an exception. [System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] public bool CanReadProperty(bool throwOnFalse) { string propertyName = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name.Substring(4); bool result = CanReadProperty(propertyName); if (throwOnFalse && result == false) throw new System.Security.SecurityException( string.Format("{0} ({1})", Resources.PropertyGetNotAllowed, propertyName)); return result; } /// /// Returns if the user is allowed to read the /// calling property. /// /// if read is allowed. /// Name of the property to read. /// Indicates whether a negative /// result should cause an exception. public bool CanReadProperty(string propertyName, bool throwOnFalse) { bool result = CanReadProperty(propertyName); if (throwOnFalse && result == false) throw new System.Security.SecurityException( string.Format("{0} ({1})", Resources.PropertyGetNotAllowed, propertyName)); return result; } /// /// Returns if the user is allowed to read the /// calling property. /// /// if read is allowed. public bool CanReadProperty() { string propertyName = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name.Substring(4); return CanReadProperty(propertyName); } /// /// Returns if the user is allowed to read the /// specified property. /// /// Name of the property to read. /// if read is allowed. /// /// /// If a list of allowed roles is provided then only users in those /// roles can read. If no list of allowed roles is provided then /// the list of denied roles is checked. /// /// If a list of denied roles is provided then users in the denied /// roles are denied read access. All other users are allowed. /// /// If neither a list of allowed nor denied roles is provided then /// all users will have read access. /// /// [EditorBrowsable(EditorBrowsableState.Advanced)] public virtual bool CanReadProperty(string propertyName) { bool result = true; VerifyAuthorizationCache(); if (_readResultCache.ContainsKey(propertyName)) { // cache contains value - get cached value result = _readResultCache[propertyName]; } else { if (AuthorizationRules.HasReadAllowedRoles(propertyName)) { // some users are explicitly granted read access // in which case all other users are denied. if (!AuthorizationRules.IsReadAllowed(propertyName)) result = false; } else if (AuthorizationRules.HasReadDeniedRoles(propertyName)) { // some users are explicitly denied read access. if (AuthorizationRules.IsReadDenied(propertyName)) result = false; } // store value in cache _readResultCache[propertyName] = result; } return result; } bool Csla.Security.IAuthorizeReadWrite.CanWriteProperty(string propertyName) { return false; } private void VerifyAuthorizationCache() { if (_readResultCache == null) _readResultCache = new Dictionary(); if (!ReferenceEquals(Csla.ApplicationContext.User, _lastPrincipal)) { // the principal has changed - reset the cache _readResultCache.Clear(); _lastPrincipal = Csla.ApplicationContext.User; } } #endregion #region IClonable object ICloneable.Clone() { return GetClone(); } /// /// Creates a clone of the object. /// /// A new object containing the exact data of the original object. [EditorBrowsable(EditorBrowsableState.Advanced)] public virtual object GetClone() { return Core.ObjectCloner.Clone(this); } /// /// Creates a clone of the object. /// /// /// A new object containing the exact data of the original object. /// 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); } /// /// Override this method to allow retrieval of an existing business /// object based on data in the database. /// /// An object containing criteria values to identify the object. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")] protected virtual void DataPortal_Fetch(object criteria) { throw new NotSupportedException(Resources.FetchNotSupportedException); } [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")] private void DataPortal_Delete(object criteria) { throw new NotSupportedException(Resources.DeleteNotSupportedException); } /// /// Called by the server-side DataPortal prior to calling the /// requested DataPortal_xyz method. /// /// The DataPortalContext object passed to the DataPortal. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")] [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e) { } /// /// Called by the server-side DataPortal after calling the /// requested DataPortal_xyz method. /// /// The DataPortalContext object passed to the DataPortal. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")] [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e) { } /// /// Called by the server-side DataPortal if an exception /// occurs during data access. /// /// The DataPortalContext object passed to the DataPortal. /// The Exception thrown during data access. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", MessageId = "Member")] [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void DataPortal_OnDataPortalException(DataPortalEventArgs e, Exception ex) { } #endregion #region Serialization Notification [OnDeserialized()] private void OnDeserializedHandler(StreamingContext context) { OnDeserialized(context); AddInstanceAuthorizationRules(); if (!Security.SharedAuthorizationRules.RulesExistFor(this.GetType())) { lock (this.GetType()) { if (!Security.SharedAuthorizationRules.RulesExistFor(this.GetType())) AddAuthorizationRules(); } } } /// /// This method is called on a newly deserialized object /// after deserialization is complete. /// /// Serialization context object. [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void OnDeserialized(StreamingContext context) { // do nothing - this is here so a subclass // could override if needed } #endregion } }