/// <summary> /// Writes an input stream to an entry in the blob storage specified by the provided token. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="input">The whole stream to write.</param> protected internal static async Task CopyFromStreamAsync(int versionId, string token, Stream input) { var tokenData = ChunkToken.Parse(token, versionId); try { using (var tran = SnTransaction.Begin()) { var context = await GetBlobStorageContextAsync(tokenData.FileId, true, versionId, tokenData.PropertyTypeId); if (context.Provider == BuiltInProvider) { // Our built-in provider does not have a special stream for the case when // the binary should be saved into a regular SQL varbinary column. await CopyFromStreamByChunksAsync(context, input); } else { // This is the recommended way to write a stream to the binary storage. using (var targetStream = context.Provider.GetStreamForWrite(context)) await input.CopyToAsync(targetStream); } tran.Commit(); } } catch (Exception e) { throw new DataException("Error during saving binary chunk to stream.", e); } }
/// <summary> /// Gets a readonly stream that contains a blob entry in the blob storage. /// </summary> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>A Task that represents the asynchronous operation containig /// a readonly stream that comes from the blob storage directly.</returns> public static async Task <Stream> GetStreamForReadAsync(string token, CancellationToken cancellationToken) { var tokenData = ChunkToken.Parse(token); var context = await GetBlobStorageContextAsync(tokenData.FileId, false, tokenData.VersionId, tokenData.PropertyTypeId, cancellationToken).ConfigureAwait(false); return(context.Provider.GetStreamForRead(context)); }
/// <summary> /// Gets a readonly stream that contains a blob entry in the blob storage. /// </summary> /// <param name="token">Blob token provided by a preliminary request.</param> /// <returns>A readonly stream that comes from the blob storage directly.</returns> public static Stream GetStreamForRead(string token) { var tokenData = ChunkToken.Parse(token); var context = GetBlobStorageContext(tokenData.FileId, false, tokenData.VersionId, tokenData.PropertyTypeId); return(context.Provider.GetStreamForRead(context)); }
/// <summary> /// Writes an input stream to an entry in the blob storage specified by the provided token. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="input">The whole stream to write.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> public async Task CopyFromStreamAsync(int versionId, string token, Stream input, CancellationToken cancellationToken) { var tokenData = ChunkToken.Parse(token, versionId); try { var context = await GetBlobStorageContextAsync(tokenData.FileId, true, versionId, tokenData.PropertyTypeId, cancellationToken).ConfigureAwait(false); if (context.Provider is IBuiltInBlobProvider) { // Our built-in provider does not have a special stream for the case when // the binary should be saved into a regular SQL varbinary column. await CopyFromStreamByChunksAsync(context, input, cancellationToken).ConfigureAwait(false); } else { // This is the recommended way to write a stream to the binary storage. using (var targetStream = context.Provider.GetStreamForWrite(context)) await input.CopyToAsync(targetStream).ConfigureAwait(false); } } catch (Exception e) { throw new DataException("Error during saving binary chunk to stream.", e); } }
/// <summary> /// Finalizes a chunked save operation. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <param name="source">Binary data containing metadata (e.g. content type).</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>A Task that represents the asynchronous operation.</returns> protected internal static Task CommitChunkAsync(int versionId, int propertyTypeId, string token, long fullSize, BinaryDataValue source, CancellationToken cancellationToken) { var tokenData = ChunkToken.Parse(token, versionId); return(BlobStorageComponents.DataProvider.CommitChunkAsync(versionId, propertyTypeId, tokenData.FileId, fullSize, source, cancellationToken)); }
/// <summary> /// Finalizes a chunked save operation. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <param name="source">Binary data containing metadata (e.g. content type).</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>A Task that represents the asynchronous operation.</returns> public async Task CommitChunkAsync(int versionId, int propertyTypeId, string token, long fullSize, BinaryDataValue source, CancellationToken cancellationToken) { var tokenData = ChunkToken.Parse(token, versionId); await DataProvider.CommitChunkAsync(versionId, propertyTypeId, tokenData.FileId, fullSize, source, cancellationToken); await DeleteOrphanedFilesAsync(cancellationToken); }
/// <summary> /// Writes a byte array to the blob entry specified by the provided token. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="buffer">Byte array to write.</param> /// <param name="offset">Starting position.</param> /// <param name="fullSize">Full size of the whole stream.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> public async Task WriteChunkAsync(int versionId, string token, byte[] buffer, long offset, long fullSize, CancellationToken cancellationToken) { var tokenData = ChunkToken.Parse(token, versionId); try { var ctx = await GetBlobStorageContextAsync(tokenData.FileId, cancellationToken).ConfigureAwait(false); // must update properties because the Length contains the actual saved size but the feature needs the full size UpdateContextProperties(ctx, versionId, tokenData.PropertyTypeId, fullSize); await ctx.Provider.WriteAsync(ctx, offset, buffer, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { throw new DataException("Error during saving binary chunk to stream.", ex); } }
/// <summary> /// Extracts the values stored in the token generated by the GetChunkToken method. This class /// is the only component that should know about the algorithm that builds the token. /// </summary> /// <param name="token">String data that will be parsed to ChunkToken instance.</param> /// <param name="versionId">Checks version id equality if the parameter value is greater than 0. /// Throws a DataException if the version ids are different.</param> /// <returns></returns> internal static ChunkToken Parse(string token, int versionId = 0) { var ids = token.Split('|').Select(int.Parse).ToArray(); var tokenData = new ChunkToken { VersionId = ids[0], PropertyTypeId = ids[1], BinaryPropertyId = ids[2], FileId = ids[3] }; if (versionId > 0 && tokenData.VersionId != versionId) { throw new DataException("Version id and chunk token mismatch."); } return(tokenData); }
/// <summary> /// Writes a byte array to the blob entry specified by the provided token. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="buffer">Byte array to write.</param> /// <param name="offset">Starting position.</param> /// <param name="fullSize">Full size of the whole stream.</param> protected internal static async Task WriteChunkAsync(int versionId, string token, byte[] buffer, long offset, long fullSize) { var tokenData = ChunkToken.Parse(token, versionId); using (var tran = SnTransaction.Begin()) { try { var ctx = await GetBlobStorageContextAsync(tokenData.FileId); // must update properties because the Length contains the actual saved size but the featue needs the full size UpdateContextProperties(ctx, versionId, tokenData.PropertyTypeId, fullSize); await ctx.Provider.WriteAsync(ctx, offset, buffer); tran.Commit(); } catch (Exception ex) { throw new DataException("Error during saving binary chunk to stream.", ex); } } }
/// <summary> /// Finalizes a chunked save operation. /// </summary> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="token">Blob token provided by a preliminary request.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <param name="source">Binary data containing metadata (e.g. content type).</param> protected internal static void CommitChunk(int versionId, int propertyTypeId, string token, long fullSize, BinaryDataValue source = null) { var tokenData = ChunkToken.Parse(token, versionId); BlobStorageComponents.DataProvider.CommitChunk(versionId, propertyTypeId, tokenData.FileId, fullSize, source); }