/// <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();
                }
            }
        }
Exemple #4
0
        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);
            }
        }