/// <summary> /// Set the external blob provider to be used by the built-in blob provider selector /// during write operations when the binary size exceeds a configured value. /// </summary> public static IRepositoryBuilder UseExternalBlobProvider(this IRepositoryBuilder builder, IBlobProvider provider) { if (provider == null) { return(builder); } BuiltInBlobProviderSelector.ExternalBlobProvider = provider; // we have to add this manually configured provider to the automatically collected list if (BlobStorageBase.Providers == null) { BlobStorageBase.Providers = new Dictionary <string, IBlobProvider>(); } // ReSharper disable once AssignNullToNotNullAttribute BlobStorageBase.Providers[provider.GetType().FullName] = provider; SnTrace.System.Write($"External blob provider configured: {provider.GetType().FullName}."); return(builder); }
public async Task <string> StartChunkAsync(IBlobProvider blobProvider, int versionId, int propertyTypeId, long fullSize, CancellationToken cancellationToken) { var db = DataProvider.DB; // Get related objects var binaryDoc = db.BinaryProperties.FirstOrDefault(r => r.VersionId == versionId && r.PropertyTypeId == propertyTypeId); if (binaryDoc == null) { return(null); } var fileDoc = db.Files.FirstOrDefault(x => x.FileId == binaryDoc.FileId); if (fileDoc == null) { return(null); } if (fileDoc.Staging) { return(null); } // Create context var binaryPropertyId = binaryDoc.BinaryPropertyId; var fileId = fileDoc.FileId; var providerName = fileDoc.BlobProvider; var providerTextData = fileDoc.BlobProviderData; var provider = BlobStorageBase.GetProvider(providerName); var context = new BlobStorageContext(provider, providerTextData) { VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = fileId, Length = fullSize, }; // Allocate a new blob await blobProvider.AllocateAsync(context, cancellationToken); var blobProviderName = blobProvider.GetType().FullName; var blobProviderData = BlobStorageContext.SerializeBlobProviderData(context.BlobProviderData); // Insert a new file row var contentType = fileDoc.ContentType; var fileNameWithoutExtension = fileDoc.FileNameWithoutExtension; var extension = fileDoc.Extension; var newFileId = db.Files.GetNextId(); db.Files.Insert(new FileDoc { FileId = newFileId, BlobProvider = blobProviderName, BlobProviderData = blobProviderData, ContentType = contentType, Extension = extension, FileNameWithoutExtension = fileNameWithoutExtension, Size = fullSize, Staging = true, }); // Return a token return(new ChunkToken { VersionId = versionId, PropertyTypeId = propertyTypeId, BinaryPropertyId = binaryPropertyId, FileId = newFileId }.GetToken()); }
/// <summary> /// Starts a chunked save operation on an existing content. It does not write any binary data /// to the storage, it only makes prerequisite operations - e.g. allocates a new slot in the storage. /// </summary> /// <param name="blobProvider">Blob storage provider.</param> /// <param name="versionId">Content version id.</param> /// <param name="propertyTypeId">Binary property type id.</param> /// <param name="fullSize">Full size (stream length) of the binary value.</param> /// <returns>A token containing all the information (db record ids) that identify a single entry in the blob storage.</returns> public string StartChunk(IBlobProvider blobProvider, int versionId, int propertyTypeId, long fullSize) { var isLocalTransaction = !TransactionScope.IsActive; if (isLocalTransaction) { TransactionScope.Begin(); } var ctx = new BlobStorageContext(blobProvider) { VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = 0, Length = fullSize }; string blobProviderName = null; string blobProviderData = null; if (blobProvider != BlobStorageBase.BuiltInProvider) { blobProvider.Allocate(ctx); blobProviderName = blobProvider.GetType().FullName; blobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData); } try { using (var cmd = new SqlProcedure { CommandText = InsertStagingBinaryScript, CommandType = CommandType.Text }) { cmd.Parameters.Add("@VersionId", SqlDbType.Int).Value = versionId; cmd.Parameters.Add("@PropertyTypeId", SqlDbType.Int).Value = propertyTypeId; cmd.Parameters.Add("@Size", SqlDbType.BigInt).Value = fullSize; cmd.Parameters.Add("@BlobProvider", SqlDbType.NVarChar, 450).Value = blobProviderName != null ? (object)blobProviderName : DBNull.Value; cmd.Parameters.Add("@BlobProviderData", SqlDbType.NVarChar, int.MaxValue).Value = blobProviderData != null ? (object)blobProviderData : DBNull.Value; int binaryPropertyId; int fileId; using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { binaryPropertyId = reader.GetSafeInt32(0); fileId = reader.GetSafeInt32(1); } else { throw new DataException("File row could not be inserted."); } } ctx.FileId = fileId; return(new ChunkToken { VersionId = versionId, PropertyTypeId = propertyTypeId, BinaryPropertyId = binaryPropertyId, FileId = fileId }.GetToken()); } } catch (Exception ex) { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Rollback(); } throw new DataException("Error during saving binary chunk to SQL Server.", ex); } finally { if (isLocalTransaction && TransactionScope.IsActive) { TransactionScope.Commit(); } } }
public async Task <string> StartChunkAsync(IBlobProvider blobProvider, int versionId, int propertyTypeId, long fullSize, CancellationToken cancellationToken) { var ctx = new BlobStorageContext(blobProvider) { VersionId = versionId, PropertyTypeId = propertyTypeId, FileId = 0, Length = fullSize }; string blobProviderName = null; string blobProviderData = null; if (!(blobProvider is IBuiltInBlobProvider)) { await blobProvider.AllocateAsync(ctx, cancellationToken).ConfigureAwait(false); blobProviderName = blobProvider.GetType().FullName; blobProviderData = BlobStorageContext.SerializeBlobProviderData(ctx.BlobProviderData); } try { using (var dctx = new MsSqlDataContext(ConnectionStrings.ConnectionString, DataOptions, cancellationToken)) { using (var transaction = dctx.BeginTransaction()) { var result = await dctx.ExecuteReaderAsync(InsertStagingBinaryScript, cmd => { cmd.Parameters.AddRange(new[] { dctx.CreateParameter("@VersionId", DbType.Int32, versionId), dctx.CreateParameter("@PropertyTypeId", DbType.Int32, propertyTypeId), dctx.CreateParameter("@Size", DbType.Int64, fullSize), dctx.CreateParameter("@BlobProvider", DbType.String, 450, blobProviderName != null ? (object)blobProviderName : DBNull.Value), dctx.CreateParameter("@BlobProviderData", DbType.String, int.MaxValue, blobProviderData != null ? (object)blobProviderData : DBNull.Value), }); }, async (reader, cancel) => { int binaryPropertyId; int fileId; cancel.ThrowIfCancellationRequested(); if (await reader.ReadAsync(cancel).ConfigureAwait(false)) { binaryPropertyId = reader.GetSafeInt32(0); fileId = reader.GetSafeInt32(1); } else { throw new DataException("File row could not be inserted."); } ctx.FileId = fileId; return(new ChunkToken { VersionId = versionId, PropertyTypeId = propertyTypeId, BinaryPropertyId = binaryPropertyId, FileId = fileId }.GetToken()); }).ConfigureAwait(false); transaction.Commit(); return(result); } } } catch (Exception ex) { throw new DataException("Error during saving binary chunk to SQL Server.", ex); } }