/// <summary>Returns the entity type of the given navigation source.</summary> /// <param name="navigationSource">The navigation source to get the element type of.</param> /// <returns>The <see cref="IEdmEntityType"/> representing the entity type of the <paramref name="navigationSource" />.</returns> internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType(); if (entityType == null) { return null; } return (IEdmEntityType)this.ResolveType(entityType); }
/// <summary> /// Initializes a new instance of <see cref="OperationImportSegment"/> class. /// </summary> /// <param name="operationImport">The wrapped Edm operation import (function import or action import).</param> /// <param name="navigationSource">The Edm navigation source.</param> public OperationImportSegment(IEdmOperationImport operationImport, IEdmNavigationSource navigationSource) : base(operationImport?.Name) { OperationImport = operationImport ?? throw new ArgumentNullException(nameof(operationImport)); NavigationSource = navigationSource; EdmType = navigationSource?.EntityType(); if (operationImport.Operation.ReturnType != null) { IsSingle = !operationImport.Operation.ReturnType.IsCollection(); } Target = operationImport.Operation.TargetName(); }
/// <summary> /// Initializes a new instance of the <see cref="NavigationSourceLinkBuilderAnnotation"/> class. /// </summary> /// <param name="navigationSource">The navigation source for which the link builder is being constructed.</param> /// <param name="model">The EDM model that this navigation source belongs to.</param> /// <remarks>This constructor creates a link builder that generates URL's that follow OData conventions for the given navigation source.</remarks> public NavigationSourceLinkBuilderAnnotation(IEdmNavigationSource navigationSource, IEdmModel model) { if (navigationSource == null) { throw Error.ArgumentNull("navigationSource"); } if (model == null) { throw Error.ArgumentNull("model"); } IEdmEntityType elementType = navigationSource.EntityType(); IEnumerable<IEdmEntityType> derivedTypes = model.FindAllDerivedTypes(elementType).Cast<IEdmEntityType>(); // Add navigation link builders for all navigation properties of entity. foreach (IEdmNavigationProperty navigationProperty in elementType.NavigationProperties()) { Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory = (entityInstanceContext, navProperty) => entityInstanceContext.GenerateNavigationPropertyLink(navProperty, includeCast: false); AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder(navigationLinkFactory, followsConventions: true)); } // Add navigation link builders for all navigation properties in derived types. bool derivedTypesDefineNavigationProperty = false; foreach (IEdmEntityType derivedEntityType in derivedTypes) { foreach (IEdmNavigationProperty navigationProperty in derivedEntityType.DeclaredNavigationProperties()) { derivedTypesDefineNavigationProperty = true; Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory = (entityInstanceContext, navProperty) => entityInstanceContext.GenerateNavigationPropertyLink(navProperty, includeCast: true); AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder(navigationLinkFactory, followsConventions: true)); } } _navigationSourceName = navigationSource.Name; _feedSelfLinkBuilder = (feedContext) => feedContext.GenerateFeedSelfLink(); Func<EntityInstanceContext, string> selfLinkFactory = (entityInstanceContext) => entityInstanceContext.GenerateSelfLink(includeCast: derivedTypesDefineNavigationProperty); _idLinkBuilder = new SelfLinkBuilder<string>(selfLinkFactory, followsConventions: true); }
/// <summary> /// Retrieve the paths for <see cref="IEdmNavigationSource"/>. /// </summary> /// <param name="navigationSource">The navigation source.</param> private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource) { Debug.Assert(navigationSource != null); // navigation source itself ODataPath path = new ODataPath(new ODataNavigationSourceSegment(navigationSource)); AppendPath(path.Clone()); IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; IEdmEntityType entityType = navigationSource.EntityType(); // for entity set, create a path with key if (entitySet != null) { path.Push(new ODataKeySegment(entityType)); AppendPath(path.Clone()); } // media entity RetrieveMediaEntityStreamPaths(entityType, path); // navigation property foreach (IEdmNavigationProperty np in entityType.DeclaredNavigationProperties()) { if (CanFilter(np)) { RetrieveNavigationPropertyPaths(np, path); } } if (entitySet != null) { path.Pop(); // end of entity } path.Pop(); // end of navigation source. Debug.Assert(path.Any() == false); }
public override Expression Visit(SingleValuePropertyAccessNode nodeIn) { Expression e; if (TuplePropertyByAliasName == null) { e = TranslateNode(nodeIn.Source); if (e == null) { return(null); } PropertyInfo property = e.Type.GetProperty(nodeIn.Property.Name); if (property == null) { if (!OeExpressionHelper.IsTupleType(e.Type)) { throw new InvalidOperationException("must by Tuple " + e.Type.ToString()); } IEdmNavigationSource navigationSource = ((ResourceRangeVariableReferenceNode)nodeIn.Source).NavigationSource; property = GetTuplePropertyByEntityType(e.Type, navigationSource.EntityType()); } return(Expression.Property(e, property)); } Expression source = TranslateNode(nodeIn.Source); e = TuplePropertyByAliasName(source ?? Parameter, nodeIn); if (e == null) { e = GetPropertyExpression(nodeIn); if (e == null) { throw new InvalidOperationException("property name " + nodeIn.Property.Name + " not found"); } } return(e); }
/// <inheritdoc /> public override bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; IEdmEntityType entityType = navigationSource.EntityType(); // function should have the [HttpGet] if (!context.Action.Attributes.Any(a => a is HttpGetAttribute)) { return(false); } ProcessOperations(context, entityType, navigationSource); return(false); }
/// <summary> /// Load the annotation value. /// </summary> /// <param name="model">The Edm model.</param> /// <param name="target">The target.</param> /// <returns>True/False</returns> public virtual bool Load(IEdmModel model, IEdmVocabularyAnnotatable target) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); string termQualifiedName = CapabilitiesConstants.Namespace + "." + Kind.ToString(); IEdmVocabularyAnnotation annotation = model.GetVocabularyAnnotation(target, termQualifiedName); if (annotation == null) { IEdmNavigationSource navigationSource = target as IEdmNavigationSource; // if not, search the entity type. if (navigationSource != null) { IEdmEntityType entityType = navigationSource.EntityType(); annotation = model.GetVocabularyAnnotation(entityType, termQualifiedName); } } return(Initialize(annotation)); }
public override Expression Visit(SingleValuePropertyAccessNode nodeIn) { if (TuplePropertyMapper == null) { Expression e = TranslateNode(nodeIn.Source); PropertyInfo property = e.Type.GetTypeInfo().GetProperty(nodeIn.Property.Name); if (property == null) { if (!OeExpressionHelper.IsTupleType(e.Type)) { throw new InvalidOperationException("must by Tuple " + e.Type.ToString()); } IEdmNavigationSource navigationSource = ((ResourceRangeVariableReferenceNode)nodeIn.Source).NavigationSource; property = GetTuplePropertyByEntityType(e.Type, navigationSource.EntityType()); e = Expression.Property(e, property); property = e.Type.GetTypeInfo().GetProperty(nodeIn.Property.Name); } return(Expression.Property(e, property)); } Expression source; String aliasName = nodeIn.Property.Name; try { source = TranslateNode(nodeIn.Source); } catch (TupleNavigationPropertyException e) { source = Parameter; aliasName = e.NavigationProperty.Name + "_" + aliasName; } return(TuplePropertyMapper(source, aliasName)); }
/// <inheritdoc /> public override bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } IEdmNavigationSource navigationSource = context.NavigationSource; IEdmEntityType entityType = navigationSource.EntityType(); // action should have the [HttpPost] if (!context.Action.Attributes.Any(a => a is HttpPostAttribute)) { return(false); } // action overload on binding type, only one action overload on the same binding type. // however, it supports the bound action on derived type. ProcessOperations(context, entityType, navigationSource); // in OData operationImport routing convention, all action are processed by default // even it's not a really edm operation import call. return(false); }
/// <inheritdoc /> public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (messageWriter == null) { throw Error.ArgumentNull("messageWriter"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } IEdmNavigationSource navigationSource = writeContext.NavigationSource; if (navigationSource == null) { throw new SerializationException(SRResources.NavigationSourceMissingDuringSerialization); } ODataWriter writer = messageWriter.CreateODataEntryWriter(navigationSource, navigationSource.EntityType()); WriteObjectInline(graph, navigationSource.EntityType().ToEdmTypeReference(isNullable: false), writer, writeContext); }
/// <summary> /// Create ODataContextUrlInfo from basic information /// </summary> /// <param name="navigationSource">Navigation source for current element.</param>\ /// <param name="expectedEntityTypeName">The expectedEntity for current element.</param> /// <param name="isSingle">Whether target is single item.</param> /// <param name="odataUri">The odata uri info for current query.</param> /// <returns>The generated ODataContextUrlInfo.</returns> internal static ODataContextUrlInfo Create(IEdmNavigationSource navigationSource, string expectedEntityTypeName, bool isSingle, ODataUri odataUri) { EdmNavigationSourceKind kind = navigationSource.NavigationSourceKind(); string navigationSourceEntityType = navigationSource.EntityType().FullName(); return new ODataContextUrlInfo() { isContained = kind == EdmNavigationSourceKind.ContainedEntitySet, IsUnknownEntitySet = kind == EdmNavigationSourceKind.UnknownEntitySet, navigationSource = navigationSource.Name, TypeCast = navigationSourceEntityType == expectedEntityTypeName ? null : expectedEntityTypeName, TypeName = navigationSourceEntityType, IncludeFragmentItemSelector = isSingle && kind != EdmNavigationSourceKind.Singleton, odataUri = odataUri }; }
internal void WriteNavigationPropertyBinding(IEdmNavigationSource navigationSource, IEdmNavigationPropertyBinding binding) { this.WriteNavigationPropertyBinding(binding, navigationSource.EntityType()); }
/// <summary> /// /// </summary> /// <param name="context"></param> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ActionModel action = context.Action; if (context.EntitySet == null && context.Singleton == null) { return(false); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; string actionName = action.ActionMethod.Name; string method = Split(actionName, out string property, out string cast, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } IEdmEntityType entityType = navigationSource.EntityType(); IEdmModel model = context.Model; string prefix = context.Prefix; IEdmEntityType declaredEntityType = null; if (declared != null) { declaredEntityType = entityType.FindTypeInInheritance(model, declared) as IEdmEntityType; if (declaredEntityType == null) { return(false); } if (declaredEntityType == entityType) { declaredEntityType = null; } } bool hasKeyParameter = HasKeyParameter(entityType, action); IEdmSingleton singleton = navigationSource as IEdmSingleton; if (singleton != null && hasKeyParameter) { // Singleton, doesn't allow to query property with key return(false); } if (singleton == null && !hasKeyParameter) { // in entityset, doesn't allow for non-key to query property return(false); } IEdmProperty edmProperty = entityType.FindProperty(property); if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Structural) { // only process structural property IEdmStructuredType castComplexType = null; if (cast != null) { IEdmTypeReference propertyType = edmProperty.Type; if (propertyType.IsCollection()) { propertyType = propertyType.AsCollection().ElementType(); } if (!propertyType.IsComplex()) { return(false); } castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(model, cast); if (castComplexType == null) { return(false); } } IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (hasKeyParameter) { segments.Add(new KeySegmentTemplate(entityType)); } if (declaredEntityType != null && declaredEntityType != entityType) { segments.Add(new CastSegmentTemplate(declaredEntityType)); } segments.Add(new PropertySegmentTemplate((IEdmStructuralProperty)edmProperty)); ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(prefix, model, template); return(true); } else { // map to a static action like: <method>Property(int key, string property)From<...> if (property == "Property" && cast == null) { if (action.Parameters.Any(p => p.ParameterInfo.Name == "property" && p.ParameterType == typeof(string))) { // we find a static method mapping for all property // we find a action route IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (hasKeyParameter) { segments.Add(new KeySegmentTemplate(entityType)); } if (declaredEntityType != null) { segments.Add(new CastSegmentTemplate(declaredEntityType)); } segments.Add(new PropertySegmentTemplate((string)null /*entityType*/)); ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(prefix, model, template); return(true); } } } return(false); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } if (context.EntitySet == null && context.Singleton == null) { return(false); } ActionModel action = context.Action; // Filter by the action name. // The action for navigation property request should follow up {httpMethod}{PropertyName}[From{Declaring}] string actionName = action.ActionMethod.Name; string method = SplitActionName(actionName, out string property, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; // filter by action parameter IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = action.HasODataKeyParameter(entityType); if (!(context.Singleton != null ^ hasKeyParameter)) { // Singleton, doesn't allow to query property with key // entityset, doesn't allow for non-key to query property return(false); } // Find the declaring type of the property if we have the declaring type name in the action name. // eitherwise, it means the property is defined on the entity type of the navigation source. IEdmEntityType declaringEntityType = entityType; if (declared != null) { declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType; if (declaringEntityType == null) { return(false); } } // Find the property, and we only care about the navigation property. IEdmProperty edmProperty = declaringEntityType.FindProperty(property); if (edmProperty == null || edmProperty.PropertyKind == EdmPropertyKind.Structural) { return(false); } // Starts the routing template //IList<ODataSegmentTemplate> segments = new List<ODataSegmentTemplate>(); //if (context.EntitySet != null) //{ // segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); //} //else //{ // segments.Add(new SingletonSegmentTemplate(context.Singleton)); //} //if (hasKeyParameter) //{ // segments.Add(new KeySegmentTemplate(entityType)); //} //if (declared != null) //{ // // It should be always single type // segments.Add(new CastSegmentTemplate(declaringEntityType, entityType, navigationSource)); //} IEdmNavigationProperty navigationProperty = (IEdmNavigationProperty)edmProperty; //IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _); //segments.Add(new NavigationSegmentTemplate(navigationProperty, targetNavigationSource)); //ODataPathTemplate template = new ODataPathTemplate(segments); //action.AddSelector(method, context.Prefix, context.Model, template); AddSelector(method, context.Prefix, context.Model, action, navigationSource, declared, declaringEntityType, navigationProperty, hasKeyParameter, false); if (CanApplyDollarCount(navigationProperty, method)) { AddSelector(method, context.Prefix, context.Model, action, navigationSource, declared, declaringEntityType, navigationProperty, hasKeyParameter, true); } return(true); }
/// <summary> /// Build a type segment using the given <paramref name="actualType"/>. /// </summary> /// <param name="actualType">The target type of this segment, which may be collection type.</param> /// <param name="navigationSource">The navigation source containing the entities that we are casting. This can be null.</param> /// <exception cref="System.ArgumentNullException">Throws if the actual edmType is null.</exception> /// <exception cref="ODataException">Throws if the actual edmType is not related to the type of elements in the input navigationSource.</exception> public TypeSegment(IEdmType actualType, IEdmNavigationSource navigationSource) : this(actualType, navigationSource == null ? actualType : navigationSource.EntityType(), navigationSource) { }
public static IEnumerable <IEdmStructuralProperty> GetConcurrencyProperties(this IEdmModel model, IEdmNavigationSource navigationSource) { Contract.Assert(model != null); Contract.Assert(navigationSource != null); // Ensure that concurrency properties cache is attached to model as an annotation to avoid expensive calculations each time ConcurrentDictionary <IEdmNavigationSource, IEnumerable <IEdmStructuralProperty> > concurrencyProperties = model.GetAnnotationValue <ConcurrencyPropertiesAnnotation>(model); if (concurrencyProperties == null) { concurrencyProperties = new ConcurrentDictionary <IEdmNavigationSource, IEnumerable <IEdmStructuralProperty> >(); model.SetAnnotationValue(model, concurrencyProperties); } IEnumerable <IEdmStructuralProperty> cachedProperties; if (concurrencyProperties != null && concurrencyProperties.TryGetValue(navigationSource, out cachedProperties)) { return(cachedProperties); } IList <IEdmStructuralProperty> results = new List <IEdmStructuralProperty>(); IEdmEntityType entityType = navigationSource.EntityType(); IEdmVocabularyAnnotatable annotatable = navigationSource as IEdmVocabularyAnnotatable; if (annotatable != null) { var annotations = model.FindVocabularyAnnotations <IEdmVocabularyAnnotation>(annotatable, CoreVocabularyModel.ConcurrencyTerm); IEdmVocabularyAnnotation annotation = annotations.FirstOrDefault(); if (annotation != null) { IEdmCollectionExpression properties = annotation.Value as IEdmCollectionExpression; if (properties != null) { foreach (var property in properties.Elements) { IEdmPathExpression pathExpression = property as IEdmPathExpression; if (pathExpression != null) { // So far, we only consider the single path, because only the direct properties from declaring type are used. // However we have an issue tracking on: https://github.com/OData/WebApi/issues/472 string propertyName = pathExpression.PathSegments.First(); IEdmProperty edmProperty = entityType.FindProperty(propertyName); IEdmStructuralProperty structuralProperty = edmProperty as IEdmStructuralProperty; if (structuralProperty != null) { results.Add(structuralProperty); } } } } } } if (concurrencyProperties == null) { concurrencyProperties = new ConcurrentDictionary <IEdmNavigationSource, IEnumerable <IEdmStructuralProperty> >(); } if (results.Any()) { concurrencyProperties[navigationSource] = results; } return(results); }
private static void GenerateBaseODataPathSegmentsForNonSingletons( ODataPath path, IEdmNavigationSource navigationSource, IList <ODataPathSegment> odataPath) { // If the navigation is not a singleton we need to walk all of the path segments to generate a // contextually accurate URI. bool segmentFound = false; bool containedFound = false; if (path != null) { var segments = path.Segments; int length = segments.Count; int previousNavigationPathIndex = -1; for (int i = 0; i < length; i++) { ODataPathSegment pathSegment = segments[i]; IEdmNavigationSource currentNavigationSource = null; var entitySetPathSegment = pathSegment as EntitySetSegment; if (entitySetPathSegment != null) { currentNavigationSource = entitySetPathSegment.EntitySet; } var navigationPathSegment = pathSegment as NavigationPropertySegment; if (navigationPathSegment != null) { currentNavigationSource = navigationPathSegment.NavigationSource; } if (containedFound) { odataPath.Add(pathSegment); } else { if (navigationPathSegment != null && navigationPathSegment.NavigationProperty.ContainsTarget) { containedFound = true; //The path should have the last non-contained navigation property if (previousNavigationPathIndex != -1) { for (int j = previousNavigationPathIndex; j <= i; j++) { odataPath.Add(segments[j]); } } } } // If we've found our target navigation in the path that means we've correctly populated the // segments up to the navigation and we can ignore the remaining segments. if (currentNavigationSource != null) { previousNavigationPathIndex = i; if (currentNavigationSource == navigationSource) { segmentFound = true; break; } } } } if (!segmentFound || !containedFound) { // If the target navigation was not found in the current path that means we lack any context that // would suggest a scenario other than directly accessing an entity set, so we must assume that's // the case. odataPath.Clear(); IEdmContainedEntitySet containmnent = navigationSource as IEdmContainedEntitySet; if (containmnent != null) { EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); IEdmEntitySet entitySet = new EdmEntitySet(container, navigationSource.Name, navigationSource.EntityType()); odataPath.Add(new EntitySetSegment(entitySet)); } else { odataPath.Add(new EntitySetSegment((IEdmEntitySet)navigationSource)); } } }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } if (context.EntitySet == null && context.Singleton == null) { return(false); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; ActionModel action = context.Action; string actionName = action.ActionMethod.Name; string method = SplitActionName(actionName, out string property, out string cast, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } // filter by action parameter IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = action.HasODataKeyParameter(entityType); if (!(context.Singleton != null ^ hasKeyParameter)) { // Singleton, doesn't allow to query property with key // entityset, doesn't allow for non-key to query property return(false); } // Find the declaring type of the property if we have the declaring type name in the action name. // eitherwise, it means the property is defined on the entity type of the navigation source. IEdmEntityType declaringEntityType = entityType; if (declared != null) { declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType; if (declaringEntityType == null) { return(false); } } IEdmProperty edmProperty = declaringEntityType.FindProperty(property); if (edmProperty == null || edmProperty.PropertyKind != EdmPropertyKind.Structural) { return(false); } if (!CanApply(edmProperty, method)) { return(false); } IEdmComplexType castType = null; if (cast != null) { IEdmType propertyElementType = edmProperty.Type.Definition.AsElementType(); if (propertyElementType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complexType = (IEdmComplexType)propertyElementType; castType = complexType.FindTypeInInheritance(context.Model, cast) as IEdmComplexType; if (castType == null) { return(false); } } else { // only support complex type cast, (TODO: maybe consider to support Edm.PrimitiveType cast) return(false); } } // only process structural property IEdmStructuredType castComplexType = null; if (cast != null) { IEdmTypeReference propertyType = edmProperty.Type; if (propertyType.IsCollection()) { propertyType = propertyType.AsCollection().ElementType(); } if (!propertyType.IsComplex()) { return(false); } castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(context.Model, cast); if (castComplexType == null) { return(false); } } AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, false); if (CanApplyDollarCount(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, true); } if (CanApplyDollarValue(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, true, false); } return(true); }
private void GetAutoSelectExpandItems( IEdmEntityType baseEntityType, IEdmModel model, IEdmNavigationSource navigationSource, bool isAllSelected, ModelBoundQuerySettings modelBoundQuerySettings, int depth, out List <SelectItem> autoSelectItems, out List <SelectItem> autoExpandItems) { autoSelectItems = new List <SelectItem>(); var autoSelectProperties = EdmLibHelpers.GetAutoSelectProperties(null, baseEntityType, model, modelBoundQuerySettings); foreach (var autoSelectProperty in autoSelectProperties) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new PropertySegment(autoSelectProperty) }; PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); autoSelectItems.Add(pathSelectItem); } autoExpandItems = new List <SelectItem>(); depth--; if (depth < 0) { return; } var autoExpandNavigationProperties = EdmLibHelpers.GetAutoExpandNavigationProperties(null, baseEntityType, model, !isAllSelected, modelBoundQuerySettings); foreach (var navigationProperty in autoExpandNavigationProperties) { IEdmNavigationSource currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty); if (currentEdmNavigationSource != null) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new NavigationPropertySegment(navigationProperty, currentEdmNavigationSource) }; ODataExpandPath expandPath = new ODataExpandPath(pathSegments); SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(), true); ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); modelBoundQuerySettings = EdmLibHelpers.GetModelBoundQuerySettings(navigationProperty, navigationProperty.ToEntityType(), model); List <SelectItem> nestedSelectItems; List <SelectItem> nestedExpandItems; int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name); if (maxExpandDepth != 0 && maxExpandDepth < depth) { depth = maxExpandDepth; } GetAutoSelectExpandItems( currentEdmNavigationSource.EntityType(), model, item.NavigationSource, true, modelBoundQuerySettings, depth, out nestedSelectItems, out nestedExpandItems); selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems), nestedSelectItems.Count == 0); item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); autoExpandItems.Add(item); if (!isAllSelected || autoSelectProperties.Count() != 0) { PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); autoExpandItems.Add(pathSelectItem); } } } }
private MetadataBinder BuildNewMetadataBinder(IEdmNavigationSource targetNavigationSource) { BindingState state = new BindingState(this.configuration) { ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource) }; state.RangeVariables.Push(state.ImplicitRangeVariable); return new MetadataBinder(state); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } IEdmNavigationSource navigationSource = context.NavigationSource; if (navigationSource == null) { return(false); } ActionModel action = context.Action; string actionName = action.ActionName; string method = SplitActionName(actionName, out string property, out string cast, out string declared); if (method == null || string.IsNullOrEmpty(property)) { return(false); } // filter by action parameter IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = action.HasODataKeyParameter(entityType, context.Options?.RouteOptions?.EnablePropertyNameCaseInsensitive ?? false); if (!(context.Singleton != null ^ hasKeyParameter)) { // Singleton, doesn't allow to query property with key // entityset, doesn't allow for non-key to query property return(false); } // Find the declaring type of the property if we have the declaring type name in the action name. // otherwise, it means the property is defined on the entity type of the navigation source. IEdmEntityType declaringEntityType = entityType; if (declared != null) { if (declared.Length == 0) { // Early return for the following cases: // - Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}From // - Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}Of{Cast}From return(false); } declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType; if (declaringEntityType == null) { return(false); } } bool enablePropertyNameCaseInsensitive = context?.Options?.RouteOptions.EnablePropertyNameCaseInsensitive ?? false; IEdmProperty edmProperty = declaringEntityType.FindProperty(property, enablePropertyNameCaseInsensitive); if (edmProperty == null || edmProperty.PropertyKind != EdmPropertyKind.Structural) { return(false); } if (!CanApply(edmProperty, method)) { return(false); } IEdmComplexType castType; // Only process structural property IEdmStructuredType castComplexType = null; if (cast != null) { if (cast.Length == 0) { // Avoid unnecessary call to FindTypeInheritance // Cases handled: Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}Of return(false); } IEdmType propertyElementType = edmProperty.Type.Definition.AsElementType(); if (propertyElementType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complexType = (IEdmComplexType)propertyElementType; castType = complexType.FindTypeInInheritance(context.Model, cast) as IEdmComplexType; if (castType == null) { return(false); } } else { // only support complex type cast, (TODO: maybe consider to support Edm.PrimitiveType cast) return(false); } IEdmTypeReference propertyType = edmProperty.Type; if (propertyType.IsCollection()) { propertyType = propertyType.AsCollection().ElementType(); } if (!propertyType.IsComplex()) { return(false); } castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(context.Model, cast); if (castComplexType == null) { return(false); } } AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, false); if (CanApplyDollarCount(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, true); } if (CanApplyDollarValue(edmProperty, method)) { AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, true, false); } return(true); }
internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource) { return navigationSource.EntityType(); }
/// <summary> /// /// </summary> /// <param name="context"></param> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ActionModel action = context.Action; if (context.EntitySet == null && context.Singleton == null) { return(false); } IEdmNavigationSource navigationSource = context.EntitySet == null ? (IEdmNavigationSource)context.Singleton : (IEdmNavigationSource)context.EntitySet; IEdmModel model = context.Model; string prefix = context.Prefix; IEdmEntityType entityType = navigationSource.EntityType(); bool hasKeyParameter = HasKeyParameter(entityType, action); // found int keyNumber = entityType.Key().Count(); IEdmType bindType = entityType; if (!hasKeyParameter) { // bond to collection bindType = new EdmCollectionType(new EdmEntityTypeReference(entityType, true)); keyNumber = 0; } string actionName = action.ActionMethod.Name; var operations = model.FindBoundOperations(bindType).Where(p => p.Name == actionName); var actions = operations.OfType <IEdmAction>().ToList(); if (actions.Count == 1) // action overload on binding type, only one action overload on the same binding type { if (action.Parameters.Any(p => p.ParameterType == typeof(ODataActionParameters))) { // we find a action route IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (hasKeyParameter) { segments.Add(new KeySegmentTemplate(entityType)); } segments.Add(new ActionSegmentTemplate(actions[0], false)); ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(prefix, model, template); return(true); } } var functions = operations.OfType <IEdmFunction>().ToList(); IEdmFunction function = FindMatchFunction(keyNumber, functions, action); if (function != null) { IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (hasKeyParameter) { segments.Add(new KeySegmentTemplate(entityType)); } segments.Add(new FunctionSegmentTemplate(function, false)); ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(prefix, model, template); return(true); } // in OData operationImport routing convention, all action are processed by default // even it's not a really edm operation import call. return(false); }
/// <summary> /// Converts an item from the data store into an ODataEntry. /// </summary> /// <param name="element">The item to convert.</param> /// <param name="navigationSource">The navigation source that the item belongs to.</param> /// <param name="targetVersion">The OData version this segment is targeting.</param> /// <returns>The converted ODataEntry.</returns> public static ODataEntry ConvertToODataEntry(object element, IEdmNavigationSource entitySource, ODataVersion targetVersion) { IEdmStructuredType entityType = EdmClrTypeUtils.GetEdmType(DataSourceManager.GetCurrentDataSource().Model, element) as IEdmStructuredType; if (entityType == null) { throw new InvalidOperationException("Can not create an entry for " + entitySource.Name); } var entry = new ODataEntry { Properties = GetProperties(element, entityType) }; // Add Annotation in Entity Level if (((ClrObject)element).Annotations != null) { foreach (InstanceAnnotationType annotation in ((ClrObject)element).Annotations) { if (string.IsNullOrEmpty(annotation.Target)) { entry.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Name, annotation.ConvertValueToODataValue())); } } } string typeName; if (entityType is IEdmEntityType) { typeName = (entityType as IEdmEntityType).Name; } else if (entityType is IEdmComplexType) { typeName = (entityType as IEdmComplexType).Name; } else { throw new InvalidOperationException("Not Supported Edmtype to convert to OData Entry."); } entry.TypeName = element.GetType().Namespace + "." + typeName; // TODO: work around for now if (!(entitySource is IEdmContainedEntitySet)) { Uri entryUri = BuildEntryUri(element, entitySource, targetVersion); if (element.GetType().BaseType != null && entitySource.EntityType().Name != typeName) { var editLink = new Uri(entryUri.AbsoluteUri.TrimEnd('/') + "/" + entry.TypeName); entry.EditLink = editLink; entry.ReadLink = editLink; } else { entry.EditLink = entryUri; entry.ReadLink = entryUri; } entry.Id = entryUri; } if (Utility.IsMediaEntity(element.GetType())) { var streamProvider = DataSourceManager.GetCurrentDataSource().StreamProvider; entry.MediaResource = new ODataStreamReferenceValue() { ContentType = streamProvider.GetContentType(element), ETag = streamProvider.GetETag(element), }; } return(entry); }
internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource) { return(navigationSource.EntityType()); }
/// <summary> /// Converts an item from the data store into an ODataEntry. /// </summary> /// <param name="element">The item to convert.</param> /// <param name="navigationSource">The navigation source that the item belongs to.</param> /// <param name="targetVersion">The OData version this segment is targeting.</param> /// <returns>The converted ODataEntry.</returns> public static ODataEntry ConvertToODataEntry(object element, IEdmNavigationSource entitySource, ODataVersion targetVersion) { IEdmStructuredType entityType = EdmClrTypeUtils.GetEdmType(DataSourceManager.GetCurrentDataSource().Model, element) as IEdmStructuredType; if (entityType == null) { throw new InvalidOperationException("Can not create an entry for " + entitySource.Name); } var entry = new ODataEntry { Properties = GetProperties(element, entityType) }; // Add Annotation in Entity Level if (((ClrObject)element).Annotations != null) { foreach (InstanceAnnotationType annotation in ((ClrObject)element).Annotations) { if (string.IsNullOrEmpty(annotation.Target)) { entry.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Name, annotation.ConvertValueToODataValue())); } } } string typeName; if (entityType is IEdmEntityType) { typeName = (entityType as IEdmEntityType).Name; } else if (entityType is IEdmComplexType) { typeName = (entityType as IEdmComplexType).Name; } else { throw new InvalidOperationException("Not Supported Edmtype to convert to OData Entry."); } entry.TypeName = element.GetType().Namespace + "." + typeName; // TODO tiano. work around for now if (!(entitySource is IEdmContainedEntitySet)) { Uri entryUri = BuildEntryUri(element, entitySource, targetVersion); if (element.GetType().BaseType != null && entitySource.EntityType().Name != typeName) { var editLink = new Uri(entryUri.AbsoluteUri.TrimEnd('/') + "/" + entry.TypeName); entry.EditLink = editLink; entry.ReadLink = editLink; } else { entry.EditLink = entryUri; entry.ReadLink = entryUri; } entry.Id = entryUri; } if (Utility.IsMediaEntity(element.GetType())) { var streamProvider = DataSourceManager.GetCurrentDataSource().StreamProvider; entry.MediaResource = new ODataStreamReferenceValue() { ContentType = streamProvider.GetContentType(element), ETag = streamProvider.GetETag(element), }; } return entry; }