/// <summary> /// Returns the type of the property on the specified type. /// </summary> /// <param name="type">The type to look for the property on.</param> /// <param name="propertyName">The name of the property to look for.</param> /// <returns>The type of the property specified.</returns> private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName) { Debug.Assert(propertyName != null, "propertyName != null"); IEdmStructuredType structuredType = type as IEdmStructuredType; IEdmProperty property = structuredType == null ? null : structuredType.FindProperty(propertyName); if (property != null) { IEdmTypeReference propertyType = property.Type; if (propertyType.IsNonEntityCollectionType()) { throw new ODataException(ODataErrorStrings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (propertyType.IsStream()) { throw new ODataException(ODataErrorStrings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (propertyType.IsSpatial()) { throw new ODataException(ODataErrorStrings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName())); } return(property.Type); } if (type != null && !type.IsOpenType()) { throw new ODataException(ODataErrorStrings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName())); } return(null); }
private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName) { IEdmStructuredType type2 = type as IEdmStructuredType; IEdmProperty property = (type2 == null) ? null : type2.FindProperty(propertyName); if (property != null) { IEdmTypeReference typeReference = property.Type; if (typeReference.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (typeReference.IsStream()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (typeReference.IsSpatial()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName())); } return(property.Type); } if ((type != null) && !type.IsOpenType()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName())); } return(null); }
internal static bool ResolveOperationFromList(string identifier, IEnumerable <string> parameterNames, IEdmType bindingType, IEdmModel model, out IEdmOperation matchingOperation, ODataUriResolver resolver) { // TODO: update code that is duplicate between operation and operation import, add more tests. // If the previous segment is an open type, the service action name is required to be fully qualified or else we always treat it as an open property name. if (bindingType != null) { // TODO: look up actual container names here? // When using extension, there may be function call with unqualified name. So loose the restriction here. if (bindingType.IsOpenType() && !identifier.Contains(".") && resolver.GetType() == typeof(ODataUriResolver)) { matchingOperation = null; return(false); } } IList <IEdmOperation> candidateMatchingOperations = null; // The extension method FindBoundOperations & FindOperations call IEdmModel.FindDeclaredBoundOperations which can be implemented by anyone and it could throw any type of exception // so catching all of them and simply putting it in the inner exception. try { if (bindingType != null) { candidateMatchingOperations = resolver.ResolveBoundOperations(model, identifier, bindingType).ToList(); } else { candidateMatchingOperations = resolver.ResolveUnboundOperations(model, identifier).ToList(); } } catch (Exception exc) { if (ExceptionUtils.IsCatchableExceptionType(exc)) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_FoundInvalidOperation(identifier), exc); } throw; } IList <IEdmAction> foundActionsWhenLookingForFunctions = new List <IEdmAction>(); int parameterNamesCount = parameterNames.Count(); if (bindingType != null) { candidateMatchingOperations = candidateMatchingOperations.EnsureOperationsBoundWithBindingParameter().ToList(); } // If the number of parameters > 0 then this has to be a function as actions can't have parameters on the uri only in the payload. Filter further by parameters in this case, otherwise don't. if (parameterNamesCount > 0) { // can only be a function as only functions have parameters on the uri. candidateMatchingOperations = candidateMatchingOperations.RemoveActions(out foundActionsWhenLookingForFunctions).FilterFunctionsByParameterNames(parameterNames, resolver.EnableCaseInsensitive).Cast <IEdmOperation>().ToList(); } else if (bindingType != null) { // Filter out functions with more than one parameter. Actions should not be filtered as the parameters are in the payload not the uri candidateMatchingOperations = candidateMatchingOperations.Where(o => (o.IsFunction() && o.Parameters.Count() == 1) || o.IsAction()).ToList(); } else { // Filter out functions with any parameters candidateMatchingOperations = candidateMatchingOperations.Where(o => (o.IsFunction() && !o.Parameters.Any()) || o.IsAction()).ToList(); } // Only filter if there is more than one and its needed. if (candidateMatchingOperations.Count > 1) { candidateMatchingOperations = candidateMatchingOperations.FilterBoundOperationsWithSameTypeHierarchyToTypeClosestToBindingType(bindingType).ToList(); } // If any of the things returned are an action, it better be the only thing returned, and there can't be parameters in the URL if (candidateMatchingOperations.Any(f => f.IsAction())) { if (candidateMatchingOperations.Count > 1) { if (candidateMatchingOperations.Any(o => o.IsFunction())) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_MultipleOperationOverloads(identifier)); } else { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_MultipleActionOverloads(identifier)); } } if (parameterNames.Count() != 0) { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } matchingOperation = candidateMatchingOperations.Single(); return(true); } if (foundActionsWhenLookingForFunctions.Count > 0) { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } if (candidateMatchingOperations.Count > 1) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_NoSingleMatchFound(identifier, string.Join(",", parameterNames.ToArray()))); } matchingOperation = candidateMatchingOperations.SingleOrDefault(); return(matchingOperation != null); }
/// <summary> /// Try to resolve a function from the given inputs. /// </summary> /// <param name="identifier">The identifier of the function that we're trying to find</param> /// <param name="parameterNames">the names of the parameters to search for.</param> /// <param name="bindingType">the type of the previous segment</param> /// <param name="model">the model to use to look up the function import</param> /// <param name="matchingFunctionImport">The single matching function found.</param> /// <returns>True if a function was matched, false otherwise. Will throw if the model has illegal function imports.</returns> internal static bool ResolveFunctionsFromList(string identifier, IList <string> parameterNames, IEdmType bindingType, IEdmModel model, out IEdmFunctionImport matchingFunctionImport) { DebugUtils.CheckNoExternalCallers(); // If the previous segment is an open type, the service action name is required to be fully qualified or else we always treat it as an open property name. if (bindingType != null) { // TODO: look up actual container names here? if (bindingType.IsOpenType() && !identifier.Contains(".")) { matchingFunctionImport = null; return(false); } } // if the model implements the extensions interface, then leave resolution entirely up to the user. var extendedModel = model as IODataUriParserModelExtensions; if (extendedModel != null) { matchingFunctionImport = extendedModel.FindFunctionImportByBindingParameterType(bindingType, identifier, parameterNames); if (matchingFunctionImport == null) { return(false); } return(true); } // Get all the possible functions by name and binding type // For this method to end up NOT throwing, this call must return a single action or 1 or more functions IList <IEdmFunctionImport> functionImports = model.FindFunctionImportsBySpecificBindingParameterType(bindingType, identifier).ToList(); if (functionImports.Count == 0) { matchingFunctionImport = null; return(false); } Debug.Assert(functionImports != null && functionImports.Count > 0, "Should have returned at least one function import to get here."); Debug.Assert(functionImports.All(f => f.Name == identifier.Split('.').Last()), "list of possible functions must have same name as identifier"); if (!functionImports.AllHaveEqualReturnTypeAndAttributes()) { throw new ODataException(ODataErrorStrings.RequestUriProcessor_FoundInvalidFunctionImport(identifier)); } // If any of the things returned are an action, it better be the only thing returned, and there can't be parameters in the URL if (functionImports.Any(f => f.IsSideEffecting)) { if (functionImports.Count > 1) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_MultipleActionOverloads(identifier)); } if (parameterNames.Count() != 0) { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } matchingFunctionImport = functionImports.Single(); return(true); } // Functions - resolve overloads as needed matchingFunctionImport = ResolveOverloadsByParameterNames(functionImports, parameterNames, identifier); return(matchingFunctionImport != null); }
internal static bool ResolveOperationFromList(string identifier, IEnumerable<string> parameterNames, IEdmType bindingType, IEdmModel model, out IEdmOperation matchingOperation, ODataUriResolver resolver) { // TODO: update code that is duplicate between operation and operation import, add more tests. // If the previous segment is an open type, the service action name is required to be fully qualified or else we always treat it as an open property name. if (bindingType != null) { // TODO: look up actual container names here? if (bindingType.IsOpenType() && !identifier.Contains(".")) { matchingOperation = null; return false; } } IList<IEdmOperation> candidateMatchingOperations = null; // The extension method FindBoundOperations & FindOperations call IEdmModel.FindDeclaredBoundOperations which can be implemented by anyone and it could throw any type of exception // so catching all of them and simply putting it in the inner exception. try { if (bindingType != null) { candidateMatchingOperations = resolver.ResolveBoundOperations(model, identifier, bindingType).ToList(); } else { candidateMatchingOperations = resolver.ResolveUnboundOperations(model, identifier).ToList(); } } catch (Exception exc) { if (ExceptionUtils.IsCatchableExceptionType(exc)) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_FoundInvalidOperation(identifier), exc); } throw; } IList<IEdmAction> foundActionsWhenLookingForFunctions = new List<IEdmAction>(); int parameterNamesCount = parameterNames.Count(); if (bindingType != null) { candidateMatchingOperations = candidateMatchingOperations.EnsureOperationsBoundWithBindingParameter().ToList(); } // If the number of parameters > 0 then this has to be a function as actions can't have parameters on the uri only in the payload. Filter further by parameters in this case, otherwise don't. if (parameterNamesCount > 0) { // can only be a function as only functions have parameters on the uri. candidateMatchingOperations = candidateMatchingOperations.RemoveActions(out foundActionsWhenLookingForFunctions).FilterFunctionsByParameterNames(parameterNames, resolver.EnableCaseInsensitive).Cast<IEdmOperation>().ToList(); } else if (bindingType != null) { // Filter out functions with more than one parameter. Actions should not be filtered as the parameters are in the payload not the uri candidateMatchingOperations = candidateMatchingOperations.Where(o => (o.IsFunction() && o.Parameters.Count() == 1) || o.IsAction()).ToList(); } else { // Filter out functions with any parameters candidateMatchingOperations = candidateMatchingOperations.Where(o => (o.IsFunction() && !o.Parameters.Any()) || o.IsAction()).ToList(); } // Only filter if there is more than one and its needed. if (candidateMatchingOperations.Count > 1) { candidateMatchingOperations = candidateMatchingOperations.FilterBoundOperationsWithSameTypeHierarchyToTypeClosestToBindingType(bindingType).ToList(); } // If any of the things returned are an action, it better be the only thing returned, and there can't be parameters in the URL if (candidateMatchingOperations.Any(f => f.IsAction())) { if (candidateMatchingOperations.Count > 1) { if (candidateMatchingOperations.Any(o => o.IsFunction())) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_MultipleOperationOverloads(identifier)); } else { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_MultipleActionOverloads(identifier)); } } if (parameterNames.Count() != 0) { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } matchingOperation = candidateMatchingOperations.Single(); return true; } if (foundActionsWhenLookingForFunctions.Count > 0) { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } if (candidateMatchingOperations.Count > 1) { throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_NoSingleMatchFound(identifier, string.Join(",", parameterNames.ToArray()))); } matchingOperation = candidateMatchingOperations.SingleOrDefault(); return matchingOperation != null; }
/// <summary> /// Returns the type of the property on the specified type. /// </summary> /// <param name="type">The type to look for the property on.</param> /// <param name="propertyName">The name of the property to look for.</param> /// <returns>The type of the property specified.</returns> private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName) { Debug.Assert(propertyName != null, "propertyName != null"); IEdmStructuredType structuredType = type as IEdmStructuredType; IEdmProperty property = structuredType == null ? null : structuredType.FindProperty(propertyName); if (property != null) { IEdmTypeReference propertyType = property.Type; if (propertyType.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(o.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (propertyType.IsStream()) { throw new ODataException(o.Strings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (propertyType.IsSpatial()) { throw new ODataException(o.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName())); } return property.Type; } if (type != null && !type.IsOpenType()) { throw new ODataException(o.Strings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName())); } return null; }
private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName) { IEdmStructuredType type2 = type as IEdmStructuredType; IEdmProperty property = (type2 == null) ? null : type2.FindProperty(propertyName); if (property != null) { IEdmTypeReference typeReference = property.Type; if (typeReference.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (typeReference.IsStream()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName())); } if (typeReference.IsSpatial()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName())); } return property.Type; } if ((type != null) && !type.IsOpenType()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName())); } return null; }