private void Initialize(IEdmFunctionImport action) { IEdmTypeReference returnType = action.ReturnType; EdmType = returnType == null ? null : returnType.Definition; IEdmEntitySet functionEntitySet = null; if (action.TryGetStaticEntitySet(out functionEntitySet)) { EntitySet = functionEntitySet; } Action = action; }
/// <summary> /// Initializes a new instance of the <see cref="ActionPathSegment" /> class. /// </summary> /// <param name="previous">The previous segment in the path.</param> /// <param name="action">The action being invoked.</param> public ActionPathSegment(ODataPathSegment previous, IEdmFunctionImport action) : base(previous) { if (action == null) { throw Error.ArgumentNull("action"); } IEdmTypeReference returnType = action.ReturnType; EdmType = returnType == null ? null : returnType.Definition; IEdmEntitySet functionEntitySet = null; if (action.TryGetStaticEntitySet(out functionEntitySet)) { EntitySet = functionEntitySet; } Action = action; }
/// <summary> /// Gets the target entity set for the given function import. /// </summary> /// <param name="functionImport">The function import.</param> /// <param name="sourceEntitySet">The source entity set.</param> /// <param name="model">The model.</param> /// <returns>The target entity set of the function import or null if it could not be determined.</returns> internal static IEdmEntitySet GetTargetEntitySet(this IEdmFunctionImport functionImport, IEdmEntitySet sourceEntitySet, IEdmModel model) { DebugUtils.CheckNoExternalCallers(); IEdmEntitySet targetEntitySet; if (functionImport.TryGetStaticEntitySet(out targetEntitySet)) { return(targetEntitySet); } if (sourceEntitySet == null) { return(null); } if (functionImport.IsBindable && functionImport.Parameters.Any()) { IEdmFunctionParameter parameter; IEnumerable <IEdmNavigationProperty> path; if (functionImport.TryGetRelativeEntitySetPath(model, out parameter, out path)) { // TODO: throw better exception ExceptionUtil.ThrowSyntaxErrorIfNotValid(parameter == functionImport.Parameters.First()); targetEntitySet = sourceEntitySet; foreach (var navigation in path) { targetEntitySet = targetEntitySet.FindNavigationTarget(navigation); if (targetEntitySet == null) { return(null); } } return(targetEntitySet); } } return(null); }
/// <inheritdoc /> public virtual bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } ActionModel action = context.Action; IEdmModel model = context.Model; // By convention, we use the operation import name as the action name in the controller string actionMethodName = action.ActionName; var edmOperationImports = model.ResolveOperationImports(actionMethodName, enableCaseInsensitive: true); if (!edmOperationImports.Any()) { return(true); } (var actionImports, var functionImports) = edmOperationImports.SplitOperationImports(); // It's not allowed to have an action import and function import with the same name. if (actionImports.Count > 0 && functionImports.Count > 0) { throw new ODataException(Error.Format(SRResources.OperationMustBeUniqueInEntitySetContainer, actionMethodName)); } else if (actionImports.Count > 0 && context.Action.Attributes.Any(a => a is HttpPostAttribute)) { if (actionImports.Count != 1) { throw new ODataException(Error.Format(SRResources.MultipleActionImportFound, actionMethodName)); } IEdmActionImport actionImport = actionImports[0]; IEdmEntitySetBase targetEntitySet; actionImport.TryGetStaticEntitySet(model, out targetEntitySet); // TODO: // 1. shall we check the [HttpPost] attribute, or does the ASP.NET Core have the default? // 2) shall we check the action has "ODataActionParameters" parameter type? ODataPathTemplate template = new ODataPathTemplate(new ActionImportSegmentTemplate(actionImport, targetEntitySet)); action.AddSelector("Post", context.Prefix, context.Model, template, context.Options?.RouteOptions); return(true); } else if (functionImports.Count > 0 && context.Action.Attributes.Any(a => a is HttpGetAttribute)) { IEdmFunctionImport functionImport = FindFunctionImport(functionImports, action); if (functionImport == null) { return(false); } IEdmEntitySetBase targetSet; functionImport.TryGetStaticEntitySet(model, out targetSet); // TODO: // 1) shall we check the [HttpGet] attribute, or does the ASP.NET Core have the default? ODataPathTemplate template = new ODataPathTemplate(new FunctionImportSegmentTemplate(functionImport, targetSet)); action.AddSelector("Get", context.Prefix, context.Model, template, context.Options?.RouteOptions); return(true); } else { // doesn't find an operation, return true means to skip the remaining conventions. return(false); } }
/// <summary> /// Tries to get entity set. /// </summary> /// <param name="uri">The URI.</param> /// <param name="model">The model.</param> /// <param name="entitySet">The entity set.</param> /// <returns> /// True if it gets and entitySet or false if it can't /// </returns> public static bool TryGetEntitySetAndEntityType(Uri uri, IEdmModel model, out IEdmEntitySet entitySet) { IEdmEntitySet currentEntitySet = null; entitySet = null; foreach (string segment in uri.Segments) { string segmentValue = segment.Replace("/", String.Empty); if (segmentValue.Length == 0) { continue; } // lopping off key pieces as we don't care int i = segment.IndexOf('('); if (i > -1) { segmentValue = segment.Remove(i); } IEdmEntityContainer container = model.EntityContainers().First(); // If there is no entitySet we need to find out which one it is if (currentEntitySet == null) { IEdmEntitySet foundEntitySet = container.FindEntitySet(segmentValue); if (foundEntitySet != null) { currentEntitySet = foundEntitySet; } else { // check to see if there the current segment is a service operation IEdmFunctionImport functionImport = container.FunctionImports().SingleOrDefault(fi => fi.Name == segmentValue); if (functionImport != null) { IEdmEntitySet functionEntitySet = null; if (functionImport.TryGetStaticEntitySet(out functionEntitySet)) { currentEntitySet = functionEntitySet; } } } } else { IEdmNavigationProperty navigationProperty = currentEntitySet.ElementType.NavigationProperties().SingleOrDefault(np => np.Name == segmentValue); if (navigationProperty != null) { currentEntitySet = currentEntitySet.FindNavigationTarget(navigationProperty); } else { // Need to update this a little so it works for Actions/Functions IEdmFunctionImport functionImport = container.FunctionImports().SingleOrDefault(fi => fi.IsBindable == true && fi.Name == segmentValue); if (functionImport != null) { IEdmEntitySet functionEntitySet = null; if (functionImport.TryGetStaticEntitySet(out functionEntitySet)) { currentEntitySet = functionEntitySet; } } } } } if (currentEntitySet != null) { entitySet = currentEntitySet; return(true); } entitySet = null; return(false); }