/// <summary> /// Selects the action for OData requests. /// </summary> /// <param name="odataPath">The OData path.</param> /// <param name="controllerContext">The controller context.</param> /// <param name="actionMap">The action map.</param> /// <returns> /// <c>null</c> if the request isn't handled by this convention; otherwise, the name of the selected action /// </returns> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (odataPath == null) { throw Error.ArgumentNull("odataPath"); } if (controllerContext == null) { throw Error.ArgumentNull("controllerContext"); } if (actionMap == null) { throw Error.ArgumentNull("actionMap"); } if (odataPath.PathTemplate == "~") { return("GetServiceDocument"); } if (odataPath.PathTemplate == "~/$metadata") { return("GetMetadata"); } return(null); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { OperationImportSegment operationImportSegment = null; if (odataPath.PathTemplate == "~/unboundfunction" && ODataRequestMethod.Get == controllerContext.Request.Method) { // The same function name may be used multiple times within a schema, each with a different set of parameters. // For unbound overloads the combination of the function name and the unordered set of parameter names // MUST identify a particular function overload. operationImportSegment = (OperationImportSegment)odataPath.Segments[0]; } else if (odataPath.PathTemplate == "~/unboundaction" && ODataRequestMethod.Post == controllerContext.Request.Method) { // The same action name may be used multiple times within a schema provided there is at most one unbound overload operationImportSegment = (OperationImportSegment)odataPath.Segments[0]; } string actionName = SelectAction(operationImportSegment, actionMap); if (actionName != null) { controllerContext.AddFunctionParameterToRouteData(operationImportSegment); return(actionName); } return(null); }
/// <inheritdoc /> internal static string SelectActionImpl(IWebApiControllerContext controllerContext) { var routeData = controllerContext.RouteData; var routingConventionsStore = controllerContext.Request.Context.RoutingConventionsStore; IDictionary <string, object> attributeRouteData = controllerContext.ControllerResult.Values; if (attributeRouteData != null) { foreach (var item in attributeRouteData) { if (item.Key.StartsWith(ODataParameterValue.ParameterValuePrefix, StringComparison.Ordinal) && item.Value is ODataParameterValue) { routingConventionsStore.Add(item); } else { routeData.Add(item); } } return(attributeRouteData["action"] as string); } return(null); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (odataPath.PathTemplate == "~/singleton") { SingletonSegment singletonSegment = (SingletonSegment)odataPath.Segments[0]; string httpMethodName = GetActionNamePrefix(controllerContext.Request.GetRequestMethodOrPreflightMethod()); if (httpMethodName != null) { // e.g. Try Get{SingletonName} first, then fallback on Get action name return(actionMap.FindMatchingAction( httpMethodName + singletonSegment.Singleton.Name, httpMethodName)); } } else if (odataPath.PathTemplate == "~/singleton/cast") { SingletonSegment singletonSegment = (SingletonSegment)odataPath.Segments[0]; IEdmEntityType entityType = (IEdmEntityType)odataPath.EdmType; string httpMethodName = GetActionNamePrefix(controllerContext.Request.GetRequestMethodOrPreflightMethod()); if (httpMethodName != null) { // e.g. Try Get{SingletonName}From{EntityTypeName} first, then fallback on Get action name return(actionMap.FindMatchingAction( httpMethodName + singletonSegment.Singleton.Name + "From" + entityType.Name, httpMethodName + "From" + entityType.Name)); } } return(null); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (ODataRequestMethod.Post == controllerContext.Request.Method) { switch (odataPath.PathTemplate) { case "~/entityset/key/cast/action": case "~/entityset/key/action": string actionName = GetAction(odataPath).SelectAction(actionMap, isCollection: false); if (actionName != null) { KeySegment keySegment = (KeySegment)odataPath.Segments[1]; controllerContext.AddKeyValueToRouteData(keySegment); } return(actionName); case "~/entityset/cast/action": case "~/entityset/action": return(GetAction(odataPath).SelectAction(actionMap, isCollection: true)); case "~/singleton/action": case "~/singleton/cast/action": return(GetAction(odataPath).SelectAction(actionMap, isCollection: false)); } } return(null); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { ODataRequestMethod requestMethod = controllerContext.Request.Method; if (!IsSupportedRequestMethod(requestMethod)) { return(null); } if (odataPath.PathTemplate == "~/entityset/key/navigation/$ref" || odataPath.PathTemplate == "~/entityset/key/cast/navigation/$ref" || odataPath.PathTemplate == "~/singleton/navigation/$ref" || odataPath.PathTemplate == "~/singleton/cast/navigation/$ref") { NavigationPropertyLinkSegment navigationLinkSegment = (NavigationPropertyLinkSegment)odataPath.Segments.Last(); IEdmNavigationProperty navigationProperty = navigationLinkSegment.NavigationProperty; IEdmEntityType declaringType = navigationProperty.DeclaringEntityType(); string refActionName = FindRefActionName(actionMap, navigationProperty, declaringType, requestMethod); if (refActionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]); } controllerContext.RouteData.Add(ODataRouteConstants.NavigationProperty, navigationLinkSegment.NavigationProperty.Name); return(refActionName); } } else if ((ODataRequestMethod.Delete == requestMethod) && ( odataPath.PathTemplate == "~/entityset/key/navigation/key/$ref" || odataPath.PathTemplate == "~/entityset/key/cast/navigation/key/$ref" || odataPath.PathTemplate == "~/singleton/navigation/key/$ref" || odataPath.PathTemplate == "~/singleton/cast/navigation/key/$ref")) { // the second key segment is the last segment in the path. // So the previous of last segment is the navigation property link segment. NavigationPropertyLinkSegment navigationLinkSegment = (NavigationPropertyLinkSegment)odataPath.Segments[odataPath.Segments.Count - 2]; IEdmNavigationProperty navigationProperty = navigationLinkSegment.NavigationProperty; IEdmEntityType declaringType = navigationProperty.DeclaringEntityType(); string refActionName = FindRefActionName(actionMap, navigationProperty, declaringType, requestMethod); if (refActionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]); } controllerContext.RouteData.Add(ODataRouteConstants.NavigationProperty, navigationLinkSegment.NavigationProperty.Name); controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments.Last(e => e is KeySegment), ODataRouteConstants.RelatedKey); return(refActionName); } } return(null); }
/// <summary> /// Selects the action for OData requests. /// </summary> /// <param name="odataPath">The OData path.</param> /// <param name="controllerContext">The controller context.</param> /// <param name="actionMap">The action map.</param> /// <returns> /// <c>null</c> if the request isn't handled by this convention; otherwise, the name of the selected action /// </returns> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { ODataRequestMethod method = controllerContext.Request.GetRequestMethodOrPreflightMethod(); if (method != ODataRequestMethod.Get) { // [EnableNestedPaths] only supports GET requests return(null); } // unsupported path segments if (odataPath.PathTemplate.EndsWith("$ref")) { return(null); } ODataPathSegment firstSegment = odataPath.Segments.FirstOrDefault(); string sourceName; if (firstSegment is EntitySetSegment entitySetSegment) { sourceName = entitySetSegment.EntitySet.Name; } else if (firstSegment is SingletonSegment singletonSegment) { sourceName = singletonSegment.Singleton.Name; } else { // this only supports paths starting with an entity set or singleton return(null); } // if we did not find a matching action amongst the conventional user-defined methods // then let's check if the controller has a Get method with [EnableNestedPaths] attribute // which should be used to catch any nested GET request string action = actionMap.FindMatchingAction("Get" + sourceName, "Get"); if (action == null) { return(null); } IWebApiActionDescriptor descriptor = actionMap.GetActionDescriptor(action); if (descriptor == null) { return(null); } if (!descriptor.GetCustomAttributes <EnableNestedPathsAttribute>(/* inherit */ true).Any()) { return(null); } return(descriptor.ActionName); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (odataPath.PathTemplate == "~/entityset/key" || odataPath.PathTemplate == "~/entityset/key/cast" || odataPath.PathTemplate == "~/entityset/cast/key") { string httpMethodName; switch (controllerContext.Request.GetRequestMethodOrPreflightMethod()) { case ODataRequestMethod.Get: httpMethodName = "Get"; break; case ODataRequestMethod.Put: httpMethodName = "Put"; break; case ODataRequestMethod.Patch: case ODataRequestMethod.Merge: httpMethodName = "Patch"; break; case ODataRequestMethod.Delete: httpMethodName = "Delete"; break; default: return(null); } Contract.Assert(httpMethodName != null); IEdmEntityType entityType = (IEdmEntityType)odataPath.EdmType; // e.g. Try GetCustomer first, then fallback on Get action name string actionName = actionMap.FindMatchingAction( httpMethodName + entityType.Name, httpMethodName); if (actionName != null) { KeySegment keySegment = (KeySegment)odataPath.Segments.First(d => d is KeySegment); controllerContext.AddKeyValueToRouteData(keySegment); return(actionName); } } return(null); }
public static void AddKeyValueToRouteData(this IWebApiControllerContext controllerContext, KeySegment segment, string keyName = "key") { Contract.Assert(controllerContext != null); Contract.Assert(segment != null); IDictionary <string, object> routingConventionsStore = controllerContext.Request.Context.RoutingConventionsStore; IEdmEntityType entityType = segment.EdmType as IEdmEntityType; Contract.Assert(entityType != null); int keyCount = segment.Keys.Count(); foreach (var keyValuePair in segment.Keys) { bool alternateKey = false; // get the key property from the entity type IEdmStructuralProperty keyProperty = entityType.Key().FirstOrDefault(k => k.Name == keyValuePair.Key); if (keyProperty == null) { // If it's alternate key. keyProperty = entityType.Properties().OfType <IEdmStructuralProperty>().FirstOrDefault(p => p.Name == keyValuePair.Key); alternateKey = true; } Contract.Assert(keyProperty != null); // if there's only one key, provide two paramters, one using the given key name, e.g., "key, relatedKey" // and the other appending the property name to the given key name: "keyId, relatedKeyId" // in other cases, just append the property names to the given key name // so for multiple keys, the parameter name is "keyId1, keyId2..." // for navigation property, the parameter name is "relatedKeyId1, relatedKeyId2 ..." if (alternateKey || keyCount > 1) { var newKeyName = keyName + keyValuePair.Key; AddKeyValues(newKeyName, keyValuePair.Value, keyProperty.Type, controllerContext.RouteData, routingConventionsStore); } else { AddKeyValues(keyName, keyValuePair.Value, keyProperty.Type, controllerContext.RouteData, routingConventionsStore); if (keyCount == 1) { var anotherKeyName = keyName + keyValuePair.Key; AddKeyValues(anotherKeyName, keyValuePair.Value, keyProperty.Type, controllerContext.RouteData, routingConventionsStore); } } IncrementKeyCount(routingConventionsStore); } }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { string prefix; TypeSegment cast; IEdmProperty property = GetProperty(odataPath, controllerContext.Request.Method, out prefix, out cast); IEdmEntityType declaringType = property == null ? null : property.DeclaringType as IEdmEntityType; if (declaringType != null) { string actionName; if (cast == null) { actionName = actionMap.FindMatchingAction( prefix + property.Name + "From" + declaringType.Name, prefix + property.Name); } else { IEdmComplexType typeCast; if (cast.EdmType.TypeKind == EdmTypeKind.Collection) { typeCast = ((IEdmCollectionType)cast.EdmType).ElementType.AsComplex().ComplexDefinition(); } else { typeCast = (IEdmComplexType)cast.EdmType; } // for example: GetCityOfSubAddressFromVipCustomer or GetCityOfSubAddress actionName = actionMap.FindMatchingAction( prefix + property.Name + "Of" + typeCast.Name + "From" + declaringType.Name, prefix + property.Name + "Of" + typeCast.Name); } if (actionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1]; controllerContext.AddKeyValueToRouteData(keyValueSegment); } return(actionName); } } return(null); }
public static void AddFunctionParameterToRouteData(this IWebApiControllerContext controllerContext, OperationImportSegment importSegment) { Contract.Assert(controllerContext != null); Contract.Assert(importSegment != null); IDictionary <string, object> routingConventionsStore = controllerContext.Request.Context.RoutingConventionsStore; IEdmFunctionImport functionImport = importSegment.OperationImports.First() as IEdmFunctionImport; if (functionImport == null) { return; } IEdmFunction function = functionImport.Function; foreach (OperationSegmentParameter parameter in importSegment.Parameters) { string name = parameter.Name; object value = importSegment.GetParameterValue(name); AddFunctionParameters(function, name, value, controllerContext.RouteData, routingConventionsStore, null); } // Append the optional parameters into RouteData. ODataOptionalParameter optional = new ODataOptionalParameter(); foreach (var optionalParameter in function.Parameters.OfType <IEdmOptionalParameter>()) { if (!importSegment.Parameters.Any(c => c.Name == optionalParameter.Name)) { optional.Add(optionalParameter); } } if (optional.OptionalParameters.Any()) { controllerContext.RouteData.Add(ODataRouteConstants.OptionalParameters, optional); } }
public static void AddFunctionParameterToRouteData(this IWebApiControllerContext controllerContext, OperationSegment functionSegment) { Contract.Assert(controllerContext != null); Contract.Assert(functionSegment != null); IDictionary <string, object> routingConventionsStore = controllerContext.Request.Context.RoutingConventionsStore; IEdmFunction function = functionSegment.Operations.First() as IEdmFunction; if (function == null) { return; } foreach (OperationSegmentParameter parameter in functionSegment.Parameters) { string name = parameter.Name; object value = functionSegment.GetParameterValue(name); AddFunctionParameters(function, name, value, controllerContext.RouteData, routingConventionsStore, null); } }
internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { string actionName = null; DynamicPathSegment dynamicPropertSegment = null; switch (odataPath.PathTemplate) { case "~/entityset/key/dynamicproperty": case "~/entityset/key/cast/dynamicproperty": case "~/singleton/dynamicproperty": case "~/singleton/cast/dynamicproperty": dynamicPropertSegment = odataPath.Segments.Last() as DynamicPathSegment; if (dynamicPropertSegment == null) { return(null); } if (ODataRequestMethod.Get == controllerContext.Request.Method) { string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", ActionName); actionName = actionMap.FindMatchingAction(actionNamePrefix); } break; case "~/entityset/key/property/dynamicproperty": case "~/entityset/key/cast/property/dynamicproperty": case "~/singleton/property/dynamicproperty": case "~/singleton/cast/property/dynamicproperty": dynamicPropertSegment = odataPath.Segments.Last() as DynamicPathSegment; if (dynamicPropertSegment == null) { return(null); } PropertySegment propertyAccessSegment = odataPath.Segments[odataPath.Segments.Count - 2] as PropertySegment; if (propertyAccessSegment == null) { return(null); } EdmComplexType complexType = propertyAccessSegment.Property.Type.Definition as EdmComplexType; if (complexType == null) { return(null); } if (ODataRequestMethod.Get == controllerContext.Request.Method) { string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", ActionName); actionName = actionMap.FindMatchingAction(actionNamePrefix + "From" + propertyAccessSegment.Property.Name); } break; default: break; } if (actionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1]; controllerContext.AddKeyValueToRouteData(keyValueSegment); } controllerContext.RouteData.Add(ODataRouteConstants.DynamicProperty, dynamicPropertSegment.Identifier); var key = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty; var value = new ODataParameterValue(dynamicPropertSegment.Identifier, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string))); controllerContext.RouteData.Add(key, value); controllerContext.Request.Context.RoutingConventionsStore.Add(key, value); return(actionName); } return(null); }
/// <summary> /// Selects the action for OData requests. /// </summary> /// <param name="odataPath">The OData path.</param> /// <param name="controllerContext">The controller context.</param> /// <param name="actionMap">The action map.</param> /// <returns> /// <c>null</c> if the request isn't handled by this convention; otherwise, the name of the selected action /// </returns> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (odataPath.PathTemplate == "~/entityset") { EntitySetSegment entitySetSegment = (EntitySetSegment)odataPath.Segments[0]; IEdmEntitySetBase entitySet = entitySetSegment.EntitySet; if (ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { // e.g. Try GetCustomers first, then fall back to Get action name return(actionMap.FindMatchingAction( "Get" + entitySet.Name, "Get")); } else if (ODataRequestMethod.Post == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { // e.g. Try PostCustomer first, then fall back to Post action name return(actionMap.FindMatchingAction( "Post" + entitySet.EntityType().Name, "Post")); } } else if (odataPath.PathTemplate == "~/entityset/$count" && ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { EntitySetSegment entitySetSegment = (EntitySetSegment)odataPath.Segments[0]; IEdmEntitySetBase entitySet = entitySetSegment.EntitySet; // e.g. Try GetCustomers first, then fall back to Get action name return(actionMap.FindMatchingAction( "Get" + entitySet.Name, "Get")); } else if (odataPath.PathTemplate == "~/entityset/cast") { EntitySetSegment entitySetSegment = (EntitySetSegment)odataPath.Segments[0]; IEdmEntitySetBase entitySet = entitySetSegment.EntitySet; IEdmCollectionType collectionType = (IEdmCollectionType)odataPath.EdmType; IEdmEntityType entityType = (IEdmEntityType)collectionType.ElementType.Definition; if (ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { // e.g. Try GetCustomersFromSpecialCustomer first, then fall back to GetFromSpecialCustomer return(actionMap.FindMatchingAction( "Get" + entitySet.Name + "From" + entityType.Name, "GetFrom" + entityType.Name)); } else if (ODataRequestMethod.Post == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { // e.g. Try PostCustomerFromSpecialCustomer first, then fall back to PostFromSpecialCustomer return(actionMap.FindMatchingAction( "Post" + entitySet.EntityType().Name + "From" + entityType.Name, "PostFrom" + entityType.Name)); } } else if (odataPath.PathTemplate == "~/entityset/cast/$count" && ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { EntitySetSegment entitySetSegment = (EntitySetSegment)odataPath.Segments[0]; IEdmEntitySetBase entitySet = entitySetSegment.EntitySet; IEdmCollectionType collectionType = (IEdmCollectionType)odataPath.Segments[1].EdmType; IEdmEntityType entityType = (IEdmEntityType)collectionType.ElementType.Definition; // e.g. Try GetCustomersFromSpecialCustomer first, then fall back to GetFromSpecialCustomer return(actionMap.FindMatchingAction( "Get" + entitySet.Name + "From" + entityType.Name, "GetFrom" + entityType.Name)); } return(null); }
public WebApiController(IWebApiControllerContext <WebApiController> context) { this.context = context ?? throw new ArgumentNullException(nameof(context)); }
public static void AddNavigationPropertyToRouteData(this IWebApiControllerContext controllerContext, NavigationPropertyLinkSegment navigationLinkSegment) { controllerContext.RouteData.Add(ODataRouteConstants.NavigationProperty, navigationLinkSegment.NavigationProperty.Name); IncrementKeyCount(controllerContext.Request.Context.RoutingConventionsStore); }
internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod()) { string actionName = null; OperationSegment function = null; switch (odataPath.PathTemplate) { case "~/entityset/key/cast/function": case "~/entityset/key/function": function = odataPath.Segments.Last() as OperationSegment; actionName = GetFunction(function).SelectAction(actionMap, isCollection: false); if (actionName != null) { controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]); } break; case "~/entityset/key/cast/function/$count": case "~/entityset/key/function/$count": function = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment; actionName = GetFunction(function).SelectAction(actionMap, isCollection: false); if (actionName != null) { controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]); } break; case "~/entityset/cast/function": case "~/entityset/function": function = odataPath.Segments.Last() as OperationSegment; actionName = GetFunction(function).SelectAction(actionMap, isCollection: true); break; case "~/entityset/cast/function/$count": case "~/entityset/function/$count": function = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment; actionName = GetFunction(function).SelectAction(actionMap, isCollection: true); break; case "~/singleton/function": case "~/singleton/cast/function": function = odataPath.Segments.Last() as OperationSegment; actionName = GetFunction(function).SelectAction(actionMap, isCollection: false); break; case "~/singleton/function/$count": case "~/singleton/cast/function/$count": function = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment; actionName = GetFunction(function).SelectAction(actionMap, isCollection: false); break; } if (actionName != null) { controllerContext.AddFunctionParameterToRouteData(function); return(actionName); } } return(null); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { ODataRequestMethod method = controllerContext.Request.GetRequestMethodOrPreflightMethod(); string actionNamePrefix = GetActionMethodPrefix(method); if (actionNamePrefix == null) { return(null); } if (odataPath.PathTemplate == "~/entityset/key/navigation" || odataPath.PathTemplate == "~/entityset/key/navigation/$count" || odataPath.PathTemplate == "~/entityset/key/cast/navigation" || odataPath.PathTemplate == "~/entityset/key/cast/navigation/$count" || odataPath.PathTemplate == "~/singleton/navigation" || odataPath.PathTemplate == "~/singleton/navigation/$count" || odataPath.PathTemplate == "~/singleton/cast/navigation" || odataPath.PathTemplate == "~/singleton/cast/navigation/$count") { NavigationPropertySegment navigationSegment = (odataPath.Segments.Last() as NavigationPropertySegment) ?? odataPath.Segments[odataPath.Segments.Count - 2] as NavigationPropertySegment; IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty; IEdmEntityType declaringType = navigationProperty.DeclaringType as IEdmEntityType; // It is not valid to *Post* to any non-collection valued navigation property. if (navigationProperty.TargetMultiplicity() != EdmMultiplicity.Many && ODataRequestMethod.Post == method) { return(null); } // It is not valid to *Put/Patch" to any collection-valued navigation property. if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many && (ODataRequestMethod.Put == method || ODataRequestMethod.Patch == method)) { return(null); } // *Get* is the only supported method for $count request. if (odataPath.Segments.Last() is CountSegment && ODataRequestMethod.Get != method) { return(null); } if (declaringType != null) { // e.g. Try GetNavigationPropertyFromDeclaringType first, then fallback on GetNavigationProperty action name string actionName = actionMap.FindMatchingAction( actionNamePrefix + navigationProperty.Name + "From" + declaringType.Name, actionNamePrefix + navigationProperty.Name); if (actionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1]; controllerContext.AddKeyValueToRouteData(keyValueSegment); } return(actionName); } } } return(null); }