/// <summary>
        /// Creates an ODataAction or ODataFunction from a operation import.
        /// </summary>
        /// <param name="metadataDocumentUri">The metadata document uri.</param>
        /// <param name="metadataReferencePropertyName">The metadata reference property name.</param>
        /// <param name="edmOperation">The operation to create the ODataOperation for.</param>
        /// <param name="isAction">true if the created ODataOperation is an ODataAction, false otherwise.</param>
        /// <returns>The created ODataAction or ODataFunction.</returns>
        internal static ODataOperation CreateODataOperation(Uri metadataDocumentUri, string metadataReferencePropertyName, IEdmOperation edmOperation, out bool isAction)
        {
            Debug.Assert(metadataDocumentUri != null, "metadataDocumentUri != null");
            Debug.Assert(!string.IsNullOrEmpty(metadataReferencePropertyName), "!string.IsNullOrEmpty(metadataReferencePropertyName)");
            Debug.Assert(edmOperation != null, "edmOperation != null");

            isAction = edmOperation.IsAction();
            ODataOperation operation = isAction ? (ODataOperation) new ODataAction() : new ODataFunction();

            // Note that the property name can be '#name' which is not a valid Uri. We need to prepend the metadata document uri in that case.
            int parameterStartIndex = 0;

            if (isAction && (parameterStartIndex = metadataReferencePropertyName.IndexOf(JsonLightConstants.FunctionParameterStart)) > 0)
            {
                metadataReferencePropertyName = metadataReferencePropertyName.Substring(0, parameterStartIndex);
            }

            operation.Metadata = GetAbsoluteUriFromMetadataReferencePropertyName(metadataDocumentUri, metadataReferencePropertyName);
            return(operation);
        }
Exemple #2
0
        /// <inheritdoc />
        protected override bool IsOperationParameterMeet(IEdmOperation operation, ActionModel action)
        {
            Contract.Assert(operation != null);
            Contract.Assert(action != null);

            if (!operation.IsAction())
            {
                return(false);
            }

            // So far, we use the "ODataActionParameters" and "ODataUntypedActionParameters" to hold the action parameter values.
            // TODO: consider to use [FromODataBody] to seperate the parameters to each corresponding
            if (operation.Parameters.Count() > 1)
            {
                if (!action.Parameters.Any(p => p.ParameterType == typeof(ODataActionParameters) || p.ParameterType == typeof(ODataUntypedActionParameters)))
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="FunctionSegmentTemplate" /> class.
        /// </summary>
        /// <param name="operationSegment">The operation segment, it should be a function segment and the parameters are template.</param>
        public ActionSegmentTemplate(OperationSegment operationSegment)
        {
            if (operationSegment == null)
            {
                throw Error.ArgumentNull(nameof(operationSegment));
            }

            IEdmOperation operation = operationSegment.Operations.FirstOrDefault();

            if (!operation.IsAction())
            {
                throw new ODataException(Error.Format(SRResources.SegmentShouldBeKind, "Action", "ActionSegmentTemplate"));
            }

            Action = (IEdmAction)operation;
            if (Action.ReturnType != null)
            {
                IsSingle = Action.ReturnType.TypeKind() != EdmTypeKind.Collection;
                EdmType  = Action.ReturnType.Definition;
            }

            Segment = operationSegment;
        }
        /// <summary>
        /// Create the <see cref="OpenApiResponses"/> for a <see cref="IEdmOperation"/>
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="operation">The Edm operation.</param>
        /// <returns>The created <see cref="OpenApiResponses"/>.</returns>
        public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(operation, nameof(operation));

            OpenApiResponses responses = new OpenApiResponses();

            if (operation.IsAction() && operation.ReturnType == null)
            {
                responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
                responses.Add(Constants.StatusCode200, Constants.StatusCode204.GetResponse());
            }
            else
            {
                OpenApiResponse response = new OpenApiResponse
                {
                    Description = "Success",
                    Content     = new Dictionary <string, OpenApiMediaType>
                    {
                        {
                            Constants.ApplicationJsonMediaType,
                            new OpenApiMediaType
                            {
                                Schema = context.CreateEdmTypeSchema(operation.ReturnType)
                            }
                        }
                    }
                };
                responses.Add(Constants.StatusCode200, response);
            }

            // both action & function has the default response.
            responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());

            return(responses);
        }
Exemple #5
0
        /// <summary>
        /// Add the template to the action
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="edmOperation">The Edm operation.</param>
        /// <param name="hasKeyParameter">Has key parameter or not.</param>
        /// <param name="entityType">The entity type.</param>
        /// <param name="navigationSource">The navigation source.</param>
        /// <param name="castType">The type cast.</param>
        protected static void AddSelector(ODataControllerActionContext context,
                                          IEdmOperation edmOperation,
                                          bool hasKeyParameter,
                                          IEdmEntityType entityType,
                                          IEdmNavigationSource navigationSource,
                                          IEdmEntityType castType)
        {
            Contract.Assert(context != null);
            Contract.Assert(entityType != null);
            Contract.Assert(navigationSource != null);
            Contract.Assert(edmOperation != null);

            // Now, let's add the selector model.
            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (context.EntitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                if (hasKeyParameter)
                {
                    segments.Add(new KeySegmentTemplate(entityType, navigationSource));
                }
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(context.Singleton));
            }

            if (castType != null)
            {
                if (context.Singleton != null || !hasKeyParameter)
                {
                    segments.Add(new CastSegmentTemplate(castType, entityType, navigationSource));
                }
                else
                {
                    segments.Add(new CastSegmentTemplate(new EdmCollectionType(castType.ToEdmTypeReference(false)),
                                                         new EdmCollectionType(entityType.ToEdmTypeReference(false)), navigationSource));
                }
            }

            IEdmNavigationSource targetset = null;

            if (edmOperation.ReturnType != null)
            {
                targetset = edmOperation.GetTargetEntitySet(navigationSource, context.Model);
            }

            string httpMethod;

            if (edmOperation.IsAction())
            {
                segments.Add(new ActionSegmentTemplate((IEdmAction)edmOperation, targetset));
                httpMethod = "post";
            }
            else
            {
                ISet <String> required = GetRequiredFunctionParamters(edmOperation, context.Action);
                segments.Add(new FunctionSegmentTemplate((IEdmFunction)edmOperation, targetset, required));
                httpMethod = "get";
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

            context.Action.AddSelector(httpMethod, context.Prefix, context.Model, template);
        }
Exemple #6
0
        /// <summary>
        /// Create the <see cref="OpenApiResponses"/> for a <see cref="IEdmOperation"/>
        /// </summary>
        /// <param name="context">The OData context.</param>
        /// <param name="operation">The Edm operation.</param>
        /// <param name="path">The OData path.</param>
        /// <returns>The created <see cref="OpenApiResponses"/>.</returns>
        public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation, ODataPath path)
        {
            Utils.CheckArgumentNull(context, nameof(context));
            Utils.CheckArgumentNull(operation, nameof(operation));
            Utils.CheckArgumentNull(path, nameof(path));

            OpenApiResponses responses = new();

            if (operation.IsAction() && operation.ReturnType == null)
            {
                responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse());
            }
            else
            {
                OpenApiSchema schema;
                if (operation.ReturnType.IsCollection())
                {
                    // Get the entity type of the previous segment
                    IEdmEntityType entityType = path.Segments.Reverse().Skip(1)?.Take(1)?.FirstOrDefault()?.EntityType;
                    schema = new OpenApiSchema
                    {
                        Title      = entityType == null ? null : $"Collection of {entityType.Name}",
                        Type       = "object",
                        Properties = new Dictionary <string, OpenApiSchema>
                        {
                            {
                                "value", context.CreateEdmTypeSchema(operation.ReturnType)
                            }
                        }
                    };
                }
                else if (operation.ReturnType.IsPrimitive())
                {
                    // A property or operation response that is of a primitive type is represented as an object with a single name/value pair,
                    // whose name is value and whose value is a primitive value.
                    schema = new OpenApiSchema
                    {
                        Type       = "object",
                        Properties = new Dictionary <string, OpenApiSchema>
                        {
                            {
                                "value", context.CreateEdmTypeSchema(operation.ReturnType)
                            }
                        }
                    };
                }
                else
                {
                    schema = context.CreateEdmTypeSchema(operation.ReturnType);
                }

                string mediaType = Constants.ApplicationJsonMediaType;
                if (operation.ReturnType.AsPrimitive()?.PrimitiveKind() == EdmPrimitiveTypeKind.Stream)
                {
                    // Responses of types Edm.Stream should be application/octet-stream
                    mediaType = Constants.ApplicationOctetStreamMediaType;
                }

                OpenApiResponse response = new()
                {
                    Description = "Success",
                    Content     = new Dictionary <string, OpenApiMediaType>
                    {
                        {
                            mediaType,
                            new OpenApiMediaType
                            {
                                Schema = schema
                            }
                        }
                    }
                };
                responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response);
            }

            if (context.Settings.ErrorResponsesAsDefault)
            {
                responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
            }
            else
            {
                responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse());
                responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse());
            }

            return(responses);
        }
Exemple #7
0
            private void WriteMethod(OdcmClass odcmClass, IEdmOperation operation, IEdmOperationImport operationImport = null)
            {
                var parameters = operation.IsBound
                    ? (from parameter in operation.Parameters
                       where parameter != operation.Parameters.First()
                       select parameter)
                    : (operation.Parameters);

                var isBoundToCollection = operation.IsBound && operation.Parameters.First().Type.IsCollection();

                var odcmMethod = new OdcmMethod(operation.Name, odcmClass.Namespace)
                {
                    IsComposable = operation.IsFunction() && ((IEdmFunction)operation).IsComposable,
                    IsBoundToCollection = isBoundToCollection,
                    Verbs = operation.IsAction() ? OdcmAllowedVerbs.Post : OdcmAllowedVerbs.Any,
                    Class = odcmClass
                };

                AddVocabularyAnnotations(odcmMethod, operation);

                if (operationImport != null)
                {
                    AddVocabularyAnnotations(odcmMethod, operationImport);
                }

                odcmClass.Methods.Add(odcmMethod);

                if (operation.ReturnType != null)
                {
                    odcmMethod.ReturnType = ResolveType(operation.ReturnType);
                    odcmMethod.IsCollection = operation.ReturnType.IsCollection();
                }

                var callingConvention =
                    operation.IsAction()
                        ? OdcmCallingConvention.InHttpMessageBody
                        : OdcmCallingConvention.InHttpRequestUri;

                foreach (var parameter in parameters)
                {
                    var odcmParameter = new OdcmParameter(parameter.Name)
                    {
                        CallingConvention = callingConvention,
                        Type = ResolveType(parameter.Type),
                        IsCollection = parameter.Type.IsCollection(),
                        IsNullable = parameter.Type.IsNullable
                    };

                    AddVocabularyAnnotations(odcmParameter, parameter);

                    odcmMethod.Parameters.Add(odcmParameter);
                }
            }
        /// <summary>
        /// Creates an ODataAction or ODataFunction from a operation import.
        /// </summary>
        /// <param name="metadataDocumentUri">The metadata document uri.</param>
        /// <param name="metadataReferencePropertyName">The metadata reference property name.</param>
        /// <param name="edmOperation">The operation to create the ODataOperation for.</param>
        /// <param name="isAction">true if the created ODataOperation is an ODataAction, false otherwise.</param>
        /// <returns>The created ODataAction or ODataFunction.</returns>
        internal static ODataOperation CreateODataOperation(Uri metadataDocumentUri, string metadataReferencePropertyName, IEdmOperation edmOperation, out bool isAction)
        {
            Debug.Assert(metadataDocumentUri != null, "metadataDocumentUri != null");
            Debug.Assert(!string.IsNullOrEmpty(metadataReferencePropertyName), "!string.IsNullOrEmpty(metadataReferencePropertyName)");
            Debug.Assert(edmOperation != null, "edmOperation != null");

            isAction = edmOperation.IsAction();
            ODataOperation operation = isAction ? (ODataOperation)new ODataAction() : new ODataFunction();

            // Note that the property name can be '#name' which is not a valid Uri. We need to prepend the metadata document uri in that case.
            int parameterStartIndex = 0;
            if (isAction && (parameterStartIndex = metadataReferencePropertyName.IndexOf(JsonLightConstants.FunctionParameterStart)) > 0)
            {
                metadataReferencePropertyName = metadataReferencePropertyName.Substring(0, parameterStartIndex);
            }

            operation.Metadata = GetAbsoluteUriFromMetadataReferencePropertyName(metadataDocumentUri, metadataReferencePropertyName);
            return operation;
        }