/// <summary> /// Translates resource bound expression tree to a URI. /// </summary> /// <param name='context'>Data context used to generate type names for types.</param> /// <param name="addTrailingParens">flag to indicate whether generated URI should include () if leaf is ResourceSet</param> /// <param name="e">The expression to translate</param> /// <param name="uri">uri</param> /// <param name="version">version for query</param> internal static void Translate(DataServiceContext context, bool addTrailingParens, Expression e, out Uri uri, out Version version) { var writer = new UriWriter(context); writer.Visit(e); string fullUri = writer.uriBuilder.ToString(); if (writer.alias.Any()) { if (fullUri.IndexOf(UriHelper.QUESTIONMARK) > -1) { fullUri += UriHelper.AMPERSAND; } else { fullUri += UriHelper.QUESTIONMARK; } foreach (var kv in writer.alias) { fullUri += kv.Key; fullUri += UriHelper.EQUALSSIGN; fullUri += kv.Value; fullUri += UriHelper.AMPERSAND; } fullUri = fullUri.Substring(0, fullUri.Length - 1); } uri = UriUtil.CreateUri(fullUri, UriKind.Absolute); version = writer.uriVersion; }
/// <summary>Loads the collection asynchronously by loading the results from the request Uri.</summary> /// <param name="requestUri">The request uri to download results from.</param> /// <remarks>This method uses the event-based async pattern. /// The method returns immediately without waiting for the query to complete. Then it calls the handler of the /// <see cref="LoadCompleted"/> event exactly once on the UI thread. The event will be raised regradless /// if the query succeeded or not. /// This class only support one asynchronous operation in flight.</remarks> public void LoadAsync(Uri requestUri) { Util.CheckArgumentNull(requestUri, "requestUri"); if (!this.IsTracking) { throw new InvalidOperationException(Strings.DataServiceCollection_OperationForTrackedOnly); } if (this.ongoingAsyncOperation != null) { throw new InvalidOperationException(Strings.DataServiceCollection_MultipleLoadAsyncOperationsAtTheSameTime); } DataServiceContext context = this.observer.Context; requestUri = UriUtil.CreateUri(context.BaseUri, requestUri); this.BeginLoadAsyncOperation( asyncCallback => context.BeginExecute <T>(requestUri, asyncCallback, null), asyncResult => { QueryOperationResponse <T> response = (QueryOperationResponse <T>)context.EndExecute <T>(asyncResult); this.Load(response); return(response); }); }
/// <summary>uri to edit the entity</summary> /// <param name="baseUriResolver">retrieves the baseUri to use for a given entity set.</param> /// <param name="queryLink">whether to return the query link or edit link</param> /// <returns>absolute uri which can be used to edit the entity</returns> internal Uri GetResourceUri(UriResolver baseUriResolver, bool queryLink) { // If the entity was inserted using the AddRelatedObject API if (this.ParentEntityDescriptor != null) { // This is the batch scenario, where the entity might not have been saved yet, and there is another operation // (for e.g. PUT $1/links/BestFriend or something). Hence we need to generate a Uri with the changeorder number. if (this.ParentEntityDescriptor.Identity == null) { Uri relativeReferenceUri = UriUtil.CreateUri("$" + this.ParentEntityDescriptor.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative); Uri absoluteReferenceUri = baseUriResolver.GetOrCreateAbsoluteUri(relativeReferenceUri); Uri requestUri = UriUtil.CreateUri(this.ParentProperty, UriKind.Relative); return(UriUtil.CreateUri(absoluteReferenceUri, requestUri)); } else { Debug.Assert(this.ParentEntityDescriptor.ParentEntityDescriptor == null, "This code assumes that parentChild relationships will only ever be one level deep"); Debug.Assert(this.ParentProperty != null, "ParentProperty != null"); LinkInfo linkInfo; if (this.ParentEntityDescriptor.TryGetLinkInfo(this.ParentProperty, out linkInfo)) { if (linkInfo.NavigationLink != null) { return(linkInfo.NavigationLink); } } return(UriUtil.CreateUri(this.ParentEntityDescriptor.GetLink(queryLink), this.GetLink(queryLink))); } } else { return(this.GetLink(queryLink)); } }
/// <summary> /// Translates resource bound expression tree to a URI. /// </summary> /// <param name='context'>Data context used to generate type names for types.</param> /// <param name="addTrailingParens">flag to indicate whether generated URI should include () if leaf is ResourceSet</param> /// <param name="e">The expression to translate</param> /// <param name="uri">uri</param> /// <param name="version">version for query</param> internal static void Translate(DataServiceContext context, bool addTrailingParens, Expression e, out Uri uri, out Version version) { var writer = new UriWriter(context); writer.leafResource = addTrailingParens ? (e as QueryableResourceExpression) : null; writer.Visit(e); uri = UriUtil.CreateUri(writer.uriBuilder.ToString(), UriKind.Absolute); version = writer.uriVersion; }
/// <summary> /// If necessary will create an absolute uri by combining the BaseUri and requestUri /// </summary> /// <param name="requestUri">The uri specified by the user</param> /// <returns>An absolute Uri based on the requestUri and if nessesary the BaseUri</returns> internal Uri GetOrCreateAbsoluteUri(Uri requestUri) { Util.CheckArgumentNull(requestUri, "requestUri"); if (!requestUri.IsAbsoluteUri) { return(UriUtil.CreateUri(this.GetBaseUriWithSlash(() => Strings.Context_RequestUriIsRelativeBaseUriRequired), requestUri)); } return(requestUri); }
/// <summary> /// Creates a ODataRequestMessage for batch request. /// </summary> /// <returns>Returns an instance of ODataRequestMessage for the batch request.</returns> private ODataRequestMessageWrapper CreateBatchRequest() { Uri requestUri = UriUtil.CreateUri(this.RequestInfo.BaseUriResolver.GetBaseUriWithSlash(), UriUtil.CreateUri("$batch", UriKind.Relative)); HeaderCollection headers = new HeaderCollection(); headers.SetRequestVersion(Util.ODataVersion4, this.RequestInfo.MaxProtocolVersionAsVersion); headers.SetHeader(XmlConstants.HttpContentType, CreateMultiPartMimeContentType()); this.RequestInfo.Format.SetRequestAcceptHeaderForBatch(headers); return(this.CreateTopLevelRequest(XmlConstants.HttpMethodPost, requestUri, headers, this.RequestInfo.HttpStack, null /*descriptor*/)); }
/// <summary> /// Appends to create the entity instance URI for the specified <paramref name="entityInstance"/>. /// </summary> /// <param name="baseUri">The URI to append to</param> /// <param name="entityInstance">The entity instance to use.</param> /// <returns> /// The entity instance URI. /// </returns> internal override Uri BuildEntityInstanceUri(Uri baseUri, IEdmStructuredValue entityInstance) { var builder = new StringBuilder(); if (baseUri != null) { builder.Append(UriUtil.UriToString(baseUri)); } this.conventions.AppendKeyExpression(entityInstance, builder); return(UriUtil.CreateUri(builder.ToString(), UriKind.RelativeOrAbsolute)); }
/// <summary> /// Validates the value of the 'Location' response header. /// </summary> /// <param name="location">the value as seen on the wire.</param> /// <returns>an absolute Uri</returns> internal static Uri ValidateLocationHeader(string location) { // We used to call the Uri constructor with the kind set to Absolute. // Hence now checking for the absoluteness. Uri locationUri = UriUtil.CreateUri(location, UriKind.RelativeOrAbsolute); if (!locationUri.IsAbsoluteUri) { throw Error.InvalidOperation(Strings.Context_LocationHeaderExpectsAbsoluteUri); } return locationUri; }
/// <summary> /// Returns a slash terminated Uri. /// /// Will be the passed in one if it is already slash terminated, or a new one /// if the passed in one is not slash terminated. /// </summary> /// <param name="uri">The Uri to be slash terminated</param> /// <returns>A slash terminated version of the passed in Uri.</returns> private static Uri ForceSlashTerminatedUri(Uri uri) { Debug.Assert(uri.IsAbsoluteUri, "the uri must be an absolute uri"); Debug.Assert(String.IsNullOrEmpty(uri.Query), "the uri must not have any query"); Debug.Assert(String.IsNullOrEmpty(uri.Fragment), "the uri must not have any fragment"); string uriString = UriUtil.UriToString(uri); if (uriString[uriString.Length - 1] != '/') { return(UriUtil.CreateUri(uriString + "/", UriKind.Absolute)); } return(uri); }
/// <summary>base uri with no trailing slash</summary> /// <param name="entitySetName">the name of the entitSet whose Uri will be retrieved.</param> /// <returns>the baseUri ended with a slash for the entitySetName passed in.</returns> internal Uri GetEntitySetUri(string entitySetName) { Uri resolved = this.GetEntitySetUriFromResolver(entitySetName); if (resolved != null) { return(ForceNonSlashTerminatedUri(resolved)); } if (this.baseUriWithSlash != null) { return(UriUtil.CreateUri(this.baseUriWithSlash, UriUtil.CreateUri(entitySetName, UriKind.Relative))); } throw Error.InvalidOperation(Strings.Context_ResolveEntitySetOrBaseUriRequired(entitySetName)); }
/// <summary> /// Validates the value of the identity, the atom:id or OData-EntityId /// </summary> /// <param name="identityValue">The value to validate</param> /// <returns>an absolute Uri</returns> internal static Uri ValidateIdentityValue(string identityValue) { Uri identity; try { // here we could just assign idText to Identity // however we used to check for AbsoluteUri, thus we need to // convert string to Uri and check for absoluteness identity = UriUtil.CreateUri(identityValue, UriKind.Absolute); } catch (FormatException) { throw Error.InvalidOperation(Strings.Context_TrackingExpectsAbsoluteUri); } return(identity); }
/// <summary> /// Try and get the navigation link. If the navigation link is not specified, then its used the self link of the entity and /// appends the property name. /// </summary> /// <param name="baseUriResolver">retrieves the appropriate baseUri for a given entitySet.</param> /// <param name="property">ClientProperty instance representing the navigation property.</param> /// <returns>returns the uri for the given link. If the link is not present, its uses the self link of the current entity and appends the navigation property name.</returns> internal Uri GetNavigationLink(UriResolver baseUriResolver, ClientPropertyAnnotation property) { LinkInfo linkInfo = null; Uri uri = null; if (this.TryGetLinkInfo(property.PropertyName, out linkInfo)) { uri = linkInfo.NavigationLink; } if (uri == null) { Uri relativeUri = UriUtil.CreateUri(property.PropertyName, UriKind.Relative); uri = UriUtil.CreateUri(this.GetResourceUri(baseUriResolver, true /*queryLink*/), relativeUri); } return(uri); }
/// <summary> /// Writes an entity reference link. /// </summary> /// <param name="binding">The link descriptor.</param> /// <param name="requestMessage">The request message used for writing the payload.</param> internal void WriteEntityReferenceLink(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage) #endif { using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, false /*isParameterPayload*/)) { EntityDescriptor targetResource = this.requestInfo.EntityTracker.GetEntityDescriptor(binding.Target); Uri targetReferenceLink = targetResource.GetLatestIdentity(); if (targetReferenceLink == null) { #if DEBUG Debug.Assert(isBatch, "we should be cross-referencing entities only in batch scenarios"); #endif targetReferenceLink = UriUtil.CreateUri("$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative); } ODataEntityReferenceLink referenceLink = new ODataEntityReferenceLink(); referenceLink.Url = targetReferenceLink; messageWriter.WriteEntityReferenceLink(referenceLink); } }
/// <summary> /// In V1, we used to not support self links. Hence we used to use edit links as self links. /// IN V2, we are adding support for self links. But if there are not specified, we need to /// fall back on the edit link. /// </summary> /// <param name="queryLink">whether to get query link or the edit link.</param> /// <returns>the query or the edit link, as specified in the <paramref name="queryLink"/> parameter.</returns> private Uri GetLink(bool queryLink) { // If asked for a self link and self-link is present, return self link Uri link; if (queryLink && this.SelfLink != null) { return(this.SelfLink); } // otherwise return edit link if present. if ((link = this.GetLatestEditLink()) != null) { return(link); } if (this.State != EntityStates.Added) { throw new ArgumentNullException(Strings.EntityDescriptor_MissingSelfEditLink(this.identity)); } else { Debug.Assert(this.TransientEntityDescriptor == null, "The transient entity container must be null, when the entity is in added state"); // If the entity is in added state, and either the parent property or the addToUri must be non-null Debug.Assert(this.addToUri != null || !String.IsNullOrEmpty(this.ParentPropertyForInsert), "For entities in added state, parentProperty or addToUri must be specified"); if (this.addToUri != null) { return(this.addToUri); } else { return(UriUtil.CreateUri(this.ParentPropertyForInsert, UriKind.Relative)); } } }
/// <summary> /// Create an instance of primitive type from a string representation /// </summary> /// <param name="text">The string representation</param> /// <returns>An instance of primitive type</returns> internal override object Parse(String text) { return(UriUtil.CreateUri(text, UriKind.RelativeOrAbsolute)); }