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
}
}