BindingEntityInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / Binding / BindingEntityInfo.cs / 1305376 / BindingEntityInfo.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//   BindingEntityInfo class
//  
// 
//---------------------------------------------------------------------
 
namespace System.Data.Services.Client
{
#region Namespaces
    using System.Collections.Generic; 
    using System.ComponentModel;
    using System.Data.Services.Common; 
    using System.Diagnostics; 
    using System.Linq;
    using System.Reflection; 
    using System.Threading;
#endregion

    /// Type of property stored in BindingPropertyInfo. 
    internal enum BindingPropertyKind
    { 
        /// Property type is a complex type. 
        BindingPropertyKindComplex,
 
        /// Property type is an entity type with keys.
        BindingPropertyKindEntity,

        /// Property is of an DataServiceCollection. 
        BindingPropertyKindCollection
    } 
 
    /// Cache of information about entity types and their observable properties
    internal class BindingEntityInfo 
    {
        /// Object reference used as a 'False' flag.
        private static readonly object FalseObject = new object();
 
        /// Object reference used as a 'False' flag.
        private static readonly object TrueObject = new object(); 
 
        /// Lock on metadata caches.
        private static readonly ReaderWriterLockSlim metadataCacheLock = new ReaderWriterLockSlim(); 

        /// Types which are known not to be entity types.
        private static readonly HashSet knownNonEntityTypes = new HashSet(EqualityComparer.Default);
 
        /// Types which are known to be (or not) collection types.
        private static readonly Dictionary knownObservableCollectionTypes = new Dictionary(EqualityComparer.Default); 
 
        /// Mapping between types and their corresponding entity information
        private static readonly Dictionary bindingEntityInfos = new Dictionary(EqualityComparer.Default); 

        /// Obtain binding info corresponding to a given type
        /// Type for which to obtain information
        /// Info about the  
        internal static IList GetObservableProperties(Type entityType)
        { 
            return GetBindingEntityInfoFor(entityType).ObservableProperties; 
        }
 
        /// Gets the ClientType corresponding to the given type
        /// Input type
        /// Corresponding ClientType
        internal static ClientType GetClientType(Type entityType) 
        {
            return GetBindingEntityInfoFor(entityType).ClientType; 
        } 

        ///  
        /// Get the entity set name for the target entity object.
        /// 
        /// An entity object.
        /// The 'currently known' entity set name for the target object. 
        /// The entity set name for the target object.
        ///  
        /// Allow user code to provide the entity set name. If user code does not provide the entity set name, then 
        /// this method will get the entity set name from the value of the EntitySetAttribute.
        /// The 'currently known' entity set name for top level collections can be provided through OEC constructor 
        /// 
        internal static string GetEntitySet(
            object target,
            string targetEntitySet) 
        {
            Debug.Assert(target != null, "Argument 'target' cannot be null."); 
            Debug.Assert(BindingEntityInfo.IsEntityType(target.GetType()), "Argument 'target' must be an entity type."); 

            // Here's the rules in order of priority for resolving entity set name 
            // 1. EntitySet name passed in the constructor or extension methods of DataServiceCollection
            // 2. EntitySet name specified in the EntitySet attribute by the code gen. {Remember this attribute is
            //    not generated in case of MEST)
            if (!String.IsNullOrEmpty(targetEntitySet)) 
            {
                return targetEntitySet; 
            } 
            else
            { 
                // If there is not a 'currently known' entity set name to validate against, then there must be
                // EntitySet attribute on the entity type
                return BindingEntityInfo.GetEntitySetAttribute(target.GetType());
            } 
        }
 
        ///  
        /// Determine if the specified type is an DataServiceCollection.
        ///  
        /// 
        /// If there a generic class in the inheritance hierarchy of the type, that has a single
        /// entity type paramenter T, and is assignable to DataServiceCollection(Of T), then
        /// the type is an DataServiceCollection. 
        /// 
        /// An object type specifier. 
        /// True if the type is an DataServiceCollection; otherwise false. 
        internal static bool IsDataServiceCollection(Type collectionType)
        { 
            Debug.Assert(collectionType != null, "Argument 'collectionType' cannot be null.");

            metadataCacheLock.EnterReadLock();
            try 
            {
                object resultAsObject; 
                if (knownObservableCollectionTypes.TryGetValue(collectionType, out resultAsObject)) 
                {
                    return resultAsObject == TrueObject; 
                }
            }
            finally
            { 
                metadataCacheLock.ExitReadLock();
            } 
 
            Type type = collectionType;
            bool result = false; 

            while (type != null)
            {
                if (type.IsGenericType) 
                {
                    // Is there a generic class in the inheritance hierarchy, that has a single 
                    // entity type paramenter T, and is assignable to DataServiceCollection 
                    Type[] parms = type.GetGenericArguments();
 
                    if (parms != null && parms.Length == 1 && IsEntityType(parms[0]))
                    {
                        // if ObservableCollection is not available dataServiceCollection will be null
                        Type dataServiceCollection = WebUtil.GetDataServiceCollectionOfT(parms); 
                        if (dataServiceCollection != null && dataServiceCollection.IsAssignableFrom(type))
                        { 
                            result = true; 
                            break;
                        } 
                    }
                }

                type = type.BaseType; 
            }
 
            metadataCacheLock.EnterWriteLock(); 
            try
            { 
                if (!knownObservableCollectionTypes.ContainsKey(collectionType))
                {
                    knownObservableCollectionTypes[collectionType] = result ? TrueObject : FalseObject;
                } 
            }
            finally 
            { 
                metadataCacheLock.ExitWriteLock();
            } 

            return result;
        }
 
        /// 
        /// Determine if the specified type is an entity type. 
        ///  
        /// An object type specifier.
        /// True if the type is an entity type; otherwise false. 
        internal static bool IsEntityType(Type type)
        {
            Debug.Assert(type != null, "Argument 'type' cannot be null.");
 
            metadataCacheLock.EnterReadLock();
            try 
            { 
                if (knownNonEntityTypes.Contains(type))
                { 
                    return false;
                }
            }
            finally 
            {
                metadataCacheLock.ExitReadLock(); 
            } 

            try 
            {
                if (BindingEntityInfo.IsDataServiceCollection(type))
                {
                    return false; 
                }
 
                return ClientType.Create(type).IsEntityType; 
            }
            catch (InvalidOperationException) 
            {
                metadataCacheLock.EnterWriteLock();
                try
                { 
                    if (!knownNonEntityTypes.Contains(type))
                    { 
                        knownNonEntityTypes.Add(type); 
                    }
                } 
                finally
                {
                    metadataCacheLock.ExitWriteLock();
                } 

                return false; 
            } 
        }
 
        /// 
        /// Gets the value of a property and corresponding BindingPropertyInfo if property is being observed
        /// 
        /// Source object whose property needs to be read 
        /// Name of the source object property
        /// BindingPropertyInfo corresponding to  
        /// Value of the property 
        internal static object GetPropertyValue(object source, string sourceProperty, out BindingPropertyInfo bindingPropertyInfo)
        { 
            Type sourceType = source.GetType();

            bindingPropertyInfo = BindingEntityInfo.GetObservableProperties(sourceType)
                                                   .SingleOrDefault(x => x.PropertyInfo.PropertyName == sourceProperty); 

            // bindingPropertyInfo is null for primitive properties. 
            if (bindingPropertyInfo == null) 
            {
                return BindingEntityInfo.GetClientType(sourceType) 
                                        .GetProperty(sourceProperty, false)
                                        .GetValue(source);
            }
            else 
            {
                return bindingPropertyInfo.PropertyInfo.GetValue(source); 
            } 
        }
 
        /// Obtain binding info corresponding to a given type
        /// Type for which to obtain information
        /// Info about the 
        private static BindingEntityInfoPerType GetBindingEntityInfoFor(Type entityType) 
        {
            BindingEntityInfoPerType bindingEntityInfo; 
 
            metadataCacheLock.EnterReadLock();
            try 
            {
                if (bindingEntityInfos.TryGetValue(entityType, out bindingEntityInfo))
                {
                    return bindingEntityInfo; 
                }
            } 
            finally 
            {
                metadataCacheLock.ExitReadLock(); 
            }

            bindingEntityInfo = new BindingEntityInfoPerType();
 
            // Try to get the entity set name from the EntitySetAttribute attributes. In order to make the
            // inheritance work, we need to look at the attributes declared in the base types also. 
            object[] attributes = entityType.GetCustomAttributes(typeof(EntitySetAttribute), true); 

            // There must be exactly one (unambiguous) EntitySetAttribute attribute. 
            bindingEntityInfo.EntitySet = (attributes != null && attributes.Length == 1) ? ((EntitySetAttribute)attributes[0]).EntitySet : null;
            bindingEntityInfo.ClientType = ClientType.Create(entityType);

            foreach (ClientType.ClientProperty p in bindingEntityInfo.ClientType.Properties) 
            {
                BindingPropertyInfo bpi = null; 
 
                Type propertyType = p.PropertyType;
 
                if (p.CollectionType != null)
                {
                    if (BindingEntityInfo.IsDataServiceCollection(propertyType))
                    { 
                        bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindCollection };
                    } 
                } 
                else
                if (BindingEntityInfo.IsEntityType(propertyType)) 
                {
                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindEntity };
                }
                else 
                if (BindingEntityInfo.CanBeComplexProperty(p))
                { 
                    // Add complex types and nothing else. 
                    bpi = new BindingPropertyInfo { PropertyKind = BindingPropertyKind.BindingPropertyKindComplex };
                } 

                if (bpi != null)
                {
                    bpi.PropertyInfo = p; 

                    // For complex types only treat complex typed properties as observable, we are not going to observer entity typed or primitive properties. 
                    if (bindingEntityInfo.ClientType.IsEntityType || bpi.PropertyKind == BindingPropertyKind.BindingPropertyKindComplex) 
                    {
                        bindingEntityInfo.ObservableProperties.Add(bpi); 
                    }
                }
            }
 
            metadataCacheLock.EnterWriteLock();
            try 
            { 
                if (!bindingEntityInfos.ContainsKey(entityType))
                { 
                    bindingEntityInfos[entityType] = bindingEntityInfo;
                }
            }
            finally 
            {
                metadataCacheLock.ExitWriteLock(); 
            } 

            return bindingEntityInfo; 
        }

        /// Checks whether a given property can be a complex property i.e. implements INotifyPropertyChanged.
        /// Input property. 
        /// true if the property is complex property, false otherwise.
        private static bool CanBeComplexProperty(ClientType.ClientProperty property) 
        { 
            Debug.Assert(property != null, "property != null");
            if (typeof(INotifyPropertyChanged).IsAssignableFrom(property.PropertyType)) 
            {
                Debug.Assert(!property.IsKnownType, "Known types do not implement INotifyPropertyChanged.");
                return true;
            } 

            return false; 
        } 

        /// Gets entity set corresponding to a given type 
        /// Intput type
        /// Entity set name for the type
        private static string GetEntitySetAttribute(Type entityType)
        { 
            return GetBindingEntityInfoFor(entityType).EntitySet;
        } 
 
        /// Information about a property interesting for binding
        internal class BindingPropertyInfo 
        {
            /// Property information
            public ClientType.ClientProperty PropertyInfo
            { 
                get;
                set; 
            } 

            /// Kind of the property i.e. complex, entity or collection. 
            public BindingPropertyKind PropertyKind
            {
                get;
                set; 
            }
        } 
 
        /// Holder of information about entity properties for a type
        private sealed class BindingEntityInfoPerType 
        {
            /// Collection of properties interesting to the observer
            private List observableProperties;
 
            /// Constructor
            public BindingEntityInfoPerType() 
            { 
                this.observableProperties = new List();
            } 

            /// Entity set of the entity
            public String EntitySet
            { 
                get;
                set; 
            } 

            /// Corresponding ClientTyp 
            public ClientType ClientType
            {
                get;
                set; 
            }
 
            /// Collection of properties interesting to the observer 
            public List ObservableProperties
            { 
                get
                {
                    return this.observableProperties;
                } 
            }
        } 
 
#if ASTORIA_LIGHT
        /// Read-writer lock, implemented over a Monitor. 
        private sealed class ReaderWriterLockSlim
        {
            /// Single object on which to lock.
            private object _lock = new object(); 

            /// Enters a reader lock. Writers will also be blocked. 
            internal void EnterReadLock() 
            {
                Monitor.Enter(_lock); 
            }

            /// Enters a writer lock. Readers will also be blocked.
            internal void EnterWriteLock() 
            {
                Monitor.Enter(_lock); 
            } 

            /// Exits a reader lock. 
            internal void ExitReadLock()
            {
                Monitor.Exit(_lock);
            } 

            /// Exits a writer lock. 
            internal void ExitWriteLock() 
            {
                Monitor.Exit(_lock); 
            }
        }
#endif
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK