Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / RequestDescription.cs / 1305376 / RequestDescription.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a description of the request a client has submitted. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services { #region Namespaces. using System; using System.Collections; using System.Collections.Generic; using System.Data.Services.Providers; using System.Diagnostics; using System.Linq; #endregion Namespaces. ////// Query Counting Option /// internal enum RequestQueryCountOption { ///Do not count the result set None, ///Count and return value inline (together with data) Inline, ///Count and return value only (as integer) ValueOnly } ////// Use this class to describe the data request a client has /// submitted to the service. /// [DebuggerDisplay("RequestDescription={TargetSource} '{ContainerName}' -> {TargetKind} '{TargetResourceType}'")] internal class RequestDescription { ////// The default response version of the data service. If no version is set for a particular response /// The DataService will respond with this version (1.0) /// internal static readonly Version DataServiceDefaultResponseVersion = new Version(1, 0); #region Private fields. ////// Default set of known data service versions, currently 1.0 and 2.0 /// private static readonly Version[] KnownDataServiceVersions = new Version[] { new Version(1, 0), new Version(2, 0) }; ///The name of the container for results. private readonly string containerName; ///Root of the projection and expansion tree. ///If this is null - no projections or expansions were part of the request. private readonly RootProjectionNode rootProjectionNode; ///The MIME type for the requested resource, if specified. private readonly string mimeType; ///URI for the result (without the query component). private readonly Uri resultUri; ///SegmentInfo containing information about every segment in the uri private readonly SegmentInfo[] segmentInfos; ///Whether the container name should be used to name the result. private readonly bool usesContainerName; ///Query count option, whether to count the result set or not, and how private RequestQueryCountOption countOption; ///The value of the row count private long countValue; ///The minimum client version requirement private Version requireMinimumVersion; ///The server response version private Version responseVersion; ////// Max version of features used in the request. We need to distinguish between feature versions and response version since /// some new features (e.g. Server Projections) do not cause response version to be raised. /// private Version maxFeatureVersion; #endregion Private fields. ////// Initializes a new RequestDescription for a query specified by the /// request Uri. /// /// The kind of target for the request. /// The source for this target. /// URI to the results requested (with no query component). internal RequestDescription(RequestTargetKind targetKind, RequestTargetSource targetSource, Uri resultUri) { WebUtil.DebugEnumIsDefined(targetKind); Debug.Assert(resultUri != null, "resultUri != null"); Debug.Assert(resultUri.IsAbsoluteUri, "resultUri.IsAbsoluteUri(" + resultUri + ")"); SegmentInfo segment = new SegmentInfo(); segment.TargetKind = targetKind; segment.TargetSource = targetSource; segment.SingleResult = true; this.segmentInfos = new SegmentInfo[] { segment }; this.resultUri = resultUri; this.requireMinimumVersion = new Version(1, 0); this.responseVersion = DataServiceDefaultResponseVersion; this.maxFeatureVersion = new Version(1, 0); } ////// Initializes a new RequestDescription for a query specified by the /// request Uri. /// /// list containing information about each segment of the request uri /// Name of the container source. /// Whether the container name should be used to name the result. /// The MIME type for the requested resource, if specified. /// URI to the results requested (with no query component). internal RequestDescription( SegmentInfo[] segmentInfos, string containerName, bool usesContainerName, string mimeType, Uri resultUri) { Debug.Assert(segmentInfos != null && segmentInfos.Length != 0, "segmentInfos != null && segmentInfos.Length != 0"); Debug.Assert(resultUri != null, "resultUri != null"); Debug.Assert(resultUri.IsAbsoluteUri, "resultUri.IsAbsoluteUri(" + resultUri + ")"); this.segmentInfos = segmentInfos; this.containerName = containerName; this.usesContainerName = usesContainerName; this.mimeType = mimeType; this.resultUri = resultUri; this.requireMinimumVersion = new Version(1, 0); this.responseVersion = DataServiceDefaultResponseVersion; this.maxFeatureVersion = new Version(1, 0); } ///Initializes a new RequestDescription based on an existing one. /// Other description to base new description on. /// Query results for new request description. /// Projection segment describing the projections on the top level of the query. internal RequestDescription( RequestDescription other, IEnumerable queryResults, RootProjectionNode rootProjectionNode) { Debug.Assert( queryResults == null || other.SegmentInfos != null, "queryResults == null || other.SegmentInfos != null -- otherwise there isn't a segment in which to replace the query."); Debug.Assert( rootProjectionNode == null || queryResults != null, "rootProjectionNode == null || queryResults != null -- otherwise there isn't a query to execute and expand"); this.containerName = other.containerName; this.mimeType = other.mimeType; this.usesContainerName = other.usesContainerName; this.resultUri = other.resultUri; this.segmentInfos = other.SegmentInfos; this.rootProjectionNode = rootProjectionNode; this.countOption = other.countOption; this.SkipTokenExpressionCount = other.SkipTokenExpressionCount; this.SkipTokenProperties = other.SkipTokenProperties; this.countValue = other.countValue; this.requireMinimumVersion = other.requireMinimumVersion; this.responseVersion = other.responseVersion; this.maxFeatureVersion = other.maxFeatureVersion; if (queryResults == null) { this.segmentInfos = other.SegmentInfos; } else { int lastSegmentIndex = other.SegmentInfos.Length - 1; SegmentInfo lastSegmentInfo = other.SegmentInfos[lastSegmentIndex]; lastSegmentInfo.RequestEnumerable = queryResults; } } ///The name of the container for results. internal string ContainerName { [DebuggerStepThrough] get { return this.containerName; } } ///Root of the projection and expansion tree. internal RootProjectionNode RootProjectionNode { [DebuggerStepThrough] get { return this.rootProjectionNode; } } ///URI for the result (without the query component). internal Uri ResultUri { [DebuggerStepThrough] get { return this.resultUri; } } ///Returns the list containing the information about each segment that make up the request uri internal SegmentInfo[] SegmentInfos { [DebuggerStepThrough] get { return this.segmentInfos; } } ///The base query for the request, before client-specified composition. internal IEnumerable RequestEnumerable { get { return this.LastSegmentInfo.RequestEnumerable; } } ///Whether the result of this request is a single element. internal bool IsSingleResult { get { return this.LastSegmentInfo.SingleResult; } } ///The MIME type for the requested resource, if specified. internal string MimeType { [DebuggerStepThrough] get { return this.mimeType; } } ///The kind of target being requested. internal RequestTargetKind TargetKind { get { return this.LastSegmentInfo.TargetKind; } } ///The type of resource targetted by this request. internal ResourceType TargetResourceType { get { return this.LastSegmentInfo.TargetResourceType; } } ///The type of source for the request target. internal RequestTargetSource TargetSource { get { return this.LastSegmentInfo.TargetSource; } } ////// Returns the resource property on which this query is targeted /// internal ResourceProperty Property { get { return this.LastSegmentInfo.ProjectedProperty; } } ///Whether the container name should be used to name the result. internal bool UsesContainerName { [DebuggerStepThrough] get { return this.usesContainerName; } } ///Returns the last segment internal SegmentInfo LastSegmentInfo { get { return this.segmentInfos[this.segmentInfos.Length - 1]; } } ///Returns true if the request description refers to a link uri. Otherwise returns false. internal bool LinkUri { get { return (this.segmentInfos.Length >= 3 && this.segmentInfos[this.segmentInfos.Length - 2].TargetKind == RequestTargetKind.Link); } } ///Returns the request's counting options internal RequestQueryCountOption CountOption { get { return this.countOption; } set { this.countOption = value; } } ///Number of expressions in the $skiptoken for top level expression internal int SkipTokenExpressionCount { get; set; } ///Collection of properties in the $skiptoken for top level expression internal ICollectionSkipTokenProperties { get; set; } /// Returns the value of the row count internal long CountValue { get { return this.countValue; } set { this.countValue = value; } } ///The minimum client version requirement internal Version RequireMinimumVersion { get { return this.requireMinimumVersion; } } ///The server response version internal Version ResponseVersion { get { return this.responseVersion; } } ///Max version of features used in the user's request internal Version MaxFeatureVersion { get { return this.maxFeatureVersion; } } ////// Is the request for an IEnumerable<T> returning service operation. /// internal bool IsRequestForEnumServiceOperation { get { return this.TargetSource == RequestTargetSource.ServiceOperation && this.SegmentInfos[0].Operation.ResultKind == ServiceOperationResultKind.Enumeration; } } ////// Get the single result from the given segment info /// /// segmentInfo which contains the request query ///query result as returned by the IQueryable query internal static IEnumerator GetSingleResultFromEnumerable(SegmentInfo segmentInfo) { IEnumerator queryResults = WebUtil.GetRequestEnumerator(segmentInfo.RequestEnumerable); bool shouldDispose = true; try { WebUtil.CheckResourceExists(queryResults.MoveNext(), segmentInfo.Identifier); CheckQueryResult(queryResults.Current, segmentInfo); shouldDispose = false; return queryResults; } finally { // Dispose the Enumerator in case of error if (shouldDispose) { WebUtil.Dispose(queryResults); } } } ////// Checks query result. /// /// Query result to be checked. /// Segment details for the. internal static void CheckQueryResult(object result, SegmentInfo segmentInfo) { // e.g. /Customers(4) - if there is a direct reference to an entity, it should not be null. // e.g. $value also must not be null, since you are dereferencing the values // Any other case, having null is fine if (segmentInfo.IsDirectReference && result == null) { throw DataServiceException.CreateResourceNotFound(segmentInfo.Identifier); } IEnumerable enumerable; if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty && WebUtil.IsElementIEnumerable(result, out enumerable)) { throw DataServiceException.CreateSyntaxError( Strings.InvalidUri_OpenPropertiesCannotBeCollection(segmentInfo.Identifier)); } } /// /// Create a new request description from the given request description and new entity as the result. /// /// Existing request description. /// entity that needs to be the result of the new request. /// container to which the entity belongs to. ///a new instance of request description containing information about the given entity. internal static RequestDescription CreateSingleResultRequestDescription( RequestDescription description, object entity, ResourceSetWrapper container) { // Create a new request description for the results that will be returned. SegmentInfo segmentInfo = new SegmentInfo(); segmentInfo.RequestEnumerable = new object[] { entity }; segmentInfo.TargetKind = description.TargetKind; segmentInfo.TargetSource = description.TargetSource; segmentInfo.SingleResult = true; segmentInfo.ProjectedProperty = description.Property; segmentInfo.TargetResourceType = container != null ? container.ResourceType : null; segmentInfo.TargetContainer = container; segmentInfo.Identifier = description.LastSegmentInfo.Identifier; #if DEBUG segmentInfo.AssertValid(); #endif SegmentInfo[] segmentInfos = description.SegmentInfos; segmentInfos[segmentInfos.Length - 1] = segmentInfo; RequestDescription resultDescription = new RequestDescription( segmentInfos, container != null ? container.Name : null, description.UsesContainerName, description.MimeType, description.ResultUri); resultDescription.requireMinimumVersion = description.RequireMinimumVersion; resultDescription.responseVersion = description.ResponseVersion; resultDescription.maxFeatureVersion = description.MaxFeatureVersion; return resultDescription; } ////// Checks whether etag headers are allowed (both request and response) for this request. /// ETag request headers are mainly If-Match and If-None-Match headers /// ETag response header is written only when its valid to specify one of the above mentioned request headers. /// /// description about the request uri. ///true if If-Match or If-None-Match are allowed request headers for this request, otherwise false. internal static bool IsETagHeaderAllowed(RequestDescription description) { // IfMatch and IfNone match request headers are allowed and etag response header must be written // only when the request targets a single resource, which does not have $count and $links segment and there are no $expands query option specified. return description.IsSingleResult && description.CountOption != RequestQueryCountOption.ValueOnly && (description.RootProjectionNode == null || !description.RootProjectionNode.ExpansionsSpecified) && !description.LinkUri; } ////// Verify that the request version is a version we know. /// /// request version from the header ///returns true if the request version is known internal static bool IsKnownRequestVersion(Version requestVersion) { return KnownDataServiceVersions.Contains(requestVersion); } ////// Raise the feature version if the target container contains any type with FF mapped properties that is KeepInContent=false. /// /// service instance ///This RequestDescription instance internal RequestDescription UpdateAndCheckEpmFeatureVersion(IDataService service) { Debug.Assert(this.LastSegmentInfo != null, "this.LastSegmentInfo != null"); if (this.LinkUri) { // For $link operations we raise the feature version if either side of $link points to a set that // is not V1 compatible. ResourceSetWrapper leftSet; ResourceSetWrapper rightSet; this.GetLinkedResourceSets(out leftSet, out rightSet); Debug.Assert(leftSet != null, "leftSet != null"); Debug.Assert(rightSet != null, "rightSet != null"); this.UpdateAndCheckEpmFeatureVersion(leftSet, service); this.UpdateAndCheckEpmFeatureVersion(rightSet, service); } else { // The last segment might not be a resource. Trace backward to find the target entity resource. int resourceIndex = this.GetIndexOfTargetEntityResource(); // Not every request has a target resource. Service Operations for example can return just primitives. if (resourceIndex != -1) { ResourceSetWrapper resourceSet = this.SegmentInfos[resourceIndex].TargetContainer; Debug.Assert(resourceSet != null, "resourceSet != null"); this.UpdateAndCheckEpmFeatureVersion(resourceSet, service); } } return this; } ////// Raise the feature version if the given set contains any type with FF mapped properties that is KeepInContent=false. /// /// Resource set to test /// service instance ///This RequestDescription instance internal RequestDescription UpdateAndCheckEpmFeatureVersion(ResourceSetWrapper resourceSet, IDataService service) { Debug.Assert(resourceSet != null, "resourceSet != null"); Debug.Assert(service != null, "provider != null"); // For feature version we only look at the SET, and bump the version if it's not V1 compatible. We do this even if the // target kind is not Resource. So we could have request and response DSV be 1.0 while feature version be 2.0. if (!resourceSet.EpmIsV1Compatible(service.Provider)) { this.RaiseFeatureVersion(2, 0, service.Configuration); } return this; } ///Updates the response version based on response format and the target resource type /// text for Accepts header content required to infere response format /// data service provider instance ///The instance for which the update of response version happens internal RequestDescription UpdateEpmResponseVersion(string acceptTypesText, DataServiceProviderWrapper provider) { return this.UpdateEpmResponseVersion(acceptTypesText, this.LastSegmentInfo.TargetContainer, provider); } ///Updates the response version based on response format and given resource type /// text for Accepts header content required to infere response format /// resourceSet to check for friendly feeds presence /// data service provider instance ///The instance for which the update of response version happens internal RequestDescription UpdateEpmResponseVersion(string acceptTypesText, ResourceSetWrapper resourceSet, DataServiceProviderWrapper provider) { Debug.Assert(provider != null, "provider != null"); // Response will be 2.0 if any of the property in the types contained in the resource set has KeepInContent false if (this.TargetKind == RequestTargetKind.Resource) { Debug.Assert(resourceSet != null, "Must have valid resource set"); if (!resourceSet.EpmIsV1Compatible(provider) && !this.LinkUri) { // Friendly feeds must only bump the response version for Atom responses if (WebUtil.IsAtomMimeType(acceptTypesText)) { this.RaiseResponseVersion(2, 0); } } } return this; } ////// Returns the last segment info whose target request kind is resource /// ///The index of the parent resource internal int GetIndexOfTargetEntityResource() { Debug.Assert(this.segmentInfos.Length >= 1, "this.segmentInfos.Length >= 1"); int result = -1; if (this.LinkUri || this.CountOption == RequestQueryCountOption.ValueOnly) { return this.SegmentInfos.Length - 1; } for (int j = this.SegmentInfos.Length - 1; j >= 0; j--) { if (this.segmentInfos[j].TargetKind == RequestTargetKind.Resource || this.segmentInfos[j].HasKeyValues) { result = j; break; } } return result; } ////// Raise the minimum client version requirement for this request /// /// The major segment of the version /// The minor segment of the version internal void RaiseMinimumVersionRequirement(int major, int minor) { this.requireMinimumVersion = RaiseVersion(this.requireMinimumVersion, major, minor); // Each time we bump the request version we need to bump the max feature version as well. // Note that sometimes we need to bump max feature version even if request version is not raised. this.maxFeatureVersion = RaiseVersion(this.maxFeatureVersion, major, minor); } ////// Raise the response version for this request /// /// The major segment of the version /// The minor segment of the version [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811", Justification = "Will be used for other 2.0 server features")] internal void RaiseResponseVersion(int major, int minor) { this.responseVersion = RaiseVersion(this.responseVersion, major, minor); // Each time we bump the response version we need to bump the max feature version as well. // Note that sometimes we need to bump max feature version even if response version is not raised. this.maxFeatureVersion = RaiseVersion(this.maxFeatureVersion, major, minor); } ////// Raise the version for features used in the user's request /// /// The major segment of the version /// The minor segment of the version /// Data service configuration instance to validate the feature version. internal void RaiseFeatureVersion(int major, int minor, DataServiceConfiguration config) { this.maxFeatureVersion = RaiseVersion(this.maxFeatureVersion, major, minor); config.ValidateMaxProtocolVersion(this); } ////// If necessary raises version to the version requested by the user. /// /// Version to raise. /// The major segment of the new version /// The minor segment of the new version ///New version if the requested version is greater than the existing version. private static Version RaiseVersion(Version versionToRaise, int major, int minor) { if (major > versionToRaise.Major || (major == versionToRaise.Major && minor > versionToRaise.Minor)) { versionToRaise = new Version(major, minor); } return versionToRaise; } ////// Returns the resource sets on the left and right hand sides of $link. /// /// Resource set to the left of $link. /// Resource set to the right of $link. private void GetLinkedResourceSets(out ResourceSetWrapper leftSet, out ResourceSetWrapper rightSet) { Debug.Assert(this.LinkUri, "GetLinkedResourceSets should only be called if this is a $link request."); int idx = 0; for (; idx < this.segmentInfos.Length; idx++) { if (this.segmentInfos[idx].TargetKind == RequestTargetKind.Link) { break; } } Debug.Assert(idx > 0 && idx < this.segmentInfos.Length - 1, "idx > 0 && idx < this.segmentInfos.Length - 1"); leftSet = this.segmentInfos[idx - 1].TargetContainer; rightSet = this.segmentInfos[idx + 1].TargetContainer; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Module.cs
- SeparatorAutomationPeer.cs
- mediaeventargs.cs
- Hex.cs
- BindingContext.cs
- OleDbSchemaGuid.cs
- TextContainerChangedEventArgs.cs
- ImageInfo.cs
- ValueProviderWrapper.cs
- EntityClientCacheEntry.cs
- SHA1.cs
- ComboBoxAutomationPeer.cs
- InstanceNotReadyException.cs
- GridViewDeletedEventArgs.cs
- WebBrowserHelper.cs
- DecimalAnimation.cs
- WebRequestModuleElement.cs
- EditingCoordinator.cs
- RSATokenProvider.cs
- AttributeQuery.cs
- Assembly.cs
- CryptoConfig.cs
- ViewCellRelation.cs
- Adorner.cs
- WindowsTreeView.cs
- RayHitTestParameters.cs
- ContextMenu.cs
- SeparatorAutomationPeer.cs
- ScanQueryOperator.cs
- RSAPKCS1SignatureFormatter.cs
- PeerCustomResolverElement.cs
- XmlDataLoader.cs
- ScriptMethodAttribute.cs
- XNameTypeConverter.cs
- XmlCountingReader.cs
- ConstNode.cs
- MachineKeySection.cs
- CodeDomSerializationProvider.cs
- GPPOINT.cs
- InvalidStoreProtectionKeyException.cs
- PropertyNames.cs
- IListConverters.cs
- RemotingServices.cs
- Rule.cs
- RepeatButton.cs
- ImageButton.cs
- BinaryNode.cs
- PerformanceCountersElement.cs
- ProfileInfo.cs
- propertytag.cs
- HTMLTagNameToTypeMapper.cs
- EpmHelper.cs
- Size.cs
- HttpResponseHeader.cs
- PolicyException.cs
- Fonts.cs
- XmlILTrace.cs
- _NTAuthentication.cs
- ArrayTypeMismatchException.cs
- CodeVariableReferenceExpression.cs
- LinearKeyFrames.cs
- StorageFunctionMapping.cs
- CacheRequest.cs
- WriteableOnDemandStream.cs
- XmlAnyElementAttributes.cs
- CodeTypeOfExpression.cs
- IssuedTokenServiceCredential.cs
- DoubleLinkListEnumerator.cs
- MetadataConversionError.cs
- EventLogger.cs
- ObjectParameter.cs
- ButtonRenderer.cs
- StylusPlugInCollection.cs
- DataContractJsonSerializerOperationBehavior.cs
- DirectionalLight.cs
- DesignerActionPanel.cs
- ProgressiveCrcCalculatingStream.cs
- MemberNameValidator.cs
- RegisteredArrayDeclaration.cs
- DataService.cs
- JsonDataContract.cs
- Misc.cs
- ScrollChrome.cs
- DataRecordObjectView.cs
- BuiltInPermissionSets.cs
- Event.cs
- Sql8ConformanceChecker.cs
- MouseEventArgs.cs
- DataGridCell.cs
- SQLGuid.cs
- BitmapEffectGeneralTransform.cs
- CheckedListBox.cs
- BitmapMetadataEnumerator.cs
- Tuple.cs
- AccessKeyManager.cs
- AnchoredBlock.cs
- SafeWaitHandle.cs
- OutputCacheSettingsSection.cs
- Variant.cs
- WinFormsSecurity.cs