Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Metadata / ObjectItemCollectionAssemblyCacheEntry.cs / 2 / ObjectItemCollectionAssemblyCacheEntry.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //--------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Xml.Serialization; using System.Xml; using System.Xml.Schema; using System.Data.Common.Utils; using System.Diagnostics; using System.Collections.ObjectModel; using System.Threading; // Using an alias for this because a lot of names in this namespace conflicts with names in metadata using DataClasses = System.Data.Objects.DataClasses; using System.Globalization; using System.Data.Entity; using System.Data.Common; namespace System.Data.Metadata.Edm { ////// Class for representing a collection of items for the object layer. /// Most of the implemetation for actual maintainance of the collection is /// done by ItemCollection /// public sealed partial class ObjectItemCollection : ItemCollection { #region PrivateNestedClass private class AssemblyCacheEntry { #region Fields private readonly List_typesInAssembly; // types in "this" assembly private readonly List _referencedAssemblies; // other assemblies referenced by "this" assembly private static object _assemblyCacheLock = new object(); //List of assemblies having view gen attribute. We cache these things if we discover //these assemblies while looking for O-space metadata. private static IList s_viewGenAssemblies = new ThreadSafeList (); #endregion #region Nested classes private class LoadingContext { #region Fields // all the types that we encountered while loading - this may contain types from various assemblies private readonly Dictionary _typesInLoading; // list of errors encountered during loading private readonly List _errors; // list of unresolved navigation properties private readonly List _unresolvedNavigationProperties = new List (); // keep the list of new assemblies that got loaded in this load assembly call. The region why we need to keep a seperate // assembly is that if we need to keep track of errors, and if there are no errors, then only add the list of assemblies // to the global cache. Hence global cache is never polluted with invalid assemblies private readonly Dictionary _listOfAssembliesLoaded = new Dictionary (); // Current assembly whose type we are loading private Assembly _currentAssembly; // Assembly Cache Entry corresponding to the current assembly private AssemblyCacheEntry _currentCacheEntry; // Indicates if this assembly is already loaded in the cache private bool _isAssemblyLoadedFromGlobalCache; // Global Assembly Cache private readonly static Dictionary s_globalAssemblyCache = new Dictionary (); // List of known assemblies - this list is initially passed by the caller and we keep adding to it, as and when we load // an assembly private readonly Dictionary _knownAssemblies; #endregion #region Constructor internal LoadingContext(Assembly assembly, Dictionary knownAssemblies) { _typesInLoading = new Dictionary (StringComparer.Ordinal); _errors = new List (); _knownAssemblies = knownAssemblies; UpdateCurrentAssembly(assembly, false/*mustAssemblyBeAlreadyLoaded*/); } #endregion #region Properties internal Dictionary TypesInLoading { get { return _typesInLoading; } } internal List EdmItemError { get { return _errors; } } internal List UnresolvedNavigationProperties { get { return _unresolvedNavigationProperties; } } internal Assembly CurrentAssembly { get { return _currentAssembly; } } internal AssemblyCacheEntry AssemblyCacheEntry { get { return _currentCacheEntry; } } internal bool IsAssemblyAlreadyLoadedInCache { get { return _isAssemblyLoadedFromGlobalCache; } } internal Dictionary KnownAssemblies { get { return _knownAssemblies; } } #endregion #region Methods /// /// Check to see if the type is already loaded - either in the typesInLoading, or ObjectItemCollection or /// in the global cache /// /// /// ///internal bool IsTypeAlreadyLoaded(Type clrType, out EdmType edmType) { edmType = null; bool isPresentInAssemblyCache = false; bool isPresentInTypesInLoading = false; if (!clrType.IsGenericType && ((isPresentInTypesInLoading = TypesInLoading.TryGetValue(clrType.FullName, out edmType)) || (isPresentInAssemblyCache = IsTypeAlreadyInCache(clrType, out edmType)))) { // If the type is primitive type, just return the type if (!Helper.IsPrimitiveType(edmType)) { Debug.Assert(!ShouldFilterAssembly(clrType.Assembly.FullName), "Since the type is already loaded, the assembly must have a schema attribute"); Debug.Assert(ObjectItemCollection.IsSchemaAttributePresent(clrType.Assembly), "Since the type is already loaded, the assembly must have a schema attribute"); // If the type is not present in the current assembly, make sure you add the type's assembly // as one of the referenced assemblies if (clrType.Assembly != _currentAssembly) { if (!_currentCacheEntry._referencedAssemblies.Contains(clrType.Assembly)) { _currentCacheEntry._referencedAssemblies.Add(clrType.Assembly); } } // If the base type BT1 of a type T1 is present in another assembly, we just load the base type from that assembly and add // that assembly to the list of referenced assemblies. When you come to loading the referenced assembly, the type BT1 // is already present in TypeInLoading, and hence we need to add it to the list of types in assembly else if (isPresentInTypesInLoading && !_currentCacheEntry.ContainsType(edmType.Identity)) { _currentCacheEntry._typesInAssembly.Add(edmType); } // If the type was loaded from the global cache, then we need to find if this assembly is already loaded. If yes, // then we don't need to add that type in typesInLoading if (isPresentInAssemblyCache && !KnownAssemblies.ContainsKey(clrType.Assembly)) { TypesInLoading.Add(clrType.FullName, edmType); } } } return (edmType != null); } /// /// Returns if the types is already loaded in the cache /// /// /// ///private bool IsTypeAlreadyInCache(Type clrType, out EdmType edmType) { AssemblyCacheEntry cacheEntry; edmType = null; Debug.Assert(!_typesInLoading.ContainsKey(clrType.FullName), "This should be called only after looking in typesInLoading"); Debug.Assert(clrType.Assembly != _currentAssembly || !_currentCacheEntry.ContainsType(clrType.FullName), "The type must never be present in the current assembly list"); if (clrType.Assembly == _currentAssembly) { return false; } if (s_globalAssemblyCache.TryGetValue(clrType.Assembly, out cacheEntry)) { return cacheEntry.TryGetEdmType(clrType.FullName, out edmType); } else if (_listOfAssembliesLoaded.TryGetValue(clrType.Assembly, out cacheEntry)) { return cacheEntry.TryGetEdmType(clrType.FullName, out edmType); } return false; } /// /// Update the current assembly for the loading context. If the second parameter is true, assert that /// the assembly must be present in the global cache. this is to make sure if a assembly was already /// present in the global cache, all its dependent assemblies must also be present in the global cache /// This method checks if the given assembly is present in the global cache, if yes, its loads from there /// otherwise creates a new AssemblyCacheEntry for this assembly. /// Also it adds the earlier current assembly, into its local cache. The reason for doing this is that until /// we have loaded all the assemblies for this context and made sure that there are no errors, then we need /// to update the global cache /// /// /// internal void UpdateCurrentAssembly(Assembly assembly, bool mustAssemblyBeAlreadyLoaded) { Debug.Assert(assembly != null, "Current Assembly can't be set to null"); Debug.Assert(!mustAssemblyBeAlreadyLoaded || s_globalAssemblyCache.ContainsKey(assembly), "The assembly must be loaded in the cache"); // Update the current assembly _currentAssembly = assembly; if (mustAssemblyBeAlreadyLoaded) { // check if the assembly is already loaded in the cache _currentCacheEntry = s_globalAssemblyCache[assembly]; _isAssemblyLoadedFromGlobalCache = true; } else if (s_globalAssemblyCache.TryGetValue(assembly, out _currentCacheEntry)) { _isAssemblyLoadedFromGlobalCache = true; } // If the assemblies have circular dependencies then the assembly might have been added in the local cache else { if (!_listOfAssembliesLoaded.TryGetValue(assembly, out _currentCacheEntry)) { _currentCacheEntry = new AssemblyCacheEntry(); _listOfAssembliesLoaded.Add(_currentAssembly, _currentCacheEntry); } _isAssemblyLoadedFromGlobalCache = false; } } // Add all assemblies to the global cache if there are no errors internal void UpdateCacheWithAssembliesLoaded() { if (_errors.Count == 0) { foreach (KeyValuePairentry in _listOfAssembliesLoaded) { // Add all the assemblies from the loading context to the global cache s_globalAssemblyCache.Add(entry.Key, entry.Value); } // Remove all entries from transient cache _listOfAssembliesLoaded.Clear(); } } #endregion } private class NavigationPropertyInfo { private StructuralType _declaringType; private PropertyInfo _propertyInfo; private EdmType _propertyType; private DataClasses.EdmRelationshipNavigationPropertyAttribute _attribute; internal NavigationPropertyInfo( StructuralType declaringType, PropertyInfo propertyInfo, EdmType propertyType, DataClasses.EdmRelationshipNavigationPropertyAttribute attribute) { _declaringType = declaringType; _propertyInfo = propertyInfo; _propertyType = propertyType; _attribute = attribute; } internal void ResolveNavigationProperty(LoadingContext context) { EdmMember member = null; EdmType type; if (context.TypesInLoading.TryGetValue(_attribute.RelationshipNamespaceName + "." + _attribute.RelationshipName, out type) && Helper.IsAssociationType(type)) { AssociationType relationshipType = (AssociationType)type; if (relationshipType != null) { // The return value of this property has been verified, so create the property now NavigationProperty navigationProperty = new NavigationProperty(_propertyInfo.Name, TypeUsage.Create(_propertyType), _propertyInfo); navigationProperty.RelationshipType = relationshipType; member = navigationProperty; if (relationshipType.Members[0].Name == _attribute.TargetRoleName) { navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[0]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[1]; } else if (relationshipType.Members[1].Name == _attribute.TargetRoleName) { navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[1]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[0]; } else { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.TargetRoleNameInNavigationPropertyNotValid( _propertyInfo.Name, _propertyInfo.DeclaringType.FullName, _attribute.TargetRoleName, _attribute.RelationshipName), navigationProperty)); member = null; } if (member != null && ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType != _declaringType.ClrType) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NavigationPropertyRelationshipEndTypeMismatch( _declaringType.FullName, navigationProperty.Name, relationshipType.FullName, navigationProperty.FromEndMember.Name, ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType), navigationProperty)); member = null; } } } else { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.RelationshipNameInNavigationPropertyNotValid( _propertyInfo.Name, _propertyInfo.DeclaringType.FullName, _attribute.RelationshipName), _declaringType)); } if (member != null) { _declaringType.AddMember(member); } } } #endregion #region Constructor public AssemblyCacheEntry() { _typesInAssembly = new List (); _referencedAssemblies = new List (); } #endregion #region Internal Methods (Entry points to the Cache) internal static IList ViewGenerationAssemblies { get { return s_viewGenAssemblies; } } internal static void LoadAssemblyFromCache(Assembly assembly, bool loadReferencedAssemblies, Dictionary knownAssemblies, out Dictionary typesInLoading, out List errors) { Debug.Assert(!ShouldFilterAssembly(assembly.FullName), "LoadAssemblyFromCache should be called on assembly having non-reserved public key token"); typesInLoading = null; errors = null; lock (_assemblyCacheLock) { // This function loads all the types from the given assembly and the dependent assemblies. We only try to load assemblies // that are requried for type closure. This is different from referenced asssemblies. If the assembly is already loaded, // then the assembly is just copied from the cache LoadingContext context = new LoadingContext(assembly, knownAssemblies); // Loads the current assembly and all the dependent assemblies (required for type closure) if (!context.KnownAssemblies.ContainsKey(context.CurrentAssembly) && IsSchemaAttributePresent(context.CurrentAssembly)) { InternalLoadAssemblyFromCache(context); } if (loadReferencedAssemblies) { InternalLoadAllReferencedAssemblies(context); } // resolve navigation properties that showed up // before the relationships that they use showed up ResolveNavigationProperties(context); // do the validation for the all the new types // Now, perform validation on all the new types EdmValidator validator = new EdmValidator(); validator.SkipReadOnlyItems = true; validator.Validate(context.TypesInLoading.Values, context.EdmItemError); // Update the global cache if there are no errors context.UpdateCacheWithAssembliesLoaded(); // Update the out parameters once you are done with loading typesInLoading = context.TypesInLoading; errors = context.EdmItemError; if (typesInLoading != null && typesInLoading.Count > 0) { foreach (EdmType edmType in typesInLoading.Values) { edmType.SetReadOnly(); } } } } internal static Assembly SafeLoadReferencedAssembly(string assemblyFullName) { Assembly referencedAssembly = null; try { referencedAssembly = Assembly.Load(assemblyFullName); } catch (System.IO.FileNotFoundException) { // See 552932: ObjectItemCollection: fails on referenced asseblies that are not available } return referencedAssembly; } #endregion #region Private Methods private bool TryGetEdmType(string typeName, out EdmType edmType) { edmType = null; foreach (EdmType loadedEdmType in this._typesInAssembly) { if (loadedEdmType.Identity == typeName) { edmType = loadedEdmType; break; } } return (edmType != null); } private bool ContainsType(string typeName) { EdmType edmType = null; return TryGetEdmType(typeName, out edmType); } private static void InternalLoadAllReferencedAssemblies(LoadingContext context) { // We will traverse through all the statically linked assemblies and their dependencies. // Only assemblies with the EdmSchemaAttribute will be loaded and rest will be ignored // Even if the schema attribute is missing, we should still check all the dependent assemblies // any of the dependent assemblies can have the schema attribute // After the given assembly has been loaded, check on the flag in _knownAssemblies to see if it has already // been recursively loaded. The flag can be true if it was already loaded before this function was called foreach (AssemblyName asmName in context.CurrentAssembly.GetReferencedAssemblies()) { string assemblyFullName = asmName.FullName; if (!ShouldFilterAssembly(assemblyFullName)) { // filter out "known" assemblies to prevent unnecessary loading EntityBid.Trace(" loadededAssembly='%ls'\n", assemblyFullName); Assembly referencedAssembly = SafeLoadReferencedAssembly(assemblyFullName); if (referencedAssembly == null) { continue; } // Mark the assembly as known assembly, and since we are loading all the referenced assemblies, // mark the value to the true context.UpdateCurrentAssembly(referencedAssembly, false/*mustAlreadyBeLoaded*/); // Check if the assembly is already loaded bool areReferencedAssembliesLoaded; if (context.KnownAssemblies.TryGetValue(referencedAssembly, out areReferencedAssembliesLoaded)) { // If all the referenced assemblies are already loaded, don't need to do anything if (areReferencedAssembliesLoaded) { continue; } } // Load this assembly if the schema attrbute is present else if (ObjectItemCollection.IsSchemaAttributePresent(referencedAssembly)) { InternalLoadAssemblyFromCache(context); } // We need to add this assembly to the list of known assemblies before we start // analyzing the referenced assemblies, since there could be circular reference // and we need to detect that and break the loop context.KnownAssemblies[referencedAssembly] = true; InternalLoadAllReferencedAssemblies(context); } } } /// /// Loads the given assembly and all the other referencd assemblies in the cache. If the assembly was already present /// then it loads from the cache /// /// ///true if the assembly was already loaded in the cache private static bool InternalLoadAssemblyFromCache(LoadingContext context) { Debug.Assert(!ShouldFilterAssembly(context.CurrentAssembly.FullName), "LoadAssemblyFromCache should be called on assembly having non-reserved public key token"); Debug.Assert(IsSchemaAttributePresent(context.CurrentAssembly), "LoadAssembly shouldn't be called with assembly having no schema attribute"); Debug.Assert(!context.KnownAssemblies.ContainsKey(context.CurrentAssembly), "InternalLoadAssemblyFromCache: This assembly must not be present in the list of known assemblies"); bool areAssembliesLoadedFromCache = context.IsAssemblyAlreadyLoadedInCache; // Check if the assembly has been loaded in the cache then: // 1) Add EdmTypes described in ----semblyCacheEntry.TypesInAssembly // 2) Add Assemblies described by AssemblyCacheEntry.ReferenceAssembly, check to make sure that it's not already loaded in ObjectItemCollection if (context.IsAssemblyAlreadyLoadedInCache) { foreach (EdmType type in context.AssemblyCacheEntry._typesInAssembly) { if (!context.TypesInLoading.ContainsKey(type.Identity)) { context.TypesInLoading.Add(type.Identity, type); } } } else { LoadTypesFromAssembly(context); } Debug.Assert(!context.KnownAssemblies.ContainsKey(context.CurrentAssembly), "This assembly must not be present in the list of known assemblies"); context.KnownAssemblies.Add(context.CurrentAssembly, false/*ReferencedAssembliesNotLoaded*/); // When loading assembly from cache, the cache provide the implicit-dependency i.e. cross-reference by it's type to types in other assemblies. // In the case where assembly is loaded for the first-time, the loading process ensures that implicitly-dependenent assemblies are loaded foreach (Assembly referencedAssembly in context.AssemblyCacheEntry._referencedAssemblies) { if (!context.KnownAssemblies.ContainsKey(referencedAssembly)) { // Update the current assembly that we are currently loading context.UpdateCurrentAssembly(referencedAssembly, context.IsAssemblyAlreadyLoadedInCache); areAssembliesLoadedFromCache |= InternalLoadAssemblyFromCache(context); } } return areAssembliesLoadedFromCache; } ////// Loads the set of types from the given assembly and adds it to the given list of types /// /// context containing information for loading private static void LoadTypesFromAssembly(LoadingContext context) { Debug.Assert(context.AssemblyCacheEntry._typesInAssembly.Count == 0); LoadRelationshipTypes(context); // Loop through each type in the assembly and process it foreach (Type type in context.CurrentAssembly.GetTypes()) { // If the type doesn't have the same EdmTypeAttribute defined, then it's not a special type // that we care about, skip it. if (!type.IsDefined(typeof(DataClasses.EdmTypeAttribute), false)) { continue; } // Load the metadata for this type LoadFromType(type, context); } } ////// Load metadata of the given type - when you call this method, you should check and make sure that the type has /// edm attribute. If it doesn't,we won't load the type and it will be returned as null /// /// /// ///private static EdmType LoadFromType(Type clrType, LoadingContext context) { EdmType edmType = null; if (clrType.IsNested) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NestedClassNotSupported(clrType.FullName, clrType.Assembly.FullName), null)); return null; } // Lookup for the specified type in the following structures: // 1) typesInLoading - that describes the (*new*) types loaded so far by the current load-operation. // 2) objectItemCollection.Items - describes the types that are already loaded in ObjectItemCollection // 3) AssemblyCache - this describes a set of AssemblyCacheEntries containing 1) assembly types and 2) (implicitly) dependent assemblies // iff type is present in assembly_cache, add it to typesInLoading. if (!clrType.IsGenericType && context.IsTypeAlreadyLoaded(clrType, out edmType)) { // Check to make sure the CLR type we got is the same as the given one if (edmType.ClrType != clrType) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NewTypeConflictsWithExistingType( clrType.AssemblyQualifiedName, edmType.ClrType.AssemblyQualifiedName), edmType)); return null; } return edmType; } DataClasses.EdmTypeAttribute[] typeAttributes = (DataClasses.EdmTypeAttribute[])clrType.GetCustomAttributes(typeof(DataClasses.EdmTypeAttribute), false /*inherit*/); // the CLR doesn't allow types to have duplicate/multiple attribute declarations if (typeAttributes.Length != 0) { DataClasses.EdmTypeAttribute typeAttribute = typeAttributes[0]; string cspaceTypeName = String.IsNullOrEmpty(typeAttribute.Name) ? clrType.Name : typeAttribute.Name; if(String.IsNullOrEmpty(typeAttribute.NamespaceName) && clrType.Namespace == null) { context.EdmItemError.Add(new EdmItemError(Strings.Validator_TypeHasNoNamespace, edmType)); return null; } string cspaceNamespaceName = String.IsNullOrEmpty(typeAttribute.NamespaceName) ? clrType.Namespace : typeAttribute.NamespaceName; if (typeAttribute.GetType() == typeof(DataClasses.EdmEntityTypeAttribute)) { edmType = new ClrEntityType(clrType, cspaceNamespaceName, cspaceTypeName); } else { Debug.Assert(typeAttribute.GetType() == typeof(DataClasses.EdmComplexTypeAttribute), "Invalid type attribute encountered"); edmType = new ClrComplexType(clrType, cspaceNamespaceName, cspaceTypeName); } } else { return ResolveNonSchemaType(clrType, context); } // If type is not present in the current assembly, make sure you add the type's assembly in the list of referenced // assembly for the current assembly. But we still have to load the type and all its dependent type if (clrType.Assembly != context.CurrentAssembly) { // 1) Enqueue the "other" assembly for being loaded // 2) Register the "other" assembly as a referenced-assembly of currentAssembly // 3) and Load the specific type from "other" assembly for resolving the forward reference if (ShouldFilterAssembly(clrType.Assembly.FullName) || !IsSchemaAttributePresent(clrType.Assembly)) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.MissingAssemblyAttribute( clrType.FullName, clrType.Assembly.FullName), edmType)); return null; } else { if (!context.AssemblyCacheEntry._referencedAssemblies.Contains(clrType.Assembly)) { context.AssemblyCacheEntry._referencedAssemblies.Add(clrType.Assembly); } } } else { Debug.Assert(!context.AssemblyCacheEntry.ContainsType(edmType.Identity), "This type must not be already present in the list of types for this assembly"); // Also add this to the list of the types for this assembly context.AssemblyCacheEntry._typesInAssembly.Add(edmType); } // Add this to the known type map so we won't try to load it again context.TypesInLoading.Add(clrType.FullName, edmType); // Load properties for structural type if (Helper.IsStructuralType(edmType)) { //Load base type only for entity type - not sure if we will allow complex type inheritance if (Helper.IsEntityType(edmType)) { edmType.BaseType = LoadFromType(clrType.BaseType, context); } // Load the properties for this type LoadPropertiesFromType((StructuralType)edmType, context); } return edmType; } /// /// Load all the property metadata of the given type /// /// The type where properties are loaded /// private static void LoadPropertiesFromType(StructuralType structuralType, LoadingContext context) { // Look at both public, internal, and private instanced properties declared at this type, inherited members // are not looked at. Internal and private properties are also looked at because they are also schematized fields PropertyInfo[] properties = structuralType.ClrType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo property in properties) { EdmMember newMember = null; bool isEntityKeyProperty = false; //used for EdmScalarProperties only // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute // we will just ignore it and skip to the next property. if (property.IsDefined(typeof(DataClasses.EdmRelationshipNavigationPropertyAttribute), false)) { SaveNavigationProperty(structuralType, property, context); } else if (property.IsDefined(typeof(DataClasses.EdmScalarPropertyAttribute), false)) { newMember = LoadScalarProperty(property, context, out isEntityKeyProperty); } else if (property.IsDefined(typeof(DataClasses.EdmComplexPropertyAttribute), false)) { newMember = LoadComplexTypeProperty(property, context); } if (newMember == null) { // Property does not have one of the following attributes: // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute, EdmRelationshipNavigationPropertyAttribute // This means its an unmapped property and can be ignored. // Or there were error encountered while loading the properties continue; } // Add the property object to the type structuralType.AddMember(newMember); // Add to the entity's collection of key members // Do this here instead of in the if condition above for scalar properties because // we want to make sure the AddMember call above did not fail before updating the key members if (structuralType.BuiltInTypeKind == BuiltInTypeKind.EntityType && isEntityKeyProperty) { ((EntityType)structuralType).AddKeyMember(newMember); } } } ////// Loads metadata for the navigation properties /// /// /// /// ///private static void SaveNavigationProperty(StructuralType declaringType, PropertyInfo property, LoadingContext context) { Debug.Assert(property.IsDefined(typeof(DataClasses.EdmRelationshipNavigationPropertyAttribute), false), "The property must have navigation property defined"); // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute // we will just ignore it and skip to the next property. object[] relationshipPropertyAttributes = property.GetCustomAttributes(typeof(DataClasses.EdmRelationshipNavigationPropertyAttribute), false); Debug.Assert(relationshipPropertyAttributes.Length == 1, "There should be exactly one property for every navigation property"); // Load the property type and create a new property object EdmType propertyType = LoadFromType(property.PropertyType, context); // The only valid return types from navigation properties are: // (1) EntityType // (2) CollectionType containing valid EntityType // If LoadFromType returned null, it could mean that we couldn't validate any part of the type, or it could mean that it's a generic // where the main generic type was validated, but the generic type parameter was not. We can't tell the difference, so just fail // with the same error message in both cases. The user will have to figure out which part of the type is wrong. // We can't just rely on checking for a generic because it can lead to a scenario where we report that the type parameter is invalid // when really it's the main generic type. That is more confusing than reporting the full name and letting the user determine the problem. if (propertyType == null || !(propertyType.BuiltInTypeKind == BuiltInTypeKind.EntityType || propertyType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)) { // Once an error is detected the property does not need to be validated further, just add to the errors // collection and continue with the next property. The failure will cause an exception to be thrown later during validation of all of the types. context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_InvalidNavPropReturnType(property.Name, property.DeclaringType.FullName, property.PropertyType.FullName), null)); } else { // else we have a valid EntityType or CollectionType that contains EntityType. ResolveNonSchemaType enforces that a collection type // must contain an EntityType, and if it doesn't, propertyType will be null here. If propertyType is EntityType or CollectionType we know it is valid // Expecting EdmRelationshipNavigationPropertyAttribute to have AllowMultiple=False, so only look at first element in the attribute array DataClasses.EdmRelationshipNavigationPropertyAttribute attribute = (DataClasses.EdmRelationshipNavigationPropertyAttribute)relationshipPropertyAttributes[0]; context.UnresolvedNavigationProperties.Add(new NavigationPropertyInfo(declaringType, property, propertyType, attribute)); } } private static void ResolveNavigationProperties(LoadingContext context) { foreach (NavigationPropertyInfo info in context.UnresolvedNavigationProperties) { info.ResolveNavigationProperty(context); } } /// /// Load the property with scalar property attribute /// /// /// /// ///private static EdmMember LoadScalarProperty(PropertyInfo property, LoadingContext context, out bool isEntityKeyProperty) { Debug.Assert(property.IsDefined(typeof(DataClasses.EdmScalarPropertyAttribute), false), "The property must have a scalar attribute"); EdmMember member = null; isEntityKeyProperty = false; // Load the property type and create a new property object EdmType propertyType = LoadFromType(property.PropertyType, context); // If the type could not be loaded it's definitely not a primitive type, so that's an error // If it could be loaded but is not a primitive that's an error as well if (propertyType == null || propertyType.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType) { // This property does not need to be validated further, just add to the errors collection and continue with the next property // This failure will cause an exception to be thrown later during validation of all of the types context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_ScalarPropertyNotPrimitive(property.Name, property.DeclaringType.FullName, property.PropertyType.FullName), null)); } else { object[] attrs = property.GetCustomAttributes(typeof(DataClasses.EdmScalarPropertyAttribute), false); Debug.Assert(attrs.Length == 1, "Every property can exactly have one ScalarProperty Attribute"); // Expecting EdmScalarPropertyAttribute to have AllowMultiple=False, so only look at first element in the attribute array isEntityKeyProperty = ((DataClasses.EdmScalarPropertyAttribute)attrs[0]).EntityKeyProperty; bool isNullable = ((DataClasses.EdmScalarPropertyAttribute)attrs[0]).IsNullable; member = new EdmProperty(property.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = isNullable }), property); } return member; } /// /// Load the property with complex type property attribute /// /// /// ///private static EdmMember LoadComplexTypeProperty(PropertyInfo property, LoadingContext context) { // Load the property type and create a new property object EdmType propertyType = LoadFromType(property.PropertyType, context); // If the type could not be loaded it's definitely not a complex type, so that's an error // If it could be loaded but is not a complex type that's an error as well if (propertyType == null || propertyType.BuiltInTypeKind != BuiltInTypeKind.ComplexType) { // This property does not need to be validated further, just add to the errors collection and continue with the next property // This failure will cause an exception to be thrown later during validation of all of the types context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_ComplexPropertyNotComplex(property.Name, property.DeclaringType.FullName, property.PropertyType.FullName), null)); } else { EdmProperty newProperty = new EdmProperty(property.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = false }), property); return newProperty; } return null; } /// /// Resolves the given non-schematized type by looking at what kind of type this is. Non-schematized types include /// collection types, nullable types, reference types, and primitive types. /// /// The non-schematized CLR type that is being resolved /// A dictionary of types that we are currently loading ///An EdmType object representing the type, null if we can't resolve it private static EdmType ResolveNonSchemaType(Type clrType, LoadingContext context) { // Let's check to see if this type is a ref type, a nullable type, or a collection type, these are the types that // we need to take special care of them if (clrType.IsGenericType) { Type genericType = clrType.GetGenericTypeDefinition(); // Try to resolve the element type into a type object EdmType elementType = LoadFromType(clrType.GetGenericArguments()[0], context); if (elementType == null) { // return null and let the caller deal with the error handling return null; } // Create the collection or reference type object or just a simple value that was wrapped inside a Nullable if (genericType == typeof(Nullable<>)) { // In here, the Nullable<> is unwrapped. In CDM, nullability is on a per property basis, there shouldn't be // the notion of a nullable type return elementType; } else if (genericType == typeof(DataClasses.EntityReference<>)) { // EntityReferenceis IEnumerable, so we need to detect this condition and return here. // We don't support EntityReference in this scenario, so just fail. return null; } else if (typeof(IEnumerable).IsAssignableFrom(clrType)) { EntityType entityType = elementType as EntityType; if (entityType == null) { // return null and let the caller deal with the error handling return null; } return entityType.GetCollectionType(); } } // For primitive types, look in clr provider manifest PrimitiveType primitiveType; if (ClrProviderManifest.Instance.TryGetPrimitiveType(clrType, out primitiveType)) { return primitiveType; } return null; } /// /// This method loads all the relationship type that this entity takes part in /// /// /// private static void LoadRelationshipTypes(LoadingContext context) { foreach (System.Data.Objects.DataClasses.EdmRelationshipAttribute roleAttribute in context.CurrentAssembly.GetCustomAttributes(typeof(System.Data.Objects.DataClasses.EdmRelationshipAttribute), false /*inherit*/)) { // Check if there is an entry already with this name if (TryFindNullParametersInRelationshipAttribute(roleAttribute, context)) { // don't give more errors for these same bad parameters continue; } bool errorEncountered = false; // return error if the role names are the same if (roleAttribute.Role1Name == roleAttribute.Role2Name) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.SameRoleNameOnRelationshipAttribute(roleAttribute.RelationshipName, roleAttribute.Role2Name), null)); errorEncountered = true; } // Make sure the clr type specified are the same EntityType type1; if (!TryGetRelationshipEndEntityType(context, roleAttribute.Role1Type, out type1)) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.RoleTypeInEdmRelationshipAttributeIsInvalidType(roleAttribute.RelationshipName, roleAttribute.Role1Name, roleAttribute.Role1Type), null)); errorEncountered = true; } EntityType type2; if (!TryGetRelationshipEndEntityType(context, roleAttribute.Role2Type, out type2)) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.RoleTypeInEdmRelationshipAttributeIsInvalidType(roleAttribute.RelationshipName, roleAttribute.Role2Name, roleAttribute.Role2Type), null)); errorEncountered = true; } if (!errorEncountered) { AssociationType associationType = new AssociationType(roleAttribute.RelationshipName, roleAttribute.RelationshipNamespaceName, DataSpace.OSpace); associationType.AddKeyMember(new AssociationEndMember(roleAttribute.Role1Name, type1.GetReferenceType(), roleAttribute.Role1Multiplicity)); associationType.AddKeyMember(new AssociationEndMember(roleAttribute.Role2Name, type2.GetReferenceType(), roleAttribute.Role2Multiplicity)); context.TypesInLoading.Add(associationType.FullName, associationType); // get assembly entry and add association type to the list of types in the assembly Debug.Assert(!context.AssemblyCacheEntry.ContainsType(associationType.FullName), "Relationship type must not be present in the list of types"); context.AssemblyCacheEntry._typesInAssembly.Add(associationType); } } } private static bool TryFindNullParametersInRelationshipAttribute(System.Data.Objects.DataClasses.EdmRelationshipAttribute roleAttribute, LoadingContext context) { if (roleAttribute.RelationshipName == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullRelationshipNameforEdmRelationshipAttribute(context.CurrentAssembly.FullName), null)); return true; } bool nullsFound = false; if (roleAttribute.RelationshipNamespaceName == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "RelationshipNamespaceName", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role1Name == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role1Name", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role1Type == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role1Type", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role2Name == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role2Name", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role2Type == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role2Type", roleAttribute.RelationshipName), null)); nullsFound = true; } return nullsFound; } private static bool TryGetRelationshipEndEntityType(LoadingContext context, Type type, out EntityType entityType) { if (type == null) { entityType = null; return false; } EdmType edmType = LoadFromType(type, context); if (edmType == null || !Helper.IsEntityType(edmType)) { entityType = null; return false; } entityType = (EntityType)edmType; return true; } #endregion } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....], [....] //--------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Xml.Serialization; using System.Xml; using System.Xml.Schema; using System.Data.Common.Utils; using System.Diagnostics; using System.Collections.ObjectModel; using System.Threading; // Using an alias for this because a lot of names in this namespace conflicts with names in metadata using DataClasses = System.Data.Objects.DataClasses; using System.Globalization; using System.Data.Entity; using System.Data.Common; namespace System.Data.Metadata.Edm { ////// Class for representing a collection of items for the object layer. /// Most of the implemetation for actual maintainance of the collection is /// done by ItemCollection /// public sealed partial class ObjectItemCollection : ItemCollection { #region PrivateNestedClass private class AssemblyCacheEntry { #region Fields private readonly List_typesInAssembly; // types in "this" assembly private readonly List _referencedAssemblies; // other assemblies referenced by "this" assembly private static object _assemblyCacheLock = new object(); //List of assemblies having view gen attribute. We cache these things if we discover //these assemblies while looking for O-space metadata. private static IList s_viewGenAssemblies = new ThreadSafeList (); #endregion #region Nested classes private class LoadingContext { #region Fields // all the types that we encountered while loading - this may contain types from various assemblies private readonly Dictionary _typesInLoading; // list of errors encountered during loading private readonly List _errors; // list of unresolved navigation properties private readonly List _unresolvedNavigationProperties = new List (); // keep the list of new assemblies that got loaded in this load assembly call. The region why we need to keep a seperate // assembly is that if we need to keep track of errors, and if there are no errors, then only add the list of assemblies // to the global cache. Hence global cache is never polluted with invalid assemblies private readonly Dictionary _listOfAssembliesLoaded = new Dictionary (); // Current assembly whose type we are loading private Assembly _currentAssembly; // Assembly Cache Entry corresponding to the current assembly private AssemblyCacheEntry _currentCacheEntry; // Indicates if this assembly is already loaded in the cache private bool _isAssemblyLoadedFromGlobalCache; // Global Assembly Cache private readonly static Dictionary s_globalAssemblyCache = new Dictionary (); // List of known assemblies - this list is initially passed by the caller and we keep adding to it, as and when we load // an assembly private readonly Dictionary _knownAssemblies; #endregion #region Constructor internal LoadingContext(Assembly assembly, Dictionary knownAssemblies) { _typesInLoading = new Dictionary (StringComparer.Ordinal); _errors = new List (); _knownAssemblies = knownAssemblies; UpdateCurrentAssembly(assembly, false/*mustAssemblyBeAlreadyLoaded*/); } #endregion #region Properties internal Dictionary TypesInLoading { get { return _typesInLoading; } } internal List EdmItemError { get { return _errors; } } internal List UnresolvedNavigationProperties { get { return _unresolvedNavigationProperties; } } internal Assembly CurrentAssembly { get { return _currentAssembly; } } internal AssemblyCacheEntry AssemblyCacheEntry { get { return _currentCacheEntry; } } internal bool IsAssemblyAlreadyLoadedInCache { get { return _isAssemblyLoadedFromGlobalCache; } } internal Dictionary KnownAssemblies { get { return _knownAssemblies; } } #endregion #region Methods /// /// Check to see if the type is already loaded - either in the typesInLoading, or ObjectItemCollection or /// in the global cache /// /// /// ///internal bool IsTypeAlreadyLoaded(Type clrType, out EdmType edmType) { edmType = null; bool isPresentInAssemblyCache = false; bool isPresentInTypesInLoading = false; if (!clrType.IsGenericType && ((isPresentInTypesInLoading = TypesInLoading.TryGetValue(clrType.FullName, out edmType)) || (isPresentInAssemblyCache = IsTypeAlreadyInCache(clrType, out edmType)))) { // If the type is primitive type, just return the type if (!Helper.IsPrimitiveType(edmType)) { Debug.Assert(!ShouldFilterAssembly(clrType.Assembly.FullName), "Since the type is already loaded, the assembly must have a schema attribute"); Debug.Assert(ObjectItemCollection.IsSchemaAttributePresent(clrType.Assembly), "Since the type is already loaded, the assembly must have a schema attribute"); // If the type is not present in the current assembly, make sure you add the type's assembly // as one of the referenced assemblies if (clrType.Assembly != _currentAssembly) { if (!_currentCacheEntry._referencedAssemblies.Contains(clrType.Assembly)) { _currentCacheEntry._referencedAssemblies.Add(clrType.Assembly); } } // If the base type BT1 of a type T1 is present in another assembly, we just load the base type from that assembly and add // that assembly to the list of referenced assemblies. When you come to loading the referenced assembly, the type BT1 // is already present in TypeInLoading, and hence we need to add it to the list of types in assembly else if (isPresentInTypesInLoading && !_currentCacheEntry.ContainsType(edmType.Identity)) { _currentCacheEntry._typesInAssembly.Add(edmType); } // If the type was loaded from the global cache, then we need to find if this assembly is already loaded. If yes, // then we don't need to add that type in typesInLoading if (isPresentInAssemblyCache && !KnownAssemblies.ContainsKey(clrType.Assembly)) { TypesInLoading.Add(clrType.FullName, edmType); } } } return (edmType != null); } /// /// Returns if the types is already loaded in the cache /// /// /// ///private bool IsTypeAlreadyInCache(Type clrType, out EdmType edmType) { AssemblyCacheEntry cacheEntry; edmType = null; Debug.Assert(!_typesInLoading.ContainsKey(clrType.FullName), "This should be called only after looking in typesInLoading"); Debug.Assert(clrType.Assembly != _currentAssembly || !_currentCacheEntry.ContainsType(clrType.FullName), "The type must never be present in the current assembly list"); if (clrType.Assembly == _currentAssembly) { return false; } if (s_globalAssemblyCache.TryGetValue(clrType.Assembly, out cacheEntry)) { return cacheEntry.TryGetEdmType(clrType.FullName, out edmType); } else if (_listOfAssembliesLoaded.TryGetValue(clrType.Assembly, out cacheEntry)) { return cacheEntry.TryGetEdmType(clrType.FullName, out edmType); } return false; } /// /// Update the current assembly for the loading context. If the second parameter is true, assert that /// the assembly must be present in the global cache. this is to make sure if a assembly was already /// present in the global cache, all its dependent assemblies must also be present in the global cache /// This method checks if the given assembly is present in the global cache, if yes, its loads from there /// otherwise creates a new AssemblyCacheEntry for this assembly. /// Also it adds the earlier current assembly, into its local cache. The reason for doing this is that until /// we have loaded all the assemblies for this context and made sure that there are no errors, then we need /// to update the global cache /// /// /// internal void UpdateCurrentAssembly(Assembly assembly, bool mustAssemblyBeAlreadyLoaded) { Debug.Assert(assembly != null, "Current Assembly can't be set to null"); Debug.Assert(!mustAssemblyBeAlreadyLoaded || s_globalAssemblyCache.ContainsKey(assembly), "The assembly must be loaded in the cache"); // Update the current assembly _currentAssembly = assembly; if (mustAssemblyBeAlreadyLoaded) { // check if the assembly is already loaded in the cache _currentCacheEntry = s_globalAssemblyCache[assembly]; _isAssemblyLoadedFromGlobalCache = true; } else if (s_globalAssemblyCache.TryGetValue(assembly, out _currentCacheEntry)) { _isAssemblyLoadedFromGlobalCache = true; } // If the assemblies have circular dependencies then the assembly might have been added in the local cache else { if (!_listOfAssembliesLoaded.TryGetValue(assembly, out _currentCacheEntry)) { _currentCacheEntry = new AssemblyCacheEntry(); _listOfAssembliesLoaded.Add(_currentAssembly, _currentCacheEntry); } _isAssemblyLoadedFromGlobalCache = false; } } // Add all assemblies to the global cache if there are no errors internal void UpdateCacheWithAssembliesLoaded() { if (_errors.Count == 0) { foreach (KeyValuePairentry in _listOfAssembliesLoaded) { // Add all the assemblies from the loading context to the global cache s_globalAssemblyCache.Add(entry.Key, entry.Value); } // Remove all entries from transient cache _listOfAssembliesLoaded.Clear(); } } #endregion } private class NavigationPropertyInfo { private StructuralType _declaringType; private PropertyInfo _propertyInfo; private EdmType _propertyType; private DataClasses.EdmRelationshipNavigationPropertyAttribute _attribute; internal NavigationPropertyInfo( StructuralType declaringType, PropertyInfo propertyInfo, EdmType propertyType, DataClasses.EdmRelationshipNavigationPropertyAttribute attribute) { _declaringType = declaringType; _propertyInfo = propertyInfo; _propertyType = propertyType; _attribute = attribute; } internal void ResolveNavigationProperty(LoadingContext context) { EdmMember member = null; EdmType type; if (context.TypesInLoading.TryGetValue(_attribute.RelationshipNamespaceName + "." + _attribute.RelationshipName, out type) && Helper.IsAssociationType(type)) { AssociationType relationshipType = (AssociationType)type; if (relationshipType != null) { // The return value of this property has been verified, so create the property now NavigationProperty navigationProperty = new NavigationProperty(_propertyInfo.Name, TypeUsage.Create(_propertyType), _propertyInfo); navigationProperty.RelationshipType = relationshipType; member = navigationProperty; if (relationshipType.Members[0].Name == _attribute.TargetRoleName) { navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[0]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[1]; } else if (relationshipType.Members[1].Name == _attribute.TargetRoleName) { navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[1]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[0]; } else { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.TargetRoleNameInNavigationPropertyNotValid( _propertyInfo.Name, _propertyInfo.DeclaringType.FullName, _attribute.TargetRoleName, _attribute.RelationshipName), navigationProperty)); member = null; } if (member != null && ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType != _declaringType.ClrType) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NavigationPropertyRelationshipEndTypeMismatch( _declaringType.FullName, navigationProperty.Name, relationshipType.FullName, navigationProperty.FromEndMember.Name, ((RefType)navigationProperty.FromEndMember.TypeUsage.EdmType).ElementType.ClrType), navigationProperty)); member = null; } } } else { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.RelationshipNameInNavigationPropertyNotValid( _propertyInfo.Name, _propertyInfo.DeclaringType.FullName, _attribute.RelationshipName), _declaringType)); } if (member != null) { _declaringType.AddMember(member); } } } #endregion #region Constructor public AssemblyCacheEntry() { _typesInAssembly = new List (); _referencedAssemblies = new List (); } #endregion #region Internal Methods (Entry points to the Cache) internal static IList ViewGenerationAssemblies { get { return s_viewGenAssemblies; } } internal static void LoadAssemblyFromCache(Assembly assembly, bool loadReferencedAssemblies, Dictionary knownAssemblies, out Dictionary typesInLoading, out List errors) { Debug.Assert(!ShouldFilterAssembly(assembly.FullName), "LoadAssemblyFromCache should be called on assembly having non-reserved public key token"); typesInLoading = null; errors = null; lock (_assemblyCacheLock) { // This function loads all the types from the given assembly and the dependent assemblies. We only try to load assemblies // that are requried for type closure. This is different from referenced asssemblies. If the assembly is already loaded, // then the assembly is just copied from the cache LoadingContext context = new LoadingContext(assembly, knownAssemblies); // Loads the current assembly and all the dependent assemblies (required for type closure) if (!context.KnownAssemblies.ContainsKey(context.CurrentAssembly) && IsSchemaAttributePresent(context.CurrentAssembly)) { InternalLoadAssemblyFromCache(context); } if (loadReferencedAssemblies) { InternalLoadAllReferencedAssemblies(context); } // resolve navigation properties that showed up // before the relationships that they use showed up ResolveNavigationProperties(context); // do the validation for the all the new types // Now, perform validation on all the new types EdmValidator validator = new EdmValidator(); validator.SkipReadOnlyItems = true; validator.Validate(context.TypesInLoading.Values, context.EdmItemError); // Update the global cache if there are no errors context.UpdateCacheWithAssembliesLoaded(); // Update the out parameters once you are done with loading typesInLoading = context.TypesInLoading; errors = context.EdmItemError; if (typesInLoading != null && typesInLoading.Count > 0) { foreach (EdmType edmType in typesInLoading.Values) { edmType.SetReadOnly(); } } } } internal static Assembly SafeLoadReferencedAssembly(string assemblyFullName) { Assembly referencedAssembly = null; try { referencedAssembly = Assembly.Load(assemblyFullName); } catch (System.IO.FileNotFoundException) { // See 552932: ObjectItemCollection: fails on referenced asseblies that are not available } return referencedAssembly; } #endregion #region Private Methods private bool TryGetEdmType(string typeName, out EdmType edmType) { edmType = null; foreach (EdmType loadedEdmType in this._typesInAssembly) { if (loadedEdmType.Identity == typeName) { edmType = loadedEdmType; break; } } return (edmType != null); } private bool ContainsType(string typeName) { EdmType edmType = null; return TryGetEdmType(typeName, out edmType); } private static void InternalLoadAllReferencedAssemblies(LoadingContext context) { // We will traverse through all the statically linked assemblies and their dependencies. // Only assemblies with the EdmSchemaAttribute will be loaded and rest will be ignored // Even if the schema attribute is missing, we should still check all the dependent assemblies // any of the dependent assemblies can have the schema attribute // After the given assembly has been loaded, check on the flag in _knownAssemblies to see if it has already // been recursively loaded. The flag can be true if it was already loaded before this function was called foreach (AssemblyName asmName in context.CurrentAssembly.GetReferencedAssemblies()) { string assemblyFullName = asmName.FullName; if (!ShouldFilterAssembly(assemblyFullName)) { // filter out "known" assemblies to prevent unnecessary loading EntityBid.Trace(" loadededAssembly='%ls'\n", assemblyFullName); Assembly referencedAssembly = SafeLoadReferencedAssembly(assemblyFullName); if (referencedAssembly == null) { continue; } // Mark the assembly as known assembly, and since we are loading all the referenced assemblies, // mark the value to the true context.UpdateCurrentAssembly(referencedAssembly, false/*mustAlreadyBeLoaded*/); // Check if the assembly is already loaded bool areReferencedAssembliesLoaded; if (context.KnownAssemblies.TryGetValue(referencedAssembly, out areReferencedAssembliesLoaded)) { // If all the referenced assemblies are already loaded, don't need to do anything if (areReferencedAssembliesLoaded) { continue; } } // Load this assembly if the schema attrbute is present else if (ObjectItemCollection.IsSchemaAttributePresent(referencedAssembly)) { InternalLoadAssemblyFromCache(context); } // We need to add this assembly to the list of known assemblies before we start // analyzing the referenced assemblies, since there could be circular reference // and we need to detect that and break the loop context.KnownAssemblies[referencedAssembly] = true; InternalLoadAllReferencedAssemblies(context); } } } /// /// Loads the given assembly and all the other referencd assemblies in the cache. If the assembly was already present /// then it loads from the cache /// /// ///true if the assembly was already loaded in the cache private static bool InternalLoadAssemblyFromCache(LoadingContext context) { Debug.Assert(!ShouldFilterAssembly(context.CurrentAssembly.FullName), "LoadAssemblyFromCache should be called on assembly having non-reserved public key token"); Debug.Assert(IsSchemaAttributePresent(context.CurrentAssembly), "LoadAssembly shouldn't be called with assembly having no schema attribute"); Debug.Assert(!context.KnownAssemblies.ContainsKey(context.CurrentAssembly), "InternalLoadAssemblyFromCache: This assembly must not be present in the list of known assemblies"); bool areAssembliesLoadedFromCache = context.IsAssemblyAlreadyLoadedInCache; // Check if the assembly has been loaded in the cache then: // 1) Add EdmTypes described in ----semblyCacheEntry.TypesInAssembly // 2) Add Assemblies described by AssemblyCacheEntry.ReferenceAssembly, check to make sure that it's not already loaded in ObjectItemCollection if (context.IsAssemblyAlreadyLoadedInCache) { foreach (EdmType type in context.AssemblyCacheEntry._typesInAssembly) { if (!context.TypesInLoading.ContainsKey(type.Identity)) { context.TypesInLoading.Add(type.Identity, type); } } } else { LoadTypesFromAssembly(context); } Debug.Assert(!context.KnownAssemblies.ContainsKey(context.CurrentAssembly), "This assembly must not be present in the list of known assemblies"); context.KnownAssemblies.Add(context.CurrentAssembly, false/*ReferencedAssembliesNotLoaded*/); // When loading assembly from cache, the cache provide the implicit-dependency i.e. cross-reference by it's type to types in other assemblies. // In the case where assembly is loaded for the first-time, the loading process ensures that implicitly-dependenent assemblies are loaded foreach (Assembly referencedAssembly in context.AssemblyCacheEntry._referencedAssemblies) { if (!context.KnownAssemblies.ContainsKey(referencedAssembly)) { // Update the current assembly that we are currently loading context.UpdateCurrentAssembly(referencedAssembly, context.IsAssemblyAlreadyLoadedInCache); areAssembliesLoadedFromCache |= InternalLoadAssemblyFromCache(context); } } return areAssembliesLoadedFromCache; } ////// Loads the set of types from the given assembly and adds it to the given list of types /// /// context containing information for loading private static void LoadTypesFromAssembly(LoadingContext context) { Debug.Assert(context.AssemblyCacheEntry._typesInAssembly.Count == 0); LoadRelationshipTypes(context); // Loop through each type in the assembly and process it foreach (Type type in context.CurrentAssembly.GetTypes()) { // If the type doesn't have the same EdmTypeAttribute defined, then it's not a special type // that we care about, skip it. if (!type.IsDefined(typeof(DataClasses.EdmTypeAttribute), false)) { continue; } // Load the metadata for this type LoadFromType(type, context); } } ////// Load metadata of the given type - when you call this method, you should check and make sure that the type has /// edm attribute. If it doesn't,we won't load the type and it will be returned as null /// /// /// ///private static EdmType LoadFromType(Type clrType, LoadingContext context) { EdmType edmType = null; if (clrType.IsNested) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NestedClassNotSupported(clrType.FullName, clrType.Assembly.FullName), null)); return null; } // Lookup for the specified type in the following structures: // 1) typesInLoading - that describes the (*new*) types loaded so far by the current load-operation. // 2) objectItemCollection.Items - describes the types that are already loaded in ObjectItemCollection // 3) AssemblyCache - this describes a set of AssemblyCacheEntries containing 1) assembly types and 2) (implicitly) dependent assemblies // iff type is present in assembly_cache, add it to typesInLoading. if (!clrType.IsGenericType && context.IsTypeAlreadyLoaded(clrType, out edmType)) { // Check to make sure the CLR type we got is the same as the given one if (edmType.ClrType != clrType) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NewTypeConflictsWithExistingType( clrType.AssemblyQualifiedName, edmType.ClrType.AssemblyQualifiedName), edmType)); return null; } return edmType; } DataClasses.EdmTypeAttribute[] typeAttributes = (DataClasses.EdmTypeAttribute[])clrType.GetCustomAttributes(typeof(DataClasses.EdmTypeAttribute), false /*inherit*/); // the CLR doesn't allow types to have duplicate/multiple attribute declarations if (typeAttributes.Length != 0) { DataClasses.EdmTypeAttribute typeAttribute = typeAttributes[0]; string cspaceTypeName = String.IsNullOrEmpty(typeAttribute.Name) ? clrType.Name : typeAttribute.Name; if(String.IsNullOrEmpty(typeAttribute.NamespaceName) && clrType.Namespace == null) { context.EdmItemError.Add(new EdmItemError(Strings.Validator_TypeHasNoNamespace, edmType)); return null; } string cspaceNamespaceName = String.IsNullOrEmpty(typeAttribute.NamespaceName) ? clrType.Namespace : typeAttribute.NamespaceName; if (typeAttribute.GetType() == typeof(DataClasses.EdmEntityTypeAttribute)) { edmType = new ClrEntityType(clrType, cspaceNamespaceName, cspaceTypeName); } else { Debug.Assert(typeAttribute.GetType() == typeof(DataClasses.EdmComplexTypeAttribute), "Invalid type attribute encountered"); edmType = new ClrComplexType(clrType, cspaceNamespaceName, cspaceTypeName); } } else { return ResolveNonSchemaType(clrType, context); } // If type is not present in the current assembly, make sure you add the type's assembly in the list of referenced // assembly for the current assembly. But we still have to load the type and all its dependent type if (clrType.Assembly != context.CurrentAssembly) { // 1) Enqueue the "other" assembly for being loaded // 2) Register the "other" assembly as a referenced-assembly of currentAssembly // 3) and Load the specific type from "other" assembly for resolving the forward reference if (ShouldFilterAssembly(clrType.Assembly.FullName) || !IsSchemaAttributePresent(clrType.Assembly)) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.MissingAssemblyAttribute( clrType.FullName, clrType.Assembly.FullName), edmType)); return null; } else { if (!context.AssemblyCacheEntry._referencedAssemblies.Contains(clrType.Assembly)) { context.AssemblyCacheEntry._referencedAssemblies.Add(clrType.Assembly); } } } else { Debug.Assert(!context.AssemblyCacheEntry.ContainsType(edmType.Identity), "This type must not be already present in the list of types for this assembly"); // Also add this to the list of the types for this assembly context.AssemblyCacheEntry._typesInAssembly.Add(edmType); } // Add this to the known type map so we won't try to load it again context.TypesInLoading.Add(clrType.FullName, edmType); // Load properties for structural type if (Helper.IsStructuralType(edmType)) { //Load base type only for entity type - not sure if we will allow complex type inheritance if (Helper.IsEntityType(edmType)) { edmType.BaseType = LoadFromType(clrType.BaseType, context); } // Load the properties for this type LoadPropertiesFromType((StructuralType)edmType, context); } return edmType; } /// /// Load all the property metadata of the given type /// /// The type where properties are loaded /// private static void LoadPropertiesFromType(StructuralType structuralType, LoadingContext context) { // Look at both public, internal, and private instanced properties declared at this type, inherited members // are not looked at. Internal and private properties are also looked at because they are also schematized fields PropertyInfo[] properties = structuralType.ClrType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo property in properties) { EdmMember newMember = null; bool isEntityKeyProperty = false; //used for EdmScalarProperties only // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute // we will just ignore it and skip to the next property. if (property.IsDefined(typeof(DataClasses.EdmRelationshipNavigationPropertyAttribute), false)) { SaveNavigationProperty(structuralType, property, context); } else if (property.IsDefined(typeof(DataClasses.EdmScalarPropertyAttribute), false)) { newMember = LoadScalarProperty(property, context, out isEntityKeyProperty); } else if (property.IsDefined(typeof(DataClasses.EdmComplexPropertyAttribute), false)) { newMember = LoadComplexTypeProperty(property, context); } if (newMember == null) { // Property does not have one of the following attributes: // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute, EdmRelationshipNavigationPropertyAttribute // This means its an unmapped property and can be ignored. // Or there were error encountered while loading the properties continue; } // Add the property object to the type structuralType.AddMember(newMember); // Add to the entity's collection of key members // Do this here instead of in the if condition above for scalar properties because // we want to make sure the AddMember call above did not fail before updating the key members if (structuralType.BuiltInTypeKind == BuiltInTypeKind.EntityType && isEntityKeyProperty) { ((EntityType)structuralType).AddKeyMember(newMember); } } } ////// Loads metadata for the navigation properties /// /// /// /// ///private static void SaveNavigationProperty(StructuralType declaringType, PropertyInfo property, LoadingContext context) { Debug.Assert(property.IsDefined(typeof(DataClasses.EdmRelationshipNavigationPropertyAttribute), false), "The property must have navigation property defined"); // EdmScalarPropertyAttribute, EdmComplexPropertyAttribute and EdmRelationshipNavigationPropertyAttribute // are all EdmPropertyAttributes that we need to process. If the current property is not an EdmPropertyAttribute // we will just ignore it and skip to the next property. object[] relationshipPropertyAttributes = property.GetCustomAttributes(typeof(DataClasses.EdmRelationshipNavigationPropertyAttribute), false); Debug.Assert(relationshipPropertyAttributes.Length == 1, "There should be exactly one property for every navigation property"); // Load the property type and create a new property object EdmType propertyType = LoadFromType(property.PropertyType, context); // The only valid return types from navigation properties are: // (1) EntityType // (2) CollectionType containing valid EntityType // If LoadFromType returned null, it could mean that we couldn't validate any part of the type, or it could mean that it's a generic // where the main generic type was validated, but the generic type parameter was not. We can't tell the difference, so just fail // with the same error message in both cases. The user will have to figure out which part of the type is wrong. // We can't just rely on checking for a generic because it can lead to a scenario where we report that the type parameter is invalid // when really it's the main generic type. That is more confusing than reporting the full name and letting the user determine the problem. if (propertyType == null || !(propertyType.BuiltInTypeKind == BuiltInTypeKind.EntityType || propertyType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)) { // Once an error is detected the property does not need to be validated further, just add to the errors // collection and continue with the next property. The failure will cause an exception to be thrown later during validation of all of the types. context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_InvalidNavPropReturnType(property.Name, property.DeclaringType.FullName, property.PropertyType.FullName), null)); } else { // else we have a valid EntityType or CollectionType that contains EntityType. ResolveNonSchemaType enforces that a collection type // must contain an EntityType, and if it doesn't, propertyType will be null here. If propertyType is EntityType or CollectionType we know it is valid // Expecting EdmRelationshipNavigationPropertyAttribute to have AllowMultiple=False, so only look at first element in the attribute array DataClasses.EdmRelationshipNavigationPropertyAttribute attribute = (DataClasses.EdmRelationshipNavigationPropertyAttribute)relationshipPropertyAttributes[0]; context.UnresolvedNavigationProperties.Add(new NavigationPropertyInfo(declaringType, property, propertyType, attribute)); } } private static void ResolveNavigationProperties(LoadingContext context) { foreach (NavigationPropertyInfo info in context.UnresolvedNavigationProperties) { info.ResolveNavigationProperty(context); } } /// /// Load the property with scalar property attribute /// /// /// /// ///private static EdmMember LoadScalarProperty(PropertyInfo property, LoadingContext context, out bool isEntityKeyProperty) { Debug.Assert(property.IsDefined(typeof(DataClasses.EdmScalarPropertyAttribute), false), "The property must have a scalar attribute"); EdmMember member = null; isEntityKeyProperty = false; // Load the property type and create a new property object EdmType propertyType = LoadFromType(property.PropertyType, context); // If the type could not be loaded it's definitely not a primitive type, so that's an error // If it could be loaded but is not a primitive that's an error as well if (propertyType == null || propertyType.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType) { // This property does not need to be validated further, just add to the errors collection and continue with the next property // This failure will cause an exception to be thrown later during validation of all of the types context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_ScalarPropertyNotPrimitive(property.Name, property.DeclaringType.FullName, property.PropertyType.FullName), null)); } else { object[] attrs = property.GetCustomAttributes(typeof(DataClasses.EdmScalarPropertyAttribute), false); Debug.Assert(attrs.Length == 1, "Every property can exactly have one ScalarProperty Attribute"); // Expecting EdmScalarPropertyAttribute to have AllowMultiple=False, so only look at first element in the attribute array isEntityKeyProperty = ((DataClasses.EdmScalarPropertyAttribute)attrs[0]).EntityKeyProperty; bool isNullable = ((DataClasses.EdmScalarPropertyAttribute)attrs[0]).IsNullable; member = new EdmProperty(property.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = isNullable }), property); } return member; } /// /// Load the property with complex type property attribute /// /// /// ///private static EdmMember LoadComplexTypeProperty(PropertyInfo property, LoadingContext context) { // Load the property type and create a new property object EdmType propertyType = LoadFromType(property.PropertyType, context); // If the type could not be loaded it's definitely not a complex type, so that's an error // If it could be loaded but is not a complex type that's an error as well if (propertyType == null || propertyType.BuiltInTypeKind != BuiltInTypeKind.ComplexType) { // This property does not need to be validated further, just add to the errors collection and continue with the next property // This failure will cause an exception to be thrown later during validation of all of the types context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.Validator_OSpace_ComplexPropertyNotComplex(property.Name, property.DeclaringType.FullName, property.PropertyType.FullName), null)); } else { EdmProperty newProperty = new EdmProperty(property.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = false }), property); return newProperty; } return null; } /// /// Resolves the given non-schematized type by looking at what kind of type this is. Non-schematized types include /// collection types, nullable types, reference types, and primitive types. /// /// The non-schematized CLR type that is being resolved /// A dictionary of types that we are currently loading ///An EdmType object representing the type, null if we can't resolve it private static EdmType ResolveNonSchemaType(Type clrType, LoadingContext context) { // Let's check to see if this type is a ref type, a nullable type, or a collection type, these are the types that // we need to take special care of them if (clrType.IsGenericType) { Type genericType = clrType.GetGenericTypeDefinition(); // Try to resolve the element type into a type object EdmType elementType = LoadFromType(clrType.GetGenericArguments()[0], context); if (elementType == null) { // return null and let the caller deal with the error handling return null; } // Create the collection or reference type object or just a simple value that was wrapped inside a Nullable if (genericType == typeof(Nullable<>)) { // In here, the Nullable<> is unwrapped. In CDM, nullability is on a per property basis, there shouldn't be // the notion of a nullable type return elementType; } else if (genericType == typeof(DataClasses.EntityReference<>)) { // EntityReferenceis IEnumerable, so we need to detect this condition and return here. // We don't support EntityReference in this scenario, so just fail. return null; } else if (typeof(IEnumerable).IsAssignableFrom(clrType)) { EntityType entityType = elementType as EntityType; if (entityType == null) { // return null and let the caller deal with the error handling return null; } return entityType.GetCollectionType(); } } // For primitive types, look in clr provider manifest PrimitiveType primitiveType; if (ClrProviderManifest.Instance.TryGetPrimitiveType(clrType, out primitiveType)) { return primitiveType; } return null; } /// /// This method loads all the relationship type that this entity takes part in /// /// /// private static void LoadRelationshipTypes(LoadingContext context) { foreach (System.Data.Objects.DataClasses.EdmRelationshipAttribute roleAttribute in context.CurrentAssembly.GetCustomAttributes(typeof(System.Data.Objects.DataClasses.EdmRelationshipAttribute), false /*inherit*/)) { // Check if there is an entry already with this name if (TryFindNullParametersInRelationshipAttribute(roleAttribute, context)) { // don't give more errors for these same bad parameters continue; } bool errorEncountered = false; // return error if the role names are the same if (roleAttribute.Role1Name == roleAttribute.Role2Name) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.SameRoleNameOnRelationshipAttribute(roleAttribute.RelationshipName, roleAttribute.Role2Name), null)); errorEncountered = true; } // Make sure the clr type specified are the same EntityType type1; if (!TryGetRelationshipEndEntityType(context, roleAttribute.Role1Type, out type1)) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.RoleTypeInEdmRelationshipAttributeIsInvalidType(roleAttribute.RelationshipName, roleAttribute.Role1Name, roleAttribute.Role1Type), null)); errorEncountered = true; } EntityType type2; if (!TryGetRelationshipEndEntityType(context, roleAttribute.Role2Type, out type2)) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.RoleTypeInEdmRelationshipAttributeIsInvalidType(roleAttribute.RelationshipName, roleAttribute.Role2Name, roleAttribute.Role2Type), null)); errorEncountered = true; } if (!errorEncountered) { AssociationType associationType = new AssociationType(roleAttribute.RelationshipName, roleAttribute.RelationshipNamespaceName, DataSpace.OSpace); associationType.AddKeyMember(new AssociationEndMember(roleAttribute.Role1Name, type1.GetReferenceType(), roleAttribute.Role1Multiplicity)); associationType.AddKeyMember(new AssociationEndMember(roleAttribute.Role2Name, type2.GetReferenceType(), roleAttribute.Role2Multiplicity)); context.TypesInLoading.Add(associationType.FullName, associationType); // get assembly entry and add association type to the list of types in the assembly Debug.Assert(!context.AssemblyCacheEntry.ContainsType(associationType.FullName), "Relationship type must not be present in the list of types"); context.AssemblyCacheEntry._typesInAssembly.Add(associationType); } } } private static bool TryFindNullParametersInRelationshipAttribute(System.Data.Objects.DataClasses.EdmRelationshipAttribute roleAttribute, LoadingContext context) { if (roleAttribute.RelationshipName == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullRelationshipNameforEdmRelationshipAttribute(context.CurrentAssembly.FullName), null)); return true; } bool nullsFound = false; if (roleAttribute.RelationshipNamespaceName == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "RelationshipNamespaceName", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role1Name == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role1Name", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role1Type == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role1Type", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role2Name == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role2Name", roleAttribute.RelationshipName), null)); nullsFound = true; } if (roleAttribute.Role2Type == null) { context.EdmItemError.Add(new EdmItemError(System.Data.Entity.Strings.NullParameterForEdmRelationshipAttribute( "Role2Type", roleAttribute.RelationshipName), null)); nullsFound = true; } return nullsFound; } private static bool TryGetRelationshipEndEntityType(LoadingContext context, Type type, out EntityType entityType) { if (type == null) { entityType = null; return false; } EdmType edmType = LoadFromType(type, context); if (edmType == null || !Helper.IsEntityType(edmType)) { entityType = null; return false; } entityType = (EntityType)edmType; return true; } #endregion } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- GenericsInstances.cs
- CustomAttributeFormatException.cs
- TextBoxBase.cs
- BrowserDefinitionCollection.cs
- Journal.cs
- ForeignKeyFactory.cs
- DataKeyArray.cs
- FindResponse.cs
- BitmapPalette.cs
- TraceEventCache.cs
- SamlAttributeStatement.cs
- GradientBrush.cs
- SuppressMergeCheckAttribute.cs
- COM2IProvidePropertyBuilderHandler.cs
- Misc.cs
- ObjectItemAttributeAssemblyLoader.cs
- ServiceModelEnhancedConfigurationElementCollection.cs
- ErrorHandler.cs
- TypeConverterAttribute.cs
- ZipPackage.cs
- NameValueSectionHandler.cs
- SQlBooleanStorage.cs
- NativeMethods.cs
- OdbcRowUpdatingEvent.cs
- Cell.cs
- StyleBamlTreeBuilder.cs
- ListenerConstants.cs
- InkCanvasFeedbackAdorner.cs
- SoapReflectionImporter.cs
- DebugView.cs
- BitmapEffectState.cs
- XslUrlEditor.cs
- TextTreeInsertElementUndoUnit.cs
- SchemaSetCompiler.cs
- BackgroundFormatInfo.cs
- BooleanKeyFrameCollection.cs
- FullTextLine.cs
- LastQueryOperator.cs
- SchemaTableOptionalColumn.cs
- Int64.cs
- PersistChildrenAttribute.cs
- QueryReaderSettings.cs
- Compensate.cs
- BinHexEncoding.cs
- XmlnsDictionary.cs
- DataGridViewIntLinkedList.cs
- TextTrailingCharacterEllipsis.cs
- ParseHttpDate.cs
- PostBackOptions.cs
- PageVisual.cs
- RouteData.cs
- PathFigureCollectionConverter.cs
- DtdParser.cs
- VisualStyleElement.cs
- AsmxEndpointPickerExtension.cs
- RequiredAttributeAttribute.cs
- IdentityReference.cs
- AnnotationResourceChangedEventArgs.cs
- SimpleHandlerBuildProvider.cs
- ClientType.cs
- OledbConnectionStringbuilder.cs
- StateChangeEvent.cs
- StringConcat.cs
- SqlTopReducer.cs
- ContentType.cs
- ModelServiceImpl.cs
- DataGridViewCellEventArgs.cs
- FamilyMap.cs
- GridViewActionList.cs
- Util.cs
- Image.cs
- InvalidComObjectException.cs
- HttpWebResponse.cs
- SqlXmlStorage.cs
- RuleSettings.cs
- _RequestCacheProtocol.cs
- EmptyStringExpandableObjectConverter.cs
- TempFiles.cs
- CodeActivityContext.cs
- ModelServiceImpl.cs
- XmlAttributeAttribute.cs
- PageVisual.cs
- AccessorTable.cs
- Math.cs
- DocumentReference.cs
- EditBehavior.cs
- File.cs
- TextParaLineResult.cs
- SystemTcpStatistics.cs
- StyleXamlTreeBuilder.cs
- State.cs
- ToolStripControlHost.cs
- AbstractExpressions.cs
- ObjectConverter.cs
- StandardCommandToolStripMenuItem.cs
- DataTemplate.cs
- ColumnBinding.cs
- FixedFlowMap.cs
- WebPartVerb.cs
- AttachedPropertyMethodSelector.cs