Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Metadata / ObjectLayer / ObjectItemConventionAssemblyLoader.cs / 1305376 / ObjectItemConventionAssemblyLoader.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Reflection;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data.Entity;
using System.Text;
namespace System.Data.Metadata.Edm
{
internal sealed class ObjectItemConventionAssemblyLoader : ObjectItemAssemblyLoader
{
// for root entities, entities with no base type, we will additionally look
// at properties on the clr base hierarchy.
private const BindingFlags RootEntityPropertyReflectionBindingFlags = PropertyReflectionBindingFlags & ~BindingFlags.DeclaredOnly | BindingFlags.FlattenHierarchy;
private new MutableAssemblyCacheEntry CacheEntry { get { return (MutableAssemblyCacheEntry)base.CacheEntry; } }
private List _referenceResolutions = new List();
internal ObjectItemConventionAssemblyLoader(Assembly assembly, ObjectItemLoadingSessionData sessionData)
: base(assembly, new MutableAssemblyCacheEntry(), sessionData)
{
Debug.Assert(Create == sessionData.ObjectItemAssemblyLoaderFactory, "Why is there a different factory creating this class");
SessionData.RegisterForLevel1PostSessionProcessing(this);
}
protected override void LoadTypesFromAssembly()
{
foreach (Type type in SourceAssembly.GetTypes())
{
StructuralType cspaceType;
if (TryGetCSpaceTypeMatch(type, out cspaceType))
{
if (type.IsValueType)
{
SessionData.LoadMessageLogger.LogLoadMessage(Strings.Validator_OSpace_Convention_Struct(cspaceType.FullName, type.FullName), cspaceType);
continue;
}
EdmType ospaceType;
if (TryCreateType(type, (StructuralType)cspaceType, out ospaceType))
{
CacheEntry.TypesInAssembly.Add(ospaceType);
// check for duplcates so we don't cause an ArgumentException,
// Mapping will do the actual error for the duplicate type later
if (!SessionData.CspaceToOspace.ContainsKey((StructuralType)cspaceType))
{
SessionData.CspaceToOspace.Add((StructuralType)cspaceType, (StructuralType)ospaceType);
}
else
{
// at this point there is already a Clr Type that is structurally matched to this CSpace type, we throw exception
StructuralType previousOSpaceType = SessionData.CspaceToOspace[cspaceType];
SessionData.EdmItemErrors.Add(
new EdmItemError(Strings.Validator_OSpace_Convention_AmbiguousClrType(cspaceType.Name, previousOSpaceType.ClrType.FullName, type.FullName), previousOSpaceType));
}
}
}
}
if (SessionData.TypesInLoading.Count == 0)
{
Debug.Assert(CacheEntry.ClosureAssemblies.Count == 0, "How did we get closure assemblies?");
// since we didn't find any types, don't lock into convention based
SessionData.ObjectItemAssemblyLoaderFactory = null;
}
}
protected override void AddToAssembliesLoaded()
{
SessionData.AssembliesLoaded.Add(SourceAssembly, CacheEntry);
}
private bool TryGetCSpaceTypeMatch(Type type, out StructuralType cspaceType)
{
// brute force try and find a matching name
KeyValuePair pair;
if (SessionData.ConventionCSpaceTypeNames.TryGetValue(type.Name, out pair))
{
if (pair.Value == 1)
{
// we found a type match
cspaceType = pair.Key;
return true;
}
else
{
Debug.Assert(pair.Value > 1, "how did we get a negative count of types in the dictionary?");
SessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_OSpace_Convention_MultipleTypesWithSameName(type.Name), pair.Key));
}
}
cspaceType = null;
return false;
}
private bool TryCreateType(Type type, StructuralType cspaceType, out EdmType newOSpaceType)
{
List referenceResolutionListForCurrentType = new List();
newOSpaceType = null;
Debug.Assert(TypesMatchByConvention(type, cspaceType), "The types passed as parameters don't match by convention.");
StructuralType ospaceType;
if (Helper.IsEntityType(cspaceType))
{
ospaceType = new ClrEntityType(type, cspaceType.NamespaceName, cspaceType.Name);
}
else
{
Debug.Assert(Helper.IsComplexType(cspaceType), "Invalid type attribute encountered");
ospaceType = new ClrComplexType(type, cspaceType.NamespaceName, cspaceType.Name);
}
if (cspaceType.BaseType != null)
{
if (TypesMatchByConvention(type.BaseType, cspaceType.BaseType))
{
TrackClosure(type.BaseType);
referenceResolutionListForCurrentType.Add(
() => ospaceType.BaseType = ResolveBaseType((StructuralType)cspaceType.BaseType, type));
}
else
{
string message = Strings.Validator_OSpace_Convention_BaseTypeIncompatible(type.BaseType.FullName, type.FullName, cspaceType.BaseType.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
// Load the properties for this type
if (!TryCreateMembers(type, (StructuralType)cspaceType, ospaceType, referenceResolutionListForCurrentType))
{
return false;
}
// Add this to the known type map so we won't try to load it again
SessionData.TypesInLoading.Add(type.FullName, ospaceType);
// we only add the referenceResolution to the list unless we structrually matched this type
foreach (var referenceResolution in referenceResolutionListForCurrentType)
{
this._referenceResolutions.Add(referenceResolution);
}
newOSpaceType = ospaceType;
return true;
}
internal override void OnLevel1SessionProcessing()
{
CreateRelationships();
foreach (Action resolve in _referenceResolutions)
{
resolve();
}
base.OnLevel1SessionProcessing();
}
private EdmType ResolveBaseType(StructuralType baseCSpaceType, Type type)
{
StructuralType ospaceType;
bool foundValue = SessionData.CspaceToOspace.TryGetValue(baseCSpaceType, out ospaceType);
if (!foundValue)
{
string message =
SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
Strings.Validator_OSpace_Convention_BaseTypeNotLoaded(type, baseCSpaceType),
baseCSpaceType);
SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
}
return ospaceType;
}
private bool TryCreateMembers(Type type, StructuralType cspaceType, StructuralType ospaceType, List referenceResolutionListForCurrentType)
{
BindingFlags flags = cspaceType.BaseType == null ? RootEntityPropertyReflectionBindingFlags : PropertyReflectionBindingFlags;
PropertyInfo[] clrProperties = type.GetProperties(flags);
// required properties scalar properties first
if (!TryFindAndCreateScalarProperties(type, cspaceType, ospaceType, clrProperties))
{
return false;
}
if (!TryFindComplexProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType))
{
return false;
}
if (!TryFindNavigationProperties(type, cspaceType, ospaceType, clrProperties, referenceResolutionListForCurrentType))
{
return false;
}
return true;
}
private bool TryFindComplexProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List referenceResolutionListForCurrentType)
{
List> typeClosureToTrack =
new List>();
foreach(EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers().Where(m => Helper.IsComplexType(m.TypeUsage.EdmType)))
{
PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty));
if (clrProperty != null)
{
typeClosureToTrack.Add(
new KeyValuePair(
cspaceProperty, clrProperty));
}
else
{
string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
foreach (var typeToTrack in typeClosureToTrack)
{
TrackClosure(typeToTrack.Value.PropertyType);
// prevent the lifting of these closure variables
var ot = ospaceType;
var cp = typeToTrack.Key;
var clrp = typeToTrack.Value;
referenceResolutionListForCurrentType.Add(() => CreateAndAddComplexType(type, ot, cp, clrp));
}
return true;
}
private bool TryFindNavigationProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties, List referenceResolutionListForCurrentType)
{
List> typeClosureToTrack =
new List>();
foreach (NavigationProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers())
{
PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => NonPrimitiveMemberMatchesByConvention(p, cspaceProperty));
if (clrProperty != null)
{
bool needsSetter = cspaceProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many;
if (clrProperty.CanRead && (!needsSetter || clrProperty.CanWrite))
{
typeClosureToTrack.Add(
new KeyValuePair(
cspaceProperty, clrProperty));
}
}
else
{
string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(
cspaceProperty.Name, type.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
foreach (var typeToTrack in typeClosureToTrack)
{
TrackClosure(typeToTrack.Value.PropertyType);
// keep from lifting these closure variables
var ct = cspaceType;
var ot = ospaceType;
var cp = typeToTrack.Key;
var clrp = typeToTrack.Value;
referenceResolutionListForCurrentType.Add(() => CreateAndAddNavigationProperty(ct, ot, cp, clrp));
}
return true;
}
private void TrackClosure(Type type)
{
if (SourceAssembly != type.Assembly &&
!CacheEntry.ClosureAssemblies.Contains(type.Assembly) &&
!(type.IsGenericType &&
(
EntityUtil.IsAnICollection(type) || // EntityCollection<>, List<>, ICollection<>
type.GetGenericTypeDefinition() == typeof(System.Data.Objects.DataClasses.EntityReference<>) ||
type.GetGenericTypeDefinition() == typeof(System.Nullable<>)
)
)
)
{
CacheEntry.ClosureAssemblies.Add(type.Assembly);
}
if (type.IsGenericType)
{
foreach (Type genericArgument in type.GetGenericArguments())
{
TrackClosure(genericArgument);
}
}
}
private void CreateAndAddComplexType(Type type, StructuralType ospaceType, EdmProperty cspaceProperty, PropertyInfo clrProperty)
{
StructuralType propertyType;
if (SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out propertyType))
{
EdmProperty property = new EdmProperty(cspaceProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = false }), clrProperty, type.TypeHandle);
ospaceType.AddMember(property);
}
else
{
string message =
SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
Strings.Validator_OSpace_Convention_MissingOSpaceType(cspaceProperty.TypeUsage.EdmType.FullName),
cspaceProperty.TypeUsage.EdmType);
SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
}
}
private void CreateAndAddNavigationProperty(StructuralType cspaceType, StructuralType ospaceType, NavigationProperty cspaceProperty, PropertyInfo clrProperty)
{
StructuralType ospaceRelationship;
if (SessionData.CspaceToOspace.TryGetValue(cspaceProperty.RelationshipType, out ospaceRelationship))
{
bool foundTarget = false;
EdmType targetType = null;
if (Helper.IsCollectionType(cspaceProperty.TypeUsage.EdmType))
{
StructuralType findType;
foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)((CollectionType)cspaceProperty.TypeUsage.EdmType).TypeUsage.EdmType, out findType);
if (foundTarget)
{
targetType = findType.GetCollectionType();
}
}
else
{
StructuralType findType;
foundTarget = SessionData.CspaceToOspace.TryGetValue((StructuralType)cspaceProperty.TypeUsage.EdmType, out findType);
if (foundTarget)
{
targetType = findType;
}
}
Debug.Assert(foundTarget, "Since the relationship will only be created if it can find the types for both ends, we will never fail to find one of the ends");
NavigationProperty navigationProperty = new NavigationProperty(cspaceProperty.Name, TypeUsage.Create(targetType), clrProperty);
navigationProperty.RelationshipType = (RelationshipType)ospaceRelationship;
// we can use First because o-space relationships are created directly from
// c-space relationship
navigationProperty.ToEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.ToEndMember.Name);
navigationProperty.FromEndMember = (RelationshipEndMember)((RelationshipType)ospaceRelationship).Members.First(e => e.Name == cspaceProperty.FromEndMember.Name);
ospaceType.AddMember(navigationProperty);
}
else
{
EntityTypeBase missingType = cspaceProperty.RelationshipType.RelationshipEndMembers.Select(e => ((RefType)e.TypeUsage.EdmType).ElementType).First(e => e != cspaceType);
string message =
SessionData.LoadMessageLogger.CreateErrorMessageWithTypeSpecificLoadLogs(
Strings.Validator_OSpace_Convention_RelationshipNotLoaded(cspaceProperty.RelationshipType.FullName, missingType.FullName),
missingType);
SessionData.EdmItemErrors.Add(new EdmItemError(message, ospaceType));
}
}
private bool TryFindAndCreateScalarProperties(Type type, StructuralType cspaceType, StructuralType ospaceType, PropertyInfo[] clrProperties)
{
foreach (EdmProperty cspaceProperty in cspaceType.GetDeclaredOnlyMembers().Where(p => Helper.IsPrimitiveType(p.TypeUsage.EdmType)))
{
PropertyInfo clrProperty = clrProperties.FirstOrDefault(p => MemberMatchesByConvention(p, cspaceProperty));
if (clrProperty != null)
{
PrimitiveType propertyType;
bool typeIsNullable;
if (TryGetPrimitiveType(clrProperty.PropertyType, out typeIsNullable, out propertyType))
{
if (clrProperty.CanRead && clrProperty.CanWrite)
{
bool isKeyMember = Helper.IsEntityType(cspaceType) && ((EntityType)cspaceType).KeyMemberNames.Contains(clrProperty.Name);
EdmProperty ospaceProperty = new EdmProperty(cspaceProperty.Name, TypeUsage.Create(propertyType, new FacetValues { Nullable = typeIsNullable && !isKeyMember }), clrProperty, type.TypeHandle);
if (isKeyMember)
{
((EntityType)ospaceType).AddKeyMember(ospaceProperty);
}
else
{
ospaceType.AddMember(ospaceProperty);
}
}
else
{
string message = Strings.Validator_OSpace_Convention_ScalarPropertyMissginGetterOrSetter(clrProperty.Name, type.FullName, type.Assembly.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
else
{
string message = Strings.Validator_OSpace_Convention_NonPrimitiveTypeProperty(clrProperty.Name, type.FullName, clrProperty.PropertyType.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
else
{
string message = Strings.Validator_OSpace_Convention_MissingRequiredProperty(cspaceProperty.Name, type.FullName);
SessionData.LoadMessageLogger.LogLoadMessage(message, cspaceType);
return false;
}
}
return true;
}
private void CreateRelationships()
{
if (SessionData.ConventionBasedRelationshipsAreLoaded)
{
return;
}
SessionData.ConventionBasedRelationshipsAreLoaded = true;
// find all the relationships
foreach (AssociationType cspaceAssociation in SessionData.EdmItemCollection.GetItems())
{
Debug.Assert(cspaceAssociation.RelationshipEndMembers.Count == 2, "Relationships are assumed to have exactly two ends");
if (SessionData.CspaceToOspace.ContainsKey(cspaceAssociation))
{
// don't try to load relationships that we already know about
continue;
}
StructuralType [] ospaceEndTypes = new StructuralType [2];
if (SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[0]), out ospaceEndTypes[0]) &&
SessionData.CspaceToOspace.TryGetValue(GetRelationshipEndType(cspaceAssociation.RelationshipEndMembers[1]), out ospaceEndTypes[1]))
{
// if we can find both ends of the relationship, then create it
AssociationType ospaceAssociation = new AssociationType(cspaceAssociation.Name, cspaceAssociation.NamespaceName, cspaceAssociation.IsForeignKey, DataSpace.OSpace);
for (int i = 0; i < cspaceAssociation.RelationshipEndMembers.Count; i++)
{
EntityType ospaceEndType = (EntityType)ospaceEndTypes[i];
RelationshipEndMember cspaceEnd = cspaceAssociation.RelationshipEndMembers[i];
ospaceAssociation.AddKeyMember(new AssociationEndMember(cspaceEnd.Name, ospaceEndType.GetReferenceType(), cspaceEnd.RelationshipMultiplicity));
}
CacheEntry.TypesInAssembly.Add(ospaceAssociation);
SessionData.TypesInLoading.Add(ospaceAssociation.FullName, ospaceAssociation);
SessionData.CspaceToOspace.Add(cspaceAssociation, ospaceAssociation);
}
}
}
private StructuralType GetRelationshipEndType(RelationshipEndMember relationshipEndMember)
{
return ((RefType)relationshipEndMember.TypeUsage.EdmType).ElementType;
}
private bool MemberMatchesByConvention(PropertyInfo clrProperty, EdmMember cspaceMember)
{
return clrProperty.Name == cspaceMember.Name;
}
private bool NonPrimitiveMemberMatchesByConvention(PropertyInfo clrProperty, EdmMember cspaceMember)
{
return !clrProperty.PropertyType.IsValueType && !clrProperty.PropertyType.IsAssignableFrom(typeof(string)) && clrProperty.Name == cspaceMember.Name;
}
internal static bool SessionContainsConventionParameters(ObjectItemLoadingSessionData sessionData)
{
return sessionData.EdmItemCollection != null;
}
internal static bool TypesMatchByConvention(Type type, EdmType cspaceType)
{
return type.Name == cspaceType.Name;
}
internal static ObjectItemAssemblyLoader Create(Assembly assembly, ObjectItemLoadingSessionData sessionData)
{
if (!ObjectItemAttributeAssemblyLoader.IsSchemaAttributePresent(assembly))
{
return new ObjectItemConventionAssemblyLoader(assembly, sessionData);
}
else
{
// we were loading in convention mode, and ran into an assembly that can't be loaded by convention
sessionData.EdmItemErrors.Add(new EdmItemError(Strings.Validator_OSpace_Convention_AttributeAssemblyReferenced(assembly.FullName), null));
return new ObjectItemNoOpAssemblyLoader(assembly, sessionData);
}
}
}
}
// 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
- ListenerSessionConnectionReader.cs
- ReadOnlyNameValueCollection.cs
- Types.cs
- DiscoveryClientRequestChannel.cs
- XpsResourceDictionary.cs
- AddInAdapter.cs
- NameHandler.cs
- CommandExpr.cs
- RC2CryptoServiceProvider.cs
- CFStream.cs
- RedistVersionInfo.cs
- DataGridAddNewRow.cs
- Column.cs
- CompositeCollectionView.cs
- AsymmetricSignatureFormatter.cs
- DbConnectionStringCommon.cs
- AnimatedTypeHelpers.cs
- MethodSignatureGenerator.cs
- CustomAttributeBuilder.cs
- ComplexTypeEmitter.cs
- DesignDataSource.cs
- SamlAuthorityBinding.cs
- XmlTextReader.cs
- GestureRecognitionResult.cs
- TextViewBase.cs
- ButtonFieldBase.cs
- BitmapScalingModeValidation.cs
- DeleteIndexBinder.cs
- PanningMessageFilter.cs
- Opcode.cs
- CryptoProvider.cs
- Token.cs
- ActionFrame.cs
- BitmapEffectDrawingContent.cs
- ControlBindingsCollection.cs
- SqlTriggerAttribute.cs
- OleDbRowUpdatedEvent.cs
- CompressStream.cs
- BinaryReader.cs
- InvokeMethodActivityDesigner.cs
- Point3D.cs
- MenuItemStyle.cs
- BooleanExpr.cs
- CellQuery.cs
- PropertyEmitterBase.cs
- Listbox.cs
- RemoteWebConfigurationHost.cs
- ReturnValue.cs
- WebPartsSection.cs
- Validator.cs
- InvokeGenerator.cs
- SubpageParagraph.cs
- DoubleAnimationBase.cs
- SmtpAuthenticationManager.cs
- MarkupCompilePass1.cs
- SecuritySessionClientSettings.cs
- ControlIdConverter.cs
- InternalCache.cs
- ServiceContractAttribute.cs
- CompositeKey.cs
- TextInfo.cs
- assertwrapper.cs
- LoginName.cs
- TrailingSpaceComparer.cs
- AssemblyAttributes.cs
- MarkupCompiler.cs
- HttpDebugHandler.cs
- CustomTrackingRecord.cs
- Error.cs
- XslException.cs
- PrePostDescendentsWalker.cs
- SecurityKeyIdentifierClause.cs
- OpCellTreeNode.cs
- PackagePartCollection.cs
- MetadataItemCollectionFactory.cs
- CustomWebEventKey.cs
- PathTooLongException.cs
- DesignerTransaction.cs
- ScriptBehaviorDescriptor.cs
- __Filters.cs
- BitmapEffectInputData.cs
- XhtmlBasicLiteralTextAdapter.cs
- FocusTracker.cs
- Calendar.cs
- OdbcHandle.cs
- OrderByLifter.cs
- FileVersion.cs
- DataTemplateKey.cs
- XmlNodeReader.cs
- PrincipalPermission.cs
- ComboBoxHelper.cs
- CustomCredentialPolicy.cs
- Hyperlink.cs
- BaseTemplateBuildProvider.cs
- LinearGradientBrush.cs
- ThemeableAttribute.cs
- DataSetUtil.cs
- InertiaRotationBehavior.cs
- GenericArgumentsUpdater.cs
- DataGridAutoFormatDialog.cs