private static String GetPropertyNameFromEpmInfo(EntityPropertyMappingInfo epmInfo) { #if ASTORIA_SERVER if (epmInfo.IsEFProvider) { if (epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty) { return(System.Data.Services.Providers.ObjectContextServiceProvider.MapSyndicationPropertyToEpmTargetPath(epmInfo.Attribute.TargetSyndicationItem)); } else { return(epmInfo.Attribute.TargetPath); } } else #endif { if (epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty) { return(epmInfo.Attribute.TargetSyndicationItem.ToString()); } else { return(epmInfo.Attribute.TargetPath); } } }
/// <summary> /// Removes a path in the tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/> /// </summary> /// <param name="epmInfo">EnitityPropertyMappingInfo holding the target path</param> internal void Remove(EntityPropertyMappingInfo epmInfo) { String targetName = epmInfo.Attribute.TargetPath; bool isSyndication = epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty; String namespaceUri = epmInfo.Attribute.TargetNamespaceUri; EpmTargetPathSegment currentSegment = isSyndication ? this.SyndicationRoot : this.NonSyndicationRoot; List <EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!String.IsNullOrEmpty(targetName), "Must have been validated during EntityPropertyMappingAttribute construction"); String[] targetSegments = targetName.Split('/'); for (int i = 0; i < targetSegments.Length; i++) { String targetSegment = targetSegments[i]; if (targetSegment.Length == 0) { throw new InvalidOperationException(Strings.EpmTargetTree_InvalidTargetPath(targetName)); } if (targetSegment[0] == '@' && i != targetSegments.Length - 1) { throw new InvalidOperationException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } EpmTargetPathSegment foundSegment = activeSubSegments.FirstOrDefault( segment => segment.SegmentName == targetSegment && (isSyndication || segment.SegmentNamespaceUri == namespaceUri)); if (foundSegment != null) { currentSegment = foundSegment; } else { return; } activeSubSegments = currentSegment.SubSegments; } // Recursively remove all the parent segments which will have no more children left // after removal of the current segment node if (currentSegment.HasContent) { // Since we are removing a property with KeepInContent false, we should decrement the count if (!currentSegment.EpmInfo.Attribute.KeepInContent) { this.countOfNonContentProperties--; } do { EpmTargetPathSegment parentSegment = currentSegment.ParentSegment; parentSegment.SubSegments.Remove(currentSegment); currentSegment = parentSegment; }while (currentSegment.ParentSegment != null && !currentSegment.HasContent && currentSegment.SubSegments.Count == 0); } }
/// <summary> /// Adds a path to the source and target tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/> /// </summary> /// <param name="epmInfo">EnitityPropertyMappingInfo holding the source path</param> internal void Add(EntityPropertyMappingInfo epmInfo) { String sourceName = epmInfo.Attribute.SourcePath; EpmSourcePathSegment currentProperty = this.Root; IList <EpmSourcePathSegment> activeSubProperties = currentProperty.SubProperties; EpmSourcePathSegment foundProperty = null; Debug.Assert(!String.IsNullOrEmpty(sourceName), "Must have been validated during EntityPropertyMappingAttribute construction"); foreach (String propertyName in sourceName.Split('/')) { if (propertyName.Length == 0) { throw new InvalidOperationException(Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.Name, sourceName)); } foundProperty = activeSubProperties.SingleOrDefault(e => e.PropertyName == propertyName); if (foundProperty != null) { currentProperty = foundProperty; } else { currentProperty = new EpmSourcePathSegment(propertyName); activeSubProperties.Add(currentProperty); } activeSubProperties = currentProperty.SubProperties; } // Two EpmAttributes with same PropertyName in the same ResourceType, this could be a result of inheritance if (foundProperty != null) { Debug.Assert(Object.ReferenceEquals(foundProperty, currentProperty), "currentProperty variable should have been updated already to foundProperty"); // Check for duplicates on the same entity type #if !ASTORIA_CLIENT Debug.Assert(foundProperty.SubProperties.Count == 0, "If non-leaf, it means we allowed complex type to be a leaf node"); if (foundProperty.EpmInfo.DefiningType == epmInfo.DefiningType) { throw new InvalidOperationException(Strings.EpmSourceTree_DuplicateEpmAttrsWithSameSourceName(epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } #else if (foundProperty.EpmInfo.DefiningType.Name == epmInfo.DefiningType.Name) { throw new InvalidOperationException(Strings.EpmSourceTree_DuplicateEpmAttrsWithSameSourceName(epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } #endif // In case of inheritance, we need to remove the node from target tree which was mapped to base type property this.epmTargetTree.Remove(foundProperty.EpmInfo); } currentProperty.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
/// <summary> /// Adds a path to the source and target tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/> /// </summary> /// <param name="epmInfo">EnitityPropertyMappingInfo holding the source path</param> internal void Add(EntityPropertyMappingInfo epmInfo) { String sourceName = epmInfo.Attribute.SourcePath; EpmSourcePathSegment currentProperty = this.Root; IList<EpmSourcePathSegment> activeSubProperties = currentProperty.SubProperties; EpmSourcePathSegment foundProperty = null; Debug.Assert(!String.IsNullOrEmpty(sourceName), "Must have been validated during EntityPropertyMappingAttribute construction"); foreach (String propertyName in sourceName.Split('/')) { if (propertyName.Length == 0) { throw new InvalidOperationException(Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.Name, sourceName)); } foundProperty = activeSubProperties.SingleOrDefault(e => e.PropertyName == propertyName); if (foundProperty != null) { currentProperty = foundProperty; } else { currentProperty = new EpmSourcePathSegment(propertyName); activeSubProperties.Add(currentProperty); } activeSubProperties = currentProperty.SubProperties; } // Two EpmAttributes with same PropertyName in the same ResourceType, this could be a result of inheritance if (foundProperty != null) { Debug.Assert(Object.ReferenceEquals(foundProperty, currentProperty), "currentProperty variable should have been updated already to foundProperty"); // Check for duplicates on the same entity type #if !ASTORIA_CLIENT Debug.Assert(foundProperty.SubProperties.Count == 0, "If non-leaf, it means we allowed complex type to be a leaf node"); if (foundProperty.EpmInfo.DefiningType == epmInfo.DefiningType) { throw new InvalidOperationException(Strings.EpmSourceTree_DuplicateEpmAttrsWithSameSourceName(epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } #else if (foundProperty.EpmInfo.DefiningType.Name == epmInfo.DefiningType.Name) { throw new InvalidOperationException(Strings.EpmSourceTree_DuplicateEpmAttrsWithSameSourceName(epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } #endif // In case of inheritance, we need to remove the node from target tree which was mapped to base type property this.epmTargetTree.Remove(foundProperty.EpmInfo); } currentProperty.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
private static String GetPropertyNameFromEpmInfo(EntityPropertyMappingInfo epmInfo) { { if (epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty) { return(epmInfo.Attribute.TargetSyndicationItem.ToString()); } else { return(epmInfo.Attribute.TargetPath); } } }
internal void Add(EntityPropertyMappingInfo epmInfo) { String sourceName = epmInfo.Attribute.SourcePath; EpmSourcePathSegment currentProperty = this.Root; IList <EpmSourcePathSegment> activeSubProperties = currentProperty.SubProperties; EpmSourcePathSegment foundProperty = null; Debug.Assert(!String.IsNullOrEmpty(sourceName), "Must have been validated during EntityPropertyMappingAttribute construction"); foreach (String propertyName in sourceName.Split('/')) { if (propertyName.Length == 0) { throw new InvalidOperationException(Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.Name, sourceName)); } foundProperty = activeSubProperties.SingleOrDefault(e => e.PropertyName == propertyName); if (foundProperty != null) { currentProperty = foundProperty; } else { currentProperty = new EpmSourcePathSegment(propertyName); activeSubProperties.Add(currentProperty); } activeSubProperties = currentProperty.SubProperties; } if (foundProperty != null) { Debug.Assert(Object.ReferenceEquals(foundProperty, currentProperty), "currentProperty variable should have been updated already to foundProperty"); if (foundProperty.EpmInfo.DefiningType.Name == epmInfo.DefiningType.Name) { throw new InvalidOperationException(Strings.EpmSourceTree_DuplicateEpmAttrsWithSameSourceName(epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } this.epmTargetTree.Remove(foundProperty.EpmInfo); } currentProperty.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
internal void Add(EntityPropertyMappingInfo epmInfo) { String sourceName = epmInfo.Attribute.SourcePath; EpmSourcePathSegment currentProperty = this.Root; IList<EpmSourcePathSegment> activeSubProperties = currentProperty.SubProperties; EpmSourcePathSegment foundProperty = null; Debug.Assert(!String.IsNullOrEmpty(sourceName), "Must have been validated during EntityPropertyMappingAttribute construction"); foreach (String propertyName in sourceName.Split('/')) { if (propertyName.Length == 0) { throw new InvalidOperationException(Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.Name, sourceName)); } foundProperty = activeSubProperties.SingleOrDefault(e => e.PropertyName == propertyName); if (foundProperty != null) { currentProperty = foundProperty; } else { currentProperty = new EpmSourcePathSegment(propertyName); activeSubProperties.Add(currentProperty); } activeSubProperties = currentProperty.SubProperties; } if (foundProperty != null) { Debug.Assert(Object.ReferenceEquals(foundProperty, currentProperty), "currentProperty variable should have been updated already to foundProperty"); if (foundProperty.EpmInfo.DefiningType.Name == epmInfo.DefiningType.Name) { throw new InvalidOperationException(Strings.EpmSourceTree_DuplicateEpmAttrsWithSameSourceName(epmInfo.Attribute.SourcePath, epmInfo.DefiningType.Name)); } this.epmTargetTree.Remove(foundProperty.EpmInfo); } currentProperty.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
internal void Add(EntityPropertyMappingInfo epmInfo) { String targetName = epmInfo.Attribute.TargetPath; bool isSyndication = epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty; String namespaceUri = epmInfo.Attribute.TargetNamespaceUri; String namespacePrefix = epmInfo.Attribute.TargetNamespacePrefix; EpmTargetPathSegment currentSegment = isSyndication ? this.SyndicationRoot : this.NonSyndicationRoot; IList<EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!String.IsNullOrEmpty(targetName), "Must have been validated during EntityPropertyMappingAttribute construction"); String[] targetSegments = targetName.Split('/'); for (int i = 0; i < targetSegments.Length; i++) { String targetSegment = targetSegments[i]; if (targetSegment.Length == 0) { throw new InvalidOperationException(Strings.EpmTargetTree_InvalidTargetPath(targetName)); } if (targetSegment[0] == '@' && i != targetSegments.Length - 1) { throw new InvalidOperationException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } EpmTargetPathSegment foundSegment = activeSubSegments.SingleOrDefault( segment => segment.SegmentName == targetSegment && (isSyndication || segment.SegmentNamespaceUri == namespaceUri)); if (foundSegment != null) { currentSegment = foundSegment; } else { currentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, namespacePrefix, currentSegment); if (targetSegment[0] == '@') { activeSubSegments.Insert(0, currentSegment); } else { activeSubSegments.Add(currentSegment); } } activeSubSegments = currentSegment.SubSegments; } if (currentSegment.HasContent) { throw new ArgumentException(Strings.EpmTargetTree_DuplicateEpmAttrsWithSameTargetName(EpmTargetTree.GetPropertyNameFromEpmInfo(currentSegment.EpmInfo), currentSegment.EpmInfo.DefiningType.Name, currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath)); } if (!epmInfo.Attribute.KeepInContent) { this.countOfNonContentProperties++; } currentSegment.EpmInfo = epmInfo; if (EpmTargetTree.HasMixedContent(this.NonSyndicationRoot, false)) { throw new InvalidOperationException(Strings.EpmTargetTree_InvalidTargetPath(targetName)); } }
private static String GetPropertyNameFromEpmInfo(EntityPropertyMappingInfo epmInfo) { #if ASTORIA_SERVER if (epmInfo.IsEFProvider) { if (epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty) { return System.Data.Services.Providers.ObjectContextServiceProvider.MapSyndicationPropertyToEpmTargetPath(epmInfo.Attribute.TargetSyndicationItem); } else { return epmInfo.Attribute.TargetPath; } } else #endif { if (epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty) { return epmInfo.Attribute.TargetSyndicationItem.ToString(); } else { return epmInfo.Attribute.TargetPath; } } }
internal void Remove(EntityPropertyMappingInfo epmInfo) { String targetName = epmInfo.Attribute.TargetPath; bool isSyndication = epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty; String namespaceUri = epmInfo.Attribute.TargetNamespaceUri; EpmTargetPathSegment currentSegment = isSyndication ? this.SyndicationRoot : this.NonSyndicationRoot; List<EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!String.IsNullOrEmpty(targetName), "Must have been validated during EntityPropertyMappingAttribute construction"); String[] targetSegments = targetName.Split('/'); for (int i = 0; i < targetSegments.Length; i++) { String targetSegment = targetSegments[i]; if (targetSegment.Length == 0) { throw new InvalidOperationException(Strings.EpmTargetTree_InvalidTargetPath(targetName)); } if (targetSegment[0] == '@' && i != targetSegments.Length - 1) { throw new InvalidOperationException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } EpmTargetPathSegment foundSegment = activeSubSegments.FirstOrDefault( segment => segment.SegmentName == targetSegment && (isSyndication || segment.SegmentNamespaceUri == namespaceUri)); if (foundSegment != null) { currentSegment = foundSegment; } else { return; } activeSubSegments = currentSegment.SubSegments; } if (currentSegment.HasContent) { if (!currentSegment.EpmInfo.Attribute.KeepInContent) { this.countOfNonContentProperties--; } do { EpmTargetPathSegment parentSegment = currentSegment.ParentSegment; parentSegment.SubSegments.Remove(currentSegment); currentSegment = parentSegment; } while (currentSegment.ParentSegment != null && !currentSegment.HasContent && currentSegment.SubSegments.Count == 0); } }
internal void Add(EntityPropertyMappingInfo epmInfo) { String targetName = epmInfo.Attribute.TargetPath; bool isSyndication = epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty; String namespaceUri = epmInfo.Attribute.TargetNamespaceUri; String namespacePrefix = epmInfo.Attribute.TargetNamespacePrefix; EpmTargetPathSegment currentSegment = isSyndication ? this.SyndicationRoot : this.NonSyndicationRoot; IList <EpmTargetPathSegment> activeSubSegments = currentSegment.SubSegments; Debug.Assert(!String.IsNullOrEmpty(targetName), "Must have been validated during EntityPropertyMappingAttribute construction"); String[] targetSegments = targetName.Split('/'); for (int i = 0; i < targetSegments.Length; i++) { String targetSegment = targetSegments[i]; if (targetSegment.Length == 0) { throw new InvalidOperationException(Strings.EpmTargetTree_InvalidTargetPath(targetName)); } if (targetSegment[0] == '@' && i != targetSegments.Length - 1) { throw new InvalidOperationException(Strings.EpmTargetTree_AttributeInMiddle(targetSegment)); } EpmTargetPathSegment foundSegment = activeSubSegments.SingleOrDefault( segment => segment.SegmentName == targetSegment && (isSyndication || segment.SegmentNamespaceUri == namespaceUri)); if (foundSegment != null) { currentSegment = foundSegment; } else { currentSegment = new EpmTargetPathSegment(targetSegment, namespaceUri, namespacePrefix, currentSegment); if (targetSegment[0] == '@') { activeSubSegments.Insert(0, currentSegment); } else { activeSubSegments.Add(currentSegment); } } activeSubSegments = currentSegment.SubSegments; } if (currentSegment.HasContent) { throw new ArgumentException(Strings.EpmTargetTree_DuplicateEpmAttrsWithSameTargetName(EpmTargetTree.GetPropertyNameFromEpmInfo(currentSegment.EpmInfo), currentSegment.EpmInfo.DefiningType.Name, currentSegment.EpmInfo.Attribute.SourcePath, epmInfo.Attribute.SourcePath)); } if (!epmInfo.Attribute.KeepInContent) { this.countOfNonContentProperties++; } currentSegment.EpmInfo = epmInfo; if (EpmTargetTree.HasMixedContent(this.NonSyndicationRoot, false)) { throw new InvalidOperationException(Strings.EpmTargetTree_InvalidTargetPath(targetName)); } }
/// <summary>Adds a property to the null valued collection</summary> /// <param name="epmInfo">EpmInfo containing the property information such as path</param> internal void Add(EntityPropertyMappingInfo epmInfo) { Debug.Assert(epmInfo != null, "epmInfo != null"); EpmNullValuedPropertyNode current = this.root; ResourceType currentType = epmInfo.DefiningType; object currentValue = this.element; // We are here because the epm path points to a null value. If the path is multiple level deep, we need to // know the first level the null value begins and we don't need to serialize deeper than that. // To serialize the complex properties correctly in the case they are not already in content, we also need // to find the type for each segment from root to the first segment that has the null property value. foreach (var segment in epmInfo.Attribute.SourcePath.Split('/')) { EpmNullValuedPropertyNode child = current.Children.FirstOrDefault(c => c.Name == segment); if (child != null) { // The current segment is already added to the tree, reuse it. current = child; currentValue = child.Element; currentType = child.ResourceType; } else { EpmNullValuedPropertyNode newNode = new EpmNullValuedPropertyNode { Name = segment }; Debug.Assert(currentType != null, "currentType != null"); ResourceProperty property = currentType.TryResolvePropertyName(segment); Debug.Assert(currentValue != null, "currentValue != null"); ProjectedWrapper projectedValue = currentValue as ProjectedWrapper; if (projectedValue == null) { if (property != null) { currentValue = this.provider.GetPropertyValue(currentValue, property, currentType); currentValue = currentValue == DBNull.Value ? null : currentValue; currentType = property.ResourceType; } else { // Handle open property... currentValue = this.provider.GetOpenPropertyValue(currentValue, segment); currentValue = currentValue == DBNull.Value ? null : currentValue; if (currentValue != null) { // Get the type from the instance. currentType = this.provider.GetResourceType(currentValue); } else { // We have a null open property at hand, we don't know its type. // Default the type to string so that we will omit the type name // and just write out null. i.e. <d:prop m:null='true'/> currentType = ResourceType.PrimitiveStringResourceType; } } } else { currentValue = projectedValue.GetProjectedPropertyValue(segment); currentValue = currentValue == DBNull.Value ? null : currentValue; if (property != null) { currentType = property.ResourceType; } else { // Handle open property... if (currentValue == null) { // We have a null open property at hand, we don't know its type. // Default the type to string so that we will omit the type name // and just write out null. i.e. <d:prop m:null='true'/> currentType = ResourceType.PrimitiveStringResourceType; } else { projectedValue = currentValue as ProjectedWrapper; if (projectedValue != null) { // Get the type from the project wrapper. currentType = this.provider.TryResolveResourceType(projectedValue.ResourceTypeName); } else { // Get the type from the instance. currentType = this.provider.GetResourceType(currentValue); } } } } Debug.Assert(currentType != null, "currentType != null"); Debug.Assert(currentValue != DBNull.Value, "currentValue != DBNull.Value -- we have converted DBNull to null"); newNode.ResourceType = currentType; newNode.Element = currentValue; current.Children.Add(newNode); current = newNode; } if (current.Element == null) { // If the current element is null, we don't need to go further since that is the obvious reason // that the children properties are null. break; } } }
/// <summary> /// Override of the base Visitor method, which actually performs mapping search and serialization /// </summary> /// <param name="targetSegment">Current segment being checked for mapping</param> /// <param name="kind">Which sub segments to serialize</param> /// <param name="provider">Data Service provider used for rights verification.</param> protected override void Serialize(EpmTargetPathSegment targetSegment, EpmSerializationKind kind, DataServiceProviderWrapper provider) { if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Object propertyValue; try { propertyValue = epmInfo.ReadPropertyValue(this.Element, provider); } catch (System.Reflection.TargetInvocationException e) { ErrorHandler.HandleTargetInvocationException(e); throw; } if (propertyValue == null) { this.nullValuedProperties.Add(epmInfo); } String textPropertyValue = propertyValue != null?PlainXmlSerializer.PrimitiveToString(propertyValue) : String.Empty; TextSyndicationContentKind contentKind = (TextSyndicationContentKind)epmInfo.Attribute.TargetTextContentKind; switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.AuthorEmail: this.CreateAuthor(false); this.author.Email = textPropertyValue; break; case SyndicationItemProperty.AuthorName: this.CreateAuthor(false); this.author.Name = textPropertyValue; this.authorNamePresent = true; break; case SyndicationItemProperty.AuthorUri: this.CreateAuthor(false); this.author.Uri = textPropertyValue; break; case SyndicationItemProperty.ContributorEmail: case SyndicationItemProperty.ContributorName: case SyndicationItemProperty.ContributorUri: this.SetContributorProperty(epmInfo.Attribute.TargetSyndicationItem, textPropertyValue); break; case SyndicationItemProperty.Updated: this.Target.LastUpdatedTime = EpmSyndicationContentSerializer.GetDate(propertyValue, Strings.EpmSerializer_UpdatedHasWrongType); break; case SyndicationItemProperty.Published: this.Target.PublishDate = EpmSyndicationContentSerializer.GetDate(propertyValue, Strings.EpmSerializer_PublishedHasWrongType); break; case SyndicationItemProperty.Rights: this.Target.Copyright = new TextSyndicationContent(textPropertyValue, contentKind); break; case SyndicationItemProperty.Summary: this.Target.Summary = new TextSyndicationContent(textPropertyValue, contentKind); break; case SyndicationItemProperty.Title: this.Target.Title = new TextSyndicationContent(textPropertyValue, contentKind); break; default: Debug.Fail("Unhandled SyndicationItemProperty enum value - should never get here."); break; } } else { base.Serialize(targetSegment, kind, provider); } }
private static String GetPropertyNameFromEpmInfo(EntityPropertyMappingInfo epmInfo) { { if (epmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty) { return epmInfo.Attribute.TargetSyndicationItem.ToString(); } else { return epmInfo.Attribute.TargetPath; } } }