/// <summary> /// Sets the metadata builder for this operation. /// </summary> /// <param name="builder">The metadata builder used to compute values from model annotations.</param> /// <param name="metadataDocumentUri">The metadata document Uri.</param> internal void SetMetadataBuilder(ODataResourceMetadataBuilder builder, Uri metadataDocumentUri) { Debug.Assert(metadataDocumentUri != null, "metadataDocumentUri != null"); Debug.Assert(metadataDocumentUri.IsAbsoluteUri, "metadataDocumentUri.IsAbsoluteUri"); ODataJsonLightValidationUtils.ValidateOperation(metadataDocumentUri, this); this.metadataBuilder = builder; this.operationFullName = ODataJsonLightUtils.GetFullyQualifiedOperationName(metadataDocumentUri, UriUtils.UriToString(this.Metadata), out this.parameterNames); this.computedTitle = null; this.computedTarget = null; }
/// <summary> /// Creates the URI for a batch request operation. /// </summary> /// <param name="uri">The uri to process.</param> /// <param name="baseUri">The base Uri to use.</param> /// <param name="payloadUriConverter">An optional custom URL converter to convert URLs for writing them into the payload.</param> /// <returns>An URI to be used in the request line of a batch request operation. It uses the <paramref name="payloadUriConverter"/> /// first and falls back to the default URI building schema if the no URL resolver is specified or the URL resolver /// returns null. In the default scheme, the method either returns the specified <paramref name="uri"/> if it was absolute, /// or it's combination with the <paramref name="baseUri"/> if it was relative.</returns> /// <remarks> /// This method will fail if no custom resolution is implemented and the specified <paramref name="uri"/> is /// relative and there's no base URI available. /// </remarks> internal static Uri CreateOperationRequestUri(Uri uri, Uri baseUri, IODataPayloadUriConverter payloadUriConverter) { Debug.Assert(uri != null, "uri != null"); Uri resultUri; if (payloadUriConverter != null) { // The resolver returns 'null' if no custom resolution is desired. resultUri = payloadUriConverter.ConvertPayloadUri(baseUri, uri); if (resultUri != null) { return(resultUri); } } if (uri.IsAbsoluteUri) { resultUri = uri; } else { if (baseUri == null) { string errorMessage = UriUtils.UriToString(uri).StartsWith("$", StringComparison.Ordinal) ? Strings.ODataBatchUtils_RelativeUriStartingWithDollarUsedWithoutBaseUriSpecified(UriUtils.UriToString(uri)) : Strings.ODataBatchUtils_RelativeUriUsedWithoutBaseUriSpecified(UriUtils.UriToString(uri)); throw new ODataException(errorMessage); } resultUri = UriUtils.UriToAbsoluteUri(baseUri, uri); } return(resultUri); }
internal static IEdmNavigationProperty ValidateNestedResourceInfo( ODataNestedResourceInfo nestedResourceInfo, IEdmStructuredType declaringStructuredType, ODataPayloadKind?expandedPayloadKind, bool throwOnUndeclaredProperty) { Debug.Assert(nestedResourceInfo != null, "nestedResourceInfo != null"); Debug.Assert( !expandedPayloadKind.HasValue || expandedPayloadKind.Value == ODataPayloadKind.EntityReferenceLink || expandedPayloadKind.Value == ODataPayloadKind.Resource || expandedPayloadKind.Value == ODataPayloadKind.ResourceSet, "If an expanded payload kind is specified it must be resource, resource set or entity reference link."); // Navigation link must have a non-empty name if (string.IsNullOrEmpty(nestedResourceInfo.Name)) { throw new ODataException(Strings.ValidationUtils_LinkMustSpecifyName); } // If we write an entity reference link, don't validate the multiplicity of the IsCollection // property if it is 'false' (since we allow writing a singleton navigation link for // a collection navigation property in requests) nor the consistency of payload kind and metadata // (which is done separately in ODataWriterCore.CheckForNestedResourceInfoWithContent). bool isEntityReferenceLinkPayload = expandedPayloadKind == ODataPayloadKind.EntityReferenceLink; // true only if the expandedPayloadKind has a value and the value is 'Resource Set' bool isResourceSetPayload = expandedPayloadKind == ODataPayloadKind.ResourceSet; // Make sure the IsCollection property agrees with the payload kind for resource and resource set payloads Func <object, string> errorTemplate = null; if (!isEntityReferenceLinkPayload && nestedResourceInfo.IsCollection.HasValue && expandedPayloadKind.HasValue) { // For resource set/resource make sure the IsCollection property is set correctly. if (isResourceSetPayload != nestedResourceInfo.IsCollection.Value) { errorTemplate = expandedPayloadKind.Value == ODataPayloadKind.ResourceSet ? (Func <object, string>)Strings.WriterValidationUtils_ExpandedLinkIsCollectionFalseWithResourceSetContent : Strings.WriterValidationUtils_ExpandedLinkIsCollectionTrueWithResourceContent; } } IEdmNavigationProperty navigationProperty = null; if (errorTemplate == null && declaringStructuredType != null) { navigationProperty = ValidateNavigationPropertyDefined(nestedResourceInfo.Name, declaringStructuredType, throwOnUndeclaredProperty); if (navigationProperty != null) { bool isCollectionType = navigationProperty.Type.TypeKind() == EdmTypeKind.Collection; // Make sure the IsCollection property agrees with the metadata type for resource and resource set payloads if (nestedResourceInfo.IsCollection.HasValue && isCollectionType != nestedResourceInfo.IsCollection) { // Ignore the case where IsCollection is 'false' and we are writing an entity reference link // (see comment above) if (!(nestedResourceInfo.IsCollection == false && isEntityReferenceLinkPayload)) { errorTemplate = isCollectionType ? (Func <object, string>)Strings.WriterValidationUtils_ExpandedLinkIsCollectionFalseWithResourceSetMetadata : Strings.WriterValidationUtils_ExpandedLinkIsCollectionTrueWithResourceMetadata; } } // Make sure that the payload kind agrees with the metadata. // For entity reference links we check separately in ODataWriterCore.CheckForNestedResourceInfoWithContent. if (!isEntityReferenceLinkPayload && expandedPayloadKind.HasValue && isCollectionType != isResourceSetPayload) { errorTemplate = isCollectionType ? (Func <object, string>)Strings.WriterValidationUtils_ExpandedLinkWithResourcePayloadAndResourceSetMetadata : Strings.WriterValidationUtils_ExpandedLinkWithResourceSetPayloadAndResourceMetadata; } } } if (errorTemplate != null) { string uri = nestedResourceInfo.Url == null ? "null" : UriUtils.UriToString(nestedResourceInfo.Url); throw new ODataException(errorTemplate(uri)); } return(navigationProperty); }
/// <summary> /// Validates that the uri's reference of $requestId, if used, is one of the depends-on requests. /// The Uri can be either absolute or relative. /// Exception is thrown if the request Id reference is not found in the list of depends-on requests. /// </summary> /// <param name="uri">The Uri to validate the request Id reference.</param> /// <param name="dependsOnRequestIds">Enumeration of request Ids used to lookup the request Id reference.</param> /// <param name="baseUri">The baseUri used for validation.</param> internal static void ValidateReferenceUri(Uri uri, IEnumerable <string> dependsOnRequestIds, Uri baseUri) { Debug.Assert(uri != null, "uri != null"); if (UriUtils.UriToString(uri).IndexOf('$') == -1) { // uri does not use $requestId, return; } string relativePath = null; if (uri.IsAbsoluteUri) { if (baseUri == null) { // The absolution Uri can contain $ character followed by name of system resource // such as $all, $metadata, etc, along with an unspecified baseUri. In such cases there are // not reference Uri to validate. return; } string baseUriString = UriUtils.UriToString(baseUri); if (!uri.AbsoluteUri.StartsWith(baseUriString, StringComparison.Ordinal)) { throw new ODataException(Strings.ODataBatchReader_AbsoluteURINotMatchingBaseUri( uri.AbsoluteUri, baseUriString)); } relativePath = uri.AbsoluteUri.Substring(baseUriString.Length); } else { relativePath = UriUtils.UriToString(uri); } // Trim the starting forward slashes as needed. while (relativePath.StartsWith("/", StringComparison.Ordinal)) { relativePath = relativePath.Substring(1); } if (relativePath.Length > 0 && relativePath[0] == '$') { // If the relative path starts with '$', find the request id reference optionally ended by '/'. int idx = relativePath.IndexOf('/', 1); string referenceId = idx > 0 ? relativePath.Substring(1, idx - 1) : relativePath.Substring(1); // Validate that dependsOn contains the Id reference. // Note that the dependsOnRequestIds here is already flattened and consists of individual request // ids, therefore it should contain the request id referenced by the Uri. if (dependsOnRequestIds == null || !dependsOnRequestIds.Contains(referenceId)) { throw new ODataException(Strings.ODataBatchReader_ReferenceIdNotIncludedInDependsOn( referenceId, UriUtils.UriToString(uri), dependsOnRequestIds != null ? string.Join(",", dependsOnRequestIds.ToArray()) : "null")); } } }
/// <summary> /// Validates that message writer settings are correct. /// </summary> /// <param name="messageWriterSettings">The message writer settings to validate.</param> /// <param name="writingResponse">True if we are writing a response.</param> internal static void ValidateMessageWriterSettings(ODataMessageWriterSettings messageWriterSettings, bool writingResponse) { Debug.Assert(messageWriterSettings != null, "messageWriterSettings != null"); if (messageWriterSettings.BaseUri != null && !messageWriterSettings.BaseUri.IsAbsoluteUri) { throw new ODataException(Strings.WriterValidationUtils_MessageWriterSettingsBaseUriMustBeNullOrAbsolute(UriUtils.UriToString(messageWriterSettings.BaseUri))); } if (messageWriterSettings.HasJsonPaddingFunction() && !writingResponse) { throw new ODataException(Strings.WriterValidationUtils_MessageWriterSettingsJsonPaddingOnRequestMessage); } }