src/NuGetGallery/Services/SymbolPackageUploadService.cs
/// <summary>
/// This method creates the symbol db entities and invokes the validations for the uploaded snupkg. 
/// It will send the message for validation and upload the snupkg to the "validations"/"symbols-packages" container
/// based on the result. It will then update the references in the database for persistence with appropriate status.
/// </summary>
/// <param name="package">The package for which symbols package is to be uplloaded</param>
/// <param name="symbolPackageStream">The symbols package stream metadata for the uploaded symbols package file.</param>
/// <returns>The <see cref="PackageCommitResult"/> for the create and upload symbol package flow.</returns>
This method creates the symbol db entities and invokes the validations for the uploaded snupkg.
It will send the message for validation and upload the snupkg to the "validations"/"symbols-packages" container
based on the result. It will then update the references in the database for persistence with appropriate status.
This method creates the symbol db entities and invokes the validations for the uploaded snupkg . It will send the message for validation and upload the snupkg to the " validations " / " symbols - packages " container based on the result . It will then update the references in the database for persistence with appropriate status .
public async Task<PackageCommitResult> CreateAndUploadSymbolsPackage(Package package, Stream symbolPackageStream)
        {
            var packageStreamMetadata = new PackageStreamMetadata
            {
                HashAlgorithm = CoreConstants.Sha512HashAlgorithmId,
                Hash = CryptographyService.GenerateHash(
                    symbolPackageStream.AsSeekableStream(),
                    CoreConstants.Sha512HashAlgorithmId),
                Size = symbolPackageStream.Length
            };
            Stream symbolPackageFile = symbolPackageStream.AsSeekableStream();
            var previousSymbolsPackage = package.LatestSymbolPackage();
            var symbolPackage = _symbolPackageService.CreateSymbolPackage(package, packageStreamMetadata);
            await _validationService.UpdatePackageAsync(symbolPackage);
            if (symbolPackage.StatusKey != PackageStatus.Available
                && symbolPackage.StatusKey != PackageStatus.Validating)
            {
                throw new InvalidOperationException(
                    $"The symbol package to commit must have either the {PackageStatus.Available} or {PackageStatus.Validating} package status.");
            }
            try
            {
                if (symbolPackage.StatusKey == PackageStatus.Validating)
                {
                    if (previousSymbolsPackage != null && previousSymbolsPackage.StatusKey == PackageStatus.FailedValidation)
                    {
                        await DeleteSymbolsPackageAsync(previousSymbolsPackage);
                    }
                    await _symbolPackageFileService.SaveValidationPackageFileAsync(symbolPackage.Package, symbolPackageFile);
                }
                else if (symbolPackage.StatusKey == PackageStatus.Available)
                {
                    if (!symbolPackage.Published.HasValue)
                    {
                        symbolPackage.Published = DateTime.UtcNow;
                    }
                    var availableSymbolPackages = package
                        .SymbolPackages
                        .Where(sp => sp.StatusKey == PackageStatus.Available
                            && sp != symbolPackage);
                    var overwrite = false;
                    if (availableSymbolPackages.Any())
                    {
                        foreach (var availableSymbolPackage in availableSymbolPackages)
                        {
                            availableSymbolPackage.StatusKey = PackageStatus.Deleted;
                        }
                        overwrite = true;
                    }
                    await _symbolPackageFileService.SavePackageFileAsync(symbolPackage.Package, symbolPackageFile, overwrite);
                }
                try
                {
                    await _validationService.StartValidationAsync(symbolPackage);
                    await _entitiesContext.SaveChangesAsync();
                }
                catch (Exception ex)
                {
                    ex.Log();
                    if (symbolPackage.StatusKey == PackageStatus.Validating)
                    {
                        await _symbolPackageFileService.DeleteValidationPackageFileAsync(
                            package.PackageRegistration.Id,
                            package.Version);
                    }
                    else if (symbolPackage.StatusKey == PackageStatus.Available)
                    {
                        await _symbolPackageFileService.DeletePackageFileAsync(
                            package.PackageRegistration.Id,
                            package.Version);
                    }
                    throw;
                }
            }
            catch (FileAlreadyExistsException ex)
            {
                ex.Log();
                return PackageCommitResult.Conflict;
            }
            _telemetryService.TrackSymbolPackagePushEvent(package.Id, package.NormalizedVersion);
            return PackageCommitResult.Success;
        }
public async Task < PackageCommitResult > CreateAndUploadSymbolsPackage ( Package package , Stream symbolPackageStream ) { var packageStreamMetadata = new PackageStreamMetadata { HashAlgorithm = CoreConstants . Sha512HashAlgorithmId , Hash = CryptographyService . GenerateHash ( symbolPackageStream . AsSeekableStream ( ) , CoreConstants . Sha512HashAlgorithmId ) , Size = symbolPackageStream . Length } ; Stream symbolPackageFile = symbolPackageStream . AsSeekableStream ( ) ; var previousSymbolsPackage = package . LatestSymbolPackage ( ) ; var symbolPackage = _symbolPackageService . CreateSymbolPackage ( package , packageStreamMetadata ) ; await _validationService . UpdatePackageAsync ( symbolPackage ) ; if ( symbolPackage . StatusKey != PackageStatus . Available && symbolPackage . StatusKey != PackageStatus . Validating ) { throw new InvalidOperationException ( $" The symbol package to commit must have either the  { PackageStatus . Available }  or  { PackageStatus . Validating }  package status. " ) ; } try { if ( symbolPackage . StatusKey == PackageStatus . Validating ) { if ( previousSymbolsPackage != null && previousSymbolsPackage . StatusKey == PackageStatus . FailedValidation ) { await DeleteSymbolsPackageAsync ( previousSymbolsPackage ) ; } await _symbolPackageFileService . SaveValidationPackageFileAsync ( symbolPackage . Package , symbolPackageFile ) ; } else if ( symbolPackage . StatusKey == PackageStatus . Available ) { if ( ! symbolPackage . Published . HasValue ) { symbolPackage . Published = DateTime . UtcNow ; } var availableSymbolPackages = package . SymbolPackages . Where ( sp => sp . StatusKey == PackageStatus . Available && sp != symbolPackage ) ; var overwrite = false ; if ( availableSymbolPackages . Any ( ) ) { foreach ( var availableSymbolPackage in availableSymbolPackages ) { availableSymbolPackage . StatusKey = PackageStatus . Deleted ; } overwrite = true ; } await _symbolPackageFileService . SavePackageFileAsync ( symbolPackage . Package , symbolPackageFile , overwrite ) ; } try { await _validationService . StartValidationAsync ( symbolPackage ) ; await _entitiesContext . SaveChangesAsync ( ) ; } catch ( Exception ex ) { ex . Log ( ) ; if ( symbolPackage . StatusKey == PackageStatus . Validating ) { await _symbolPackageFileService . DeleteValidationPackageFileAsync ( package . PackageRegistration . Id , package . Version ) ; } else if ( symbolPackage . StatusKey == PackageStatus . Available ) { await _symbolPackageFileService . DeletePackageFileAsync ( package . PackageRegistration . Id , package . Version ) ; } throw ; } } catch ( FileAlreadyExistsException ex ) { ex . Log ( ) ; return PackageCommitResult . Conflict ; } _telemetryService . TrackSymbolPackagePushEvent ( package . Id , package . NormalizedVersion ) ; return PackageCommitResult . Success ; }
This method creates the symbol db entities and invokes the validations for the uploaded snupkg.
This method creates the symbol db entities and invokes the validations for the uploaded snupkg .
// If the last uploaded symbol package has failed validation, it will leave the snupkg in the  // validations container. We could possibly overwrite it, but that might introduce a concurrency  // issue on multiple snupkg uploads with a prior failed validation. The best thing to do would be // to delete the failed validation snupkg from validations container and then proceed with normal // upload. // Mark any other associated available symbol packages for deletion. // Mark the currently available packages for deletion, and replace the file in the container. // Caveat: This doesn't really affect our prod flow since the package is validating, however, when the async validation // is disabled there is a chance that there could be concurrency issues when pushing multiple symbols simultaneously.  // This could result in an inconsistent data or multiple symbol entities marked as available. This could be sovled using etag // for saving files, however since it doesn't really affect nuget.org which happen have async validations flow I will leave it as is. // Sending the validation request right before updating the database, so all file operations // are complete by that time and all possible conflicts are resolved. // commit all changes to database as an atomic transaction // If sending the validation request or saving to the DB fails for any reason // we need to delete the package we just saved.
The  for the create and upload symbol package flow.
The for the create and upload symbol package flow .
package
Package
The package for which symbols package is to be uplloaded
The package for which symbols package is to be uplloaded
symbolPackageStream
Stream
The symbols package stream metadata for the uploaded symbols package file.
The symbols package stream metadata for the uploaded symbols package file .