protected CsdlSemanticsOperationImport(CsdlSemanticsEntityContainer container, CsdlOperationImport operationImport, IEdmOperation operation) : base(operationImport) { this.container = container; this.operationImport = operationImport; this.Operation = operation; }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonLightOutputContext">The output context to write to.</param> /// <param name="operation">The operation import whose parameters will be written.</param> internal ODataJsonLightParameterWriter(ODataJsonLightOutputContext jsonLightOutputContext, IEdmOperation operation) : base(jsonLightOutputContext, operation) { Debug.Assert(jsonLightOutputContext != null, "jsonLightOutputContext != null"); this.jsonLightOutputContext = jsonLightOutputContext; this.jsonLightValueSerializer = new ODataJsonLightValueSerializer(this.jsonLightOutputContext); }
public ODataAvroParameterReader(ODataAvroInputContext inputContext, IEdmOperation operation) { Debug.Assert(inputContext != null, "inputContext != null"); Debug.Assert(operation != null, "operation != null"); this.inputContext = inputContext; this.operation = operation; this.state = ODataParameterReaderState.Start; }
public ODataAvroParameterWriter(ODataAvroOutputContext outputContext, IEdmOperation operation) { Debug.Assert(outputContext != null, "outputContext != null"); Debug.Assert(operation != null, "operation != null"); this.outputContext = outputContext; schema = (RecordSchema)this.outputContext.AvroWriter.UpdateSchema(null, this.GetTmpType(operation)); this.record = new AvroRecord(schema); }
/// <summary> /// Initializes a new instance of the <see cref="EdmOperationParameter"/> class. /// </summary> /// <param name="declaringOperation">Declaring function of the parameter.</param> /// <param name="name">Name of the parameter.</param> /// <param name="type">Type of the parameter.</param> public EdmOperationParameter(IEdmOperation declaringOperation, string name, IEdmTypeReference type) : base(name) { EdmUtil.CheckArgumentNull(declaringOperation, "declaringFunction"); EdmUtil.CheckArgumentNull(name, "name"); EdmUtil.CheckArgumentNull(type, "type"); this.Type = type; this.DeclaringOperation = declaringOperation; }
public static bool IsDuplicateOperation(IEdmOperation operation, IEnumerable<IEdmOperation> candidateDuplicateOperations) { var validator = new DuplicateOperationValidator(null); foreach (var candidateOperation in candidateDuplicateOperations) { validator.ValidateNotDuplicate(candidateOperation, true /*skipError*/); } return validator.ValidateNotDuplicate(operation, true /*skipError*/); }
/// <summary> /// Constructor. /// </summary> /// <param name="jsonLightInputContext">The input to read the payload from.</param> /// <param name="operation">The operation import whose parameters are being read.</param> internal ODataJsonLightParameterReader(ODataJsonLightInputContext jsonLightInputContext, IEdmOperation operation) : base(jsonLightInputContext, operation) { Debug.Assert(jsonLightInputContext != null, "jsonLightInputContext != null"); Debug.Assert(jsonLightInputContext.ReadingResponse == false, "jsonLightInputContext.ReadingResponse == false"); Debug.Assert(operation != null, "operationImport != null"); this.jsonLightInputContext = jsonLightInputContext; this.jsonLightParameterDeserializer = new ODataJsonLightParameterDeserializer(this, jsonLightInputContext); Debug.Assert(this.jsonLightInputContext.Model.IsUserModel(), "this.jsonLightInputContext.Model.IsUserModel()"); }
private IEdmType GetTmpType(IEdmOperation operation) { EdmComplexType type = new EdmComplexType(operation.Namespace, operation.Name + AvroConstants.ParameterTypeSuffix); foreach (var parameter in operation.Parameters.Skip(operation.IsBound ? 1 : 0)) { type.AddStructuralProperty(parameter.Name, parameter.Type); } return type; }
/// <summary> /// Initializes a new instance of <see cref="EdmOperationImport"/> class. /// </summary> /// <param name="container">An <see cref="IEdmEntityContainer"/> containing this operation import.</param> /// <param name="operation">The operation of the import.</param> /// <param name="name">Name of the operation import.</param> /// <param name="entitySet">An entity set containing entities returned by this operation import. /// The two expression kinds supported are <see cref="IEdmEntitySetReferenceExpression"/> and <see cref="IEdmPathExpression"/>.</param> protected EdmOperationImport( IEdmEntityContainer container, IEdmOperation operation, string name, IEdmExpression entitySet) : base(name) { EdmUtil.CheckArgumentNull(container, "container"); EdmUtil.CheckArgumentNull(operation, this.OperationArgumentNullParameterName()); this.Container = container; this.Operation = operation; this.EntitySet = entitySet; }
public override IDictionary<IEdmOperationParameter, SingleValueNode> ResolveOperationParameters(IEdmOperation operation, IDictionary<string, SingleValueNode> input) { Dictionary<IEdmOperationParameter, SingleValueNode> result = new Dictionary<IEdmOperationParameter, SingleValueNode>(EqualityComparer<IEdmOperationParameter>.Default); foreach (var item in input) { IEdmOperationParameter functionParameter = null; if (EnableCaseInsensitive) { functionParameter = ODataUriResolver.ResolveOpearationParameterNameCaseInsensitive(operation, item.Key); } else { functionParameter = operation.FindParameter(item.Key); } // ensure parameter name existis if (functionParameter == null) { throw new ODataException(Strings.ODataParameterWriterCore_ParameterNameNotFoundInOperation(item.Key, operation.Name)); } SingleValueNode newVal = item.Value; if (functionParameter.Type.IsEnum() && newVal is ConstantNode && newVal.TypeReference != null && newVal.TypeReference.IsString()) { string text = ((ConstantNode)item.Value).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = functionParameter.Type; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { newVal = new ConstantNode(val, text, typeRef); } } result.Add(functionParameter, newVal); } return result; }
/// <summary /// Compares Action and Function elements from CSDL to IEdmComplexTypes in the model. /// </summary> /// <param name="schemaElements">The CSDL schema elements to extract ComplexType elements from.</param> /// <param name="model">The Edm model to extract the IEdmComplexTypes from.</param> private static void CompareActionsAndFunctions(IEnumerable <XElement> schemaElements, IEdmModel model) { foreach (var schemaElement in schemaElements) { var namespaceName = schemaElement.GetAttributeValue("Namespace"); var operationElements = schemaElement.EdmElements("Action").Concat(schemaElement.EdmElements("Function")); foreach (var operationElement in operationElements) { // Find matching operation from model, matching and validating // parameters at the same time. var parameterElements = operationElement.EdmElements("Parameter").ToList(); var operationName = operationElement.GetAttributeValue("Name"); var possibleMatches = model.FindDeclaredOperations(namespaceName + "." + operationName).ToArray(); ExceptionUtilities.Assert(possibleMatches.Any(), "Failed to find action or function import " + operationName); IEdmOperation operation = null; foreach (var possibleMatch in possibleMatches) { try { CompareOperationParameters(parameterElements, possibleMatch.Parameters); operation = possibleMatch; break; } catch (InvalidOperationException) { // Swallow exception for failed comparison } } ExceptionUtilities.Assert(operation != null, "Failed to find a matching operation for " + operationName); string returnTypeValue; if (operationElement.TryGetAttributeValue("ReturnType", out returnTypeValue)) { ExceptionUtilities.CheckObjectNotNull(operation.ReturnType, "Expected a return type for operation"); CompareTypeValue(returnTypeValue, operation.ReturnType); } else { var returnTypeElement = operationElement.EdmElements("ReturnType").SingleOrDefault(); if (returnTypeElement != null) { CompareType(returnTypeElement, operation.ReturnType); // TODO: Enable this. // CompareTypeFacets(propertyElement, propertyOnModel.Type); } else { ExceptionUtilities.Assert(operation.ReturnType == null, "Did not expect a return type for operation"); } } CompareBooleanAttribute(operationElement, "IsBound", operation.IsBound, false); string entitySetPathValue; if (operationElement.TryGetAttributeValue("EntitySetPath", out entitySetPathValue)) { ExceptionUtilities.Assert(operation.EntitySetPath != null, "Expected a value for EntitySetPath"); CompareEntitySetPaths(entitySetPathValue, operation.EntitySetPath); } else { ExceptionUtilities.Assert(operation.EntitySetPath == null, "Did not expect a value for EntitySetPath"); } bool isFunction = operationElement.Name.LocalName == "Function"; if (isFunction) { // Function specific verification ExceptionUtilities.Assert(operation is IEdmFunction, "Model operation is not a function"); // TODO: Enable this. // CompareBooleanAttribute(operationElement, "IsComposable", operation.IsComposable, false); } else { // Action specific verification ExceptionUtilities.Assert(operation is IEdmAction, "Model operation is not an action"); } } } }
private static bool TryParseOperationParameters(string functionName, string parenthesisExpression, ParameterAliasValueAccessor paramAliasAccessor, IEdmOperation operation, out ICollection<OperationSegmentParameter> parsedSegementParameters) { ICollection<FunctionParameterToken> splitParameters; parsedSegementParameters = null; ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(HardCodedTestModel.TestModel) { ParameterAliasValueAccessor = paramAliasAccessor }; if (FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { parsedSegementParameters = FunctionCallBinder.BindSegmentParameters(configuration, operation, splitParameters); return true; } return false; }
/// <summary> /// Resolve an operation parameter's name with case insensitive enabled /// </summary> /// <param name="operation">The operation.</param> /// <param name="identifier">Name for the parameter.</param> /// <returns>The resolved operation parameter.</returns> internal static IEdmOperationParameter ResolveOpearationParameterNameCaseInsensitive(IEdmOperation operation, string identifier) { var list = operation.Parameters.Where(parameter => string.Equals(identifier, parameter.Name, StringComparison.OrdinalIgnoreCase)).ToList(); if (list.Count > 1) { throw new ODataException(Strings.UriParserMetadata_MultipleMatchingParametersFound(identifier)); } if (list.Count == 1) { return list.Single(); } return null; }
/// <summary> /// Bind path segment's operation or operationImport's parameters. /// </summary> /// <param name="configuration">The ODataUriParserConfiguration.</param> /// <param name="functionOrOpertion">The function or operation.</param> /// <param name="segmentParameterTokens">The parameter tokens to be binded.</param> /// <returns>The binded semantic nodes.</returns> internal static List <OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection <FunctionParameterToken> segmentParameterTokens) { // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value. ICollection <FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.Resolver.EnableCaseInsensitive, configuration.EnableUriTemplateParsing); // Bind it to metadata BindingState state = new BindingState(configuration); state.ImplicitRangeVariable = null; state.RangeVariables.Clear(); MetadataBinder binder = new MetadataBinder(state); List <OperationSegmentParameter> boundParameters = new List <OperationSegmentParameter>(); IDictionary <string, SingleValueNode> input = new Dictionary <string, SingleValueNode>(StringComparer.Ordinal); foreach (var paraToken in parametersParsed) { // TODO: considering another better exception if (paraToken.ValueToken is EndPathToken) { throw new ODataException(Strings.MetadataBinder_ParameterNotInScope( string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier))); } SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken); if (!input.ContainsKey(paraToken.ParameterName)) { input.Add(paraToken.ParameterName, boundNode); } } IDictionary <IEdmOperationParameter, SingleValueNode> result = configuration.Resolver.ResolveOperationParameters(functionOrOpertion, input); foreach (var item in result) { SingleValueNode boundNode = item.Value; // ensure node type is compatible with parameter type. var sourceTypeReference = boundNode.GetEdmTypeReference(); bool sourceIsNullOrOpenType = (sourceTypeReference == null); if (!sourceIsNullOrOpenType) { // if the node has been rewritten, no further conversion is needed. if (!TryRewriteIntegralConstantNode(ref boundNode, item.Key.Type)) { boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, item.Key.Type); } } OperationSegmentParameter boundParamer = new OperationSegmentParameter(item.Key.Name, boundNode); boundParameters.Add(boundParamer); } return(boundParameters); }
/// <summary> /// Create a <see cref="ODataParameterReader"/>. /// </summary> /// <param name="operation">The operation import whose parameters are being read.</param> /// <returns>The newly created <see cref="ODataParameterReader"/>.</returns> private ODataParameterReader CreateParameterReaderImplementation(IEdmOperation operation) { return(new ODataJsonLightParameterReader(this, operation)); }
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); }
private static ODataOperation CreateODataOperation(IEdmOperation operation, ProcedureLinkBuilder builder, EntityInstanceContext entityInstanceContext) { Contract.Assert(operation != null); Contract.Assert(builder != null); Contract.Assert(entityInstanceContext != null); ODataMetadataLevel metadataLevel = entityInstanceContext.SerializerContext.MetadataLevel; IEdmModel model = entityInstanceContext.EdmModel; if (ShouldOmitOperation(operation, builder, metadataLevel)) { return null; } Uri target = builder.BuildLink(entityInstanceContext); if (target == null) { return null; } Uri baseUri = new Uri(entityInstanceContext.Url.CreateODataLink(new MetadataPathSegment())); Uri metadata = new Uri(baseUri, "#" + CreateMetadataFragment(operation)); ODataOperation odataOperation; if (operation is IEdmAction) { odataOperation = new ODataAction(); } else { odataOperation = new ODataFunction(); } odataOperation.Metadata = metadata; // Always omit the title in minimal/no metadata modes. if (metadataLevel == ODataMetadataLevel.FullMetadata) { EmitTitle(model, operation, odataOperation); } // Omit the target in minimal/no metadata modes unless it doesn't follow conventions. if (!builder.FollowsConventions || metadataLevel == ODataMetadataLevel.FullMetadata) { odataOperation.Target = target; } return odataOperation; }
internal static bool ShouldOmitOperation(IEdmOperation operation, ProcedureLinkBuilder builder, ODataMetadataLevel metadataLevel) { Contract.Assert(builder != null); switch (metadataLevel) { case ODataMetadataLevel.MinimalMetadata: case ODataMetadataLevel.NoMetadata: return operation.IsBound && builder.FollowsConventions; case ODataMetadataLevel.FullMetadata: default: // All values already specified; just keeping the compiler happy. return false; } }
private static void ValidateNoError(IEdmModel model, IEdmOperation operation) { IEnumerable<EdmError> errorsFound = null; IEdmOperationParameter operationParameter = null; IEnumerable<IEdmNavigationProperty> navigationProperties = null; IEdmEntityType entityType = null; operation.TryGetRelativeEntitySetPath(model, out operationParameter, out navigationProperties, out entityType, out errorsFound); errorsFound.Should().HaveCount(0); }
/// <summary> /// Generates an function link following the OData URL conventions for the function <paramref name="function"/> and bound to the entity /// represented by <paramref name="entityContext"/>. /// </summary> /// <param name="entityContext">The <see cref="EntityInstanceContext"/> representing the entity for which the function link needs to be generated.</param> /// <param name="function">The function for which the function link needs to be generated.</param> /// <returns>The generated function link following OData URL conventions.</returns> public static Uri GenerateFunctionLink(this EntityInstanceContext entityContext, IEdmOperation function) { if (entityContext == null) { throw Error.ArgumentNull("entityContext"); } if (function == null) { throw Error.ArgumentNull("function"); } IEdmOperationParameter bindingParameter = function.Parameters.FirstOrDefault(); if (bindingParameter == null || !bindingParameter.Type.IsEntity()) { throw Error.Argument("function", SRResources.FunctionNotBoundToEntity, function.Name); } return(GenerateFunctionLink(entityContext, bindingParameter.Type.FullName(), function.Name, function.Parameters.Select(p => p.Name))); }
private static void ValidateError(IEdmModel model, IEdmOperation operation, EdmErrorCode expectedErrorCode, string expectedError) { IEnumerable<EdmError> errorsFound = null; IEdmOperationParameter operationParameter = null; IEnumerable<IEdmNavigationProperty> navigationProperties = null; IEdmEntityType entityType = null; operation.TryGetRelativeEntitySetPath(model, out operationParameter, out navigationProperties, out entityType, out errorsFound); errorsFound.Should().HaveCount(1); var errorsFoundList = errorsFound.ToList(); errorsFoundList[0].ErrorCode.Should().Be(expectedErrorCode); errorsFoundList[0].ErrorMessage.Should().Be(expectedError); }
internal static string FullyQualifiedName(IEdmVocabularyAnnotatable element) { IEdmSchemaElement schemaElement = element as IEdmSchemaElement; if (schemaElement != null) { IEdmOperation operation = schemaElement as IEdmOperation; if (operation != null) { return(ParameterizedName(operation)); } else { return(schemaElement.FullName()); } } else { IEdmEntityContainerElement containerElement = element as IEdmEntityContainerElement; if (containerElement != null) { return(containerElement.Container.FullName() + "/" + containerElement.Name); } else { IEdmProperty property = element as IEdmProperty; if (property != null) { IEdmSchemaType declaringSchemaType = property.DeclaringType as IEdmSchemaType; if (declaringSchemaType != null) { string propertyOwnerName = FullyQualifiedName(declaringSchemaType); if (propertyOwnerName != null) { return(propertyOwnerName + "/" + property.Name); } } } else { IEdmOperationReturn operationReturn; IEdmEnumMember enumMember; IEdmOperationParameter parameter = element as IEdmOperationParameter; if (parameter != null) { string parameterOwnerName = FullyQualifiedName(parameter.DeclaringOperation); if (parameterOwnerName != null) { return(parameterOwnerName + "/" + parameter.Name); } } else if ((enumMember = element as IEdmEnumMember) != null) { string enumMemberOwnerName = FullyQualifiedName(enumMember.DeclaringType); if (enumMemberOwnerName != null) { return(enumMemberOwnerName + "/" + enumMember.Name); } } else if ((operationReturn = element as IEdmOperationReturn) != null) { string operationName = FullyQualifiedName(operationReturn.DeclaringOperation); if (operationName != null) { return(operationName + "/" + CsdlConstants.OperationReturnExternalTarget); } } } } } return(null); }
private static void ValidateErrorInList(IEdmModel model, IEdmOperation operation, EdmErrorCode expectedErrorCode, string expectedError) { IEnumerable<EdmError> errorsFound = null; IEdmOperationParameter operationParameter = null; IEnumerable<IEdmNavigationProperty> navigationProperties = null; IEdmEntityType entityType = null; operation.TryGetRelativeEntitySetPath(model, out operationParameter, out navigationProperties, out entityType, out errorsFound); var error = errorsFound.SingleOrDefault(e => e.ErrorCode == expectedErrorCode); error.Should().NotBeNull(); error.ErrorMessage.Should().Be(expectedError); }
/// <summary> /// Checks whether the <paramref name="annotatableOperation"/> has a MIME type annotation. /// </summary> /// <param name="model">The <see cref="IEdmModel"/> containing the annotation.</param> /// <param name="annotatableOperation">The <see cref="IEdmOperation"/> to check.</param> /// <returns>The (non-null) value of the MIME type annotation of the <paramref name="annotatableOperation"/> or null if no MIME type annotation exists.</returns> public static string GetMimeType(this IEdmModel model, IEdmOperation annotatableOperation) { return(GetStringAnnotationValue(model, annotatableOperation, EdmConstants.MimeTypeAttributeName, () => Strings.EdmUtil_NullValueForMimeTypeAnnotation)); }
/// <summary> /// Asynchronously creates an <see cref="ODataParameterWriter" /> to write a parameter payload. /// </summary> /// <param name="operation">The operation whose parameters will be written.</param> /// <returns>A running task for the created parameter writer.</returns> /// <remarks>The write must flush the output when it's finished (inside the last Write call).</remarks> public virtual Task<ODataParameterWriter> CreateODataParameterWriterAsync(IEdmOperation operation) { throw this.CreatePayloadKindNotSupportedException(ODataPayloadKind.Error); }
/// <summary> /// Initializes a new instance of the <see cref="EdmApplyExpression"/> class. /// </summary> /// <param name="appliedOperation">Operation to apply.</param> /// <param name="arguments">Application arguments. Value may be null, in which case it is treated as an empty enumerable.</param> public EdmApplyExpression(IEdmOperation appliedOperation, params IEdmExpression[] arguments) : this(appliedOperation, (IEnumerable <IEdmExpression>)arguments) { }
/// <summary> /// Generates an function link following the OData URL conventions for the function <paramref name="function"/> and bound to the entity /// represented by <paramref name="entityContext"/>. /// </summary> /// <param name="entityContext">The <see cref="EntityInstanceContext"/> representing the entity for which the function link needs to be generated.</param> /// <param name="function">The function for which the function link needs to be generated.</param> /// <returns>The generated function link following OData URL conventions.</returns> public static Uri GenerateFunctionLink(this EntityInstanceContext entityContext, IEdmOperation function) { if (entityContext == null) { throw Error.ArgumentNull("entityContext"); } if (function == null) { throw Error.ArgumentNull("function"); } IEdmOperationParameter bindingParameter = function.Parameters.FirstOrDefault(); if (bindingParameter == null || !bindingParameter.Type.IsEntity()) { throw Error.Argument("function", SRResources.FunctionNotBoundToEntity, function.Name); } return GenerateFunctionLink(entityContext, bindingParameter.Type.FullName(), function.Name, function.Parameters.Select(p => p.Name)); }
public static void SetIsDbFunction(this IEdmModel edmModel, IEdmOperation edmOperation, bool isDbFunction) { edmModel.SetAnnotationValue(edmOperation, new OeValueAnnotation <bool>(isDbFunction)); }
internal static Uri GenerateFunctionLink(this ResourceContext resourceContext, IEdmTypeReference bindingParameterType, IEdmOperation function, IEnumerable <string> parameterNames) { IList <ODataPathSegment> functionPathSegments = resourceContext.GenerateBaseODataPathSegments(); // generate link with cast if the navigation source type doesn't match the entity type the function is bound to. if (resourceContext.NavigationSource.EntityType() != bindingParameterType.Definition) { functionPathSegments.Add(new TypeSegment(bindingParameterType.Definition, null)); } IList <OperationSegmentParameter> parameters = new List <OperationSegmentParameter>(); // skip the binding parameter foreach (string param in parameterNames.Skip(1)) { string value = "@" + param; parameters.Add(new OperationSegmentParameter(param, new ConstantNode(value, value))); } OperationSegment segment = new OperationSegment(new[] { function }, parameters, null); functionPathSegments.Add(segment); string functionLink = resourceContext.InternalUrlHelper.CreateODataLink(functionPathSegments); return(functionLink == null ? null : new Uri(functionLink)); }
public static bool IsDbFunction(this IEdmModel edmModel, IEdmOperation edmOperation) { OeValueAnnotation <bool> valueAnnotation = edmModel.GetAnnotationValue <OeValueAnnotation <bool> >(edmOperation); return(valueAnnotation.Value); }
public void InvokeAvroAction() { ODataEntry product1 = new ODataEntry { TypeName = "Microsoft.Test.OData.Services.PluggableFormat.Product", Properties = new[] { new ODataProperty { Name = "Id", Value = 1 }, new ODataProperty { Name = "Name", Value = "Peach" }, new ODataProperty { Name = "Info", Value = new ODataComplexValue() { TypeName = "Microsoft.Test.OData.Services.PluggableFormat.ProductInfo", Properties = new [] { new ODataProperty { Name = "Site", Value = "G1" }, new ODataProperty { Name = "Serial", Value = 1024L }, } } }, }, }; IEdmModel model = new PluggableFormatService(null).Format.LoadServiceModel(); IEdmOperation action = model.FindDeclaredOperations("Microsoft.Test.OData.Services.PluggableFormat.AddProduct").Single(); var requestMessage = new HttpWebRequestMessage(new Uri(ServiceBaseUri.AbsoluteUri + "Products/Microsoft.Test.OData.Services.PluggableFormat.AddProduct", UriKind.Absolute)); requestMessage.Method = "POST"; using (var mw = new ODataMessageWriter(requestMessage, GetAvroWriterSettings(), model)) { var pw = mw.CreateODataParameterWriter(action); pw.WriteStart(); var ew = pw.CreateEntryWriter("Value"); { ew.WriteStart(product1); ew.WriteEnd(); ew.Flush(); } pw.WriteValue("Override", true); pw.WriteEnd(); pw.Flush(); } var responseMessage = requestMessage.GetResponse(); Assert.AreEqual(204, responseMessage.StatusCode); requestMessage = new HttpWebRequestMessage(new Uri(ServiceBaseUri.AbsoluteUri + "Products(1)", UriKind.Absolute)); requestMessage.SetHeader("Accept", "avro/binary"); responseMessage = requestMessage.GetResponse(); ODataEntry entry = null; using (var messageReader = new ODataMessageReader(responseMessage, GetAvroReaderSettings(), Model)) { var reader = messageReader.CreateODataEntryReader(); while (reader.Read()) { if (reader.State == ODataReaderState.EntryEnd) { entry = reader.Item as ODataEntry; } } } Assert.IsNotNull(entry); Assert.IsTrue(TestHelper.EntryEqual(product1, entry)); }
private bool IsExactMatch(IEdmOperation operation) { IEnumerator<IEdmExpression> parameterExpressionEnumerator = this.Arguments.GetEnumerator(); foreach (IEdmOperationParameter parameter in operation.Parameters) { parameterExpressionEnumerator.MoveNext(); IEnumerable<EdmError> recursiveErrors; if (!parameterExpressionEnumerator.Current.TryCast(parameter.Type, this.bindingContext, true, out recursiveErrors)) { return false; } } return true; }
/// <summary> /// Asynchronously create a <see cref="ODataParameterReader"/>. /// </summary> /// <param name="operation">The operation whose parameters are being read.</param> /// <returns>Task which when completed returns the newly created <see cref="ODataParameterReader"/>.</returns> public virtual Task <ODataParameterReader> CreateParameterReaderAsync(IEdmOperation operation) { throw this.CreatePayloadKindNotSupportedException(ODataPayloadKind.Parameter); }
/// <summary> /// Tries to find a single matching operation import for the given identifier, parametes, and binding type. /// </summary> /// <param name="identifier">The identifier from the URI.</param> /// <param name="parenthesisExpression">The parenthesis expression contianing parameters, if any.</param> /// <param name="bindingType">The current binding type or null if there isn't one.</param> /// <param name="configuration">The configuration of the parser.</param> /// <param name="boundParameters">The parsed parameters from the parenthesis expression.</param> /// <param name="matchingOperation">The single matching operation import if one could be determined.</param> /// <returns>Whether or not a matching operation import could be found.</returns> private static bool TryBindingParametersAndMatchingOperation(string identifier, string parenthesisExpression, IEdmType bindingType, ODataUriParserConfiguration configuration, out ICollection<OperationSegmentParameter> boundParameters, out IEdmOperation matchingOperation) { // If the name isn't fully qualified then it can't be a function or action. // When using extension, there may be function call with unqualified name. So loose the restriction here. if (identifier != null && identifier.IndexOf(".", StringComparison.Ordinal) == -1 && configuration.Resolver.GetType() == typeof(ODataUriResolver)) { boundParameters = null; matchingOperation = null; return false; } // TODO: update code that is duplicate between operation and operation import, add more tests. matchingOperation = null; ICollection<FunctionParameterToken> splitParameters; if (!String.IsNullOrEmpty(parenthesisExpression)) { if (!FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { IEdmOperation possibleMatchingOperation = null; // Look for an overload that returns an entity collection by the specified name. If so parthensis is just key parameters. if (FunctionOverloadResolver.ResolveOperationFromList(identifier, new List<string>(), bindingType, configuration.Model, out possibleMatchingOperation, configuration.Resolver)) { IEdmCollectionTypeReference collectionReturnType = possibleMatchingOperation.ReturnType as IEdmCollectionTypeReference; if (collectionReturnType != null && collectionReturnType.ElementType().IsEntity()) { matchingOperation = possibleMatchingOperation; boundParameters = null; return true; } else { throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier)); } } boundParameters = null; return false; } } else { splitParameters = new Collection<FunctionParameterToken>(); } // Resolve the specific overload. if (FunctionOverloadResolver.ResolveOperationFromList(identifier, splitParameters.Select(k => k.ParameterName).ToList(), bindingType, configuration.Model, out matchingOperation, configuration.Resolver)) { boundParameters = FunctionCallBinder.BindSegmentParameters(configuration, matchingOperation, splitParameters); return true; } boundParameters = null; return false; }
internal static string CreateMetadataFragment(IEdmOperation operation) { // There can only be one entity container in OData V4. string actionName = operation.Name; string fragment = operation.Namespace + "." + actionName; return fragment; }
/// <summary> /// Determines the entity set for segment. /// </summary> /// <param name="identifier">The identifier.</param> /// <param name="returnType">Type of the return.</param> /// <param name="segment">The segment.</param> /// <param name="targetset">The targetset.</param> /// <param name="singleOperation">The single operation.</param> /// <exception cref="ODataException">Throws and exception if entity set not specified.</exception> private static void DetermineEntitySetForSegment(string identifier, IEdmTypeReference returnType, ODataPathSegment segment, IEdmEntitySetBase targetset, IEdmOperation singleOperation) { if (returnType != null) { segment.TargetEdmNavigationSource = targetset; segment.TargetEdmType = returnType.Definition; segment.TargetKind = TargetKindFromType(segment.TargetEdmType); segment.SingleResult = !singleOperation.ReturnType.IsCollection(); } else { segment.TargetEdmNavigationSource = null; segment.TargetEdmType = null; segment.TargetKind = RequestTargetKind.VoidOperation; } }
private Expression[] ProcessActionInvokePostBody(IODataRequestMessage message, IEdmOperation operation) { using (var messageReader = new ODataMessageReader(message, this.GetReaderSettings(), this.DataSource.Model)) { List<Expression> parameterValues = new List<Expression>(); var parameterReader = messageReader.CreateODataParameterReader(operation); while (parameterReader.Read()) { switch (parameterReader.State) { case ODataParameterReaderState.Value: { object clrValue = ODataObjectModelConverter.ConvertPropertyValue(parameterReader.Value); parameterValues.Add(Expression.Constant(clrValue)); break; } case ODataParameterReaderState.Collection: { ODataCollectionReader collectionReader = parameterReader.CreateCollectionReader(); object clrValue = ODataObjectModelConverter.ConvertPropertyValue(ODataObjectModelConverter.ReadCollectionParameterValue(collectionReader)); parameterValues.Add(Expression.Constant(clrValue, clrValue.GetType())); break; } case ODataParameterReaderState.Entry: { var entryReader = parameterReader.CreateEntryReader(); object clrValue = ODataObjectModelConverter.ConvertPropertyValue(ODataObjectModelConverter.ReadEntryParameterValue(entryReader)); parameterValues.Add(Expression.Constant(clrValue, clrValue.GetType())); break; } case ODataParameterReaderState.Feed: { IList collectionList = null; var feedReader = parameterReader.CreateFeedReader(); while (feedReader.Read()) { if (feedReader.State == ODataReaderState.EntryEnd) { object clrItem = ODataObjectModelConverter.ConvertPropertyValue(feedReader.Item); if (collectionList == null) { Type itemType = clrItem.GetType(); Type listType = typeof(List<>).MakeGenericType(new[] { itemType }); collectionList = (IList)Utility.QuickCreateInstance(listType); } collectionList.Add(clrItem); } } parameterValues.Add(Expression.Constant(collectionList, collectionList.GetType())); break; } } } return parameterValues.ToArray(); } }
/// <summary> /// Get the string representation of <see cref="ODataPath"/>. /// mainly translate Context Url path. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <returns>The string representation of the Context Url path.</returns> public static string ToContextUrlPathString(this ODataPath path) { StringBuilder pathString = new StringBuilder(); PathSegmentToContextUrlPathTranslator pathTranslator = PathSegmentToContextUrlPathTranslator.DefaultInstance; ODataPathSegment priorSegment = null; bool foundOperationWithoutPath = false; foreach (ODataPathSegment segment in path) { OperationSegment operationSegment = segment as OperationSegment; OperationImportSegment operationImportSegment = segment as OperationImportSegment; if (operationImportSegment != null) { IEdmOperationImport operationImport = operationImportSegment.OperationImports.FirstOrDefault(); Debug.Assert(operationImport != null); EdmPathExpression pathExpression = operationImport.EntitySet as EdmPathExpression; if (pathExpression != null) { Debug.Assert(priorSegment == null); // operation import is always the first segment? pathString.Append(pathExpression.Path); } else { pathString = operationImport.Operation.ReturnType != null ? new StringBuilder(operationImport.Operation.ReturnType.FullName()) : new StringBuilder("Edm.Untyped"); foundOperationWithoutPath = true; } } else if (operationSegment != null) { IEdmOperation operation = operationSegment.Operations.FirstOrDefault(); Debug.Assert(operation != null); if (operation.IsBound && priorSegment != null && operation.Parameters.First().Type.Definition == priorSegment.EdmType) { if (operation.EntitySetPath != null) { foreach (string pathSegment in operation.EntitySetPath.PathSegments.Skip(1)) { pathString.Append('/'); pathString.Append(pathSegment); } } else if (operationSegment.EntitySet != null) { // Is it correct to check EntitySet? pathString = new StringBuilder(operationSegment.EntitySet.Name); } else { pathString = operation.ReturnType != null ? new StringBuilder(operation.ReturnType.FullName()) : new StringBuilder("Edm.Untyped"); foundOperationWithoutPath = true; } } } else { if (foundOperationWithoutPath) { pathString = new StringBuilder(segment.EdmType.FullTypeName()); foundOperationWithoutPath = false; } else { pathString.Append(segment.TranslateWith(pathTranslator)); } } priorSegment = segment; } return(pathString.ToString().TrimStart('/')); }
public UnresolvedParameter(IEdmOperation declaringOperation, string name, EdmLocation location) : base(new EdmError[] { new EdmError(location, EdmErrorCode.BadUnresolvedParameter, Edm.Strings.Bad_UnresolvedParameter(name)) }) { this.Name = name ?? string.Empty; this.DeclaringOperation = declaringOperation; }
public override IDictionary <IEdmOperationParameter, SingleValueNode> ResolveOperationParameters(IEdmOperation operation, IDictionary <string, SingleValueNode> input) { Dictionary <IEdmOperationParameter, SingleValueNode> result = new Dictionary <IEdmOperationParameter, SingleValueNode>(EqualityComparer <IEdmOperationParameter> .Default); foreach (var item in input) { IEdmOperationParameter functionParameter = null; if (EnableCaseInsensitive) { functionParameter = ODataUriResolver.ResolveOpearationParameterNameCaseInsensitive(operation, item.Key); } else { functionParameter = operation.FindParameter(item.Key); } // ensure parameter name existis if (functionParameter == null) { throw new ODataException(Strings.ODataParameterWriterCore_ParameterNameNotFoundInOperation(item.Key, operation.Name)); } SingleValueNode newVal = item.Value; if (functionParameter.Type.IsEnum() && newVal is ConstantNode && newVal.TypeReference != null && newVal.TypeReference.IsString()) { string text = ((ConstantNode)item.Value).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = functionParameter.Type; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { newVal = new ConstantNode(val, text, typeRef); } } result.Add(functionParameter, newVal); } return(result); }
/// <summary> /// Create a <see cref="ODataParameterReader"/>. /// </summary> /// <param name="operationImport">The operation import whose parameters are being read.</param> /// <returns>The newly created <see cref="ODataParameterReader"/>.</returns> private ODataParameterReader CreateParameterReaderImplementation(IEdmOperationImport operationImport) { IEdmOperation operation = operationImport != null ? operationImport.Operation : null; return(new ODataJsonLightParameterReader(this, operation)); }
/// <summary> /// Creates an <see cref="ODataParameterWriter" /> to write a parameter payload. /// </summary> /// <param name="operation">The operation whose parameters will be written.</param> /// <returns>The created parameter writer.</returns> /// <remarks>The write must flush the output when it's finished (inside the last Write call).</remarks> public virtual ODataParameterWriter CreateODataParameterWriter(IEdmOperation operation) { throw this.CreatePayloadKindNotSupportedException(ODataPayloadKind.Error); }
public virtual ODataOperation CreateODataOperation(IEdmOperation operation, ResourceSetContext resourceSetContext, ODataSerializerContext writeContext) { if (operation == null) { throw Error.ArgumentNull(nameof(operation)); } if (resourceSetContext == null) { throw Error.ArgumentNull(nameof(resourceSetContext)); } if (writeContext == null) { throw Error.ArgumentNull(nameof(writeContext)); } ODataMetadataLevel metadataLevel = writeContext.MetadataLevel; IEdmModel model = writeContext.Model; if (metadataLevel != ODataMetadataLevel.Full) { return(null); } OperationLinkBuilder builder; builder = model.GetOperationLinkBuilder(operation); if (builder == null) { return(null); } Uri target = builder.BuildLink(resourceSetContext); if (target == null) { return(null); } Uri baseUri = new Uri(writeContext.Request.CreateODataLink(MetadataSegment.Instance)); Uri metadata = new Uri(baseUri, "#" + operation.FullName()); ODataOperation odataOperation; IEdmAction action = operation as IEdmAction; if (action != null) { odataOperation = new ODataAction(); } else { odataOperation = new ODataFunction(); } odataOperation.Metadata = metadata; // Always omit the title in minimal/no metadata modes. ODataResourceSerializer.EmitTitle(model, operation, odataOperation); // Omit the target in minimal/no metadata modes unless it doesn't follow conventions. if (metadataLevel == ODataMetadataLevel.Full || !builder.FollowsConventions) { odataOperation.Target = target; } return(odataOperation); }
/// <summary> /// Determines if the type of an expression is compatible with the provided type /// </summary> /// <param name="expression">The expression to assert the type of.</param> /// <param name="type">The type to assert the expression as.</param> /// <param name="context">The context paths are to be evaluated in.</param> /// <param name="matchExactly">A value indicating whether the expression must match the asserted type exactly, or simply be compatible.</param> /// <param name="discoveredErrors">Errors produced if the expression does not match the specified type.</param> /// <returns>A value indicating whether the expression is valid for the given type or not.</returns> /// <remarks>If the expression has an associated type, this function will check that it matches the expected type and stop looking further. /// If an expression claims a type, it must be validated that the type is valid for the expression. If the expression does not claim a type /// this method will attempt to check the validity of the expression itself with the asserted type.</remarks> public static bool TryCast(this IEdmExpression expression, IEdmTypeReference type, IEdmType context, bool matchExactly, out IEnumerable <EdmError> discoveredErrors) { EdmUtil.CheckArgumentNull(expression, "expression"); type = type.AsActualTypeReference(); // If we don't have a type to assert this passes vacuously. if (type == null || type.TypeKind() == EdmTypeKind.None) { discoveredErrors = Enumerable.Empty <EdmError>(); return(true); } switch (expression.ExpressionKind) { case EdmExpressionKind.IntegerConstant: case EdmExpressionKind.StringConstant: case EdmExpressionKind.BinaryConstant: case EdmExpressionKind.BooleanConstant: case EdmExpressionKind.DateTimeOffsetConstant: case EdmExpressionKind.DecimalConstant: case EdmExpressionKind.FloatingConstant: case EdmExpressionKind.GuidConstant: case EdmExpressionKind.DurationConstant: case EdmExpressionKind.DateConstant: case EdmExpressionKind.TimeOfDayConstant: IEdmPrimitiveValue primitiveValue = (IEdmPrimitiveValue)expression; if (primitiveValue.Type != null) { return(TestTypeReferenceMatch(primitiveValue.Type, type, expression.Location(), matchExactly, out discoveredErrors)); } return(TryCastPrimitiveAsType(primitiveValue, type, out discoveredErrors)); case EdmExpressionKind.Null: return(TryCastNullAsType((IEdmNullExpression)expression, type, out discoveredErrors)); case EdmExpressionKind.Path: case EdmExpressionKind.PropertyPath: case EdmExpressionKind.NavigationPropertyPath: case EdmExpressionKind.AnnotationPath: return(TryCastPathAsType((IEdmPathExpression)expression, type, context, matchExactly, out discoveredErrors)); case EdmExpressionKind.FunctionApplication: IEdmApplyExpression applyExpression = (IEdmApplyExpression)expression; if (applyExpression.AppliedFunction != null) { IEdmOperation operation = applyExpression.AppliedFunction as IEdmOperation; if (operation != null) { return(TestTypeReferenceMatch(operation.ReturnType, type, expression.Location(), matchExactly, out discoveredErrors)); } } // If we don't have the applied function we just assume that it will work. discoveredErrors = Enumerable.Empty <EdmError>(); return(true); case EdmExpressionKind.If: return(TryCastIfAsType((IEdmIfExpression)expression, type, context, matchExactly, out discoveredErrors)); case EdmExpressionKind.IsType: return(TestTypeReferenceMatch(EdmCoreModel.Instance.GetBoolean(false), type, expression.Location(), matchExactly, out discoveredErrors)); case EdmExpressionKind.Record: IEdmRecordExpression recordExpression = (IEdmRecordExpression)expression; if (recordExpression.DeclaredType != null) { return(TestTypeReferenceMatch(recordExpression.DeclaredType, type, expression.Location(), matchExactly, out discoveredErrors)); } return(TryCastRecordAsType(recordExpression, type, context, matchExactly, out discoveredErrors)); case EdmExpressionKind.Collection: IEdmCollectionExpression collectionExpression = (IEdmCollectionExpression)expression; if (collectionExpression.DeclaredType != null) { return(TestTypeReferenceMatch(collectionExpression.DeclaredType, type, expression.Location(), matchExactly, out discoveredErrors)); } return(TryCastCollectionAsType(collectionExpression, type, context, matchExactly, out discoveredErrors)); case EdmExpressionKind.Labeled: return(TryCast(((IEdmLabeledExpression)expression).Expression, type, context, matchExactly, out discoveredErrors)); case EdmExpressionKind.Cast: return(TestTypeReferenceMatch(((IEdmCastExpression)expression).Type, type, expression.Location(), matchExactly, out discoveredErrors)); case EdmExpressionKind.LabeledExpressionReference: return(TryCast(((IEdmLabeledExpressionReferenceExpression)expression).ReferencedLabeledExpression, type, out discoveredErrors)); case EdmExpressionKind.EnumMember: return(TryCastEnumConstantAsType((IEdmEnumMemberExpression)expression, type, matchExactly, out discoveredErrors)); default: discoveredErrors = new EdmError[] { new EdmError(expression.Location(), EdmErrorCode.ExpressionNotValidForTheAssertedType, Edm.Strings.EdmModel_Validator_Semantic_ExpressionNotValidForTheAssertedType) }; return(false); } }
/// <summary> /// Creates an <see cref="ODataParameterWriter" /> to write a parameter payload. /// </summary> /// <param name="operation">The operation whose parameters will be written.</param> /// <returns>The created parameter writer.</returns> /// <remarks>The write must flush the output when it's finished (inside the last Write call).</remarks> public override ODataParameterWriter CreateODataParameterWriter(IEdmOperation operation) { this.AssertSynchronous(); return(this.CreateODataParameterWriterImplementation(operation)); }
/// <summary> /// This is temp work around for $filter $orderby parameter expression which contains complex or collection /// like "Fully.Qualified.Namespace.CanMoveToAddresses(addresses=[{\"Street\":\"NE 24th St.\",\"City\":\"Redmond\"},{\"Street\":\"Pine St.\",\"City\":\"Seattle\"}])"; /// TODO: $filter $orderby parameter expression which contains nested complex or collection should NOT be supported in this way /// but should be parsed into token tree, and binded to node tree: parsedParameters.Select(p => this.bindMethod(p)); /// </summary> /// <param name="model">The model.</param> /// <param name="operation">IEdmFunction or IEdmOperation</param> /// <param name="parameterTokens">The tokens to bind.</param> /// <param name="enableCaseInsensitive">Whether to enable case-insensitive when resolving parameter name.</param> /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param> /// <returns>The FunctionParameterTokens with complex or collection values converted from string like "{...}", or "[..,..,..]".</returns> private static ICollection <FunctionParameterToken> HandleComplexOrCollectionParameterValueIfExists(IEdmModel model, IEdmOperation operation, ICollection <FunctionParameterToken> parameterTokens, bool enableCaseInsensitive, bool enableUriTemplateParsing = false) { ICollection <FunctionParameterToken> partiallyParsedParametersWithComplexOrCollection = new Collection <FunctionParameterToken>(); foreach (FunctionParameterToken paraToken in parameterTokens) { FunctionParameterToken funcParaToken; IEdmOperationParameter functionParameter = operation.FindParameter(paraToken.ParameterName); if (enableCaseInsensitive && functionParameter == null) { functionParameter = ODataUriResolver.ResolveOpearationParameterNameCaseInsensitive(operation, paraToken.ParameterName); // The functionParameter can not be null here, else this method won't be called. funcParaToken = new FunctionParameterToken(functionParameter.Name, paraToken.ValueToken); } else { funcParaToken = paraToken; } FunctionParameterAliasToken aliasToken = funcParaToken.ValueToken as FunctionParameterAliasToken; if (aliasToken != null) { aliasToken.ExpectedParameterType = functionParameter.Type; } LiteralToken valueToken = funcParaToken.ValueToken as LiteralToken; string valueStr = null; if (valueToken != null && (valueStr = valueToken.Value as string) != null && !string.IsNullOrEmpty(valueToken.OriginalText)) { var lexer = new ExpressionLexer(valueToken.OriginalText, true /*moveToFirstToken*/, false /*useSemicolonDelimiter*/, true /*parsingFunctionParameters*/); if (lexer.CurrentToken.Kind == ExpressionTokenKind.BracketedExpression || lexer.CurrentToken.Kind == ExpressionTokenKind.BracedExpression) { object result; UriTemplateExpression expression; if (enableUriTemplateParsing && UriTemplateParser.TryParseLiteral(lexer.CurrentToken.Text, functionParameter.Type, out expression)) { result = expression; } else if (!functionParameter.Type.IsStructured() && !functionParameter.Type.IsStructuredCollectionType()) { // ExpressionTokenKind.BracketedExpression means text like [1,2] // so now try convert it to collection type value: result = ODataUriUtils.ConvertFromUriLiteral(valueStr, ODataVersion.V4, model, functionParameter.Type); } else { // For complex & colleciton of complex directly return the raw string. partiallyParsedParametersWithComplexOrCollection.Add(funcParaToken); continue; } LiteralToken newValueToken = new LiteralToken(result, valueToken.OriginalText); FunctionParameterToken newFuncParaToken = new FunctionParameterToken(funcParaToken.ParameterName, newValueToken); partiallyParsedParametersWithComplexOrCollection.Add(newFuncParaToken); continue; } } partiallyParsedParametersWithComplexOrCollection.Add(funcParaToken); } return(partiallyParsedParametersWithComplexOrCollection); }
/// <summary> /// Asynchronously creates an <see cref="ODataParameterWriter" /> to write a parameter payload. /// </summary> /// <param name="operation">The operation import whose parameters will be written.</param> /// <returns>A running task for the created parameter writer.</returns> /// <remarks>The write must flush the output when it's finished (inside the last Write call).</remarks> public override Task <ODataParameterWriter> CreateODataParameterWriterAsync(IEdmOperation operation) { this.AssertAsynchronous(); return(TaskUtils.GetTaskForSynchronousOperation(() => this.CreateODataParameterWriterImplementation(operation))); }
/// <summary> /// Resolve operation's parameters. /// </summary> /// <param name="operation">Current operation for parameters.</param> /// <param name="input">A dictionary the parameter list.</param> /// <returns>A dictionary containing resolved parameters.</returns> public virtual IDictionary<IEdmOperationParameter, SingleValueNode> ResolveOperationParameters(IEdmOperation operation, IDictionary<string, SingleValueNode> input) { Dictionary<IEdmOperationParameter, SingleValueNode> result = new Dictionary<IEdmOperationParameter, SingleValueNode>(EqualityComparer<IEdmOperationParameter>.Default); foreach (var item in input) { IEdmOperationParameter functionParameter = null; if (EnableCaseInsensitive) { functionParameter = ResolveOpearationParameterNameCaseInsensitive(operation, item.Key); } else { functionParameter = operation.FindParameter(item.Key); } // ensure parameter name existis if (functionParameter == null) { throw new ODataException(Strings.ODataParameterWriterCore_ParameterNameNotFoundInOperation(item.Key, operation.Name)); } result.Add(functionParameter, item.Value); } return result; }
/// <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); }
/// <summary> /// Build a segment representing a call to an operation - action, function, or service operation. /// </summary> /// <param name="operation">A single operation import that this segment will represent.</param> /// <param name="parameters">The list of parameters supplied to this segment.</param> /// <param name="entitySet">The <see cref="IEdmEntitySetBase"/> containing the entities that this function returns.</param> public OperationSegment(IEdmOperation operation, IEnumerable <OperationSegmentParameter> parameters, IEdmEntitySetBase entitySet) : this(operation, entitySet) { this.parameters = new ReadOnlyCollection <OperationSegmentParameter>(parameters == null ? new List <OperationSegmentParameter>() : parameters.ToList()); }
internal bool CheckMethodsInBaseClass(IEdmStructuredType structuredType, IEdmOperation operation, Dictionary<IEdmStructuredType, List<IEdmOperation>> boundOperationsMap) { if (structuredType != null) { List<IEdmOperation> operations; if (boundOperationsMap.TryGetValue(structuredType, out operations)) { foreach (var op in operations) { var targetParameter = operation.Parameters.ToList(); var checkParameter = op.Parameters.ToList(); if (operation.Name == op.Name && targetParameter.Count == checkParameter.Count) { var areSame = true; for (var i = 1; i < targetParameter.Count; ++i) { var targetParameterType = targetParameter[i].Type; var checkParameterType = checkParameter[i].Type; if (!targetParameterType.Definition.Equals(checkParameterType.Definition) || targetParameterType.IsNullable != checkParameterType.IsNullable) { areSame = false; break; } } if (areSame) { return true; } } } } return CheckMethodsInBaseClass(structuredType.BaseType, operation, boundOperationsMap); } return false; }
private static void AddProcedureLinkBuilder(IEdmModel model, IEdmOperation operation, ProcedureConfiguration procedure) { if (procedure.BindingParameter.TypeConfiguration.Kind == EdmTypeKind.Entity) { ActionConfiguration actionConfiguration = procedure as ActionConfiguration; IEdmAction action = operation as IEdmAction; FunctionConfiguration functionConfiguration = procedure as FunctionConfiguration; IEdmFunction function = operation as IEdmFunction; if (actionConfiguration != null && actionConfiguration.GetActionLink() != null && action != null) { model.SetActionLinkBuilder( action, new ActionLinkBuilder(actionConfiguration.GetActionLink(), actionConfiguration.FollowsConventions)); } else if (functionConfiguration != null && functionConfiguration.GetFunctionLink() != null && function != null) { model.SetFunctionLinkBuilder( function, new FunctionLinkBuilder(functionConfiguration.GetFunctionLink(), functionConfiguration.FollowsConventions)); } } }
public override IDictionary<IEdmOperationParameter, SingleValueNode> ResolveOperationParameters( IEdmOperation operation, IDictionary<string, SingleValueNode> input) { return _stringAsEnum.ResolveOperationParameters(operation, input); }
private static bool TryParseOperationParameters(string functionName, string parenthesisExpression, IEdmOperation operation, out ICollection<OperationSegmentParameter> parsedSegementParameters, bool enableUriTemplateParsing = false) { ICollection<FunctionParameterToken> splitParameters; parsedSegementParameters = null; ODataUriParserConfiguration configuration = new ODataUriParserConfiguration(HardCodedTestModel.TestModel) { EnableUriTemplateParsing = enableUriTemplateParsing }; if (FunctionParameterParser.TrySplitOperationParameters(parenthesisExpression, configuration, out splitParameters)) { parsedSegementParameters = FunctionCallBinder.BindSegmentParameters(configuration, operation, splitParameters); return true; } return false; }
/// <summary> /// Generates a function link following the OData URL conventions for the function <paramref name="function"/> and bound to the /// collection of entity represented by <paramref name="resourceSetContext"/>. /// </summary> /// <param name="resourceSetContext">The <see cref="ResourceSetContext"/> representing the feed for which the function link needs to be generated.</param> /// <param name="function">The function for which the function link needs to be generated.</param> /// <returns>The generated function link following OData URL conventions.</returns> public static Uri GenerateFunctionLink(this ResourceSetContext resourceSetContext, IEdmOperation function) { if (resourceSetContext == null) { throw Error.ArgumentNull("resourceSetContext"); } if (function == null) { throw Error.ArgumentNull("function"); } IEdmOperationParameter bindingParameter = function.Parameters.FirstOrDefault(); if (bindingParameter == null || !bindingParameter.Type.IsCollection() || !((IEdmCollectionType)bindingParameter.Type.Definition).ElementType.IsEntity()) { throw Error.Argument("function", SRResources.FunctionNotBoundToCollectionOfEntity, function.Name); } return(GenerateFunctionLink(resourceSetContext, bindingParameter.Type, function, function.Parameters.Select(p => p.Name))); }
internal static void EmitTitle(IEdmModel model, IEdmOperation operation, ODataOperation odataAction) { // The title should only be emitted in full metadata. OperationTitleAnnotation titleAnnotation = model.GetOperationTitleAnnotation(operation); if (titleAnnotation != null) { odataAction.Title = titleAnnotation.Title; } else { odataAction.Title = operation.Name; } }
internal static Uri GenerateActionLink(this ResourceContext resourceContext, IEdmTypeReference bindingParameterType, IEdmOperation action) { Contract.Assert(resourceContext != null); if (resourceContext.NavigationSource is IEdmContainedEntitySet) { return(null); } IList <ODataPathSegment> actionPathSegments = resourceContext.GenerateBaseODataPathSegments(); // generate link with cast if the navigation source doesn't match the entity type the action is bound to. if (resourceContext.NavigationSource.EntityType() != bindingParameterType.Definition) { actionPathSegments.Add(new TypeSegment((IEdmEntityType)bindingParameterType.Definition, null)); // entity set can be null } OperationSegment operationSegment = new OperationSegment(new[] { action }, null); actionPathSegments.Add(operationSegment); string actionLink = resourceContext.InternalUrlHelper.CreateODataLink(actionPathSegments); return(actionLink == null ? null : new Uri(actionLink)); }