Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Providers / DataServiceStreamProviderWrapper.cs / 1305376 / DataServiceStreamProviderWrapper.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// This wrapper class forwards calls to the underlying IDataServiceStreamProvider // instance and validates responses from it. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Providers { using System; using System.IO; using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Data.Services; ////// Wrapper class to forward calls to the underlying IDataServiceStreamProvider instance and validates responses from it. /// internal class DataServiceStreamProviderWrapper { #region Private Fields ////// Default buffer size used for stream copy. /// private const int DefaultBufferSize = 64 * 1024; ////// Stream provider instance /// private IDataServiceStreamProvider streamProvider; ////// Data service instance /// private IDataService dataService; #endregion Private Fields #region Constructor ////// Constructs the wrapper class for IDataServiceStreamProvider /// /// Data service instance public DataServiceStreamProviderWrapper(IDataService dataService) { Debug.Assert(dataService != null, "dataService != null"); this.dataService = dataService; } #endregion Constructor #region Public Properties ////// Gets buffer size the data service will use when reading from read stream or writing to the write stream. /// If the size is less than or equals to 0, the default of 64k will be used. /// public int StreamBufferSize { get { int size = this.StreamProvider.StreamBufferSize; return size > 0 ? size : DataServiceStreamProviderWrapper.DefaultBufferSize; } } #endregion Public Properties #region Private Properties ////// Asks the service for an IDataServiceStreamProvider implementation /// private IDataServiceStreamProvider StreamProvider { get { if (this.streamProvider == null) { this.streamProvider = LoadStreamProvider(this.dataService); Debug.Assert(this.streamProvider != null, "this.streamProvider != null"); } return this.streamProvider; } } #endregion Private Properties #region Internal Methods ////// Take the given Media Link Entry uri, and construct the default Edit Media Uri. /// /// Uri to the Media Link Entry. ///Uri to the Media Resource. internal static string GetStreamEditMediaUri(string mediaLinkEntryUri) { Debug.Assert(!string.IsNullOrEmpty(mediaLinkEntryUri), "!string.IsNullOrEmpty(mediaLinkEntryUri)"); string result = mediaLinkEntryUri; if (!result.EndsWith(XmlConstants.UriValueSegment, StringComparison.Ordinal)) { if (!result.EndsWith("/", StringComparison.Ordinal)) { result += "/"; } result += XmlConstants.UriValueSegment; } return result; } ////// Asks the data service for a stream provider instance. Throw if none is implemented. /// /// data service instance ///stream provider instance internal static IDataServiceStreamProvider LoadStreamProvider(IDataService dataService) { IDataServiceStreamProvider streamProvider = dataService.Provider.GetService(dataService); if (streamProvider == null) { throw new DataServiceException(500, Strings.DataServiceStreamProviderWrapper_MustImplementIDataServiceStreamProviderToSupportStreaming); } return streamProvider; } /// /// This method is invoked by the data services framework to retrieve the default stream associated /// with the Entity Type specified by the /// The stream returned should be the default stream associated with this entity. /// A reference to the context for the current operation. ///parameter. /// Note that we set the response ETag in the host object before we return. /// A valid stream the data service use to query / read a streamed BLOB which is associated with the internal Stream GetReadStream(object entity, DataServiceOperationContext operationContext) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); string etagFromHeader; bool? checkETagForEquality; DataServiceStreamProviderWrapper.GetETagFromHeaders(operationContext, out etagFromHeader, out checkETagForEquality); Debug.Assert( string.IsNullOrEmpty(etagFromHeader) && !checkETagForEquality.HasValue || !string.IsNullOrEmpty(etagFromHeader) && checkETagForEquality.HasValue, "etag and checkETagForEquality parameters must both be set or not set at the same time."); Stream readStream = null; try { readStream = InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.GetReadStream", () => this.StreamProvider.GetReadStream(entity, etagFromHeader, checkETagForEquality, operationContext), operationContext); } catch (DataServiceException e) { if (e.StatusCode == (int)System.Net.HttpStatusCode.NotModified) { // For status code 304, we MUST set the etag value. Our Error handler will translate // DataServiceException(304) to a normal response with status code 304 and an empty message-body. #if DEBUG WebUtil.WriteETagValueInResponseHeader(null, this.GetStreamETag(entity, operationContext), operationContext.Host); #else WebUtil.WriteETagValueInResponseHeader(this.GetStreamETag(entity, operationContext), operationContext.Host); #endif } throw; } try { if (readStream == null || !readStream.CanRead) { throw new InvalidOperationException(Strings.DataService_InvalidStreamFromGetReadStream); } // GetStreamETag can throw and we need to catch and dispose the stream. #if DEBUG WebUtil.WriteETagValueInResponseHeader(null, this.GetStreamETag(entity, operationContext), operationContext.Host); #else WebUtil.WriteETagValueInResponseHeader(this.GetStreamETag(entity, operationContext), operationContext.Host); #endif } catch { WebUtil.Dispose(readStream); throw; } return readStream; } ///. /// This method is invoked by the data services framework whenever an insert or update operation is /// being processed for the stream associated with the Entity Type specified via the entity parameter. /// /// The stream returned should be the default stream associated with this entity. /// A reference to the context for the current operation. ///A valid stream the data service use to write the contents of a BLOB which is associated with internal Stream GetWriteStream(object entity, DataServiceOperationContext operationContext) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); string etag; bool? checkETagForEquality; DataServiceStreamProviderWrapper.GetETagFromHeaders(operationContext, out etag, out checkETagForEquality); Debug.Assert( string.IsNullOrEmpty(etag) && !checkETagForEquality.HasValue || !string.IsNullOrEmpty(etag) && checkETagForEquality.HasValue, "etag and checkETagForEquality parameters must both be set or not set at the same time."); Stream writeStream = InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.GetWriteStream", () => this.StreamProvider.GetWriteStream(entity, etag, checkETagForEquality, operationContext), operationContext); if (writeStream == null || !writeStream.CanWrite) { WebUtil.Dispose(writeStream); throw new InvalidOperationException(Strings.DataService_InvalidStreamFromGetWriteStream); } return writeStream; } ///. /// This method is invoked by the data services framework whenever an delete operation is being processed for the stream associated with /// the Entity Type specified via the entity parameter. /// /// The stream deleted should be the default stream associated with this entity. /// A reference to the context for the current operation. internal void DeleteStream(object entity, DataServiceOperationContext operationContext) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.DeleteStream", () => { this.StreamProvider.DeleteStream(entity, operationContext); return true; }, operationContext); } ////// This method is invoked by the data services framework to obtain the IANA content type (aka media type) of the stream associated /// with the specified entity. This metadata is needed when constructing the payload for the Media Link Entry associated with the /// stream (aka Media Resource) or setting the Content-Type HTTP response header. /// /// The entity associated with the stream for which the content type is to be obtained /// A reference to the context for the current operation. ///Valid Content-Type string for the stream associated with the entity internal string GetStreamContentType(object entity, DataServiceOperationContext operationContext) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); string contentType = InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.GetStreamContentType", () => this.StreamProvider.GetStreamContentType(entity, operationContext), operationContext); if (string.IsNullOrEmpty(contentType)) { throw new InvalidOperationException(Strings.DataServiceStreamProviderWrapper_GetStreamContentTypeReturnsEmptyOrNull); } return contentType; } ////// This method is invoked by the data services framework to obtain the URI clients should use when making retrieve (ie. GET) /// requests to the stream(ie. Media Resource). This metadata is needed when constructing the payload for the Media Link Entry /// associated with the stream (aka Media Resource). /// /// If IDataServiceStreamProvider.GetReadStreamUri returns a valid Uri, we return that as the Uri to the Media Resource. /// Otherwise we take the given Media Link Entry uri, and construct the default Media Resource Uri. /// /// The entity associated with the stream for which a “read stream” is to be obtained /// A reference to the context for the current operation. /// Uri to the Media Link Entry. ///The URI clients should use when making retrieve (ie. GET) requests to the stream(ie. Media Resource). internal Uri GetReadStreamUri(object entity, DataServiceOperationContext operationContext, string mediaLinkEntryUri) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); Uri readStreamUri = InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.GetReadStreamUri", () => this.StreamProvider.GetReadStreamUri(entity, operationContext), operationContext); if (readStreamUri != null) { if (!readStreamUri.IsAbsoluteUri) { throw new InvalidOperationException(Strings.DataServiceStreamProviderWrapper_GetReadStreamUriMustReturnAbsoluteUriOrNull); } else { return readStreamUri; } } else { return new Uri(DataServiceStreamProviderWrapper.GetStreamEditMediaUri(mediaLinkEntryUri), UriKind.RelativeOrAbsolute); } } ////// This method is invoked by the data services framework to obtain the ETag of the stream associated with the entity specified. /// This metadata is needed when constructing the payload for the Media Link Entry associated with the stream (aka Media Resource) /// as well as to be used as the value of the ETag HTTP response header. /// /// The entity associated with the stream for which an etag is to be obtained /// A reference to the context for the current operation. ///ETag of the stream associated with the entity specified internal string GetStreamETag(object entity, DataServiceOperationContext operationContext) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); string etag = InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.GetStreamETag", () => this.StreamProvider.GetStreamETag(entity, operationContext), operationContext); if (!WebUtil.IsETagValueValid(etag, true)) { throw new InvalidOperationException(Strings.DataServiceStreamProviderWrapper_GetStreamETagReturnedInvalidETagFormat); } return etag; } ////// This method is invoked by the data services framework when a request is received to insert into an Entity Set with an associated /// Entity Type hierarchy that has > 1 Entity Type and >= 1 Entity Type which is tagged as an MLE (ie. includes a stream). /// /// Fully qualified name entity set name. /// Data service instance. ////// Namespace qualified type name which represents the type the Astoria framework should instantiate to create the MLE associated /// with the BLOB/MR being inserted. /// internal ResourceType ResolveType(string entitySetName, IDataService service) { DataServiceOperationContext operationContext = service.OperationContext; Debug.Assert(operationContext != null, "operationContext != null"); string resourceTypeName = InvokeApiCallAndValidateHeaders("IDataServiceStreamProvider.ResolveType", () => this.StreamProvider.ResolveType(entitySetName, operationContext), operationContext); if (string.IsNullOrEmpty(resourceTypeName)) { throw new InvalidOperationException(Strings.DataServiceStreamProviderWrapper_ResolveTypeMustReturnValidResourceTypeName); } ResourceType resourceType = service.Provider.TryResolveResourceType(resourceTypeName); if (resourceType == null) { throw new InvalidOperationException(Strings.DataServiceStreamProviderWrapper_ResolveTypeMustReturnValidResourceTypeName); } return resourceType; } ////// Gets the ETag, ReadStreamUri and ContentType of the stream /// /// MLE instance /// context of the current operation /// Uri to the MLE /// returns the etag for the stream /// returns the read stream uri /// returns the content type of the stream internal void GetStreamDescription(object entity, DataServiceOperationContext operationContext, string mediaLinkEntryUri, out string etag, out Uri readStreamUri, out string contentType) { Debug.Assert(entity != null, "entity != null"); Debug.Assert(operationContext != null, "operationContext != null"); // Call order is part of our contract, do not change it. etag = this.GetStreamETag(entity, operationContext); readStreamUri = this.GetReadStreamUri(entity, operationContext, mediaLinkEntryUri); contentType = this.GetStreamContentType(entity, operationContext); } ////// Dispose the stream provider instance /// internal void DisposeProvider() { if (this.streamProvider != null) { WebUtil.Dispose(this.streamProvider); this.streamProvider = null; } } #endregion Public Methods #region Private Methods ////// Get the ETag header value from the request headers. /// /// A reference to the context for the current operation. /// /// The etag value sent by the client (as the value of an If[-None-]Match header) as part of the HTTP request sent to the data service /// This parameter will be null if no If[-None-]Match header was present /// /// /// True if an value of the etag parameter was sent to the server as the value of an If-Match HTTP request header /// False if an value of the etag parameter was sent to the server as the value of an If-None-Match HTTP request header /// null if the HTTP request for the stream was not a conditional request /// private static void GetETagFromHeaders(DataServiceOperationContext operationContext, out string etag, out bool? checkETagForEquality) { Debug.Assert(operationContext != null, "operationContext != null"); Debug.Assert(operationContext.Host != null, "operationContext.Host != null"); DataServiceHostWrapper host = operationContext.Host; Debug.Assert(string.IsNullOrEmpty(host.RequestIfMatch) || string.IsNullOrEmpty(host.RequestIfNoneMatch), "IfMatch and IfNoneMatch should not be both set."); if (string.IsNullOrEmpty(host.RequestIfMatch) && string.IsNullOrEmpty(host.RequestIfNoneMatch)) { etag = null; checkETagForEquality = null; } else if (!string.IsNullOrEmpty(host.RequestIfMatch)) { etag = host.RequestIfMatch; checkETagForEquality = true; } else { etag = host.RequestIfNoneMatch; checkETagForEquality = false; } } ////// Invokes an API call and verifies the response Content-Type and ETag headers are not being modified by the API call. /// ///Return type from the API call /// API name /// Delegate to be called /// A reference to the context for the current operation. ///Returns the result from the api call private static T InvokeApiCallAndValidateHeaders(string methodName, Func apiCall, DataServiceOperationContext operationContext) { Debug.Assert(!string.IsNullOrEmpty(methodName), "!string.IsNullOrEmpty(methodName)"); Debug.Assert(operationContext != null, "operationContext != null"); Debug.Assert(apiCall != null, "apiCall != null"); string responseContentType = operationContext.Host.ResponseContentType; string responseETag = operationContext.Host.ResponseETag; T result = apiCall(); if (operationContext.Host.ResponseContentType != responseContentType || operationContext.Host.ResponseETag != responseETag) { throw new InvalidOperationException(Strings.DataServiceStreamProviderWrapper_MustNotSetContentTypeAndEtag(methodName)); } return result; } #endregion Private Methods } } // 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
- TypedTableBase.cs
- DesignerHierarchicalDataSourceView.cs
- DataGridPagingPage.cs
- PlaceHolder.cs
- HttpConfigurationSystem.cs
- ExtensionSimplifierMarkupObject.cs
- ExceptionHandler.cs
- Descriptor.cs
- _ListenerRequestStream.cs
- RegexRunnerFactory.cs
- DataGridItem.cs
- Grant.cs
- QilDataSource.cs
- Nodes.cs
- ObjectContext.cs
- BufferedWebEventProvider.cs
- WsiProfilesElement.cs
- NumberFormatInfo.cs
- propertytag.cs
- ObjectListCommandsPage.cs
- CompositionAdorner.cs
- FlowLayoutSettings.cs
- BufferAllocator.cs
- DynamicPropertyHolder.cs
- XamlRtfConverter.cs
- SkinBuilder.cs
- ScalarConstant.cs
- WebControlToolBoxItem.cs
- ImageDrawing.cs
- HitTestFilterBehavior.cs
- ApplicationGesture.cs
- GeneralTransform3DTo2DTo3D.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- COAUTHINFO.cs
- NotImplementedException.cs
- TemplateColumn.cs
- FixedPosition.cs
- EntitySetBaseCollection.cs
- MediaContext.cs
- SparseMemoryStream.cs
- BitmapEffectOutputConnector.cs
- DecimalConverter.cs
- SoapExtensionStream.cs
- ParamArrayAttribute.cs
- brushes.cs
- ContentElement.cs
- CompleteWizardStep.cs
- ToolboxItemCollection.cs
- Schema.cs
- TdsRecordBufferSetter.cs
- XXXInfos.cs
- X509WindowsSecurityToken.cs
- CounterCreationDataCollection.cs
- TabControl.cs
- SQLGuidStorage.cs
- AutomationEvent.cs
- ToolStripItemRenderEventArgs.cs
- Drawing.cs
- JavaScriptObjectDeserializer.cs
- WpfWebRequestHelper.cs
- InboundActivityHelper.cs
- GacUtil.cs
- OdbcConnectionHandle.cs
- XPathAncestorQuery.cs
- CreatingCookieEventArgs.cs
- UserInitiatedNavigationPermission.cs
- MiniCustomAttributeInfo.cs
- DelegatingConfigHost.cs
- ZoneButton.cs
- Transaction.cs
- FtpWebResponse.cs
- WebZone.cs
- PartialTrustHelpers.cs
- XmlIlTypeHelper.cs
- LinkedList.cs
- FolderNameEditor.cs
- EventLogPermissionEntry.cs
- TreeBuilderBamlTranslator.cs
- FontStyles.cs
- ActiveXHelper.cs
- HuffModule.cs
- MatrixTransform3D.cs
- ConnectionStringsExpressionBuilder.cs
- PropertyFilter.cs
- DmlSqlGenerator.cs
- DataObject.cs
- BmpBitmapDecoder.cs
- QueryCoreOp.cs
- QuaternionAnimationUsingKeyFrames.cs
- FixedSchema.cs
- ObjectAnimationBase.cs
- DataGridSortCommandEventArgs.cs
- ExceptionHelpers.cs
- IDQuery.cs
- ParameterBuilder.cs
- AxHost.cs
- TemplateControl.cs
- AsymmetricSignatureDeformatter.cs
- TypeViewSchema.cs
- ShapeTypeface.cs