public async Task <ActionResult <DocumentDetails> > PostDocument([FromForm] AddDocumentRequest doc, IFormFile file, ApiVersion version) // ApiVersion required for Routing { _logger.LogInformation("Begin Upload of File {Name}", file.FileName); var fileContent = await file.GetFileBytesAsync(HttpContext.RequestAborted); if (!_validator.IsValid(file.FileName, fileContent, out var message)) { _logger.LogError("Posted File {Name} is not Valid: {Error}", file.FileName, message); return(BadRequest(message)); } var details = new DocumentDetailsDto { Description = doc.Description, FileName = file.FileName, Owner = doc.Owner, Title = doc.Title, FileSize = file.Length, DocumentType = _fileInfoProvider.GetDocumentType(file.FileName) }; try { var result = await _repository.InsertAsync(details, fileContent, HttpContext.RequestAborted); if (result <= 0) { _logger.LogError("Unable to upload Document {Name} ({Title}). A document with this title already exists.", details.FileName, details.Title); return(Conflict("A document with this title already exists")); } _logger.LogInformation("Document {Name} was uploaded as {Id} ({Title})", details.FileName, result, details.Title); return(CreatedAtAction(nameof(Get), new { version = version.ToString(), id = result }, result)); } catch (Exception e) { _logger.LogError(e, "An error has prevented upload of Document {Name}", details.FileName); return(StatusCode(StatusCodes.Status500InternalServerError)); } }
public Task <long> InsertAsync(DocumentDetailsDto details, byte[] dataBytes, CancellationToken token) { if (details is null) { throw new ArgumentNullException(nameof(details)); } if (dataBytes is null) { throw new ArgumentNullException(nameof(dataBytes)); } return(Impl()); async Task <long> Impl() { await new SyncContextRemover(); if (string.IsNullOrWhiteSpace(details.Description)) { details.Description = await GetFileDescription(details.DocumentType, dataBytes); } using var scope = new TransactionScope(TransactionScopeOption.RequiresNew, TransactionScopeAsyncFlowOption.Enabled); await using var conn = await CreateAndOpenConnection(token); const string insertDetailsQuery = @" INSERT INTO [dbo].[Documents] ([FileName], [Title], [Description], [FileSize], [DocumentType], [Owner]) VALUES (@FileName, @Title, @Description, @FileSize, @DocumentType, @Owner); SELECT SCOPE_IDENTITY() AS ID; "; var insertDetailsDefinition = CreateCommand(insertDetailsQuery, details, token); long newId; try { newId = await conn.ExecuteScalarAsync <long>(insertDetailsDefinition); } // catching UniqueConstraint Violation -- just for demo catch (SqlException s) when(s.Number == SqlErrorCodeUniqueViolation) { newId = 0; } // should probably throw an exception if (newId <= 0) { return(0); // rolls back scope } const string insertDataQuery = @" INSERT INTO [dbo].[DocumentContent] ([DocumentId], [Content]) VALUES (@Id, @Content) "; var insertDataDefinition = CreateCommand(insertDataQuery, new { Id = newId, Content = dataBytes }, token); await conn.ExecuteAsync(insertDataDefinition); scope.Complete(); return(newId); } }