Code:
/ 4.0 / 4.0 / 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. //---------------------------------------------------------------------- // // 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
- WizardDesigner.cs
- ToolStripEditorManager.cs
- CodeAccessSecurityEngine.cs
- CertificateElement.cs
- InternalConfigSettingsFactory.cs
- HandlerBase.cs
- FileDocument.cs
- AsynchronousChannel.cs
- ComponentEvent.cs
- SoapTransportImporter.cs
- ConfigurationProviderException.cs
- Run.cs
- RuntimeEnvironment.cs
- XmlArrayItemAttributes.cs
- Operator.cs
- GregorianCalendarHelper.cs
- HostingMessageProperty.cs
- Rules.cs
- BlockUIContainer.cs
- AsyncOperationManager.cs
- OleDbSchemaGuid.cs
- InlineUIContainer.cs
- ExitEventArgs.cs
- FrameworkElementFactory.cs
- ResourceReader.cs
- ToggleButtonAutomationPeer.cs
- XmlDataCollection.cs
- ScaleTransform.cs
- MsmqIntegrationBinding.cs
- SourceFileBuildProvider.cs
- CompositeControl.cs
- PreProcessInputEventArgs.cs
- UIElement3DAutomationPeer.cs
- Convert.cs
- MobileDeviceCapabilitiesSectionHandler.cs
- Thickness.cs
- ManifestSignatureInformation.cs
- WinEventQueueItem.cs
- DetailsView.cs
- HttpDictionary.cs
- ChildrenQuery.cs
- WorkflowControlEndpoint.cs
- DataGridViewSelectedCellsAccessibleObject.cs
- HitTestParameters.cs
- TdsParserHelperClasses.cs
- Item.cs
- XmlSchemaAttributeGroup.cs
- SubordinateTransaction.cs
- TouchPoint.cs
- TextWriter.cs
- TypeProvider.cs
- AuthenticationServiceManager.cs
- XmlStreamStore.cs
- datacache.cs
- PersistenceTypeAttribute.cs
- RemoveStoryboard.cs
- GridViewRow.cs
- PageThemeParser.cs
- SqlCommandSet.cs
- ControlCodeDomSerializer.cs
- ValueTable.cs
- _UriTypeConverter.cs
- Stackframe.cs
- DetailsViewDeleteEventArgs.cs
- EmissiveMaterial.cs
- TypeBuilderInstantiation.cs
- SafeSecurityHandles.cs
- DateTimeAutomationPeer.cs
- ViewStateException.cs
- UrlParameterWriter.cs
- MailWriter.cs
- BackgroundFormatInfo.cs
- AlgoModule.cs
- Int32Converter.cs
- DataGridViewAutoSizeModeEventArgs.cs
- DbParameterCollectionHelper.cs
- DataGridViewCellConverter.cs
- ScriptControlManager.cs
- MultiPageTextView.cs
- ProfileSection.cs
- XmlSchemaValidator.cs
- GridViewColumnHeader.cs
- RunClient.cs
- ContainerSelectorActiveEvent.cs
- TypeHelpers.cs
- TransformGroup.cs
- Atom10FormatterFactory.cs
- CustomError.cs
- BindingNavigator.cs
- SystemIcmpV6Statistics.cs
- ResourcesBuildProvider.cs
- ReaderWriterLock.cs
- Drawing.cs
- ElementAtQueryOperator.cs
- CodeObject.cs
- SqlBooleanMismatchVisitor.cs
- VScrollBar.cs
- WorkflowQueueInfo.cs
- RequestStatusBarUpdateEventArgs.cs
- ErrorFormatter.cs