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
- IPHostEntry.cs
- BitmapEffectDrawing.cs
- DashStyle.cs
- LabelTarget.cs
- RecordConverter.cs
- pingexception.cs
- VirtualPathUtility.cs
- PeerDuplexChannelListener.cs
- FieldNameLookup.cs
- Dispatcher.cs
- oledbmetadatacollectionnames.cs
- EasingQuaternionKeyFrame.cs
- DependencyPropertyChangedEventArgs.cs
- DataSourceCacheDurationConverter.cs
- DefaultPrintController.cs
- DecimalAnimationBase.cs
- XmlRawWriterWrapper.cs
- DES.cs
- CqlParserHelpers.cs
- GradientBrush.cs
- BackStopAuthenticationModule.cs
- DllNotFoundException.cs
- ObjectQueryExecutionPlan.cs
- ReadOnlyCollection.cs
- WorkflowTraceTransfer.cs
- COAUTHINFO.cs
- BindingManagerDataErrorEventArgs.cs
- SID.cs
- AttributeAction.cs
- ParameterCollectionEditorForm.cs
- TerminatorSinks.cs
- TextServicesCompartmentEventSink.cs
- AutomationEvent.cs
- ModelPerspective.cs
- SqlBooleanizer.cs
- AspNetSynchronizationContext.cs
- SourceFilter.cs
- StateMachineWorkflowInstance.cs
- WebBrowserNavigatingEventHandler.cs
- OracleConnectionStringBuilder.cs
- XmlSerializationReader.cs
- AssemblyResourceLoader.cs
- SecurityRuntime.cs
- BoundsDrawingContextWalker.cs
- ScriptResourceAttribute.cs
- CustomLineCap.cs
- SinglePhaseEnlistment.cs
- precedingquery.cs
- Set.cs
- PermissionToken.cs
- GestureRecognizer.cs
- SQlBooleanStorage.cs
- DeviceContexts.cs
- XdrBuilder.cs
- DBPropSet.cs
- IndexOutOfRangeException.cs
- VScrollBar.cs
- WCFModelStrings.Designer.cs
- MsmqException.cs
- BorderGapMaskConverter.cs
- ExpressionPrefixAttribute.cs
- Geometry3D.cs
- SmiConnection.cs
- OleDbFactory.cs
- DeclarationUpdate.cs
- IsolatedStorage.cs
- X509Extension.cs
- InputProcessorProfiles.cs
- SkewTransform.cs
- SerializationUtilities.cs
- PartialList.cs
- backend.cs
- datacache.cs
- DbModificationCommandTree.cs
- ErrorRuntimeConfig.cs
- SqlConnectionStringBuilder.cs
- Effect.cs
- IndexerNameAttribute.cs
- XpsFixedDocumentSequenceReaderWriter.cs
- ErrorStyle.cs
- EmptyStringExpandableObjectConverter.cs
- hebrewshape.cs
- StatusBar.cs
- WrappedReader.cs
- SignedXml.cs
- SaveFileDialog.cs
- TaskCanceledException.cs
- WebPartConnectionsCancelVerb.cs
- FrameworkElement.cs
- ObjectQuery_EntitySqlExtensions.cs
- HttpWebRequestElement.cs
- FlowDocumentReaderAutomationPeer.cs
- ListItemDetailViewAttribute.cs
- DataGridViewCellEventArgs.cs
- BaseTemplateBuildProvider.cs
- ProvideValueServiceProvider.cs
- DataGridSortCommandEventArgs.cs
- ToolStripPanelRow.cs
- LongValidatorAttribute.cs
- FontStyleConverter.cs