/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; string httpMethod = request.Method.ToUpperInvariant(); string prefix; TypeSegment cast; IEdmProperty property = GetProperty(odataPath, httpMethod, out prefix, out cast); IEdmEntityType declaringType = property == null ? null : property.DeclaringType as IEdmEntityType; if (declaringType != null) { ControllerActionDescriptor actionDescriptor; if (cast == null) { actionDescriptor = actionDescriptors.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 actionDescriptor = actionDescriptors.FindMatchingAction( prefix + property.Name + "Of" + typeCast.Name + "From" + declaringType.Name, prefix + property.Name + "Of" + typeCast.Name); } if (actionDescriptor != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1]; routeContext.AddKeyValueToRouteData(keyValueSegment); } return(actionDescriptor); } } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.Request.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; if (odataPath.PathTemplate == "~/entityset/key" || odataPath.PathTemplate == "~/entityset/key/cast") { string httpMethod = request.Method.ToUpperInvariant(); string httpMethodName; switch (httpMethod) { case ODataRouteConstants.HttpGet: httpMethodName = "Get"; break; case ODataRouteConstants.HttpPut: httpMethodName = "Put"; break; case ODataRouteConstants.HttpPatch: httpMethodName = "Patch"; break; case ODataRouteConstants.HttpDelete: 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 ActionDescriptor actionDescriptor = actionDescriptors.FindMatchingAction( httpMethodName + entityType.Name, httpMethodName); if (actionDescriptor != null) { KeySegment keySegment = (KeySegment)odataPath.Segments[1]; routeContext.AddKeyValueToRouteData(keySegment); return(actionDescriptor); } } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } // TODO: do we need to match the action parameters? to match ODataActionParameters or one by one? ODataPath odataPath = routeContext.HttpContext.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; string httpMethod = request.Method.ToUpperInvariant(); if (httpMethod == ODataRouteConstants.HttpPost) { switch (odataPath.PathTemplate) { case "~/entityset/key/cast/action": case "~/entityset/key/action": ControllerActionDescriptor descriptor = GetAction(odataPath).SelectAction(actionDescriptors, isCollection: false); if (descriptor != null) { KeySegment keySegment = (KeySegment)odataPath.Segments[1]; routeContext.AddKeyValueToRouteData(keySegment, descriptor); } return(descriptor); case "~/entityset/cast/action": case "~/entityset/action": return(GetAction(odataPath).SelectAction(actionDescriptors, isCollection: true)); case "~/singleton/action": case "~/singleton/cast/action": return(GetAction(odataPath).SelectAction(actionDescriptors, isCollection: false)); } } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.Request.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; string httpMethod = request.Method.ToUpperInvariant(); if (httpMethod == ODataRouteConstants.HttpGet) { ActionDescriptor actionDescriptor = null; OperationSegment function = null; switch (odataPath.PathTemplate) { case "~/entityset/key/cast/function": case "~/entityset/key/function": function = odataPath.Segments.Last() as OperationSegment; actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false); if (actionDescriptor != null) { routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1], actionDescriptor); } break; case "~/entityset/key/cast/function/$count": case "~/entityset/key/function/$count": function = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment; actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false); if (actionDescriptor != null) { routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1], actionDescriptor); } break; case "~/entityset/cast/function": case "~/entityset/function": function = odataPath.Segments.Last() as OperationSegment; actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: true); break; case "~/entityset/cast/function/$count": case "~/entityset/function/$count": function = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment; actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: true); break; case "~/singleton/function": case "~/singleton/cast/function": function = odataPath.Segments.Last() as OperationSegment; actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false); break; case "~/singleton/function/$count": case "~/singleton/cast/function/$count": function = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment; actionDescriptor = GetFunction(function).SelectAction(actionDescriptors, isCollection: false); break; } if (actionDescriptor != null) { routeContext.AddFunctionParameterToRouteData(function); return(actionDescriptor); } } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.Request.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; string httpMethod = request.Method.ToUpperInvariant(); string actionNamePrefix = GetActionMethodPrefix(httpMethod); 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 && httpMethod == ODataRouteConstants.HttpPost) { return(null); } // It is not valid to *Put/Patch" to any collection-valued navigation property. if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many && (httpMethod == ODataRouteConstants.HttpPut || httpMethod == ODataRouteConstants.HttpPatch)) { return(null); } // *Get* is the only supported method for $count request. if (odataPath.Segments.Last() is CountSegment && httpMethod != ODataRouteConstants.HttpGet) { return(null); } if (declaringType != null) { // e.g. Try GetNavigationPropertyFromDeclaringType first, then fallback on GetNavigationProperty action name ControllerActionDescriptor actionDescriptor = actionDescriptors.FindMatchingAction( actionNamePrefix + navigationProperty.Name + "From" + declaringType.Name, actionNamePrefix + navigationProperty.Name); if (actionDescriptor != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1]; routeContext.AddKeyValueToRouteData(keyValueSegment); } return(actionDescriptor); } } } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.Request.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; string httpMethod = request.Method.ToUpperInvariant(); if (!IsSupportedRequestMethod(httpMethod)) { 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(); ActionDescriptor refActionName = FindRefActionName(actionDescriptors, navigationProperty, declaringType, httpMethod); if (refActionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]); } routeContext.RouteData.Values[ODataRouteConstants.NavigationProperty] = navigationLinkSegment.NavigationProperty.Name; return(refActionName); } } else if ((httpMethod == ODataRouteConstants.HttpDelete) && ( 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(); ActionDescriptor refActionName = FindRefActionName(actionDescriptors, navigationProperty, declaringType, httpMethod); if (refActionName != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]); } routeContext.RouteData.Values[ODataRouteConstants.NavigationProperty] = navigationLinkSegment.NavigationProperty.Name; routeContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments.Last(e => e is KeySegment), ODataRouteConstants.RelatedKey); return(refActionName); } } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.Request.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; string httpMethod = request.Method.ToUpperInvariant(); ControllerActionDescriptor actionDescriptor = 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 (httpMethod == ODataRouteConstants.HttpGet) { string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", _actionName); actionDescriptor = actionDescriptors.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 (httpMethod == ODataRouteConstants.HttpGet) { string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", _actionName); actionDescriptor = actionDescriptors.FindMatchingAction(actionNamePrefix + "From" + propertyAccessSegment.Property.Name); } break; default: break; } if (actionDescriptors != null && dynamicPropertSegment != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1]; routeContext.AddKeyValueToRouteData(keyValueSegment); } routeContext.RouteData.Values[ODataRouteConstants.DynamicProperty] = dynamicPropertSegment.Identifier; var key = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty; var value = new ODataParameterValue(dynamicPropertSegment.Identifier, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string))); routeContext.RouteData.Values[key] = value; request.ODataFeature().RoutingConventionsStore[key] = value; return(actionDescriptor); } return(null); }
/// <inheritdoc/> public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors) { if (routeContext == null) { throw Error.ArgumentNull("routeContext"); } ODataPath odataPath = routeContext.HttpContext.Request.ODataFeature().Path; HttpRequest request = routeContext.HttpContext.Request; if (odataPath.PathTemplate == "~/entityset/key" || odataPath.PathTemplate == "~/entityset/key/cast") { string httpMethod = request.Method.ToUpperInvariant(); string httpMethodName; switch (httpMethod) { case ODataRouteConstants.HttpGet: httpMethodName = "Get"; break; case ODataRouteConstants.HttpPut: httpMethodName = "Put"; break; case ODataRouteConstants.HttpPatch: httpMethodName = "Patch"; break; case ODataRouteConstants.HttpDelete: 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 var actions = actionDescriptors.FindMatchingActions( httpMethodName + entityType.Name, httpMethodName); // TODO: Cache these results var keyNames = entityType.Key().Select(k => k.Type.AsTypeDefinition().ShortQualifiedName()).ToArray(); var actionDescriptor = actions.FirstOrDefault(action => { if (action.Parameters.Count == keyNames.Length && action.Parameters.All( p => { if (keyNames.Contains(p.ParameterType.EdmName())) { return(true); } var type = typeof(KeyValuePair <string, object>[]); if (p.ParameterType == type) { return(true); } return(false); })) { return(true); } if (action.Parameters.Count == 1 && typeof(IEnumerable <KeyValuePair <string, object> >).IsAssignableFrom(action.Parameters[0].ParameterType)) { return(true); } return(false); }); if (actionDescriptor != null) { KeySegment keySegment = (KeySegment)odataPath.Segments[1]; routeContext.AddKeyValueToRouteData(keySegment, actionDescriptor); return(actionDescriptor); } } return(null); }