/// <summary>
        /// Validates and creates a <see cref="Package"/> entity from a NuGet package archive.
        /// </summary>
        /// <param name="nugetPackage">A <see cref="PackageArchiveReader"/> instance from which package metadata can be read.</param>
        /// <param name="packageStreamMetadata">The <see cref="PackageStreamMetadata"/> instance providing metadata about the package stream.</param>
        /// <param name="owner">The <see cref="User"/> creating the package.</param>
        /// <param name="commitChanges"><c>True</c> to commit the changes to the data store and notify the indexing service; otherwise <c>false</c>.</param>
        /// <returns>Returns the created <see cref="Package"/> entity.</returns>
        /// <exception cref="InvalidPackageException">
        /// This exception will be thrown when a package metadata property violates a data validation constraint.
        /// </exception>
        public async Task <Package> CreatePackageAsync(PackageArchiveReader nugetPackage, PackageStreamMetadata packageStreamMetadata, User owner, User currentUser, bool isVerified)
        {
            PackageMetadata     packageMetadata;
            PackageRegistration packageRegistration;

            try
            {
                packageMetadata = PackageMetadata.FromNuspecReader(
                    nugetPackage.GetNuspecReader(),
                    strict: true);

                PackageHelper.ValidateNuGetPackageMetadata(packageMetadata);

                packageRegistration = CreateOrGetPackageRegistration(owner, packageMetadata, isVerified);
            }
            catch (Exception exception) when(exception is EntityException || exception is PackagingException)
            {
                // Wrap the exception for consistency of this API.
                throw new InvalidPackageException(exception.Message, exception);
            }

            var package = CreatePackageFromNuGetPackage(packageRegistration, nugetPackage, packageMetadata, packageStreamMetadata, currentUser);

            packageRegistration.Packages.Add(package);
            await UpdateIsLatestAsync(packageRegistration, commitChanges : false);

            return(package);
        }
        /// <summary>
        /// When no exceptions thrown, this method ensures the package metadata is valid.
        /// </summary>
        /// <param name="packageArchiveReader">
        /// The <see cref="PackageArchiveReader"/> instance providing the package metadata.
        /// </param>
        /// <exception cref="InvalidPackageException">
        /// This exception will be thrown when a package metadata property violates a data validation constraint.
        /// </exception>
        public async Task EnsureValid(PackageArchiveReader packageArchiveReader)
        {
            try
            {
                var packageMetadata = PackageMetadata.FromNuspecReader(
                    packageArchiveReader.GetNuspecReader(),
                    strict: true);

                if (packageMetadata.IsSymbolsPackage())
                {
                    throw new InvalidPackageException(ServicesStrings.UploadPackage_SymbolsPackageNotAllowed);
                }

                PackageHelper.ValidateNuGetPackageMetadata(packageMetadata);

                var supportedFrameworks = GetSupportedFrameworks(packageArchiveReader).Select(fn => fn.ToShortNameOrNull()).ToArray();
                if (!supportedFrameworks.AnySafe(sf => sf == null))
                {
                    ValidateSupportedFrameworks(supportedFrameworks);
                }

                // This will throw if the package contains an entry which will extract outside of the target extraction directory
                await packageArchiveReader.ValidatePackageEntriesAsync(CancellationToken.None);
            }
            catch (Exception exception) when(exception is EntityException || exception is PackagingException)
            {
                // Wrap the exception for consistency of this API.
                throw new InvalidPackageException(exception.Message, exception);
            }
        }
        private static void ValidateSymbolPackage(PackageArchiveReader symbolPackage, PackageMetadata metadata)
        {
            PackageHelper.ValidateNuGetPackageMetadata(metadata);

            // Validate nuspec manifest.
            var errors = ManifestValidator.Validate(symbolPackage.GetNuspec(), out var nuspec, out var packageMetadata).ToArray();

            if (errors.Length > 0)
            {
                var errorsString = string.Join("', '", errors.Select(error => error.ErrorMessage));
                throw new InvalidDataException(string.Format(
                                                   CultureInfo.CurrentCulture,
                                                   errors.Length > 1 ? Strings.UploadPackage_InvalidNuspecMultiple : Strings.UploadPackage_InvalidNuspec,
                                                   errorsString));
            }

            // Validate that the PII is not embedded in nuspec
            var invalidItems = new List <string>();

            if (metadata.Authors != null &&
                (metadata.Authors.Count > 1 ||
                 !string.IsNullOrWhiteSpace(metadata.Authors.FirstOrDefault())))
            {
                invalidItems.Add("Authors");
            }

            if (metadata.Owners != null && metadata.Owners.Any())
            {
                invalidItems.Add("Owners");
            }

            if (invalidItems.Any())
            {
                throw new InvalidDataException(string.Format(Strings.SymbolsPackage_InvalidDataInNuspec, string.Join(",", invalidItems.ToArray())));
            }

            if (!CheckForAllowedFiles(symbolPackage))
            {
                throw new InvalidDataException(string.Format(Strings.SymbolsPackage_InvalidFiles, PDBExtension));
            }

            if (!CheckForPDBFiles(symbolPackage))
            {
                throw new InvalidDataException(string.Format(Strings.SymbolsPackage_NoSymbols));
            }
        }