diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs deleted file mode 100644 index 952cf7c36d..0000000000 --- a/src/Shared/CertificateGeneration/CertificateManager.cs +++ /dev/null @@ -1,951 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Text.RegularExpressions; - -namespace Microsoft.AspNetCore.Certificates.Generation -{ - internal class CertificateManager - { - public const string AspNetHttpsOid = "1.3.6.1.4.1.311.84.1.1"; - public const string AspNetHttpsOidFriendlyName = "ASP.NET Core HTTPS development certificate"; - - private const string ServerAuthenticationEnhancedKeyUsageOid = "1.3.6.1.5.5.7.3.1"; - private const string ServerAuthenticationEnhancedKeyUsageOidFriendlyName = "Server Authentication"; - - private const string LocalhostHttpsDnsName = "localhost"; - private const string LocalhostHttpsDistinguishedName = "CN=" + LocalhostHttpsDnsName; - - public const int RSAMinimumKeySizeInBits = 2048; - - private static readonly TimeSpan MaxRegexTimeout = TimeSpan.FromMinutes(1); - private const string CertificateSubjectRegex = "CN=(.*[^,]+).*"; - private const string MacOSSystemKeyChain = "/Library/Keychains/System.keychain"; - private static readonly string MacOSUserKeyChain = Environment.GetEnvironmentVariable("HOME") + "/Library/Keychains/login.keychain-db"; - private const string MacOSFindCertificateCommandLine = "security"; -#if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 - private static readonly string MacOSFindCertificateCommandLineArgumentsFormat = "find-certificate -c {0} -a -Z -p " + MacOSSystemKeyChain; -#endif - private const string MacOSFindCertificateOutputRegex = "SHA-1 hash: ([0-9A-Z]+)"; - private const string MacOSRemoveCertificateTrustCommandLine = "sudo"; - private const string MacOSRemoveCertificateTrustCommandLineArgumentsFormat = "security remove-trusted-cert -d {0}"; - private const string MacOSDeleteCertificateCommandLine = "sudo"; - private const string MacOSDeleteCertificateCommandLineArgumentsFormat = "security delete-certificate -Z {0} {1}"; - private const string MacOSTrustCertificateCommandLine = "sudo"; -#if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 - private static readonly string MacOSTrustCertificateCommandLineArguments = "security add-trusted-cert -d -r trustRoot -k " + MacOSSystemKeyChain + " "; -#endif - private const int UserCancelledErrorCode = 1223; - - public IList ListCertificates( - CertificatePurpose purpose, - StoreName storeName, - StoreLocation location, - bool isValid, - bool requireExportable = true, - DiagnosticInformation diagnostics = null) - { - diagnostics?.Debug($"Listing '{purpose.ToString()}' certificates on '{location}\\{storeName}'."); - var certificates = new List(); - try - { - using (var store = new X509Store(storeName, location)) - { - store.Open(OpenFlags.ReadOnly); - certificates.AddRange(store.Certificates.OfType()); - IEnumerable matchingCertificates = certificates; - switch (purpose) - { - case CertificatePurpose.All: - matchingCertificates = matchingCertificates - .Where(c => HasOid(c, AspNetHttpsOid)); - break; - case CertificatePurpose.HTTPS: - matchingCertificates = matchingCertificates - .Where(c => HasOid(c, AspNetHttpsOid)); - break; - default: - break; - } - - diagnostics?.Debug(diagnostics.DescribeCertificates(matchingCertificates)); - if (isValid) - { - // Ensure the certificate hasn't expired, has a private key and its exportable - // (for container/unix scenarios). - diagnostics?.Debug("Checking certificates for validity."); - var now = DateTimeOffset.Now; - var validCertificates = matchingCertificates - .Where(c => c.NotBefore <= now && - now <= c.NotAfter && - (!requireExportable || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || IsExportable(c))) - .ToArray(); - - var invalidCertificates = matchingCertificates.Except(validCertificates); - - diagnostics?.Debug("Listing valid certificates"); - diagnostics?.Debug(diagnostics.DescribeCertificates(validCertificates)); - diagnostics?.Debug("Listing invalid certificates"); - diagnostics?.Debug(diagnostics.DescribeCertificates(invalidCertificates)); - - matchingCertificates = validCertificates; - } - - // We need to enumerate the certificates early to prevent dispoisng issues. - matchingCertificates = matchingCertificates.ToList(); - - var certificatesToDispose = certificates.Except(matchingCertificates); - DisposeCertificates(certificatesToDispose); - - store.Close(); - - return (IList)matchingCertificates; - } - } - catch - { - DisposeCertificates(certificates); - certificates.Clear(); - return certificates; - } - - bool HasOid(X509Certificate2 certificate, string oid) => - certificate.Extensions.OfType() - .Any(e => string.Equals(oid, e.Oid.Value, StringComparison.Ordinal)); -#if !XPLAT - bool IsExportable(X509Certificate2 c) => - ((c.GetRSAPrivateKey() is RSACryptoServiceProvider rsaPrivateKey && - rsaPrivateKey.CspKeyContainerInfo.Exportable) || - (c.GetRSAPrivateKey() is RSACng cngPrivateKey && - cngPrivateKey.Key.ExportPolicy == CngExportPolicies.AllowExport)); -#else - // Only check for RSA CryptoServiceProvider and do not fail in XPlat tooling as - // System.Security.Cryptography.Cng is not part of the shared framework and we don't - // want to bring the dependency in on CLI scenarios. This functionality will be used - // on CLI scenarios as part of the first run experience, so checking the exportability - // of the certificate is not important. - bool IsExportable(X509Certificate2 c) => - ((c.GetRSAPrivateKey() is RSACryptoServiceProvider rsaPrivateKey && - rsaPrivateKey.CspKeyContainerInfo.Exportable) || !(c.GetRSAPrivateKey() is RSACryptoServiceProvider)); -#endif - } - - private static void DisposeCertificates(IEnumerable disposables) - { - foreach (var disposable in disposables) - { - try - { - disposable.Dispose(); - } - catch - { - } - } - } - -#if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 - - public X509Certificate2 CreateAspNetCoreHttpsDevelopmentCertificate(DateTimeOffset notBefore, DateTimeOffset notAfter, string subjectOverride, DiagnosticInformation diagnostics = null) - { - var subject = new X500DistinguishedName(subjectOverride ?? LocalhostHttpsDistinguishedName); - var extensions = new List(); - var sanBuilder = new SubjectAlternativeNameBuilder(); - sanBuilder.AddDnsName(LocalhostHttpsDnsName); - - var keyUsage = new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment, critical: true); - var enhancedKeyUsage = new X509EnhancedKeyUsageExtension( - new OidCollection() { - new Oid( - ServerAuthenticationEnhancedKeyUsageOid, - ServerAuthenticationEnhancedKeyUsageOidFriendlyName) - }, - critical: true); - - var basicConstraints = new X509BasicConstraintsExtension( - certificateAuthority: false, - hasPathLengthConstraint: false, - pathLengthConstraint: 0, - critical: true); - - var aspNetHttpsExtension = new X509Extension( - new AsnEncodedData( - new Oid(AspNetHttpsOid, AspNetHttpsOidFriendlyName), - Encoding.ASCII.GetBytes(AspNetHttpsOidFriendlyName)), - critical: false); - - extensions.Add(basicConstraints); - extensions.Add(keyUsage); - extensions.Add(enhancedKeyUsage); - extensions.Add(sanBuilder.Build(critical: true)); - extensions.Add(aspNetHttpsExtension); - - var certificate = CreateSelfSignedCertificate(subject, extensions, notBefore, notAfter); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - certificate.FriendlyName = AspNetHttpsOidFriendlyName; - } - - return certificate; - } - - public X509Certificate2 CreateSelfSignedCertificate( - X500DistinguishedName subject, - IEnumerable extensions, - DateTimeOffset notBefore, - DateTimeOffset notAfter) - { - var key = CreateKeyMaterial(RSAMinimumKeySizeInBits); - - var request = new CertificateRequest(subject, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - foreach (var extension in extensions) - { - request.CertificateExtensions.Add(extension); - } - - return request.CreateSelfSigned(notBefore, notAfter); - - RSA CreateKeyMaterial(int minimumKeySize) - { - var rsa = RSA.Create(minimumKeySize); - if (rsa.KeySize < minimumKeySize) - { - throw new InvalidOperationException($"Failed to create a key with a size of {minimumKeySize} bits"); - } - - return rsa; - } - } - - public X509Certificate2 SaveCertificateInStore(X509Certificate2 certificate, StoreName name, StoreLocation location, DiagnosticInformation diagnostics = null) - { - diagnostics?.Debug("Saving the certificate into the certificate store."); - var imported = certificate; - if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - // On non OSX systems we need to export the certificate and import it so that the transient - // key that we generated gets persisted. - var export = certificate.Export(X509ContentType.Pkcs12, ""); - imported = new X509Certificate2(export, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); - Array.Clear(export, 0, export.Length); - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - imported.FriendlyName = certificate.FriendlyName; - } - - using (var store = new X509Store(name, location)) - { - store.Open(OpenFlags.ReadWrite); - store.Add(imported); - store.Close(); - }; - - return imported; - } - - public void ExportCertificate(X509Certificate2 certificate, string path, bool includePrivateKey, string password, DiagnosticInformation diagnostics = null) - { - diagnostics?.Debug( - $"Exporting certificate to '{path}'", - includePrivateKey ? "The certificate will contain the private key" : "The certificate will not contain the private key"); - if (includePrivateKey && password == null) - { - diagnostics?.Debug("No password was provided for the certificate."); - } - - var targetDirectoryPath = Path.GetDirectoryName(path); - if (targetDirectoryPath != "") - { - diagnostics?.Debug($"Ensuring that the directory for the target exported certificate path exists '{targetDirectoryPath}'"); - Directory.CreateDirectory(targetDirectoryPath); - } - - byte[] bytes; - if (includePrivateKey) - { - try - { - diagnostics?.Debug($"Exporting the certificate including the private key."); - bytes = certificate.Export(X509ContentType.Pkcs12, password); - } - catch (Exception e) - { - diagnostics?.Error($"Failed to export the certificate with the private key", e); - throw; - } - } - else - { - try - { - diagnostics?.Debug($"Exporting the certificate without the private key."); - bytes = certificate.Export(X509ContentType.Cert); - } - catch (Exception ex) - { - diagnostics?.Error($"Failed to export the certificate without the private key", ex); - throw; - } - } - try - { - diagnostics?.Debug($"Writing exported certificate to path '{path}'."); - File.WriteAllBytes(path, bytes); - } - catch (Exception ex) - { - diagnostics?.Error("Failed writing the certificate to the target path", ex); - throw; - } - finally - { - Array.Clear(bytes, 0, bytes.Length); - } - } - - public void TrustCertificate(X509Certificate2 certificate, DiagnosticInformation diagnostics = null) - { - // Strip certificate of the private key if any. - var publicCertificate = new X509Certificate2(certificate.Export(X509ContentType.Cert)); - - if (!IsTrusted(publicCertificate)) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - diagnostics?.Debug("Trusting the certificate on Windows."); - TrustCertificateOnWindows(certificate, publicCertificate, diagnostics); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - diagnostics?.Debug("Trusting the certificate on MAC."); - TrustCertificateOnMac(publicCertificate, diagnostics); - } - } - } - - private void TrustCertificateOnMac(X509Certificate2 publicCertificate, DiagnosticInformation diagnostics) - { - var tmpFile = Path.GetTempFileName(); - try - { - ExportCertificate(publicCertificate, tmpFile, includePrivateKey: false, password: null); - diagnostics?.Debug("Running the trust command on Mac OS"); - using (var process = Process.Start(MacOSTrustCertificateCommandLine, MacOSTrustCertificateCommandLineArguments + tmpFile)) - { - process.WaitForExit(); - if (process.ExitCode != 0) - { - throw new InvalidOperationException("There was an error trusting the certificate."); - } - } - } - finally - { - try - { - if (File.Exists(tmpFile)) - { - File.Delete(tmpFile); - } - } - catch - { - // We don't care if we can't delete the temp file. - } - } - } - - private static void TrustCertificateOnWindows(X509Certificate2 certificate, X509Certificate2 publicCertificate, DiagnosticInformation diagnostics = null) - { - publicCertificate.FriendlyName = certificate.FriendlyName; - - using (var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser)) - { - store.Open(OpenFlags.ReadWrite); - var existing = store.Certificates.Find(X509FindType.FindByThumbprint, publicCertificate.Thumbprint, validOnly: false); - if (existing.Count > 0) - { - diagnostics?.Debug("Certificate already trusted. Skipping trust step."); - DisposeCertificates(existing.OfType()); - return; - } - - try - { - diagnostics?.Debug("Adding certificate to the store."); - store.Add(publicCertificate); - } - catch (CryptographicException exception) when (exception.HResult == UserCancelledErrorCode) - { - diagnostics?.Debug("User cancelled the trust prompt."); - throw new UserCancelledTrustException(); - } - store.Close(); - }; - } - - public bool IsTrusted(X509Certificate2 certificate) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return ListCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, isValid: true, requireExportable: false) - .Any(c => c.Thumbprint == certificate.Thumbprint); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - var subjectMatch = Regex.Match(certificate.Subject, CertificateSubjectRegex, RegexOptions.Singleline, MaxRegexTimeout); - if (!subjectMatch.Success) - { - throw new InvalidOperationException($"Can't determine the subject for the certificate with subject '{certificate.Subject}'."); - } - var subject = subjectMatch.Groups[1].Value; - using (var checkTrustProcess = Process.Start(new ProcessStartInfo( - MacOSFindCertificateCommandLine, - string.Format(MacOSFindCertificateCommandLineArgumentsFormat, subject)) - { - RedirectStandardOutput = true - })) - { - var output = checkTrustProcess.StandardOutput.ReadToEnd(); - checkTrustProcess.WaitForExit(); - var matches = Regex.Matches(output, MacOSFindCertificateOutputRegex, RegexOptions.Multiline, MaxRegexTimeout); - var hashes = matches.OfType().Select(m => m.Groups[1].Value).ToList(); - return hashes.Any(h => string.Equals(h, certificate.Thumbprint, StringComparison.Ordinal)); - } - } - else - { - return false; - } - } - - public void CleanupHttpsCertificates(string subject = LocalhostHttpsDistinguishedName) - { - CleanupCertificates(CertificatePurpose.HTTPS, subject); - } - - public void CleanupCertificates(CertificatePurpose purpose, string subject) - { - // On OS X we don't have a good way to manage trusted certificates in the system keychain - // so we do everything by invoking the native toolchain. - // This has some limitations, like for example not being able to identify our custom OID extension. For that - // matter, when we are cleaning up certificates on the machine, we start by removing the trusted certificates. - // To do this, we list the certificates that we can identify on the current user personal store and we invoke - // the native toolchain to remove them from the sytem keychain. Once we have removed the trusted certificates, - // we remove the certificates from the local user store to finish up the cleanup. - var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: false); - foreach (var certificate in certificates) - { - RemoveCertificate(certificate, RemoveLocations.All); - } - } - - public DiagnosticInformation CleanupHttpsCertificates2(string subject = LocalhostHttpsDistinguishedName) - { - return CleanupCertificates2(CertificatePurpose.HTTPS, subject); - } - - public DiagnosticInformation CleanupCertificates2(CertificatePurpose purpose, string subject) - { - var diagnostics = new DiagnosticInformation(); - // On OS X we don't have a good way to manage trusted certificates in the system keychain - // so we do everything by invoking the native toolchain. - // This has some limitations, like for example not being able to identify our custom OID extension. For that - // matter, when we are cleaning up certificates on the machine, we start by removing the trusted certificates. - // To do this, we list the certificates that we can identify on the current user personal store and we invoke - // the native toolchain to remove them from the sytem keychain. Once we have removed the trusted certificates, - // we remove the certificates from the local user store to finish up the cleanup. - var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: false, requireExportable: true, diagnostics); - foreach (var certificate in certificates) - { - RemoveCertificate(certificate, RemoveLocations.All, diagnostics); - } - - return diagnostics; - } - - public void RemoveAllCertificates(CertificatePurpose purpose, StoreName storeName, StoreLocation storeLocation, string subject = null) - { - var certificates = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? - ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: false) : - ListCertificates(purpose, storeName, storeLocation, isValid: false); - var certificatesWithName = subject == null ? certificates : certificates.Where(c => c.Subject == subject); - - var removeLocation = storeName == StoreName.My ? RemoveLocations.Local : RemoveLocations.Trusted; - - foreach (var certificate in certificates) - { - RemoveCertificate(certificate, removeLocation); - } - - DisposeCertificates(certificates); - } - - private void RemoveCertificate(X509Certificate2 certificate, RemoveLocations locations, DiagnosticInformation diagnostics = null) - { - switch (locations) - { - case RemoveLocations.Undefined: - throw new InvalidOperationException($"'{nameof(RemoveLocations.Undefined)}' is not a valid location."); - case RemoveLocations.Local: - RemoveCertificateFromUserStore(certificate, diagnostics); - break; - case RemoveLocations.Trusted when !RuntimeInformation.IsOSPlatform(OSPlatform.Linux): - RemoveCertificateFromTrustedRoots(certificate, diagnostics); - break; - case RemoveLocations.All: - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - RemoveCertificateFromTrustedRoots(certificate, diagnostics); - } - RemoveCertificateFromUserStore(certificate, diagnostics); - break; - default: - throw new InvalidOperationException("Invalid location."); - } - } - - private static void RemoveCertificateFromUserStore(X509Certificate2 certificate, DiagnosticInformation diagnostics) - { - diagnostics?.Debug($"Trying to remove certificate with thumbprint '{certificate.Thumbprint}' from certificate store '{StoreLocation.CurrentUser}\\{StoreName.My}'."); - using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) - { - store.Open(OpenFlags.ReadWrite); - var matching = store.Certificates - .OfType() - .Single(c => c.SerialNumber == certificate.SerialNumber); - - store.Remove(matching); - store.Close(); - } - } - - private void RemoveCertificateFromTrustedRoots(X509Certificate2 certificate, DiagnosticInformation diagnostics) - { - diagnostics?.Debug($"Trying to remove certificate with thumbprint '{certificate.Thumbprint}' from certificate store '{StoreLocation.CurrentUser}\\{StoreName.Root}'."); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - using (var store = new X509Store(StoreName.Root, StoreLocation.CurrentUser)) - { - store.Open(OpenFlags.ReadWrite); - var matching = store.Certificates - .OfType() - .SingleOrDefault(c => c.SerialNumber == certificate.SerialNumber); - - if (matching != null) - { - store.Remove(matching); - } - - store.Close(); - } - } - else - { - if (IsTrusted(certificate)) // On OSX this check just ensures its on the system keychain - { - try - { - diagnostics?.Debug("Trying to remove the certificate trust rule."); - RemoveCertificateTrustRule(certificate); - } - catch - { - diagnostics?.Debug("Failed to remove the certificate trust rule."); - // We don't care if we fail to remove the trust rule if - // for some reason the certificate became untrusted. - // The delete command will fail if the certificate is - // trusted. - } - RemoveCertificateFromKeyChain(MacOSSystemKeyChain, certificate); - } - else - { - diagnostics?.Debug("The certificate was not trusted."); - } - } - } - - private static void RemoveCertificateTrustRule(X509Certificate2 certificate) - { - var certificatePath = Path.GetTempFileName(); - try - { - var certBytes = certificate.Export(X509ContentType.Cert); - File.WriteAllBytes(certificatePath, certBytes); - var processInfo = new ProcessStartInfo( - MacOSRemoveCertificateTrustCommandLine, - string.Format( - MacOSRemoveCertificateTrustCommandLineArgumentsFormat, - certificatePath - )); - using (var process = Process.Start(processInfo)) - { - process.WaitForExit(); - } - } - finally - { - try - { - if (File.Exists(certificatePath)) - { - File.Delete(certificatePath); - } - } - catch - { - // We don't care about failing to do clean-up on a temp file. - } - } - } - - private static void RemoveCertificateFromKeyChain(string keyChain, X509Certificate2 certificate) - { - var processInfo = new ProcessStartInfo( - MacOSDeleteCertificateCommandLine, - string.Format( - MacOSDeleteCertificateCommandLineArgumentsFormat, - certificate.Thumbprint.ToUpperInvariant(), - keyChain - )) - { - RedirectStandardOutput = true, - RedirectStandardError = true - }; - - using (var process = Process.Start(processInfo)) - { - var output = process.StandardOutput.ReadToEnd() + process.StandardError.ReadToEnd(); - process.WaitForExit(); - - if (process.ExitCode != 0) - { - throw new InvalidOperationException($@"There was an error removing the certificate with thumbprint '{certificate.Thumbprint}'. - -{output}"); - } - } - } - - public EnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate( - DateTimeOffset notBefore, - DateTimeOffset notAfter, - string path = null, - bool trust = false, - bool includePrivateKey = false, - string password = null, - string subject = LocalhostHttpsDistinguishedName) - { - return EnsureValidCertificateExists(notBefore, notAfter, CertificatePurpose.HTTPS, path, trust, includePrivateKey, password, subject); - } - - public EnsureCertificateResult EnsureValidCertificateExists( - DateTimeOffset notBefore, - DateTimeOffset notAfter, - CertificatePurpose purpose, - string path = null, - bool trust = false, - bool includePrivateKey = false, - string password = null, - string subjectOverride = null) - { - if (purpose == CertificatePurpose.All) - { - throw new ArgumentException("The certificate must have a specific purpose."); - } - - var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: true).Concat( - ListCertificates(purpose, StoreName.My, StoreLocation.LocalMachine, isValid: true)); - - certificates = subjectOverride == null ? certificates : certificates.Where(c => c.Subject == subjectOverride); - - var result = EnsureCertificateResult.Succeeded; - - X509Certificate2 certificate = null; - if (certificates.Count() > 0) - { - certificate = certificates.FirstOrDefault(); - result = EnsureCertificateResult.ValidCertificatePresent; - } - else - { - try - { - switch (purpose) - { - case CertificatePurpose.All: - throw new InvalidOperationException("The certificate must have a specific purpose."); - case CertificatePurpose.HTTPS: - certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subjectOverride); - break; - default: - throw new InvalidOperationException("The certificate must have a purpose."); - } - } - catch - { - return EnsureCertificateResult.ErrorCreatingTheCertificate; - } - - try - { - certificate = SaveCertificateInStore(certificate, StoreName.My, StoreLocation.CurrentUser); - } - catch - { - return EnsureCertificateResult.ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore; - } - } - if (path != null) - { - try - { - ExportCertificate(certificate, path, includePrivateKey, password); - } - catch - { - return EnsureCertificateResult.ErrorExportingTheCertificate; - } - } - - if ((RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) && trust) - { - try - { - TrustCertificate(certificate); - } - catch (UserCancelledTrustException) - { - return EnsureCertificateResult.UserCancelledTrustStep; - } - catch - { - return EnsureCertificateResult.FailedToTrustTheCertificate; - } - } - - return result; - } - - // This is just to avoid breaking changes across repos. - // Will be renamed back to EnsureAspNetCoreHttpsDevelopmentCertificate once updates are made elsewhere. - public DetailedEnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate2( - DateTimeOffset notBefore, - DateTimeOffset notAfter, - string path = null, - bool trust = false, - bool includePrivateKey = false, - string password = null, - string subject = LocalhostHttpsDistinguishedName) - { - return EnsureValidCertificateExists2(notBefore, notAfter, CertificatePurpose.HTTPS, path, trust, includePrivateKey, password, subject); - } - - public DetailedEnsureCertificateResult EnsureValidCertificateExists2( - DateTimeOffset notBefore, - DateTimeOffset notAfter, - CertificatePurpose purpose, - string path, - bool trust, - bool includePrivateKey, - string password, - string subject) - { - if (purpose == CertificatePurpose.All) - { - throw new ArgumentException("The certificate must have a specific purpose."); - } - - var result = new DetailedEnsureCertificateResult(); - - var certificates = ListCertificates(purpose, StoreName.My, StoreLocation.CurrentUser, isValid: true, requireExportable: true, result.Diagnostics).Concat( - ListCertificates(purpose, StoreName.My, StoreLocation.LocalMachine, isValid: true, requireExportable: true, result.Diagnostics)); - - var filteredCertificates = subject == null ? certificates : certificates.Where(c => c.Subject == subject); - if (subject != null) - { - var excludedCertificates = certificates.Except(filteredCertificates); - - result.Diagnostics.Debug($"Filtering found certificates to those with a subject equal to '{subject}'"); - result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(filteredCertificates)); - result.Diagnostics.Debug($"Listing certificates excluded from consideration."); - result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(excludedCertificates)); - } - else - { - result.Diagnostics.Debug("Skipped filtering certificates by subject."); - } - - certificates = filteredCertificates; - - result.ResultCode = EnsureCertificateResult.Succeeded; - - X509Certificate2 certificate = null; - if (certificates.Count() > 0) - { - result.Diagnostics.Debug("Found valid certificates present on the machine."); - result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificates)); - certificate = certificates.First(); - result.Diagnostics.Debug("Selected certificate"); - result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificate)); - result.ResultCode = EnsureCertificateResult.ValidCertificatePresent; - } - else - { - result.Diagnostics.Debug("No valid certificates present on this machine. Trying to create one."); - try - { - switch (purpose) - { - case CertificatePurpose.All: - throw new InvalidOperationException("The certificate must have a specific purpose."); - case CertificatePurpose.HTTPS: - certificate = CreateAspNetCoreHttpsDevelopmentCertificate(notBefore, notAfter, subject, result.Diagnostics); - break; - default: - throw new InvalidOperationException("The certificate must have a purpose."); - } - } - catch (Exception e) - { - result.Diagnostics.Error("Error creating the certificate.", e); - result.ResultCode = EnsureCertificateResult.ErrorCreatingTheCertificate; - return result; - } - - try - { - certificate = SaveCertificateInStore(certificate, StoreName.My, StoreLocation.CurrentUser, result.Diagnostics); - } - catch (Exception e) - { - result.Diagnostics.Error($"Error saving the certificate in the certificate store '{StoreLocation.CurrentUser}\\{StoreName.My}'.", e); - result.ResultCode = EnsureCertificateResult.ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore; - return result; - } - } - if (path != null) - { - result.Diagnostics.Debug("Trying to export the certificate."); - result.Diagnostics.Debug(result.Diagnostics.DescribeCertificates(certificate)); - try - { - ExportCertificate(certificate, path, includePrivateKey, password, result.Diagnostics); - } - catch (Exception e) - { - result.Diagnostics.Error("An error ocurred exporting the certificate.", e); - result.ResultCode = EnsureCertificateResult.ErrorExportingTheCertificate; - return result; - } - } - - if ((RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) && trust) - { - try - { - result.Diagnostics.Debug("Trying to export the certificate."); - TrustCertificate(certificate, result.Diagnostics); - } - catch (UserCancelledTrustException) - { - result.Diagnostics.Error("The user cancelled trusting the certificate.", null); - result.ResultCode = EnsureCertificateResult.UserCancelledTrustStep; - return result; - } - catch (Exception e) - { - result.Diagnostics.Error("There was an error trusting the certificate.", e); - result.ResultCode = EnsureCertificateResult.FailedToTrustTheCertificate; - return result; - } - } - - return result; - } - - private class UserCancelledTrustException : Exception - { - } - - private enum RemoveLocations - { - Undefined, - Local, - Trusted, - All - } - - internal class DetailedEnsureCertificateResult - { - public EnsureCertificateResult ResultCode { get; set; } - public DiagnosticInformation Diagnostics { get; set; } = new DiagnosticInformation(); - } -#endif - - internal class DiagnosticInformation - { - public IList Messages { get; } = new List(); - - public IList Exceptions { get; } = new List(); - - internal void Debug(params string[] messages) - { - foreach (var message in messages) - { - Messages.Add(message); - } - } - - internal string[] DescribeCertificates(params X509Certificate2[] certificates) - { - return DescribeCertificates(certificates.AsEnumerable()); - } - - internal string[] DescribeCertificates(IEnumerable certificates) - { - var result = new List(); - result.Add($"'{certificates.Count()}' found matching the criteria."); - result.Add($"SUBJECT - THUMBPRINT - NOT BEFORE - EXPIRES - HAS PRIVATE KEY"); - foreach (var certificate in certificates) - { - result.Add(DescribeCertificate(certificate)); - } - - return result.ToArray(); - } - - private static string DescribeCertificate(X509Certificate2 certificate) => - $"{certificate.Subject} - {certificate.Thumbprint} - {certificate.NotBefore} - {certificate.NotAfter} - {certificate.HasPrivateKey}"; - - internal void Error(string preamble, Exception e) - { - Messages.Add(preamble); - if (Exceptions.Count > 0 && Exceptions[Exceptions.Count - 1] == e) - { - return; - } - - var ex = e; - while (ex != null) - { - Messages.Add("Exception message: " + ex.Message); - ex = ex.InnerException; - } - - } - } - } -} \ No newline at end of file diff --git a/src/Shared/CertificateGeneration/CertificatePurpose.cs b/src/Shared/CertificateGeneration/CertificatePurpose.cs deleted file mode 100644 index 7b3231f80d..0000000000 --- a/src/Shared/CertificateGeneration/CertificatePurpose.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Certificates.Generation -{ - internal enum CertificatePurpose - { - All, - HTTPS - } -} \ No newline at end of file diff --git a/src/Shared/CertificateGeneration/Directory.Build.props b/src/Shared/CertificateGeneration/Directory.Build.props deleted file mode 100644 index f3f6fc4b35..0000000000 --- a/src/Shared/CertificateGeneration/Directory.Build.props +++ /dev/null @@ -1,7 +0,0 @@ - - - - - Microsoft.AspNetCore.Certificates.Generation.Sources - - diff --git a/src/Shared/CertificateGeneration/EnsureCertificateResult.cs b/src/Shared/CertificateGeneration/EnsureCertificateResult.cs deleted file mode 100644 index 84c495249d..0000000000 --- a/src/Shared/CertificateGeneration/EnsureCertificateResult.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 - -namespace Microsoft.AspNetCore.Certificates.Generation -{ - internal enum EnsureCertificateResult - { - Succeeded = 1, - ValidCertificatePresent, - ErrorCreatingTheCertificate, - ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore, - ErrorExportingTheCertificate, - FailedToTrustTheCertificate, - UserCancelledTrustStep - } -} - -#endif \ No newline at end of file diff --git a/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs b/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs deleted file mode 100644 index f234c2edbc..0000000000 --- a/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Reflection; - -namespace Microsoft.Extensions.Internal -{ - /// - /// Helper related to generic interface definitions and implementing classes. - /// - internal static class ClosedGenericMatcher - { - /// - /// Determine whether is or implements a closed generic - /// created from . - /// - /// The of interest. - /// The open generic to match. Usually an interface. - /// - /// The closed generic created from that - /// is or implements. null if the two s have no such - /// relationship. - /// - /// - /// This method will return if is - /// typeof(KeyValuePair{,}), and is - /// typeof(KeyValuePair{string, object}). - /// - public static Type ExtractGenericInterface(Type queryType, Type interfaceType) - { - if (queryType == null) - { - throw new ArgumentNullException(nameof(queryType)); - } - - if (interfaceType == null) - { - throw new ArgumentNullException(nameof(interfaceType)); - } - - if (IsGenericInstantiation(queryType, interfaceType)) - { - // queryType matches (i.e. is a closed generic type created from) the open generic type. - return queryType; - } - - // Otherwise check all interfaces the type implements for a match. - // - If multiple different generic instantiations exists, we want the most derived one. - // - If that doesn't break the tie, then we sort alphabetically so that it's deterministic. - // - // We do this by looking at interfaces on the type, and recursing to the base type - // if we don't find any matches. - return GetGenericInstantiation(queryType, interfaceType); - } - - private static bool IsGenericInstantiation(Type candidate, Type interfaceType) - { - return - candidate.GetTypeInfo().IsGenericType && - candidate.GetGenericTypeDefinition() == interfaceType; - } - - private static Type GetGenericInstantiation(Type queryType, Type interfaceType) - { - Type bestMatch = null; - var interfaces = queryType.GetInterfaces(); - foreach (var @interface in interfaces) - { - if (IsGenericInstantiation(@interface, interfaceType)) - { - if (bestMatch == null) - { - bestMatch = @interface; - } - else if (StringComparer.Ordinal.Compare(@interface.FullName, bestMatch.FullName) < 0) - { - bestMatch = @interface; - } - else - { - // There are two matches at this level of the class hierarchy, but @interface is after - // bestMatch in the sort order. - } - } - } - - if (bestMatch != null) - { - return bestMatch; - } - - // BaseType will be null for object and interfaces, which means we've reached 'bottom'. - var baseType = queryType?.GetTypeInfo().BaseType; - if (baseType == null) - { - return null; - } - else - { - return GetGenericInstantiation(baseType, interfaceType); - } - } - } -} \ No newline at end of file diff --git a/src/Shared/CopyOnWriteDictionary/CopyOnWriteDictionary.cs b/src/Shared/CopyOnWriteDictionary/CopyOnWriteDictionary.cs deleted file mode 100644 index 1408059ad9..0000000000 --- a/src/Shared/CopyOnWriteDictionary/CopyOnWriteDictionary.cs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Microsoft.Extensions.Internal -{ - internal class CopyOnWriteDictionary : IDictionary - { - private readonly IDictionary _sourceDictionary; - private readonly IEqualityComparer _comparer; - private IDictionary _innerDictionary; - - public CopyOnWriteDictionary( - IDictionary sourceDictionary, - IEqualityComparer comparer) - { - if (sourceDictionary == null) - { - throw new ArgumentNullException(nameof(sourceDictionary)); - } - - if (comparer == null) - { - throw new ArgumentNullException(nameof(comparer)); - } - - _sourceDictionary = sourceDictionary; - _comparer = comparer; - } - - private IDictionary ReadDictionary - { - get - { - return _innerDictionary ?? _sourceDictionary; - } - } - - private IDictionary WriteDictionary - { - get - { - if (_innerDictionary == null) - { - _innerDictionary = new Dictionary(_sourceDictionary, - _comparer); - } - - return _innerDictionary; - } - } - - public virtual ICollection Keys - { - get - { - return ReadDictionary.Keys; - } - } - - public virtual ICollection Values - { - get - { - return ReadDictionary.Values; - } - } - - public virtual int Count - { - get - { - return ReadDictionary.Count; - } - } - - public virtual bool IsReadOnly - { - get - { - return false; - } - } - - public virtual TValue this[TKey key] - { - get - { - return ReadDictionary[key]; - } - set - { - WriteDictionary[key] = value; - } - } - - public virtual bool ContainsKey(TKey key) - { - return ReadDictionary.ContainsKey(key); - } - - public virtual void Add(TKey key, TValue value) - { - WriteDictionary.Add(key, value); - } - - public virtual bool Remove(TKey key) - { - return WriteDictionary.Remove(key); - } - - public virtual bool TryGetValue(TKey key, out TValue value) - { - return ReadDictionary.TryGetValue(key, out value); - } - - public virtual void Add(KeyValuePair item) - { - WriteDictionary.Add(item); - } - - public virtual void Clear() - { - WriteDictionary.Clear(); - } - - public virtual bool Contains(KeyValuePair item) - { - return ReadDictionary.Contains(item); - } - - public virtual void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ReadDictionary.CopyTo(array, arrayIndex); - } - - public bool Remove(KeyValuePair item) - { - return WriteDictionary.Remove(item); - } - - public virtual IEnumerator> GetEnumerator() - { - return ReadDictionary.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} \ No newline at end of file diff --git a/src/Shared/CopyOnWriteDictionary/CopyOnWriteDictionaryHolder.cs b/src/Shared/CopyOnWriteDictionary/CopyOnWriteDictionaryHolder.cs deleted file mode 100644 index 7cd935e940..0000000000 --- a/src/Shared/CopyOnWriteDictionary/CopyOnWriteDictionaryHolder.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.Extensions.Internal -{ - internal struct CopyOnWriteDictionaryHolder - { - private readonly Dictionary _source; - private Dictionary _copy; - - public CopyOnWriteDictionaryHolder(Dictionary source) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - _source = source; - _copy = null; - } - - public CopyOnWriteDictionaryHolder(CopyOnWriteDictionaryHolder source) - { - _source = source._copy ?? source._source; - _copy = null; - } - - public bool HasBeenCopied => _copy != null; - - public Dictionary ReadDictionary - { - get - { - if (_copy != null) - { - return _copy; - } - else if (_source != null) - { - return _source; - } - else - { - // Default-Constructor case - _copy = new Dictionary(); - return _copy; - } - } - } - - public Dictionary WriteDictionary - { - get - { - if (_copy == null && _source == null) - { - // Default-Constructor case - _copy = new Dictionary(); - } - else if (_copy == null) - { - _copy = new Dictionary(_source, _source.Comparer); - } - - return _copy; - } - } - - public Dictionary.KeyCollection Keys - { - get - { - return ReadDictionary.Keys; - } - } - - public Dictionary.ValueCollection Values - { - get - { - return ReadDictionary.Values; - } - } - - public int Count - { - get - { - return ReadDictionary.Count; - } - } - - public bool IsReadOnly - { - get - { - return false; - } - } - - public TValue this[TKey key] - { - get - { - return ReadDictionary[key]; - } - set - { - WriteDictionary[key] = value; - } - } - - public bool ContainsKey(TKey key) - { - return ReadDictionary.ContainsKey(key); - } - - public void Add(TKey key, TValue value) - { - WriteDictionary.Add(key, value); - } - - public bool Remove(TKey key) - { - return WriteDictionary.Remove(key); - } - - public bool TryGetValue(TKey key, out TValue value) - { - return ReadDictionary.TryGetValue(key, out value); - } - - public void Add(KeyValuePair item) - { - ((ICollection>)WriteDictionary).Add(item); - } - - public void Clear() - { - WriteDictionary.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ((ICollection>)ReadDictionary).Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((ICollection>)ReadDictionary).CopyTo(array, arrayIndex); - } - - public bool Remove(KeyValuePair item) - { - return ((ICollection>)WriteDictionary).Remove(item); - } - - public Dictionary.Enumerator GetEnumerator() - { - return ReadDictionary.GetEnumerator(); - } - } -} diff --git a/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs b/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs deleted file mode 100644 index 431b83a6e5..0000000000 --- a/src/Shared/ObjectMethodExecutor/AwaitableInfo.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Microsoft.Extensions.Internal -{ - internal struct AwaitableInfo - { - public Type AwaiterType { get; } - public PropertyInfo AwaiterIsCompletedProperty { get; } - public MethodInfo AwaiterGetResultMethod { get; } - public MethodInfo AwaiterOnCompletedMethod { get; } - public MethodInfo AwaiterUnsafeOnCompletedMethod { get; } - public Type ResultType { get; } - public MethodInfo GetAwaiterMethod { get; } - - public AwaitableInfo( - Type awaiterType, - PropertyInfo awaiterIsCompletedProperty, - MethodInfo awaiterGetResultMethod, - MethodInfo awaiterOnCompletedMethod, - MethodInfo awaiterUnsafeOnCompletedMethod, - Type resultType, - MethodInfo getAwaiterMethod) - { - AwaiterType = awaiterType; - AwaiterIsCompletedProperty = awaiterIsCompletedProperty; - AwaiterGetResultMethod = awaiterGetResultMethod; - AwaiterOnCompletedMethod = awaiterOnCompletedMethod; - AwaiterUnsafeOnCompletedMethod = awaiterUnsafeOnCompletedMethod; - ResultType = resultType; - GetAwaiterMethod = getAwaiterMethod; - } - - public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo) - { - // Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347 - - // Awaitable must have method matching "object GetAwaiter()" - var getAwaiterMethod = type.GetRuntimeMethods().FirstOrDefault(m => - m.Name.Equals("GetAwaiter", StringComparison.OrdinalIgnoreCase) - && m.GetParameters().Length == 0 - && m.ReturnType != null); - if (getAwaiterMethod == null) - { - awaitableInfo = default(AwaitableInfo); - return false; - } - - var awaiterType = getAwaiterMethod.ReturnType; - - // Awaiter must have property matching "bool IsCompleted { get; }" - var isCompletedProperty = awaiterType.GetRuntimeProperties().FirstOrDefault(p => - p.Name.Equals("IsCompleted", StringComparison.OrdinalIgnoreCase) - && p.PropertyType == typeof(bool) - && p.GetMethod != null); - if (isCompletedProperty == null) - { - awaitableInfo = default(AwaitableInfo); - return false; - } - - // Awaiter must implement INotifyCompletion - var awaiterInterfaces = awaiterType.GetInterfaces(); - var implementsINotifyCompletion = awaiterInterfaces.Any(t => t == typeof(INotifyCompletion)); - if (!implementsINotifyCompletion) - { - awaitableInfo = default(AwaitableInfo); - return false; - } - - // INotifyCompletion supplies a method matching "void OnCompleted(Action action)" - var iNotifyCompletionMap = awaiterType - .GetTypeInfo() - .GetRuntimeInterfaceMap(typeof(INotifyCompletion)); - var onCompletedMethod = iNotifyCompletionMap.InterfaceMethods.Single(m => - m.Name.Equals("OnCompleted", StringComparison.OrdinalIgnoreCase) - && m.ReturnType == typeof(void) - && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(Action)); - - // Awaiter optionally implements ICriticalNotifyCompletion - var implementsICriticalNotifyCompletion = awaiterInterfaces.Any(t => t == typeof(ICriticalNotifyCompletion)); - MethodInfo unsafeOnCompletedMethod; - if (implementsICriticalNotifyCompletion) - { - // ICriticalNotifyCompletion supplies a method matching "void UnsafeOnCompleted(Action action)" - var iCriticalNotifyCompletionMap = awaiterType - .GetTypeInfo() - .GetRuntimeInterfaceMap(typeof(ICriticalNotifyCompletion)); - unsafeOnCompletedMethod = iCriticalNotifyCompletionMap.InterfaceMethods.Single(m => - m.Name.Equals("UnsafeOnCompleted", StringComparison.OrdinalIgnoreCase) - && m.ReturnType == typeof(void) - && m.GetParameters().Length == 1 - && m.GetParameters()[0].ParameterType == typeof(Action)); - } - else - { - unsafeOnCompletedMethod = null; - } - - // Awaiter must have method matching "void GetResult" or "T GetResult()" - var getResultMethod = awaiterType.GetRuntimeMethods().FirstOrDefault(m => - m.Name.Equals("GetResult") - && m.GetParameters().Length == 0); - if (getResultMethod == null) - { - awaitableInfo = default(AwaitableInfo); - return false; - } - - awaitableInfo = new AwaitableInfo( - awaiterType, - isCompletedProperty, - getResultMethod, - onCompletedMethod, - unsafeOnCompletedMethod, - getResultMethod.ReturnType, - getAwaiterMethod); - return true; - } - } -} diff --git a/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs b/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs deleted file mode 100644 index 4e48ef09a1..0000000000 --- a/src/Shared/ObjectMethodExecutor/CoercedAwaitableInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq.Expressions; - -namespace Microsoft.Extensions.Internal -{ - internal struct CoercedAwaitableInfo - { - public AwaitableInfo AwaitableInfo { get; } - public Expression CoercerExpression { get; } - public Type CoercerResultType { get; } - public bool RequiresCoercion => CoercerExpression != null; - - public CoercedAwaitableInfo(AwaitableInfo awaitableInfo) - { - AwaitableInfo = awaitableInfo; - CoercerExpression = null; - CoercerResultType = null; - } - - public CoercedAwaitableInfo(Expression coercerExpression, Type coercerResultType, AwaitableInfo coercedAwaitableInfo) - { - CoercerExpression = coercerExpression; - CoercerResultType = coercerResultType; - AwaitableInfo = coercedAwaitableInfo; - } - - public static bool IsTypeAwaitable(Type type, out CoercedAwaitableInfo info) - { - if (AwaitableInfo.IsTypeAwaitable(type, out var directlyAwaitableInfo)) - { - info = new CoercedAwaitableInfo(directlyAwaitableInfo); - return true; - } - - // It's not directly awaitable, but maybe we can coerce it. - // Currently we support coercing FSharpAsync. - if (ObjectMethodExecutorFSharpSupport.TryBuildCoercerFromFSharpAsyncToAwaitable(type, - out var coercerExpression, - out var coercerResultType)) - { - if (AwaitableInfo.IsTypeAwaitable(coercerResultType, out var coercedAwaitableInfo)) - { - info = new CoercedAwaitableInfo(coercerExpression, coercerResultType, coercedAwaitableInfo); - return true; - } - } - - info = default(CoercedAwaitableInfo); - return false; - } - } -} diff --git a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs deleted file mode 100644 index f8e5b70f0d..0000000000 --- a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutor.cs +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; - -namespace Microsoft.Extensions.Internal -{ - internal class ObjectMethodExecutor - { - private readonly object[] _parameterDefaultValues; - private readonly MethodExecutorAsync _executorAsync; - private readonly MethodExecutor _executor; - - private static readonly ConstructorInfo _objectMethodExecutorAwaitableConstructor = - typeof(ObjectMethodExecutorAwaitable).GetConstructor(new[] { - typeof(object), // customAwaitable - typeof(Func), // getAwaiterMethod - typeof(Func), // isCompletedMethod - typeof(Func), // getResultMethod - typeof(Action), // onCompletedMethod - typeof(Action) // unsafeOnCompletedMethod - }); - - private ObjectMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo, object[] parameterDefaultValues) - { - if (methodInfo == null) - { - throw new ArgumentNullException(nameof(methodInfo)); - } - - MethodInfo = methodInfo; - MethodParameters = methodInfo.GetParameters(); - TargetTypeInfo = targetTypeInfo; - MethodReturnType = methodInfo.ReturnType; - - var isAwaitable = CoercedAwaitableInfo.IsTypeAwaitable(MethodReturnType, out var coercedAwaitableInfo); - - IsMethodAsync = isAwaitable; - AsyncResultType = isAwaitable ? coercedAwaitableInfo.AwaitableInfo.ResultType : null; - - // Upstream code may prefer to use the sync-executor even for async methods, because if it knows - // that the result is a specific Task where T is known, then it can directly cast to that type - // and await it without the extra heap allocations involved in the _executorAsync code path. - _executor = GetExecutor(methodInfo, targetTypeInfo); - - if (IsMethodAsync) - { - _executorAsync = GetExecutorAsync(methodInfo, targetTypeInfo, coercedAwaitableInfo); - } - - _parameterDefaultValues = parameterDefaultValues; - } - - private delegate ObjectMethodExecutorAwaitable MethodExecutorAsync(object target, object[] parameters); - - private delegate object MethodExecutor(object target, object[] parameters); - - private delegate void VoidMethodExecutor(object target, object[] parameters); - - public MethodInfo MethodInfo { get; } - - public ParameterInfo[] MethodParameters { get; } - - public TypeInfo TargetTypeInfo { get; } - - public Type AsyncResultType { get; } - - // This field is made internal set because it is set in unit tests. - public Type MethodReturnType { get; internal set; } - - public bool IsMethodAsync { get; } - - public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo) - { - return new ObjectMethodExecutor(methodInfo, targetTypeInfo, null); - } - - public static ObjectMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo, object[] parameterDefaultValues) - { - if (parameterDefaultValues == null) - { - throw new ArgumentNullException(nameof(parameterDefaultValues)); - } - - return new ObjectMethodExecutor(methodInfo, targetTypeInfo, parameterDefaultValues); - } - - /// - /// Executes the configured method on . This can be used whether or not - /// the configured method is asynchronous. - /// - /// - /// Even if the target method is asynchronous, it's desirable to invoke it using Execute rather than - /// ExecuteAsync if you know at compile time what the return type is, because then you can directly - /// "await" that value (via a cast), and then the generated code will be able to reference the - /// resulting awaitable as a value-typed variable. If you use ExecuteAsync instead, the generated - /// code will have to treat the resulting awaitable as a boxed object, because it doesn't know at - /// compile time what type it would be. - /// - /// The object whose method is to be executed. - /// Parameters to pass to the method. - /// The method return value. - public object Execute(object target, object[] parameters) - { - return _executor(target, parameters); - } - - /// - /// Executes the configured method on . This can only be used if the configured - /// method is asynchronous. - /// - /// - /// If you don't know at compile time the type of the method's returned awaitable, you can use ExecuteAsync, - /// which supplies an awaitable-of-object. This always works, but can incur several extra heap allocations - /// as compared with using Execute and then using "await" on the result value typecasted to the known - /// awaitable type. The possible extra heap allocations are for: - /// - /// 1. The custom awaitable (though usually there's a heap allocation for this anyway, since normally - /// it's a reference type, and you normally create a new instance per call). - /// 2. The custom awaiter (whether or not it's a value type, since if it's not, you need a new instance - /// of it, and if it is, it will have to be boxed so the calling code can reference it as an object). - /// 3. The async result value, if it's a value type (it has to be boxed as an object, since the calling - /// code doesn't know what type it's going to be). - /// - /// The object whose method is to be executed. - /// Parameters to pass to the method. - /// An object that you can "await" to get the method return value. - public ObjectMethodExecutorAwaitable ExecuteAsync(object target, object[] parameters) - { - return _executorAsync(target, parameters); - } - - public object GetDefaultValueForParameter(int index) - { - if (_parameterDefaultValues == null) - { - throw new InvalidOperationException($"Cannot call {nameof(GetDefaultValueForParameter)}, because no parameter default values were supplied."); - } - - if (index < 0 || index > MethodParameters.Length - 1) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - return _parameterDefaultValues[index]; - } - - private static MethodExecutor GetExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo) - { - // Parameters to executor - var targetParameter = Expression.Parameter(typeof(object), "target"); - var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); - - // Build parameter list - var parameters = new List(); - var paramInfos = methodInfo.GetParameters(); - for (int i = 0; i < paramInfos.Length; i++) - { - var paramInfo = paramInfos[i]; - var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i)); - var valueCast = Expression.Convert(valueObj, paramInfo.ParameterType); - - // valueCast is "(Ti) parameters[i]" - parameters.Add(valueCast); - } - - // Call method - var instanceCast = Expression.Convert(targetParameter, targetTypeInfo.AsType()); - var methodCall = Expression.Call(instanceCast, methodInfo, parameters); - - // methodCall is "((Ttarget) target) method((T0) parameters[0], (T1) parameters[1], ...)" - // Create function - if (methodCall.Type == typeof(void)) - { - var lambda = Expression.Lambda(methodCall, targetParameter, parametersParameter); - var voidExecutor = lambda.Compile(); - return WrapVoidMethod(voidExecutor); - } - else - { - // must coerce methodCall to match ActionExecutor signature - var castMethodCall = Expression.Convert(methodCall, typeof(object)); - var lambda = Expression.Lambda(castMethodCall, targetParameter, parametersParameter); - return lambda.Compile(); - } - } - - private static MethodExecutor WrapVoidMethod(VoidMethodExecutor executor) - { - return delegate (object target, object[] parameters) - { - executor(target, parameters); - return null; - }; - } - - private static MethodExecutorAsync GetExecutorAsync( - MethodInfo methodInfo, - TypeInfo targetTypeInfo, - CoercedAwaitableInfo coercedAwaitableInfo) - { - // Parameters to executor - var targetParameter = Expression.Parameter(typeof(object), "target"); - var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); - - // Build parameter list - var parameters = new List(); - var paramInfos = methodInfo.GetParameters(); - for (int i = 0; i < paramInfos.Length; i++) - { - var paramInfo = paramInfos[i]; - var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i)); - var valueCast = Expression.Convert(valueObj, paramInfo.ParameterType); - - // valueCast is "(Ti) parameters[i]" - parameters.Add(valueCast); - } - - // Call method - var instanceCast = Expression.Convert(targetParameter, targetTypeInfo.AsType()); - var methodCall = Expression.Call(instanceCast, methodInfo, parameters); - - // Using the method return value, construct an ObjectMethodExecutorAwaitable based on - // the info we have about its implementation of the awaitable pattern. Note that all - // the funcs/actions we construct here are precompiled, so that only one instance of - // each is preserved throughout the lifetime of the ObjectMethodExecutor. - - // var getAwaiterFunc = (object awaitable) => - // (object)((CustomAwaitableType)awaitable).GetAwaiter(); - var customAwaitableParam = Expression.Parameter(typeof(object), "awaitable"); - var awaitableInfo = coercedAwaitableInfo.AwaitableInfo; - var postCoercionMethodReturnType = coercedAwaitableInfo.CoercerResultType ?? methodInfo.ReturnType; - var getAwaiterFunc = Expression.Lambda>( - Expression.Convert( - Expression.Call( - Expression.Convert(customAwaitableParam, postCoercionMethodReturnType), - awaitableInfo.GetAwaiterMethod), - typeof(object)), - customAwaitableParam).Compile(); - - // var isCompletedFunc = (object awaiter) => - // ((CustomAwaiterType)awaiter).IsCompleted; - var isCompletedParam = Expression.Parameter(typeof(object), "awaiter"); - var isCompletedFunc = Expression.Lambda>( - Expression.MakeMemberAccess( - Expression.Convert(isCompletedParam, awaitableInfo.AwaiterType), - awaitableInfo.AwaiterIsCompletedProperty), - isCompletedParam).Compile(); - - var getResultParam = Expression.Parameter(typeof(object), "awaiter"); - Func getResultFunc; - if (awaitableInfo.ResultType == typeof(void)) - { - // var getResultFunc = (object awaiter) => - // { - // ((CustomAwaiterType)awaiter).GetResult(); // We need to invoke this to surface any exceptions - // return (object)null; - // }; - getResultFunc = Expression.Lambda>( - Expression.Block( - Expression.Call( - Expression.Convert(getResultParam, awaitableInfo.AwaiterType), - awaitableInfo.AwaiterGetResultMethod), - Expression.Constant(null) - ), - getResultParam).Compile(); - } - else - { - // var getResultFunc = (object awaiter) => - // (object)((CustomAwaiterType)awaiter).GetResult(); - getResultFunc = Expression.Lambda>( - Expression.Convert( - Expression.Call( - Expression.Convert(getResultParam, awaitableInfo.AwaiterType), - awaitableInfo.AwaiterGetResultMethod), - typeof(object)), - getResultParam).Compile(); - } - - // var onCompletedFunc = (object awaiter, Action continuation) => { - // ((CustomAwaiterType)awaiter).OnCompleted(continuation); - // }; - var onCompletedParam1 = Expression.Parameter(typeof(object), "awaiter"); - var onCompletedParam2 = Expression.Parameter(typeof(Action), "continuation"); - var onCompletedFunc = Expression.Lambda>( - Expression.Call( - Expression.Convert(onCompletedParam1, awaitableInfo.AwaiterType), - awaitableInfo.AwaiterOnCompletedMethod, - onCompletedParam2), - onCompletedParam1, - onCompletedParam2).Compile(); - - Action unsafeOnCompletedFunc = null; - if (awaitableInfo.AwaiterUnsafeOnCompletedMethod != null) - { - // var unsafeOnCompletedFunc = (object awaiter, Action continuation) => { - // ((CustomAwaiterType)awaiter).UnsafeOnCompleted(continuation); - // }; - var unsafeOnCompletedParam1 = Expression.Parameter(typeof(object), "awaiter"); - var unsafeOnCompletedParam2 = Expression.Parameter(typeof(Action), "continuation"); - unsafeOnCompletedFunc = Expression.Lambda>( - Expression.Call( - Expression.Convert(unsafeOnCompletedParam1, awaitableInfo.AwaiterType), - awaitableInfo.AwaiterUnsafeOnCompletedMethod, - unsafeOnCompletedParam2), - unsafeOnCompletedParam1, - unsafeOnCompletedParam2).Compile(); - } - - // If we need to pass the method call result through a coercer function to get an - // awaitable, then do so. - var coercedMethodCall = coercedAwaitableInfo.RequiresCoercion - ? Expression.Invoke(coercedAwaitableInfo.CoercerExpression, methodCall) - : (Expression)methodCall; - - // return new ObjectMethodExecutorAwaitable( - // (object)coercedMethodCall, - // getAwaiterFunc, - // isCompletedFunc, - // getResultFunc, - // onCompletedFunc, - // unsafeOnCompletedFunc); - var returnValueExpression = Expression.New( - _objectMethodExecutorAwaitableConstructor, - Expression.Convert(coercedMethodCall, typeof(object)), - Expression.Constant(getAwaiterFunc), - Expression.Constant(isCompletedFunc), - Expression.Constant(getResultFunc), - Expression.Constant(onCompletedFunc), - Expression.Constant(unsafeOnCompletedFunc, typeof(Action))); - - var lambda = Expression.Lambda(returnValueExpression, targetParameter, parametersParameter); - return lambda.Compile(); - } - } -} diff --git a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorAwaitable.cs b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorAwaitable.cs deleted file mode 100644 index 7509b86b2b..0000000000 --- a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorAwaitable.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Runtime.CompilerServices; - -namespace Microsoft.Extensions.Internal -{ - /// - /// Provides a common awaitable structure that can - /// return, regardless of whether the underlying value is a System.Task, an FSharpAsync, or an - /// application-defined custom awaitable. - /// - internal struct ObjectMethodExecutorAwaitable - { - private readonly object _customAwaitable; - private readonly Func _getAwaiterMethod; - private readonly Func _isCompletedMethod; - private readonly Func _getResultMethod; - private readonly Action _onCompletedMethod; - private readonly Action _unsafeOnCompletedMethod; - - // Perf note: since we're requiring the customAwaitable to be supplied here as an object, - // this will trigger a further allocation if it was a value type (i.e., to box it). We can't - // fix this by making the customAwaitable type generic, because the calling code typically - // does not know the type of the awaitable/awaiter at compile-time anyway. - // - // However, we could fix it by not passing the customAwaitable here at all, and instead - // passing a func that maps directly from the target object (e.g., controller instance), - // target method (e.g., action method info), and params array to the custom awaiter in the - // GetAwaiter() method below. In effect, by delaying the actual method call until the - // upstream code calls GetAwaiter on this ObjectMethodExecutorAwaitable instance. - // This optimization is not currently implemented because: - // [1] It would make no difference when the awaitable was an object type, which is - // by far the most common scenario (e.g., System.Task). - // [2] It would be complex - we'd need some kind of object pool to track all the parameter - // arrays until we needed to use them in GetAwaiter(). - // We can reconsider this in the future if there's a need to optimize for ValueTask - // or other value-typed awaitables. - - public ObjectMethodExecutorAwaitable( - object customAwaitable, - Func getAwaiterMethod, - Func isCompletedMethod, - Func getResultMethod, - Action onCompletedMethod, - Action unsafeOnCompletedMethod) - { - _customAwaitable = customAwaitable; - _getAwaiterMethod = getAwaiterMethod; - _isCompletedMethod = isCompletedMethod; - _getResultMethod = getResultMethod; - _onCompletedMethod = onCompletedMethod; - _unsafeOnCompletedMethod = unsafeOnCompletedMethod; - } - - public Awaiter GetAwaiter() - { - var customAwaiter = _getAwaiterMethod(_customAwaitable); - return new Awaiter(customAwaiter, _isCompletedMethod, _getResultMethod, _onCompletedMethod, _unsafeOnCompletedMethod); - } - - public struct Awaiter : ICriticalNotifyCompletion - { - private readonly object _customAwaiter; - private readonly Func _isCompletedMethod; - private readonly Func _getResultMethod; - private readonly Action _onCompletedMethod; - private readonly Action _unsafeOnCompletedMethod; - - public Awaiter( - object customAwaiter, - Func isCompletedMethod, - Func getResultMethod, - Action onCompletedMethod, - Action unsafeOnCompletedMethod) - { - _customAwaiter = customAwaiter; - _isCompletedMethod = isCompletedMethod; - _getResultMethod = getResultMethod; - _onCompletedMethod = onCompletedMethod; - _unsafeOnCompletedMethod = unsafeOnCompletedMethod; - } - - public bool IsCompleted => _isCompletedMethod(_customAwaiter); - - public object GetResult() => _getResultMethod(_customAwaiter); - - public void OnCompleted(Action continuation) - { - _onCompletedMethod(_customAwaiter, continuation); - } - - public void UnsafeOnCompleted(Action continuation) - { - // If the underlying awaitable implements ICriticalNotifyCompletion, use its UnsafeOnCompleted. - // If not, fall back on using its OnCompleted. - // - // Why this is safe: - // - Implementing ICriticalNotifyCompletion is a way of saying the caller can choose whether it - // needs the execution context to be preserved (which it signals by calling OnCompleted), or - // that it doesn't (which it signals by calling UnsafeOnCompleted). Obviously it's faster *not* - // to preserve and restore the context, so we prefer that where possible. - // - If a caller doesn't need the execution context to be preserved and hence calls UnsafeOnCompleted, - // there's no harm in preserving it anyway - it's just a bit of wasted cost. That's what will happen - // if a caller sees that the proxy implements ICriticalNotifyCompletion but the proxy chooses to - // pass the call on to the underlying awaitable's OnCompleted method. - - var underlyingMethodToUse = _unsafeOnCompletedMethod ?? _onCompletedMethod; - underlyingMethodToUse(_customAwaiter, continuation); - } - } - } -} \ No newline at end of file diff --git a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs b/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs deleted file mode 100644 index 2198c0ce45..0000000000 --- a/src/Shared/ObjectMethodExecutor/ObjectMethodExecutorFSharpSupport.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.Internal -{ - /// - /// Helper for detecting whether a given type is FSharpAsync`1, and if so, supplying - /// an for mapping instances of that type to a C# awaitable. - /// - /// - /// The main design goal here is to avoid taking a compile-time dependency on - /// FSharp.Core.dll, because non-F# applications wouldn't use it. So all the references - /// to FSharp types have to be constructed dynamically at runtime. - /// - internal static class ObjectMethodExecutorFSharpSupport - { - private static object _fsharpValuesCacheLock = new object(); - private static Assembly _fsharpCoreAssembly; - private static MethodInfo _fsharpAsyncStartAsTaskGenericMethod; - private static PropertyInfo _fsharpOptionOfTaskCreationOptionsNoneProperty; - private static PropertyInfo _fsharpOptionOfCancellationTokenNoneProperty; - - public static bool TryBuildCoercerFromFSharpAsyncToAwaitable( - Type possibleFSharpAsyncType, - out Expression coerceToAwaitableExpression, - out Type awaitableType) - { - var methodReturnGenericType = possibleFSharpAsyncType.IsGenericType - ? possibleFSharpAsyncType.GetGenericTypeDefinition() - : null; - - if (!IsFSharpAsyncOpenGenericType(methodReturnGenericType)) - { - coerceToAwaitableExpression = null; - awaitableType = null; - return false; - } - - var awaiterResultType = possibleFSharpAsyncType.GetGenericArguments().Single(); - awaitableType = typeof(Task<>).MakeGenericType(awaiterResultType); - - // coerceToAwaitableExpression = (object fsharpAsync) => - // { - // return (object)FSharpAsync.StartAsTask( - // (Microsoft.FSharp.Control.FSharpAsync)fsharpAsync, - // FSharpOption.None, - // FSharpOption.None); - // }; - var startAsTaskClosedMethod = _fsharpAsyncStartAsTaskGenericMethod - .MakeGenericMethod(awaiterResultType); - var coerceToAwaitableParam = Expression.Parameter(typeof(object)); - coerceToAwaitableExpression = Expression.Lambda( - Expression.Convert( - Expression.Call( - startAsTaskClosedMethod, - Expression.Convert(coerceToAwaitableParam, possibleFSharpAsyncType), - Expression.MakeMemberAccess(null, _fsharpOptionOfTaskCreationOptionsNoneProperty), - Expression.MakeMemberAccess(null, _fsharpOptionOfCancellationTokenNoneProperty)), - typeof(object)), - coerceToAwaitableParam); - - return true; - } - - private static bool IsFSharpAsyncOpenGenericType(Type possibleFSharpAsyncGenericType) - { - var typeFullName = possibleFSharpAsyncGenericType?.FullName; - if (!string.Equals(typeFullName, "Microsoft.FSharp.Control.FSharpAsync`1", StringComparison.Ordinal)) - { - return false; - } - - lock (_fsharpValuesCacheLock) - { - if (_fsharpCoreAssembly != null) - { - // Since we've already found the real FSharpAsync.Core assembly, we just have - // to check that the supplied FSharpAsync`1 type is the one from that assembly. - return possibleFSharpAsyncGenericType.Assembly == _fsharpCoreAssembly; - } - else - { - // We'll keep trying to find the FSharp types/values each time any type called - // FSharpAsync`1 is supplied. - return TryPopulateFSharpValueCaches(possibleFSharpAsyncGenericType); - } - } - } - - private static bool TryPopulateFSharpValueCaches(Type possibleFSharpAsyncGenericType) - { - var assembly = possibleFSharpAsyncGenericType.Assembly; - var fsharpOptionType = assembly.GetType("Microsoft.FSharp.Core.FSharpOption`1"); - var fsharpAsyncType = assembly.GetType("Microsoft.FSharp.Control.FSharpAsync"); - - if (fsharpOptionType == null || fsharpAsyncType == null) - { - return false; - } - - // Get a reference to FSharpOption.None - var fsharpOptionOfTaskCreationOptionsType = fsharpOptionType - .MakeGenericType(typeof(TaskCreationOptions)); - _fsharpOptionOfTaskCreationOptionsNoneProperty = fsharpOptionOfTaskCreationOptionsType - .GetTypeInfo() - .GetRuntimeProperty("None"); - - // Get a reference to FSharpOption.None - var fsharpOptionOfCancellationTokenType = fsharpOptionType - .MakeGenericType(typeof(CancellationToken)); - _fsharpOptionOfCancellationTokenNoneProperty = fsharpOptionOfCancellationTokenType - .GetTypeInfo() - .GetRuntimeProperty("None"); - - // Get a reference to FSharpAsync.StartAsTask<> - var fsharpAsyncMethods = fsharpAsyncType - .GetRuntimeMethods() - .Where(m => m.Name.Equals("StartAsTask", StringComparison.Ordinal)); - foreach (var candidateMethodInfo in fsharpAsyncMethods) - { - var parameters = candidateMethodInfo.GetParameters(); - if (parameters.Length == 3 - && TypesHaveSameIdentity(parameters[0].ParameterType, possibleFSharpAsyncGenericType) - && parameters[1].ParameterType == fsharpOptionOfTaskCreationOptionsType - && parameters[2].ParameterType == fsharpOptionOfCancellationTokenType) - { - // This really does look like the correct method (and hence assembly). - _fsharpAsyncStartAsTaskGenericMethod = candidateMethodInfo; - _fsharpCoreAssembly = assembly; - break; - } - } - - return _fsharpCoreAssembly != null; - } - - private static bool TypesHaveSameIdentity(Type type1, Type type2) - { - return type1.Assembly == type2.Assembly - && string.Equals(type1.Namespace, type2.Namespace, StringComparison.Ordinal) - && string.Equals(type1.Name, type2.Name, StringComparison.Ordinal); - } - } -} diff --git a/src/Shared/Process/ProcessHelper.cs b/src/Shared/Process/ProcessHelper.cs deleted file mode 100644 index c6cbd1f970..0000000000 --- a/src/Shared/Process/ProcessHelper.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; - -namespace Microsoft.Extensions.Internal -{ - internal static class ProcessExtensions - { - private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30); - - public static void KillTree(this Process process) => process.KillTree(_defaultTimeout); - - public static void KillTree(this Process process, TimeSpan timeout) - { - var pid = process.Id; - if (_isWindows) - { - RunProcessAndWaitForExit( - "taskkill", - $"/T /F /PID {pid}", - timeout, - out var _); - } - else - { - var children = new HashSet(); - GetAllChildIdsUnix(pid, children, timeout); - foreach (var childId in children) - { - KillProcessUnix(childId, timeout); - } - KillProcessUnix(pid, timeout); - } - } - - private static void GetAllChildIdsUnix(int parentId, ISet children, TimeSpan timeout) - { - RunProcessAndWaitForExit( - "pgrep", - $"-P {parentId}", - timeout, - out var stdout); - - if (!string.IsNullOrEmpty(stdout)) - { - using (var reader = new StringReader(stdout)) - { - while (true) - { - var text = reader.ReadLine(); - if (text == null) - { - return; - } - - if (int.TryParse(text, out var id)) - { - children.Add(id); - // Recursively get the children - GetAllChildIdsUnix(id, children, timeout); - } - } - } - } - } - - private static void KillProcessUnix(int processId, TimeSpan timeout) - { - RunProcessAndWaitForExit( - "kill", - $"-TERM {processId}", - timeout, - out var stdout); - } - - private static void RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout) - { - var startInfo = new ProcessStartInfo - { - FileName = fileName, - Arguments = arguments, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - }; - - var process = Process.Start(startInfo); - - stdout = null; - if (process.WaitForExit((int)timeout.TotalMilliseconds)) - { - stdout = process.StandardOutput.ReadToEnd(); - } - else - { - process.Kill(); - } - } - } -} diff --git a/src/Shared/PropertyActivator/PropertyActivator.cs b/src/Shared/PropertyActivator/PropertyActivator.cs deleted file mode 100644 index 925f6a76ae..0000000000 --- a/src/Shared/PropertyActivator/PropertyActivator.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Reflection; - -namespace Microsoft.Extensions.Internal -{ - internal class PropertyActivator - { - private readonly Func _valueAccessor; - private readonly Action _fastPropertySetter; - - public PropertyActivator( - PropertyInfo propertyInfo, - Func valueAccessor) - { - if (propertyInfo == null) - { - throw new ArgumentNullException(nameof(propertyInfo)); - } - - if (valueAccessor == null) - { - throw new ArgumentNullException(nameof(valueAccessor)); - } - - PropertyInfo = propertyInfo; - _valueAccessor = valueAccessor; - _fastPropertySetter = PropertyHelper.MakeFastPropertySetter(propertyInfo); - } - - public PropertyInfo PropertyInfo { get; private set; } - - public object Activate(object instance, TContext context) - { - if (instance == null) - { - throw new ArgumentNullException(nameof(instance)); - } - - var value = _valueAccessor(context); - _fastPropertySetter(instance, value); - return value; - } - - public static PropertyActivator[] GetPropertiesToActivate( - Type type, - Type activateAttributeType, - Func> createActivateInfo) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (activateAttributeType == null) - { - throw new ArgumentNullException(nameof(activateAttributeType)); - } - - if (createActivateInfo == null) - { - throw new ArgumentNullException(nameof(createActivateInfo)); - } - - return GetPropertiesToActivate(type, activateAttributeType, createActivateInfo, includeNonPublic: false); - } - - public static PropertyActivator[] GetPropertiesToActivate( - Type type, - Type activateAttributeType, - Func> createActivateInfo, - bool includeNonPublic) - { - if (type == null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (activateAttributeType == null) - { - throw new ArgumentNullException(nameof(activateAttributeType)); - } - - if (createActivateInfo == null) - { - throw new ArgumentNullException(nameof(createActivateInfo)); - } - - var properties = type.GetRuntimeProperties() - .Where((property) => - { - return - property.IsDefined(activateAttributeType) && - property.GetIndexParameters().Length == 0 && - property.SetMethod != null && - !property.SetMethod.IsStatic; - }); - - if (!includeNonPublic) - { - properties = properties.Where(property => property.SetMethod.IsPublic); - } - - return properties.Select(createActivateInfo).ToArray(); - } - } -} \ No newline at end of file diff --git a/src/Shared/PropertyHelper/PropertyHelper.cs b/src/Shared/PropertyHelper/PropertyHelper.cs deleted file mode 100644 index f6aad151e5..0000000000 --- a/src/Shared/PropertyHelper/PropertyHelper.cs +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Microsoft.Extensions.Internal -{ - internal class PropertyHelper - { - // Delegate type for a by-ref property getter - private delegate TValue ByRefFunc(ref TDeclaringType arg); - - private static readonly MethodInfo CallPropertyGetterOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter)); - - private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetterByReference)); - - private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetter)); - - private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallNullSafePropertyGetterByReference)); - - private static readonly MethodInfo CallPropertySetterOpenGenericMethod = - typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter)); - - // Using an array rather than IEnumerable, as target will be called on the hot path numerous times. - private static readonly ConcurrentDictionary PropertiesCache = - new ConcurrentDictionary(); - - private static readonly ConcurrentDictionary VisiblePropertiesCache = - new ConcurrentDictionary(); - - // We need to be able to check if a type is a 'ref struct' - but we need to be able to compile - // for platforms where the attribute is not defined, like net46. So we can fetch the attribute - // by late binding. If the attribute isn't defined, then we assume we won't encounter any - // 'ref struct' types. - private static readonly Type IsByRefLikeAttribute = Type.GetType("System.Runtime.CompilerServices.IsByRefLikeAttribute", throwOnError: false); - - private Action _valueSetter; - private Func _valueGetter; - - /// - /// Initializes a fast . - /// This constructor does not cache the helper. For caching, use . - /// - public PropertyHelper(PropertyInfo property) - { - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } - - Property = property; - Name = property.Name; - } - - /// - /// Gets the backing . - /// - public PropertyInfo Property { get; } - - /// - /// Gets (or sets in derived types) the property name. - /// - public virtual string Name { get; protected set; } - - /// - /// Gets the property value getter. - /// - public Func ValueGetter - { - get - { - if (_valueGetter == null) - { - _valueGetter = MakeFastPropertyGetter(Property); - } - - return _valueGetter; - } - } - - /// - /// Gets the property value setter. - /// - public Action ValueSetter - { - get - { - if (_valueSetter == null) - { - _valueSetter = MakeFastPropertySetter(Property); - } - - return _valueSetter; - } - } - - /// - /// Returns the property value for the specified . - /// - /// The object whose property value will be returned. - /// The property value. - public object GetValue(object instance) - { - return ValueGetter(instance); - } - - /// - /// Sets the property value for the specified . - /// - /// The object whose property value will be set. - /// The property value. - public void SetValue(object instance, object value) - { - ValueSetter(instance, value); - } - - /// - /// Creates and caches fast property helpers that expose getters for every public get property on the - /// underlying type. - /// - /// The type info to extract property accessors for. - /// A cached array of all public properties of the specified type. - /// - public static PropertyHelper[] GetProperties(TypeInfo typeInfo) - { - return GetProperties(typeInfo.AsType()); - } - - /// - /// Creates and caches fast property helpers that expose getters for every public get property on the - /// specified type. - /// - /// The type to extract property accessors for. - /// A cached array of all public properties of the specified type. - /// - public static PropertyHelper[] GetProperties(Type type) - { - return GetProperties(type, CreateInstance, PropertiesCache); - } - - /// - /// - /// Creates and caches fast property helpers that expose getters for every non-hidden get property - /// on the specified type. - /// - /// - /// excludes properties defined on base types that have been - /// hidden by definitions using the new keyword. - /// - /// - /// The type info to extract property accessors for. - /// - /// A cached array of all public properties of the specified type. - /// - public static PropertyHelper[] GetVisibleProperties(TypeInfo typeInfo) - { - return GetVisibleProperties(typeInfo.AsType(), CreateInstance, PropertiesCache, VisiblePropertiesCache); - } - - /// - /// - /// Creates and caches fast property helpers that expose getters for every non-hidden get property - /// on the specified type. - /// - /// - /// excludes properties defined on base types that have been - /// hidden by definitions using the new keyword. - /// - /// - /// The type to extract property accessors for. - /// - /// A cached array of all public properties of the specified type. - /// - public static PropertyHelper[] GetVisibleProperties(Type type) - { - return GetVisibleProperties(type, CreateInstance, PropertiesCache, VisiblePropertiesCache); - } - - /// - /// Creates a single fast property getter. The result is not cached. - /// - /// propertyInfo to extract the getter for. - /// a fast getter. - /// - /// This method is more memory efficient than a dynamically compiled lambda, and about the - /// same speed. - /// - public static Func MakeFastPropertyGetter(PropertyInfo propertyInfo) - { - Debug.Assert(propertyInfo != null); - - return MakeFastPropertyGetter( - propertyInfo, - CallPropertyGetterOpenGenericMethod, - CallPropertyGetterByReferenceOpenGenericMethod); - } - - /// - /// Creates a single fast property getter which is safe for a null input object. The result is not cached. - /// - /// propertyInfo to extract the getter for. - /// a fast getter. - /// - /// This method is more memory efficient than a dynamically compiled lambda, and about the - /// same speed. - /// - public static Func MakeNullSafeFastPropertyGetter(PropertyInfo propertyInfo) - { - Debug.Assert(propertyInfo != null); - - return MakeFastPropertyGetter( - propertyInfo, - CallNullSafePropertyGetterOpenGenericMethod, - CallNullSafePropertyGetterByReferenceOpenGenericMethod); - } - - private static Func MakeFastPropertyGetter( - PropertyInfo propertyInfo, - MethodInfo propertyGetterWrapperMethod, - MethodInfo propertyGetterByRefWrapperMethod) - { - Debug.Assert(propertyInfo != null); - - // Must be a generic method with a Func<,> parameter - Debug.Assert(propertyGetterWrapperMethod != null); - Debug.Assert(propertyGetterWrapperMethod.IsGenericMethodDefinition); - Debug.Assert(propertyGetterWrapperMethod.GetParameters().Length == 2); - - // Must be a generic method with a ByRefFunc<,> parameter - Debug.Assert(propertyGetterByRefWrapperMethod != null); - Debug.Assert(propertyGetterByRefWrapperMethod.IsGenericMethodDefinition); - Debug.Assert(propertyGetterByRefWrapperMethod.GetParameters().Length == 2); - - var getMethod = propertyInfo.GetMethod; - Debug.Assert(getMethod != null); - Debug.Assert(!getMethod.IsStatic); - Debug.Assert(getMethod.GetParameters().Length == 0); - - // Instance methods in the CLR can be turned into static methods where the first parameter - // is open over "target". This parameter is always passed by reference, so we have a code - // path for value types and a code path for reference types. - if (getMethod.DeclaringType.GetTypeInfo().IsValueType) - { - // Create a delegate (ref TDeclaringType) -> TValue - return MakeFastPropertyGetter( - typeof(ByRefFunc<,>), - getMethod, - propertyGetterByRefWrapperMethod); - } - else - { - // Create a delegate TDeclaringType -> TValue - return MakeFastPropertyGetter( - typeof(Func<,>), - getMethod, - propertyGetterWrapperMethod); - } - } - - private static Func MakeFastPropertyGetter( - Type openGenericDelegateType, - MethodInfo propertyGetMethod, - MethodInfo openGenericWrapperMethod) - { - var typeInput = propertyGetMethod.DeclaringType; - var typeOutput = propertyGetMethod.ReturnType; - - var delegateType = openGenericDelegateType.MakeGenericType(typeInput, typeOutput); - var propertyGetterDelegate = propertyGetMethod.CreateDelegate(delegateType); - - var wrapperDelegateMethod = openGenericWrapperMethod.MakeGenericMethod(typeInput, typeOutput); - var accessorDelegate = wrapperDelegateMethod.CreateDelegate( - typeof(Func), - propertyGetterDelegate); - - return (Func)accessorDelegate; - } - - /// - /// Creates a single fast property setter for reference types. The result is not cached. - /// - /// propertyInfo to extract the setter for. - /// a fast getter. - /// - /// This method is more memory efficient than a dynamically compiled lambda, and about the - /// same speed. This only works for reference types. - /// - public static Action MakeFastPropertySetter(PropertyInfo propertyInfo) - { - Debug.Assert(propertyInfo != null); - Debug.Assert(!propertyInfo.DeclaringType.GetTypeInfo().IsValueType); - - var setMethod = propertyInfo.SetMethod; - Debug.Assert(setMethod != null); - Debug.Assert(!setMethod.IsStatic); - Debug.Assert(setMethod.ReturnType == typeof(void)); - var parameters = setMethod.GetParameters(); - Debug.Assert(parameters.Length == 1); - - // Instance methods in the CLR can be turned into static methods where the first parameter - // is open over "target". This parameter is always passed by reference, so we have a code - // path for value types and a code path for reference types. - var typeInput = setMethod.DeclaringType; - var parameterType = parameters[0].ParameterType; - - // Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; } - var propertySetterAsAction = - setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, parameterType)); - var callPropertySetterClosedGenericMethod = - CallPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, parameterType); - var callPropertySetterDelegate = - callPropertySetterClosedGenericMethod.CreateDelegate( - typeof(Action), propertySetterAsAction); - - return (Action)callPropertySetterDelegate; - } - - /// - /// Given an object, adds each instance property with a public get method as a key and its - /// associated value to a dictionary. - /// - /// If the object is already an instance, then a copy - /// is returned. - /// - /// - /// The implementation of PropertyHelper will cache the property accessors per-type. This is - /// faster when the same type is used multiple times with ObjectToDictionary. - /// - public static IDictionary ObjectToDictionary(object value) - { - var dictionary = value as IDictionary; - if (dictionary != null) - { - return new Dictionary(dictionary, StringComparer.OrdinalIgnoreCase); - } - - dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); - - if (value != null) - { - foreach (var helper in GetProperties(value.GetType())) - { - dictionary[helper.Name] = helper.GetValue(value); - } - } - - return dictionary; - } - - private static PropertyHelper CreateInstance(PropertyInfo property) - { - return new PropertyHelper(property); - } - - // Called via reflection - private static object CallPropertyGetter( - Func getter, - object target) - { - return getter((TDeclaringType)target); - } - - // Called via reflection - private static object CallPropertyGetterByReference( - ByRefFunc getter, - object target) - { - var unboxed = (TDeclaringType)target; - return getter(ref unboxed); - } - - // Called via reflection - private static object CallNullSafePropertyGetter( - Func getter, - object target) - { - if (target == null) - { - return null; - } - - return getter((TDeclaringType)target); - } - - // Called via reflection - private static object CallNullSafePropertyGetterByReference( - ByRefFunc getter, - object target) - { - if (target == null) - { - return null; - } - - var unboxed = (TDeclaringType)target; - return getter(ref unboxed); - } - - private static void CallPropertySetter( - Action setter, - object target, - object value) - { - setter((TDeclaringType)target, (TValue)value); - } - - protected static PropertyHelper[] GetVisibleProperties( - Type type, - Func createPropertyHelper, - ConcurrentDictionary allPropertiesCache, - ConcurrentDictionary visiblePropertiesCache) - { - PropertyHelper[] result; - if (visiblePropertiesCache.TryGetValue(type, out result)) - { - return result; - } - - // The simple and common case, this is normal POCO object - no need to allocate. - var allPropertiesDefinedOnType = true; - var allProperties = GetProperties(type, createPropertyHelper, allPropertiesCache); - foreach (var propertyHelper in allProperties) - { - if (propertyHelper.Property.DeclaringType != type) - { - allPropertiesDefinedOnType = false; - break; - } - } - - if (allPropertiesDefinedOnType) - { - result = allProperties; - visiblePropertiesCache.TryAdd(type, result); - return result; - } - - // There's some inherited properties here, so we need to check for hiding via 'new'. - var filteredProperties = new List(allProperties.Length); - foreach (var propertyHelper in allProperties) - { - var declaringType = propertyHelper.Property.DeclaringType; - if (declaringType == type) - { - filteredProperties.Add(propertyHelper); - continue; - } - - // If this property was declared on a base type then look for the definition closest to the - // the type to see if we should include it. - var ignoreProperty = false; - - // Walk up the hierarchy until we find the type that actually declares this - // PropertyInfo. - var currentTypeInfo = type.GetTypeInfo(); - var declaringTypeInfo = declaringType.GetTypeInfo(); - while (currentTypeInfo != null && currentTypeInfo != declaringTypeInfo) - { - // We've found a 'more proximal' public definition - var declaredProperty = currentTypeInfo.GetDeclaredProperty(propertyHelper.Name); - if (declaredProperty != null) - { - ignoreProperty = true; - break; - } - - currentTypeInfo = currentTypeInfo.BaseType?.GetTypeInfo(); - } - - if (!ignoreProperty) - { - filteredProperties.Add(propertyHelper); - } - } - - result = filteredProperties.ToArray(); - visiblePropertiesCache.TryAdd(type, result); - return result; - } - - protected static PropertyHelper[] GetProperties( - Type type, - Func createPropertyHelper, - ConcurrentDictionary cache) - { - // Unwrap nullable types. This means Nullable.Value and Nullable.HasValue will not be - // part of the sequence of properties returned by this method. - type = Nullable.GetUnderlyingType(type) ?? type; - - PropertyHelper[] helpers; - if (!cache.TryGetValue(type, out helpers)) - { - // We avoid loading indexed properties using the Where statement. - var properties = type.GetRuntimeProperties().Where(IsInterestingProperty); - - var typeInfo = type.GetTypeInfo(); - if (typeInfo.IsInterface) - { - // Reflection does not return information about inherited properties on the interface itself. - properties = properties.Concat(typeInfo.ImplementedInterfaces.SelectMany( - interfaceType => interfaceType.GetRuntimeProperties().Where(IsInterestingProperty))); - } - - helpers = properties.Select(p => createPropertyHelper(p)).ToArray(); - cache.TryAdd(type, helpers); - } - - return helpers; - } - - - private static bool IsInterestingProperty(PropertyInfo property) - { - // For improving application startup time, do not use GetIndexParameters() api early in this check as it - // creates a copy of parameter array and also we would like to check for the presence of a get method - // and short circuit asap. - return - property.GetMethod != null && - property.GetMethod.IsPublic && - !property.GetMethod.IsStatic && - - // PropertyHelper can't work with ref structs. - !IsRefStructProperty(property) && - - // Indexed properties are not useful (or valid) for grabbing properties off an object. - property.GetMethod.GetParameters().Length == 0; - } - - // PropertyHelper can't really interact with ref-struct properties since they can't be - // boxed and can't be used as generic types. We just ignore them. - // - // see: https://github.com/aspnet/Mvc/issues/8545 - private static bool IsRefStructProperty(PropertyInfo property) - { - return - IsByRefLikeAttribute != null && - property.PropertyType.IsValueType && - property.PropertyType.IsDefined(IsByRefLikeAttribute); - } - } -} diff --git a/src/Shared/RazorViews/AttributeValue.cs b/src/Shared/RazorViews/AttributeValue.cs deleted file mode 100644 index 7a066a7040..0000000000 --- a/src/Shared/RazorViews/AttributeValue.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.Extensions.RazorViews -{ - internal class AttributeValue - { - public AttributeValue(string prefix, object value, bool literal) - { - Prefix = prefix; - Value = value; - Literal = literal; - } - - public string Prefix { get; } - - public object Value { get; } - - public bool Literal { get; } - - public static AttributeValue FromTuple(Tuple value) - { - return new AttributeValue(value.Item1, value.Item2, value.Item3); - } - - public static AttributeValue FromTuple(Tuple value) - { - return new AttributeValue(value.Item1, value.Item2, value.Item3); - } - - public static implicit operator AttributeValue(Tuple value) - { - return FromTuple(value); - } - } -} \ No newline at end of file diff --git a/src/Shared/RazorViews/BaseView.cs b/src/Shared/RazorViews/BaseView.cs deleted file mode 100644 index a171d8d1f2..0000000000 --- a/src/Shared/RazorViews/BaseView.cs +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.Extensions.RazorViews -{ - /// - /// Infrastructure - /// - internal abstract class BaseView - { - private static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); - private readonly Stack _textWriterStack = new Stack(); - - /// - /// The request context - /// - protected HttpContext Context { get; private set; } - - /// - /// The request - /// - protected HttpRequest Request { get; private set; } - - /// - /// The response - /// - protected HttpResponse Response { get; private set; } - - /// - /// The output stream - /// - protected TextWriter Output { get; private set; } - - /// - /// Html encoder used to encode content. - /// - protected HtmlEncoder HtmlEncoder { get; set; } = HtmlEncoder.Default; - - /// - /// Url encoder used to encode content. - /// - protected UrlEncoder UrlEncoder { get; set; } = UrlEncoder.Default; - - /// - /// JavaScript encoder used to encode content. - /// - protected JavaScriptEncoder JavaScriptEncoder { get; set; } = JavaScriptEncoder.Default; - - /// - /// Execute an individual request - /// - /// - public async Task ExecuteAsync(HttpContext context) - { - Context = context; - Request = Context.Request; - Response = Context.Response; - Output = new StreamWriter(Response.Body, UTF8NoBOM, 4096, leaveOpen: true); - await ExecuteAsync(); - Output.Dispose(); - } - - /// - /// Execute an individual request - /// - public abstract Task ExecuteAsync(); - - protected virtual void PushWriter(TextWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - _textWriterStack.Push(Output); - Output = writer; - } - - protected virtual TextWriter PopWriter() - { - Output = _textWriterStack.Pop(); - return Output; - } - - /// - /// Write the given value without HTML encoding directly to . - /// - /// The to write. - protected void WriteLiteral(object value) - { - WriteLiteral(Convert.ToString(value, CultureInfo.InvariantCulture)); - } - - /// - /// Write the given value without HTML encoding directly to . - /// - /// The to write. - protected void WriteLiteral(string value) - { - if (!string.IsNullOrEmpty(value)) - { - Output.Write(value); - } - } - - private List AttributeValues { get; set; } - - protected void WriteAttributeValue(string thingy, int startPostion, object value, int endValue, int dealyo, bool yesno) - { - if (AttributeValues == null) - { - AttributeValues = new List(); - } - - AttributeValues.Add(value.ToString()); - } - - private string AttributeEnding { get; set; } - - protected void BeginWriteAttribute(string name, string begining, int startPosition, string ending, int endPosition, int thingy) - { - Debug.Assert(string.IsNullOrEmpty(AttributeEnding)); - - Output.Write(begining); - AttributeEnding = ending; - } - - protected void EndWriteAttribute() - { - Debug.Assert(!string.IsNullOrEmpty(AttributeEnding)); - - var attributes = string.Join(" ", AttributeValues); - Output.Write(attributes); - AttributeValues = null; - - Output.Write(AttributeEnding); - AttributeEnding = null; - } - - /// - /// Writes the given attribute to the given writer - /// - /// The name of the attribute to write - /// The value of the prefix - /// The value of the suffix - /// The s to write. - protected void WriteAttribute( - string name, - string leader, - string trailer, - params AttributeValue[] values) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - - if (leader == null) - { - throw new ArgumentNullException(nameof(leader)); - } - - if (trailer == null) - { - throw new ArgumentNullException(nameof(trailer)); - } - - WriteLiteral(leader); - foreach (var value in values) - { - WriteLiteral(value.Prefix); - - // The special cases here are that the value we're writing might already be a string, or that the - // value might be a bool. If the value is the bool 'true' we want to write the attribute name - // instead of the string 'true'. If the value is the bool 'false' we don't want to write anything. - // Otherwise the value is another object (perhaps an HtmlString) and we'll ask it to format itself. - string stringValue; - if (value.Value is bool) - { - if ((bool)value.Value) - { - stringValue = name; - } - else - { - continue; - } - } - else - { - stringValue = value.Value as string; - } - - // Call the WriteTo(string) overload when possible - if (value.Literal && stringValue != null) - { - WriteLiteral(stringValue); - } - else if (value.Literal) - { - WriteLiteral(value.Value); - } - else if (stringValue != null) - { - Write(stringValue); - } - else - { - Write(value.Value); - } - } - WriteLiteral(trailer); - } - - /// - /// is invoked - /// - /// The to invoke - protected void Write(HelperResult result) - { - Write(result); - } - - /// - /// Writes the specified to . - /// - /// The to write. - /// - /// is invoked for types. - /// For all other types, the encoded result of is written to - /// . - /// - protected void Write(object value) - { - if (value is HelperResult helperResult) - { - helperResult.WriteTo(Output); - } - else - { - Write(Convert.ToString(value, CultureInfo.InvariantCulture)); - } - } - - /// - /// Writes the specified with HTML encoding to . - /// - /// The to write. - protected void Write(string value) - { - WriteLiteral(HtmlEncoder.Encode(value)); - } - - protected string HtmlEncodeAndReplaceLineBreaks(string input) - { - if (string.IsNullOrEmpty(input)) - { - return string.Empty; - } - - // Split on line breaks before passing it through the encoder. - return string.Join("
" + Environment.NewLine, - input.Split(new[] { "\r\n" }, StringSplitOptions.None) - .SelectMany(s => s.Split(new[] { '\r', '\n' }, StringSplitOptions.None)) - .Select(HtmlEncoder.Encode)); - } - } -} \ No newline at end of file diff --git a/src/Shared/RazorViews/HelperResult.cs b/src/Shared/RazorViews/HelperResult.cs deleted file mode 100644 index c79944aae6..0000000000 --- a/src/Shared/RazorViews/HelperResult.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.IO; - -namespace Microsoft.Extensions.RazorViews -{ - /// - /// Represents a deferred write operation in a . - /// - internal class HelperResult - { - /// - /// Creates a new instance of . - /// - /// The delegate to invoke when is called. - public HelperResult(Action action) - { - WriteAction = action; - } - - public Action WriteAction { get; } - - /// - /// Method invoked to produce content from the . - /// - /// The instance to write to. - public void WriteTo(TextWriter writer) - { - WriteAction(writer); - } - } -} \ No newline at end of file diff --git a/src/Shared/SecurityHelper/SecurityHelper.cs b/src/Shared/SecurityHelper/SecurityHelper.cs deleted file mode 100644 index 408ef6b224..0000000000 --- a/src/Shared/SecurityHelper/SecurityHelper.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Security.Claims; - -namespace Microsoft.Extensions.Internal -{ - /// - /// Helper code used when implementing authentication middleware - /// - internal static class SecurityHelper - { - /// - /// Add all ClaimsIdentities from an additional ClaimPrincipal to the ClaimsPrincipal - /// Merges a new claims principal, placing all new identities first, and eliminating - /// any empty unauthenticated identities from context.User - /// - /// The containing existing . - /// The containing to be added. - public static ClaimsPrincipal MergeUserPrincipal(ClaimsPrincipal existingPrincipal, ClaimsPrincipal additionalPrincipal) - { - var newPrincipal = new ClaimsPrincipal(); - - // New principal identities go first - if (additionalPrincipal != null) - { - newPrincipal.AddIdentities(additionalPrincipal.Identities); - } - - // Then add any existing non empty or authenticated identities - if (existingPrincipal != null) - { - newPrincipal.AddIdentities(existingPrincipal.Identities.Where(i => i.IsAuthenticated || i.Claims.Any())); - } - return newPrincipal; - } - } -} diff --git a/src/Shared/StackTrace/ExceptionDetails/ExceptionDetails.cs b/src/Shared/StackTrace/ExceptionDetails/ExceptionDetails.cs deleted file mode 100644 index 8862611136..0000000000 --- a/src/Shared/StackTrace/ExceptionDetails/ExceptionDetails.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - /// - /// Contains details for individual exception messages. - /// - internal class ExceptionDetails - { - /// - /// An individual exception - /// - public Exception Error { get; set; } - - /// - /// The generated stack frames - /// - public IEnumerable StackFrames { get; set; } - - /// - /// Gets or sets the summary message. - /// - public string ErrorMessage { get; set; } - } -} diff --git a/src/Shared/StackTrace/ExceptionDetails/ExceptionDetailsProvider.cs b/src/Shared/StackTrace/ExceptionDetails/ExceptionDetailsProvider.cs deleted file mode 100644 index 2d1dd20710..0000000000 --- a/src/Shared/StackTrace/ExceptionDetails/ExceptionDetailsProvider.cs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using Microsoft.Extensions.FileProviders; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - internal class ExceptionDetailsProvider - { - private readonly IFileProvider _fileProvider; - private readonly int _sourceCodeLineCount; - - public ExceptionDetailsProvider(IFileProvider fileProvider, int sourceCodeLineCount) - { - _fileProvider = fileProvider; - _sourceCodeLineCount = sourceCodeLineCount; - } - - public IEnumerable GetDetails(Exception exception) - { - var exceptions = FlattenAndReverseExceptionTree(exception); - - foreach (var ex in exceptions) - { - yield return new ExceptionDetails - { - Error = ex, - StackFrames = StackTraceHelper.GetFrames(ex) - .Select(frame => GetStackFrameSourceCodeInfo( - frame.MethodDisplayInfo.ToString(), - frame.FilePath, - frame.LineNumber)) - }; - } - } - - private static IEnumerable FlattenAndReverseExceptionTree(Exception ex) - { - // ReflectionTypeLoadException is special because the details are in - // the LoaderExceptions property - var typeLoadException = ex as ReflectionTypeLoadException; - if (typeLoadException != null) - { - var typeLoadExceptions = new List(); - foreach (var loadException in typeLoadException.LoaderExceptions) - { - typeLoadExceptions.AddRange(FlattenAndReverseExceptionTree(loadException)); - } - - typeLoadExceptions.Add(ex); - return typeLoadExceptions; - } - - var list = new List(); - if (ex is AggregateException aggregateException) - { - list.Add(ex); - foreach (var innerException in aggregateException.Flatten().InnerExceptions) - { - list.Add(innerException); - } - } - - else - { - while (ex != null) - { - list.Add(ex); - ex = ex.InnerException; - } - list.Reverse(); - } - - return list; - } - - // make it internal to enable unit testing - internal StackFrameSourceCodeInfo GetStackFrameSourceCodeInfo(string method, string filePath, int lineNumber) - { - var stackFrame = new StackFrameSourceCodeInfo - { - Function = method, - File = filePath, - Line = lineNumber - }; - - if (string.IsNullOrEmpty(stackFrame.File)) - { - return stackFrame; - } - - IEnumerable lines = null; - if (File.Exists(stackFrame.File)) - { - lines = File.ReadLines(stackFrame.File); - } - else - { - // Handle relative paths and embedded files - var fileInfo = _fileProvider.GetFileInfo(stackFrame.File); - if (fileInfo.Exists) - { - // ReadLines doesn't accept a stream. Use ReadLines as its more efficient - // relative to reading lines via stream reader - if (!string.IsNullOrEmpty(fileInfo.PhysicalPath)) - { - lines = File.ReadLines(fileInfo.PhysicalPath); - } - else - { - lines = ReadLines(fileInfo); - } - } - } - - if (lines != null) - { - ReadFrameContent(stackFrame, lines, stackFrame.Line, stackFrame.Line); - } - - return stackFrame; - } - - // make it internal to enable unit testing - internal void ReadFrameContent( - StackFrameSourceCodeInfo frame, - IEnumerable allLines, - int errorStartLineNumberInFile, - int errorEndLineNumberInFile) - { - // Get the line boundaries in the file to be read and read all these lines at once into an array. - var preErrorLineNumberInFile = Math.Max(errorStartLineNumberInFile - _sourceCodeLineCount, 1); - var postErrorLineNumberInFile = errorEndLineNumberInFile + _sourceCodeLineCount; - var codeBlock = allLines - .Skip(preErrorLineNumberInFile - 1) - .Take(postErrorLineNumberInFile - preErrorLineNumberInFile + 1) - .ToArray(); - - var numOfErrorLines = (errorEndLineNumberInFile - errorStartLineNumberInFile) + 1; - var errorStartLineNumberInArray = errorStartLineNumberInFile - preErrorLineNumberInFile; - - frame.PreContextLine = preErrorLineNumberInFile; - frame.PreContextCode = codeBlock.Take(errorStartLineNumberInArray).ToArray(); - frame.ContextCode = codeBlock - .Skip(errorStartLineNumberInArray) - .Take(numOfErrorLines) - .ToArray(); - frame.PostContextCode = codeBlock - .Skip(errorStartLineNumberInArray + numOfErrorLines) - .ToArray(); - } - - private static IEnumerable ReadLines(IFileInfo fileInfo) - { - using (var reader = new StreamReader(fileInfo.CreateReadStream())) - { - string line; - while ((line = reader.ReadLine()) != null) - { - yield return line; - } - } - } - } -} diff --git a/src/Shared/StackTrace/StackFrame/MethodDisplayInfo.cs b/src/Shared/StackTrace/StackFrame/MethodDisplayInfo.cs deleted file mode 100644 index b1c0ccc188..0000000000 --- a/src/Shared/StackTrace/StackFrame/MethodDisplayInfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - internal class MethodDisplayInfo - { - public string DeclaringTypeName { get; set; } - - public string Name { get; set; } - - public string GenericArguments { get; set; } - - public string SubMethod { get; set; } - - public IEnumerable Parameters { get; set; } - - public override string ToString() - { - var builder = new StringBuilder(); - if (!string.IsNullOrEmpty(DeclaringTypeName)) - { - builder - .Append(DeclaringTypeName) - .Append("."); - } - - builder.Append(Name); - builder.Append(GenericArguments); - - builder.Append("("); - builder.Append(string.Join(", ", Parameters.Select(p => p.ToString()))); - builder.Append(")"); - - if (!string.IsNullOrEmpty(SubMethod)) - { - builder.Append("+"); - builder.Append(SubMethod); - builder.Append("()"); - } - - return builder.ToString(); - } - } -} diff --git a/src/Shared/StackTrace/StackFrame/ParameterDisplayInfo.cs b/src/Shared/StackTrace/StackFrame/ParameterDisplayInfo.cs deleted file mode 100644 index 1199a8386d..0000000000 --- a/src/Shared/StackTrace/StackFrame/ParameterDisplayInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Text; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - internal class ParameterDisplayInfo - { - public string Name { get; set; } - - public string Type { get; set; } - - public string Prefix { get; set; } - - public override string ToString() - { - var builder = new StringBuilder(); - if (!string.IsNullOrEmpty(Prefix)) - { - builder - .Append(Prefix) - .Append(" "); - } - - builder.Append(Type); - builder.Append(" "); - builder.Append(Name); - - return builder.ToString(); - } - } -} diff --git a/src/Shared/StackTrace/StackFrame/PortablePdbReader.cs b/src/Shared/StackTrace/StackFrame/PortablePdbReader.cs deleted file mode 100644 index ff6a4947f8..0000000000 --- a/src/Shared/StackTrace/StackFrame/PortablePdbReader.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - internal class PortablePdbReader : IDisposable - { - private readonly Dictionary _cache = - new Dictionary(StringComparer.Ordinal); - - public void PopulateStackFrame(StackFrameInfo frameInfo, MethodBase method, int IlOffset) - { - if (method.Module.Assembly.IsDynamic) - { - return; - } - - var metadataReader = GetMetadataReader(method.Module.Assembly.Location); - - if (metadataReader == null) - { - return; - } - - var methodToken = MetadataTokens.Handle(method.MetadataToken); - - Debug.Assert(methodToken.Kind == HandleKind.MethodDefinition); - - var handle = ((MethodDefinitionHandle)methodToken).ToDebugInformationHandle(); - - if (!handle.IsNil) - { - var methodDebugInfo = metadataReader.GetMethodDebugInformation(handle); - var sequencePoints = methodDebugInfo.GetSequencePoints(); - SequencePoint? bestPointSoFar = null; - - foreach (var point in sequencePoints) - { - if (point.Offset > IlOffset) - { - break; - } - - if (point.StartLine != SequencePoint.HiddenLine) - { - bestPointSoFar = point; - } - } - - if (bestPointSoFar.HasValue) - { - frameInfo.LineNumber = bestPointSoFar.Value.StartLine; - frameInfo.FilePath = metadataReader.GetString(metadataReader.GetDocument(bestPointSoFar.Value.Document).Name); - } - } - } - - private MetadataReader GetMetadataReader(string assemblyPath) - { - MetadataReaderProvider provider = null; - if (!_cache.TryGetValue(assemblyPath, out provider)) - { - var pdbPath = GetPdbPath(assemblyPath); - - if (!string.IsNullOrEmpty(pdbPath) && File.Exists(pdbPath) && IsPortable(pdbPath)) - { - var pdbStream = File.OpenRead(pdbPath); - provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); - } - - _cache[assemblyPath] = provider; - } - - return provider?.GetMetadataReader(); - } - - private static string GetPdbPath(string assemblyPath) - { - if (string.IsNullOrEmpty(assemblyPath)) - { - return null; - } - - if (File.Exists(assemblyPath)) - { - var peStream = File.OpenRead(assemblyPath); - - using (var peReader = new PEReader(peStream)) - { - foreach (var entry in peReader.ReadDebugDirectory()) - { - if (entry.Type == DebugDirectoryEntryType.CodeView) - { - var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry); - var peDirectory = Path.GetDirectoryName(assemblyPath); - return Path.Combine(peDirectory, Path.GetFileName(codeViewData.Path)); - } - } - } - } - - return null; - } - - private static bool IsPortable(string pdbPath) - { - using (var pdbStream = File.OpenRead(pdbPath)) - { - return pdbStream.ReadByte() == 'B' && - pdbStream.ReadByte() == 'S' && - pdbStream.ReadByte() == 'J' && - pdbStream.ReadByte() == 'B'; - } - } - - public void Dispose() - { - foreach (var entry in _cache) - { - entry.Value?.Dispose(); - } - - _cache.Clear(); - } - } -} diff --git a/src/Shared/StackTrace/StackFrame/StackFrameInfo.cs b/src/Shared/StackTrace/StackFrame/StackFrameInfo.cs deleted file mode 100644 index ffd91f213c..0000000000 --- a/src/Shared/StackTrace/StackFrame/StackFrameInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Diagnostics; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - internal class StackFrameInfo - { - public int LineNumber { get; set; } - - public string FilePath { get; set; } - - public StackFrame StackFrame { get; set; } - - public MethodDisplayInfo MethodDisplayInfo { get; set; } - } -} diff --git a/src/Shared/StackTrace/StackFrame/StackFrameSourceCodeInfo.cs b/src/Shared/StackTrace/StackFrame/StackFrameSourceCodeInfo.cs deleted file mode 100644 index 2932e083b1..0000000000 --- a/src/Shared/StackTrace/StackFrame/StackFrameSourceCodeInfo.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - /// - /// Contains the source code where the exception occurred. - /// - internal class StackFrameSourceCodeInfo - { - /// - /// Function containing instruction - /// - public string Function { get; set; } - - /// - /// File containing the instruction - /// - public string File { get; set; } - - /// - /// The line number of the instruction - /// - public int Line { get; set; } - - /// - /// The line preceding the frame line - /// - public int PreContextLine { get; set; } - - /// - /// Lines of code before the actual error line(s). - /// - public IEnumerable PreContextCode { get; set; } = Enumerable.Empty(); - - /// - /// Line(s) of code responsible for the error. - /// - public IEnumerable ContextCode { get; set; } = Enumerable.Empty(); - - /// - /// Lines of code after the actual error line(s). - /// - public IEnumerable PostContextCode { get; set; } = Enumerable.Empty(); - - /// - /// Specific error details for this stack frame. - /// - public string ErrorDetails { get; set; } - } -} diff --git a/src/Shared/StackTrace/StackFrame/StackTraceHelper.cs b/src/Shared/StackTrace/StackFrame/StackTraceHelper.cs deleted file mode 100644 index 5ce9a40903..0000000000 --- a/src/Shared/StackTrace/StackFrame/StackTraceHelper.cs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; -using Microsoft.Extensions.Internal; - -namespace Microsoft.Extensions.StackTrace.Sources -{ - internal class StackTraceHelper - { - public static IList GetFrames(Exception exception) - { - var frames = new List(); - - if (exception == null) - { - return frames; - } - - using (var portablePdbReader = new PortablePdbReader()) - { - var needFileInfo = true; - var stackTrace = new System.Diagnostics.StackTrace(exception, needFileInfo); - var stackFrames = stackTrace.GetFrames(); - - if (stackFrames == null) - { - return frames; - } - - for (var i = 0; i < stackFrames.Length; i++) - { - var frame = stackFrames[i]; - var method = frame.GetMethod(); - - // Always show last stackFrame - if (!ShowInStackTrace(method) && i < stackFrames.Length - 1) - { - continue; - } - - var stackFrame = new StackFrameInfo - { - StackFrame = frame, - FilePath = frame.GetFileName(), - LineNumber = frame.GetFileLineNumber(), - MethodDisplayInfo = GetMethodDisplayString(frame.GetMethod()), - }; - - if (string.IsNullOrEmpty(stackFrame.FilePath)) - { - // .NET Framework and older versions of mono don't support portable PDBs - // so we read it manually to get file name and line information - portablePdbReader.PopulateStackFrame(stackFrame, method, frame.GetILOffset()); - } - - frames.Add(stackFrame); - } - - return frames; - } - } - - internal static MethodDisplayInfo GetMethodDisplayString(MethodBase method) - { - // Special case: no method available - if (method == null) - { - return null; - } - - var methodDisplayInfo = new MethodDisplayInfo(); - - // Type name - var type = method.DeclaringType; - - var methodName = method.Name; - - if (type != null && type.IsDefined(typeof(CompilerGeneratedAttribute)) && - (typeof(IAsyncStateMachine).IsAssignableFrom(type) || typeof(IEnumerator).IsAssignableFrom(type))) - { - // Convert StateMachine methods to correct overload +MoveNext() - if (TryResolveStateMachineMethod(ref method, out type)) - { - methodDisplayInfo.SubMethod = methodName; - } - } - // ResolveStateMachineMethod may have set declaringType to null - if (type != null) - { - methodDisplayInfo.DeclaringTypeName = TypeNameHelper.GetTypeDisplayName(type, includeGenericParameterNames: true); - } - - // Method name - methodDisplayInfo.Name = method.Name; - if (method.IsGenericMethod) - { - var genericArguments = string.Join(", ", method.GetGenericArguments() - .Select(arg => TypeNameHelper.GetTypeDisplayName(arg, fullName: false, includeGenericParameterNames: true))); - methodDisplayInfo.GenericArguments += "<" + genericArguments + ">"; - } - - // Method parameters - methodDisplayInfo.Parameters = method.GetParameters().Select(parameter => - { - var parameterType = parameter.ParameterType; - - var prefix = string.Empty; - if (parameter.IsOut) - { - prefix = "out"; - } - else if (parameterType != null && parameterType.IsByRef) - { - prefix = "ref"; - } - - var parameterTypeString = "?"; - if (parameterType != null) - { - if (parameterType.IsByRef) - { - parameterType = parameterType.GetElementType(); - } - - parameterTypeString = TypeNameHelper.GetTypeDisplayName(parameterType, fullName: false, includeGenericParameterNames: true); - } - - return new ParameterDisplayInfo - { - Prefix = prefix, - Name = parameter.Name, - Type = parameterTypeString, - }; - }); - - return methodDisplayInfo; - } - - private static bool ShowInStackTrace(MethodBase method) - { - Debug.Assert(method != null); - - // Don't show any methods marked with the StackTraceHiddenAttribute - // https://github.com/dotnet/coreclr/pull/14652 - if (HasStackTraceHiddenAttribute(method)) - { - return false; - } - - - var type = method.DeclaringType; - if (type == null) - { - return true; - } - - if (HasStackTraceHiddenAttribute(type)) - { - return false; - } - - // Fallbacks for runtime pre-StackTraceHiddenAttribute - if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw") - { - return false; - } - else if (type == typeof(TaskAwaiter) || - type == typeof(TaskAwaiter<>) || - type == typeof(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter) || - type == typeof(ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter)) - { - switch (method.Name) - { - case "HandleNonSuccessAndDebuggerNotification": - case "ThrowForNonSuccess": - case "ValidateEnd": - case "GetResult": - return false; - } - } - - return true; - } - - private static bool TryResolveStateMachineMethod(ref MethodBase method, out Type declaringType) - { - Debug.Assert(method != null); - Debug.Assert(method.DeclaringType != null); - - declaringType = method.DeclaringType; - - var parentType = declaringType.DeclaringType; - if (parentType == null) - { - return false; - } - - var methods = parentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); - if (methods == null) - { - return false; - } - - foreach (var candidateMethod in methods) - { - var attributes = candidateMethod.GetCustomAttributes(); - if (attributes == null) - { - continue; - } - - foreach (var asma in attributes) - { - if (asma.StateMachineType == declaringType) - { - method = candidateMethod; - declaringType = candidateMethod.DeclaringType; - // Mark the iterator as changed; so it gets the + annotation of the original method - // async statemachines resolve directly to their builder methods so aren't marked as changed - return asma is IteratorStateMachineAttribute; - } - } - } - - return false; - } - - private static bool HasStackTraceHiddenAttribute(MemberInfo memberInfo) - { - IList attributes; - try - { - // Accessing MembmerInfo.GetCustomAttributesData throws for some types (such as types in dynamically generated assemblies). - // We'll skip looking up StackTraceHiddenAttributes on such types. - attributes = memberInfo.GetCustomAttributesData(); - } - catch - { - return false; - } - - for (var i = 0; i < attributes.Count; i++) - { - if (attributes[i].AttributeType.Name == "StackTraceHiddenAttribute") - { - return true; - } - } - - return false; - } - } -} diff --git a/src/Shared/WebEncoders/Properties/EncoderResources.cs b/src/Shared/WebEncoders/Properties/EncoderResources.cs deleted file mode 100644 index 3474ae82c5..0000000000 --- a/src/Shared/WebEncoders/Properties/EncoderResources.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Globalization; - -namespace Microsoft.Extensions.WebEncoders.Sources -{ - // TODO using a resx file. project.json, unfortunately, fails to embed resx files when there are also compile items - // in the contentFiles section. Revisit once we convert repos to MSBuild - internal static class EncoderResources - { - /// - /// Invalid {0}, {1} or {2} length. - /// - internal static readonly string WebEncoders_InvalidCountOffsetOrLength = "Invalid {0}, {1} or {2} length."; - - /// - /// Malformed input: {0} is an invalid input length. - /// - internal static readonly string WebEncoders_MalformedInput = "Malformed input: {0} is an invalid input length."; - - /// - /// Invalid {0}, {1} or {2} length. - /// - internal static string FormatWebEncoders_InvalidCountOffsetOrLength(object p0, object p1, object p2) - { - return string.Format(CultureInfo.CurrentCulture, WebEncoders_InvalidCountOffsetOrLength, p0, p1, p2); - } - - /// - /// Malformed input: {0} is an invalid input length. - /// - internal static string FormatWebEncoders_MalformedInput(object p0) - { - return string.Format(CultureInfo.CurrentCulture, WebEncoders_MalformedInput, p0); - } - } -} diff --git a/src/Shared/WebEncoders/WebEncoders.cs b/src/Shared/WebEncoders/WebEncoders.cs deleted file mode 100644 index 17068ae67a..0000000000 --- a/src/Shared/WebEncoders/WebEncoders.cs +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using System.Globalization; -using Microsoft.Extensions.WebEncoders.Sources; - -#if WebEncoders_In_WebUtilities -namespace Microsoft.AspNetCore.WebUtilities -#else -namespace Microsoft.Extensions.Internal -#endif -{ - /// - /// Contains utility APIs to assist with common encoding and decoding operations. - /// -#if WebEncoders_In_WebUtilities - public -#else - internal -#endif - static class WebEncoders - { - private static readonly byte[] EmptyBytes = new byte[0]; - - /// - /// Decodes a base64url-encoded string. - /// - /// The base64url-encoded input to decode. - /// The base64url-decoded form of the input. - /// - /// The input must not contain any whitespace or padding characters. - /// Throws if the input is malformed. - /// - public static byte[] Base64UrlDecode(string input) - { - if (input == null) - { - throw new ArgumentNullException(nameof(input)); - } - - return Base64UrlDecode(input, offset: 0, count: input.Length); - } - - /// - /// Decodes a base64url-encoded substring of a given string. - /// - /// A string containing the base64url-encoded input to decode. - /// The position in at which decoding should begin. - /// The number of characters in to decode. - /// The base64url-decoded form of the input. - /// - /// The input must not contain any whitespace or padding characters. - /// Throws if the input is malformed. - /// - public static byte[] Base64UrlDecode(string input, int offset, int count) - { - if (input == null) - { - throw new ArgumentNullException(nameof(input)); - } - - ValidateParameters(input.Length, nameof(input), offset, count); - - // Special-case empty input - if (count == 0) - { - return EmptyBytes; - } - - // Create array large enough for the Base64 characters, not just shorter Base64-URL-encoded form. - var buffer = new char[GetArraySizeRequiredToDecode(count)]; - - return Base64UrlDecode(input, offset, buffer, bufferOffset: 0, count: count); - } - - /// - /// Decodes a base64url-encoded into a byte[]. - /// - /// A string containing the base64url-encoded input to decode. - /// The position in at which decoding should begin. - /// - /// Scratch buffer to hold the s to decode. Array must be large enough to hold - /// and characters as well as Base64 padding - /// characters. Content is not preserved. - /// - /// - /// The offset into at which to begin writing the s to decode. - /// - /// The number of characters in to decode. - /// The base64url-decoded form of the . - /// - /// The input must not contain any whitespace or padding characters. - /// Throws if the input is malformed. - /// - public static byte[] Base64UrlDecode(string input, int offset, char[] buffer, int bufferOffset, int count) - { - if (input == null) - { - throw new ArgumentNullException(nameof(input)); - } - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - ValidateParameters(input.Length, nameof(input), offset, count); - if (bufferOffset < 0) - { - throw new ArgumentOutOfRangeException(nameof(bufferOffset)); - } - - if (count == 0) - { - return EmptyBytes; - } - - // Assumption: input is base64url encoded without padding and contains no whitespace. - - var paddingCharsToAdd = GetNumBase64PaddingCharsToAddForDecode(count); - var arraySizeRequired = checked(count + paddingCharsToAdd); - Debug.Assert(arraySizeRequired % 4 == 0, "Invariant: Array length must be a multiple of 4."); - - if (buffer.Length - bufferOffset < arraySizeRequired) - { - throw new ArgumentException( - string.Format( - CultureInfo.CurrentCulture, - EncoderResources.WebEncoders_InvalidCountOffsetOrLength, - nameof(count), - nameof(bufferOffset), - nameof(input)), - nameof(count)); - } - - // Copy input into buffer, fixing up '-' -> '+' and '_' -> '/'. - var i = bufferOffset; - for (var j = offset; i - bufferOffset < count; i++, j++) - { - var ch = input[j]; - if (ch == '-') - { - buffer[i] = '+'; - } - else if (ch == '_') - { - buffer[i] = '/'; - } - else - { - buffer[i] = ch; - } - } - - // Add the padding characters back. - for (; paddingCharsToAdd > 0; i++, paddingCharsToAdd--) - { - buffer[i] = '='; - } - - // Decode. - // If the caller provided invalid base64 chars, they'll be caught here. - return Convert.FromBase64CharArray(buffer, bufferOffset, arraySizeRequired); - } - - /// - /// Gets the minimum char[] size required for decoding of characters - /// with the method. - /// - /// The number of characters to decode. - /// - /// The minimum char[] size required for decoding of characters. - /// - public static int GetArraySizeRequiredToDecode(int count) - { - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - if (count == 0) - { - return 0; - } - - var numPaddingCharsToAdd = GetNumBase64PaddingCharsToAddForDecode(count); - - return checked(count + numPaddingCharsToAdd); - } - - /// - /// Encodes using base64url encoding. - /// - /// The binary input to encode. - /// The base64url-encoded form of . - public static string Base64UrlEncode(byte[] input) - { - if (input == null) - { - throw new ArgumentNullException(nameof(input)); - } - - return Base64UrlEncode(input, offset: 0, count: input.Length); - } - - /// - /// Encodes using base64url encoding. - /// - /// The binary input to encode. - /// The offset into at which to begin encoding. - /// The number of bytes from to encode. - /// The base64url-encoded form of . - public static string Base64UrlEncode(byte[] input, int offset, int count) - { - if (input == null) - { - throw new ArgumentNullException(nameof(input)); - } - - ValidateParameters(input.Length, nameof(input), offset, count); - - // Special-case empty input - if (count == 0) - { - return string.Empty; - } - - var buffer = new char[GetArraySizeRequiredToEncode(count)]; - var numBase64Chars = Base64UrlEncode(input, offset, buffer, outputOffset: 0, count: count); - - return new String(buffer, startIndex: 0, length: numBase64Chars); - } - - /// - /// Encodes using base64url encoding. - /// - /// The binary input to encode. - /// The offset into at which to begin encoding. - /// - /// Buffer to receive the base64url-encoded form of . Array must be large enough to - /// hold characters and the full base64-encoded form of - /// , including padding characters. - /// - /// - /// The offset into at which to begin writing the base64url-encoded form of - /// . - /// - /// The number of bytes from to encode. - /// - /// The number of characters written to , less any padding characters. - /// - public static int Base64UrlEncode(byte[] input, int offset, char[] output, int outputOffset, int count) - { - if (input == null) - { - throw new ArgumentNullException(nameof(input)); - } - if (output == null) - { - throw new ArgumentNullException(nameof(output)); - } - - ValidateParameters(input.Length, nameof(input), offset, count); - if (outputOffset < 0) - { - throw new ArgumentOutOfRangeException(nameof(outputOffset)); - } - - var arraySizeRequired = GetArraySizeRequiredToEncode(count); - if (output.Length - outputOffset < arraySizeRequired) - { - throw new ArgumentException( - string.Format( - CultureInfo.CurrentCulture, - EncoderResources.WebEncoders_InvalidCountOffsetOrLength, - nameof(count), - nameof(outputOffset), - nameof(output)), - nameof(count)); - } - - // Special-case empty input. - if (count == 0) - { - return 0; - } - - // Use base64url encoding with no padding characters. See RFC 4648, Sec. 5. - - // Start with default Base64 encoding. - var numBase64Chars = Convert.ToBase64CharArray(input, offset, count, output, outputOffset); - - // Fix up '+' -> '-' and '/' -> '_'. Drop padding characters. - for (var i = outputOffset; i - outputOffset < numBase64Chars; i++) - { - var ch = output[i]; - if (ch == '+') - { - output[i] = '-'; - } - else if (ch == '/') - { - output[i] = '_'; - } - else if (ch == '=') - { - // We've reached a padding character; truncate the remainder. - return i - outputOffset; - } - } - - return numBase64Chars; - } - - /// - /// Get the minimum output char[] size required for encoding - /// s with the method. - /// - /// The number of characters to encode. - /// - /// The minimum output char[] size required for encoding s. - /// - public static int GetArraySizeRequiredToEncode(int count) - { - var numWholeOrPartialInputBlocks = checked(count + 2) / 3; - return checked(numWholeOrPartialInputBlocks * 4); - } - - private static int GetNumBase64PaddingCharsInString(string str) - { - // Assumption: input contains a well-formed base64 string with no whitespace. - - // base64 guaranteed have 0 - 2 padding characters. - if (str[str.Length - 1] == '=') - { - if (str[str.Length - 2] == '=') - { - return 2; - } - return 1; - } - return 0; - } - - private static int GetNumBase64PaddingCharsToAddForDecode(int inputLength) - { - switch (inputLength % 4) - { - case 0: - return 0; - case 2: - return 2; - case 3: - return 1; - default: - throw new FormatException( - string.Format( - CultureInfo.CurrentCulture, - EncoderResources.WebEncoders_MalformedInput, - inputLength)); - } - } - - private static void ValidateParameters(int bufferLength, string inputName, int offset, int count) - { - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - if (bufferLength - offset < count) - { - throw new ArgumentException( - string.Format( - CultureInfo.CurrentCulture, - EncoderResources.WebEncoders_InvalidCountOffsetOrLength, - nameof(count), - nameof(offset), - inputName), - nameof(count)); - } - } - } -} diff --git a/src/Shared/test/Shared.Tests/CertificateManagerTests.cs b/src/Shared/test/Shared.Tests/CertificateManagerTests.cs deleted file mode 100644 index cd314383c9..0000000000 --- a/src/Shared/test/Shared.Tests/CertificateManagerTests.cs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#if NETCOREAPP2_2 - -using System; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using Xunit; -using Xunit.Abstractions; - -namespace Microsoft.AspNetCore.Certificates.Generation.Tests -{ - public class CertificateManagerTests - { - public CertificateManagerTests(ITestOutputHelper output) - { - Output = output; - } - - public const string TestCertificateSubject = "CN=aspnet.test"; - - public ITestOutputHelper Output { get; } - - [Fact(Skip = "True")] - public void EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates() - { - try - { - // Arrange - const string CertificateName = nameof(EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates) + ".cer"; - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } - - // Act - DateTimeOffset now = DateTimeOffset.UtcNow; - now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, subject: TestCertificateSubject); - - // Assert - Assert.Equal(EnsureCertificateResult.Succeeded, result); - Assert.True(File.Exists(CertificateName)); - - var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName)); - Assert.NotNull(exportedCertificate); - Assert.False(exportedCertificate.HasPrivateKey); - - var httpsCertificates = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false); - var httpsCertificate = Assert.Single(httpsCertificates, c => c.Subject == TestCertificateSubject); - Assert.True(httpsCertificate.HasPrivateKey); - Assert.Equal(TestCertificateSubject, httpsCertificate.Subject); - Assert.Equal(TestCertificateSubject, httpsCertificate.Issuer); - Assert.Equal("sha256RSA", httpsCertificate.SignatureAlgorithm.FriendlyName); - Assert.Equal("1.2.840.113549.1.1.11", httpsCertificate.SignatureAlgorithm.Value); - - Assert.Equal(now.LocalDateTime, httpsCertificate.NotBefore); - Assert.Equal(now.AddYears(1).LocalDateTime, httpsCertificate.NotAfter); - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509BasicConstraintsExtension basicConstraints && - basicConstraints.Critical == true && - basicConstraints.CertificateAuthority == false && - basicConstraints.HasPathLengthConstraint == false && - basicConstraints.PathLengthConstraint == 0); - - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509KeyUsageExtension keyUsage && - keyUsage.Critical == true && - keyUsage.KeyUsages == X509KeyUsageFlags.KeyEncipherment); - - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509EnhancedKeyUsageExtension enhancedKeyUsage && - enhancedKeyUsage.Critical == true && - enhancedKeyUsage.EnhancedKeyUsages.OfType().Single() is Oid keyUsage && - keyUsage.Value == "1.3.6.1.5.5.7.3.1"); - - // Subject alternative name - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e.Critical == true && - e.Oid.Value == "2.5.29.17"); - - // ASP.NET HTTPS Development certificate extension - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e.Critical == false && - e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - Encoding.ASCII.GetString(e.RawData) == "ASP.NET Core HTTPS development certificate"); - - Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); - - } - catch (Exception e) - { - Output.WriteLine(e.Message); - ListCertificates(Output); - throw; - } - } - - [Fact] - public void EnsureCreateHttpsCertificate2_CreatesACertificate_WhenThereAreNoHttpsCertificates() - { - try - { - // Arrange - const string CertificateName = nameof(EnsureCreateHttpsCertificate_CreatesACertificate_WhenThereAreNoHttpsCertificates) + ".cer"; - var manager = new CertificateManager(); - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } - - // Act - DateTimeOffset now = DateTimeOffset.UtcNow; - now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate2(now, now.AddYears(1), CertificateName, trust: false, subject: TestCertificateSubject); - - // Assert - Assert.Equal(EnsureCertificateResult.Succeeded, result.ResultCode); - Assert.NotNull(result.Diagnostics); - Assert.NotEmpty(result.Diagnostics.Messages); - Assert.Empty(result.Diagnostics.Exceptions); - - Assert.True(File.Exists(CertificateName)); - - var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName)); - Assert.NotNull(exportedCertificate); - Assert.False(exportedCertificate.HasPrivateKey); - - var httpsCertificates = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false); - var httpsCertificate = Assert.Single(httpsCertificates, c => c.Subject == TestCertificateSubject); - Assert.True(httpsCertificate.HasPrivateKey); - Assert.Equal(TestCertificateSubject, httpsCertificate.Subject); - Assert.Equal(TestCertificateSubject, httpsCertificate.Issuer); - Assert.Equal("sha256RSA", httpsCertificate.SignatureAlgorithm.FriendlyName); - Assert.Equal("1.2.840.113549.1.1.11", httpsCertificate.SignatureAlgorithm.Value); - - Assert.Equal(now.LocalDateTime, httpsCertificate.NotBefore); - Assert.Equal(now.AddYears(1).LocalDateTime, httpsCertificate.NotAfter); - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509BasicConstraintsExtension basicConstraints && - basicConstraints.Critical == true && - basicConstraints.CertificateAuthority == false && - basicConstraints.HasPathLengthConstraint == false && - basicConstraints.PathLengthConstraint == 0); - - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509KeyUsageExtension keyUsage && - keyUsage.Critical == true && - keyUsage.KeyUsages == X509KeyUsageFlags.KeyEncipherment); - - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e is X509EnhancedKeyUsageExtension enhancedKeyUsage && - enhancedKeyUsage.Critical == true && - enhancedKeyUsage.EnhancedKeyUsages.OfType().Single() is Oid keyUsage && - keyUsage.Value == "1.3.6.1.5.5.7.3.1"); - - // Subject alternative name - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e.Critical == true && - e.Oid.Value == "2.5.29.17"); - - // ASP.NET HTTPS Development certificate extension - Assert.Contains( - httpsCertificate.Extensions.OfType(), - e => e.Critical == false && - e.Oid.Value == "1.3.6.1.4.1.311.84.1.1" && - Encoding.ASCII.GetString(e.RawData) == "ASP.NET Core HTTPS development certificate"); - - Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); - - } - catch (Exception e) - { - Output.WriteLine(e.Message); - ListCertificates(Output); - throw; - } - } - - private void ListCertificates(ITestOutputHelper output) - { - using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) - { - store.Open(OpenFlags.ReadOnly); - var certificates = store.Certificates; - foreach (var certificate in certificates) - { - Output.WriteLine($"Certificate: '{Convert.ToBase64String(certificate.Export(X509ContentType.Cert))}'."); - certificate.Dispose(); - } - - store.Close(); - } - } - - [Fact(Skip = "true")] - public void EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates() - { - // Arrange - const string CertificateName = nameof(EnsureCreateHttpsCertificate_DoesNotCreateACertificate_WhenThereIsAnExistingHttpsCertificates) + ".pfx"; - var certificatePassword = Guid.NewGuid().ToString(); - - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } - - DateTimeOffset now = DateTimeOffset.UtcNow; - now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: false, subject: TestCertificateSubject); - - var httpsCertificate = manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Single(c => c.Subject == TestCertificateSubject); - - // Act - var result = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), CertificateName, trust: false, includePrivateKey: true, password: certificatePassword, subject: TestCertificateSubject); - - // Assert - Assert.Equal(EnsureCertificateResult.ValidCertificatePresent, result); - Assert.True(File.Exists(CertificateName)); - - var exportedCertificate = new X509Certificate2(File.ReadAllBytes(CertificateName), certificatePassword); - Assert.NotNull(exportedCertificate); - Assert.True(exportedCertificate.HasPrivateKey); - - - Assert.Equal(httpsCertificate.GetCertHashString(), exportedCertificate.GetCertHashString()); - } - - [Fact(Skip = "Requires user interaction")] - public void EnsureAspNetCoreHttpsDevelopmentCertificate_ReturnsCorrectResult_WhenUserCancelsTrustStepOnWindows() - { - var manager = new CertificateManager(); - - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, TestCertificateSubject); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - manager.RemoveAllCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, TestCertificateSubject); - } - - DateTimeOffset now = DateTimeOffset.UtcNow; - now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - var trustFailed = manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); - - Assert.Equal(EnsureCertificateResult.UserCancelledTrustStep, trustFailed); - } - - [Fact(Skip = "Requires user interaction")] - public void EnsureAspNetCoreHttpsDevelopmentCertificate_CanRemoveCertificates() - { - var manager = new CertificateManager(); - - DateTimeOffset now = DateTimeOffset.UtcNow; - now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0, now.Offset); - manager.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), path: null, trust: true, subject: TestCertificateSubject); - - manager.CleanupHttpsCertificates(TestCertificateSubject); - - Assert.Empty(manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.My, StoreLocation.CurrentUser, isValid: false).Where(c => c.Subject == TestCertificateSubject)); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Assert.Empty(manager.ListCertificates(CertificatePurpose.HTTPS, StoreName.Root, StoreLocation.CurrentUser, isValid: false).Where(c => c.Subject == TestCertificateSubject)); - } - } - } -} - -#endif \ No newline at end of file diff --git a/src/Shared/test/Shared.Tests/ClosedGenericMatcherTest.cs b/src/Shared/test/Shared.Tests/ClosedGenericMatcherTest.cs deleted file mode 100644 index e71a792692..0000000000 --- a/src/Shared/test/Shared.Tests/ClosedGenericMatcherTest.cs +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class ClosedGenericMatcherTest - { - // queryType, interfaceType, expectedResult - public static TheoryData ExtractGenericInterfaceDataSet - { - get - { - return new TheoryData - { - // Closed generic types that match given open generic type. - { - typeof(IEnumerable), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - { - typeof(IReadOnlyList), - typeof(IReadOnlyList<>), - typeof(IReadOnlyList) - }, - { - typeof(KeyValuePair), - typeof(KeyValuePair<,>), - typeof(KeyValuePair) - }, - // Closed generic interfaces that implement sub-interface of given open generic type. - { - typeof(ICollection), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - { - typeof(IReadOnlyList), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - { - typeof(IDictionary), - typeof(IEnumerable<>), - typeof(IEnumerable>) - }, - // Class that implements closed generic based on given open generic interface. - { - typeof(BaseClass), - typeof(IDictionary<,>), - typeof(IDictionary) - }, - { - typeof(BaseClass), - typeof(IEquatable<>), - typeof(IEquatable) - }, - { - typeof(BaseClass), - typeof(ICollection<>), - typeof(ICollection>) - }, - // Derived class that implements closed generic based on given open generic interface. - { - typeof(DerivedClass), - typeof(IDictionary<,>), - typeof(IDictionary) - }, - { - typeof(DerivedClass), - typeof(IEquatable<>), - typeof(IEquatable) - }, - { - typeof(DerivedClass), - typeof(ICollection<>), - typeof(ICollection>) - }, - // Derived class that also implements another interface. - { - typeof(DerivedClassWithComparable), - typeof(IDictionary<,>), - typeof(IDictionary) - }, - { - typeof(DerivedClassWithComparable), - typeof(IEquatable<>), - typeof(IEquatable) - }, - { - typeof(DerivedClassWithComparable), - typeof(ICollection<>), - typeof(ICollection>) - }, - { - typeof(DerivedClassWithComparable), - typeof(IComparable<>), - typeof(IComparable) - }, - // Derived class using system implementation. - { - typeof(DerivedClassFromSystemImplementation), - typeof(ICollection<>), - typeof(ICollection) - }, - { - typeof(DerivedClassFromSystemImplementation), - typeof(IReadOnlyList<>), - typeof(IReadOnlyList) - }, - { - typeof(DerivedClassFromSystemImplementation), - typeof(IEnumerable<>), - typeof(IEnumerable) - }, - // Not given an open generic type. - { - typeof(IEnumerable), - typeof(IEnumerable), - null - }, - { - typeof(IEnumerable), - typeof(IEnumerable), - null - }, - { - typeof(IReadOnlyList), - typeof(BaseClass), - null - }, - { - typeof(KeyValuePair<,>), - typeof(KeyValuePair), - null - }, - // Not a match. - { - typeof(IEnumerable), - typeof(IReadOnlyList<>), - null - }, - { - typeof(IList), - typeof(IReadOnlyList<>), - null - }, - { - typeof(IDictionary), - typeof(KeyValuePair<,>), - null - }, - }; - } - } - - [Theory] - [MemberData(nameof(ExtractGenericInterfaceDataSet))] - public void ExtractGenericInterface_ReturnsExpectedType( - Type queryType, - Type interfaceType, - Type expectedResult) - { - // Arrange & Act - var result = ClosedGenericMatcher.ExtractGenericInterface(queryType, interfaceType); - - // Assert - Assert.Equal(expectedResult, result); - } - - // IEnumerable is preferred because it is defined on the more-derived type. - [Fact] - public void ExtractGenericInterface_MultipleDefinitionsInherited() - { - // Arrange - var type = typeof(TwoIEnumerableImplementationsInherited); - - // Act - var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable<>)); - - // Sort - Assert.Equal(typeof(IEnumerable), result); - } - - // IEnumerable is preferred because we sort by Ordinal on the full name. - [Fact] - public void ExtractGenericInterface_MultipleDefinitionsOnSameType() - { - // Arrange - var type = typeof(TwoIEnumerableImplementationsOnSameClass); - - // Act - var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable<>)); - - // Sort - Assert.Equal(typeof(IEnumerable), result); - } - - private class TwoIEnumerableImplementationsOnSameClass : IEnumerable, IEnumerable - { - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - } - - private class TwoIEnumerableImplementationsInherited : List, IEnumerable - { - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - } - - private class BaseClass : IDictionary, IEquatable - { - object IDictionary.this[string key] - { - get - { - throw new NotImplementedException(); - } - - set - { - throw new NotImplementedException(); - } - } - - int ICollection>.Count - { - get - { - throw new NotImplementedException(); - } - } - - bool ICollection>.IsReadOnly - { - get - { - throw new NotImplementedException(); - } - } - - ICollection IDictionary.Keys - { - get - { - throw new NotImplementedException(); - } - } - - ICollection IDictionary.Values - { - get - { - throw new NotImplementedException(); - } - } - - public bool Equals(BaseClass other) - { - throw new NotImplementedException(); - } - - void ICollection>.Add(KeyValuePair item) - { - throw new NotImplementedException(); - } - - void IDictionary.Add(string key, object value) - { - throw new NotImplementedException(); - } - - void ICollection>.Clear() - { - throw new NotImplementedException(); - } - - bool ICollection>.Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - bool IDictionary.ContainsKey(string key) - { - throw new NotImplementedException(); - } - - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - throw new NotImplementedException(); - } - - bool ICollection>.Remove(KeyValuePair item) - { - throw new NotImplementedException(); - } - - bool IDictionary.Remove(string key) - { - throw new NotImplementedException(); - } - - bool IDictionary.TryGetValue(string key, out object value) - { - throw new NotImplementedException(); - } - } - - private class DerivedClass : BaseClass - { - } - - private class DerivedClassWithComparable : DerivedClass, IComparable - { - public int CompareTo(DerivedClassWithComparable other) - { - throw new NotImplementedException(); - } - } - - private class DerivedClassFromSystemImplementation : Collection - { - } - } -} \ No newline at end of file diff --git a/src/Shared/test/Shared.Tests/CopyOnWriteDictionaryHolderTest.cs b/src/Shared/test/Shared.Tests/CopyOnWriteDictionaryHolderTest.cs deleted file mode 100644 index 9a0951eb27..0000000000 --- a/src/Shared/test/Shared.Tests/CopyOnWriteDictionaryHolderTest.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class CopyOnWriteDictionaryHolderTest - { - [Fact] - public void ReadOperation_DelegatesToSourceDictionary_IfNoMutationsArePerformed() - { - // Arrange - var source = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "test-key", "test-value" }, - { "key2", "key2-value" } - }; - - var holder = new CopyOnWriteDictionaryHolder(source); - - // Act and Assert - Assert.Equal("key2-value", holder["key2"]); - Assert.Equal(2, holder.Count); - Assert.Equal(new string[] { "test-key", "key2" }, holder.Keys.ToArray()); - Assert.Equal(new object[] { "test-value", "key2-value" }, holder.Values.ToArray()); - Assert.True(holder.ContainsKey("test-key")); - - object value; - Assert.False(holder.TryGetValue("different-key", out value)); - - Assert.False(holder.HasBeenCopied); - Assert.Same(source, holder.ReadDictionary); - } - - [Fact] - public void ReadOperation_DoesNotDelegateToSourceDictionary_OnceAValueIsChanged() - { - // Arrange - var source = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "key1", "value1" }, - { "key2", "value2" } - }; - - var holder = new CopyOnWriteDictionaryHolder(source); - - // Act - holder["key2"] = "value3"; - - // Assert - Assert.Equal("value2", source["key2"]); - Assert.Equal(2, holder.Count); - Assert.Equal("value1", holder["key1"]); - Assert.Equal("value3", holder["key2"]); - - Assert.True(holder.HasBeenCopied); - Assert.NotSame(source, holder.ReadDictionary); - } - - [Fact] - public void ReadOperation_DoesNotDelegateToSourceDictionary_OnceValueIsAdded() - { - // Arrange - var source = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "key1", "value1" }, - { "key2", "value2" } - }; - - var holder = new CopyOnWriteDictionaryHolder(source); - - // Act - holder.Add("key3", "value3"); - holder.Remove("key1"); - - // Assert - Assert.Equal(2, source.Count); - Assert.Equal("value1", source["key1"]); - Assert.Equal(2, holder.Count); - Assert.Equal("value2", holder["KeY2"]); - Assert.Equal("value3", holder["key3"]); - - Assert.True(holder.HasBeenCopied); - Assert.NotSame(source, holder.ReadDictionary); - } - } -} diff --git a/src/Shared/test/Shared.Tests/CopyOnWriteDictionaryTest.cs b/src/Shared/test/Shared.Tests/CopyOnWriteDictionaryTest.cs deleted file mode 100644 index c1b54036d4..0000000000 --- a/src/Shared/test/Shared.Tests/CopyOnWriteDictionaryTest.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using Moq; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class CopyOnWriteDictionaryTest - { - [Fact] - public void ReadOperation_DelegatesToSourceDictionary_IfNoMutationsArePerformed() - { - // Arrange - var values = new List(); - var enumerator = Mock.Of>>(); - var sourceDictionary = new Mock>(MockBehavior.Strict); - sourceDictionary - .SetupGet(d => d.Count) - .Returns(100) - .Verifiable(); - sourceDictionary - .SetupGet(d => d.Values) - .Returns(values) - .Verifiable(); - sourceDictionary - .Setup(d => d.ContainsKey("test-key")) - .Returns(value: true) - .Verifiable(); - sourceDictionary - .Setup(d => d.GetEnumerator()) - .Returns(enumerator) - .Verifiable(); - sourceDictionary - .Setup(d => d["key2"]) - .Returns("key2-value") - .Verifiable(); - object value; - sourceDictionary.Setup(d => d.TryGetValue("different-key", out value)) - .Returns(false) - .Verifiable(); - - var copyOnWriteDictionary = new CopyOnWriteDictionary(sourceDictionary.Object, - StringComparer.OrdinalIgnoreCase); - - // Act and Assert - Assert.Equal("key2-value", copyOnWriteDictionary["key2"]); - Assert.Equal(100, copyOnWriteDictionary.Count); - Assert.Same(values, copyOnWriteDictionary.Values); - Assert.True(copyOnWriteDictionary.ContainsKey("test-key")); - Assert.Same(enumerator, copyOnWriteDictionary.GetEnumerator()); - Assert.False(copyOnWriteDictionary.TryGetValue("different-key", out value)); - sourceDictionary.Verify(); - } - - [Fact] - public void ReadOperation_DoesNotDelegateToSourceDictionary_OnceAValueIsChanged() - { - // Arrange - var values = new List(); - var sourceDictionary = new Dictionary - { - { "key1", "value1" }, - { "key2", "value2" } - }; - var copyOnWriteDictionary = new CopyOnWriteDictionary( - sourceDictionary, - StringComparer.OrdinalIgnoreCase); - - // Act - copyOnWriteDictionary["key2"] = "value3"; - - // Assert - Assert.Equal("value2", sourceDictionary["key2"]); - Assert.Equal(2, copyOnWriteDictionary.Count); - Assert.Equal("value1", copyOnWriteDictionary["key1"]); - Assert.Equal("value3", copyOnWriteDictionary["key2"]); - } - - [Fact] - public void ReadOperation_DoesNotDelegateToSourceDictionary_OnceDictionaryIsModified() - { - // Arrange - var values = new List(); - var sourceDictionary = new Dictionary - { - { "key1", "value1" }, - { "key2", "value2" } - }; - var copyOnWriteDictionary = new CopyOnWriteDictionary( - sourceDictionary, - StringComparer.OrdinalIgnoreCase); - - // Act - copyOnWriteDictionary.Add("key3", "value3"); - copyOnWriteDictionary.Remove("key1"); - - - // Assert - Assert.Equal(2, sourceDictionary.Count); - Assert.Equal("value1", sourceDictionary["key1"]); - Assert.Equal(2, copyOnWriteDictionary.Count); - Assert.Equal("value2", copyOnWriteDictionary["KeY2"]); - Assert.Equal("value3", copyOnWriteDictionary["key3"]); - } - } -} diff --git a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj index 05b321a6d6..1873e485a9 100644 --- a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj +++ b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj @@ -2,7 +2,6 @@ $(StandardTestTfms) - portable true @@ -10,19 +9,11 @@ - - - - - - - diff --git a/src/Shared/test/Shared.Tests/ObjectMethodExecutorTest.cs b/src/Shared/test/Shared.Tests/ObjectMethodExecutorTest.cs deleted file mode 100644 index 1c26ef1de1..0000000000 --- a/src/Shared/test/Shared.Tests/ObjectMethodExecutorTest.cs +++ /dev/null @@ -1,634 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.FSharp.Control; -using Microsoft.FSharp.Core; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class ObjectMethodExecutorTest - { - private TestObject _targetObject = new TestObject(); - private TypeInfo targetTypeInfo = typeof(TestObject).GetTypeInfo(); - - [Fact] - public void ExecuteValueMethod() - { - var executor = GetExecutorForMethod("ValueMethod"); - var result = executor.Execute( - _targetObject, - new object[] { 10, 20 }); - Assert.False(executor.IsMethodAsync); - Assert.Equal(30, (int)result); - } - - [Fact] - public void ExecuteVoidValueMethod() - { - var executor = GetExecutorForMethod("VoidValueMethod"); - var result = executor.Execute( - _targetObject, - new object[] { 10 }); - Assert.False(executor.IsMethodAsync); - Assert.Null(result); - } - - [Fact] - public void ExecuteValueMethodWithReturnType() - { - var executor = GetExecutorForMethod("ValueMethodWithReturnType"); - var result = executor.Execute( - _targetObject, - new object[] { 10 }); - var resultObject = Assert.IsType(result); - Assert.False(executor.IsMethodAsync); - Assert.Equal("Hello", resultObject.value); - } - - [Fact] - public void ExecuteValueMethodUpdateValue() - { - var executor = GetExecutorForMethod("ValueMethodUpdateValue"); - var parameter = new TestObject(); - var result = executor.Execute( - _targetObject, - new object[] { parameter }); - var resultObject = Assert.IsType(result); - Assert.False(executor.IsMethodAsync); - Assert.Equal("HelloWorld", resultObject.value); - } - - [Fact] - public void ExecuteValueMethodWithReturnTypeThrowsException() - { - var executor = GetExecutorForMethod("ValueMethodWithReturnTypeThrowsException"); - var parameter = new TestObject(); - Assert.False(executor.IsMethodAsync); - Assert.Throws( - () => executor.Execute( - _targetObject, - new object[] { parameter })); - } - - [Fact] - public async Task ExecuteValueMethodAsync() - { - var executor = GetExecutorForMethod("ValueMethodAsync"); - var result = await executor.ExecuteAsync( - _targetObject, - new object[] { 10, 20 }); - Assert.True(executor.IsMethodAsync); - Assert.Equal(30, (int)result); - } - - [Fact] - public async Task ExecuteValueMethodWithReturnTypeAsync() - { - var executor = GetExecutorForMethod("ValueMethodWithReturnTypeAsync"); - var result = await executor.ExecuteAsync( - _targetObject, - new object[] { 10 }); - var resultObject = Assert.IsType(result); - Assert.True(executor.IsMethodAsync); - Assert.Equal("Hello", resultObject.value); - } - - [Fact] - public async Task ExecuteValueMethodUpdateValueAsync() - { - var executor = GetExecutorForMethod("ValueMethodUpdateValueAsync"); - var parameter = new TestObject(); - var result = await executor.ExecuteAsync( - _targetObject, - new object[] { parameter }); - var resultObject = Assert.IsType(result); - Assert.True(executor.IsMethodAsync); - Assert.Equal("HelloWorld", resultObject.value); - } - - [Fact] - public async Task ExecuteValueMethodWithReturnTypeThrowsExceptionAsync() - { - var executor = GetExecutorForMethod("ValueMethodWithReturnTypeThrowsExceptionAsync"); - var parameter = new TestObject(); - Assert.True(executor.IsMethodAsync); - await Assert.ThrowsAsync( - async () => await executor.ExecuteAsync( - _targetObject, - new object[] { parameter })); - } - - [Fact] - public async Task ExecuteValueMethodWithReturnVoidThrowsExceptionAsync() - { - var executor = GetExecutorForMethod("ValueMethodWithReturnVoidThrowsExceptionAsync"); - var parameter = new TestObject(); - Assert.True(executor.IsMethodAsync); - await Assert.ThrowsAsync( - async () => await executor.ExecuteAsync( - _targetObject, - new object[] { parameter })); - } - - [Fact] - public void GetDefaultValueForParameters_ReturnsSuppliedValues() - { - var suppliedDefaultValues = new object[] { 123, "test value" }; - var executor = GetExecutorForMethod("MethodWithMultipleParameters", suppliedDefaultValues); - Assert.Equal(suppliedDefaultValues[0], executor.GetDefaultValueForParameter(0)); - Assert.Equal(suppliedDefaultValues[1], executor.GetDefaultValueForParameter(1)); - Assert.Throws(() => executor.GetDefaultValueForParameter(2)); - } - - [Fact] - public void GetDefaultValueForParameters_ThrowsIfNoneWereSupplied() - { - var executor = GetExecutorForMethod("MethodWithMultipleParameters"); - Assert.Throws(() => executor.GetDefaultValueForParameter(0)); - } - - [Fact] - public async void TargetMethodReturningCustomAwaitableOfReferenceType_CanInvokeViaExecute() - { - // Arrange - var executor = GetExecutorForMethod("CustomAwaitableOfReferenceTypeAsync"); - - // Act - var result = await (TestAwaitable)executor.Execute(_targetObject, new object[] { "Hello", 123 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(TestObject), executor.AsyncResultType); - Assert.NotNull(result); - Assert.Equal("Hello 123", result.value); - } - - [Fact] - public async void TargetMethodReturningCustomAwaitableOfValueType_CanInvokeViaExecute() - { - // Arrange - var executor = GetExecutorForMethod("CustomAwaitableOfValueTypeAsync"); - - // Act - var result = await (TestAwaitable)executor.Execute(_targetObject, new object[] { 123, 456 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(int), executor.AsyncResultType); - Assert.Equal(579, result); - } - - [Fact] - public async void TargetMethodReturningCustomAwaitableOfReferenceType_CanInvokeViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("CustomAwaitableOfReferenceTypeAsync"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[] { "Hello", 123 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(TestObject), executor.AsyncResultType); - Assert.NotNull(result); - Assert.IsType(result); - Assert.Equal("Hello 123", ((TestObject)result).value); - } - - [Fact] - public async void TargetMethodReturningCustomAwaitableOfValueType_CanInvokeViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("CustomAwaitableOfValueTypeAsync"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[] { 123, 456 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(int), executor.AsyncResultType); - Assert.NotNull(result); - Assert.IsType(result); - Assert.Equal(579, (int)result); - } - - [Fact] - public async void TargetMethodReturningAwaitableOfVoidType_CanInvokeViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("VoidValueMethodAsync"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[] { 123 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(void), executor.AsyncResultType); - Assert.Null(result); - } - - [Fact] - public async void TargetMethodReturningAwaitableWithICriticalNotifyCompletion_UsesUnsafeOnCompleted() - { - // Arrange - var executor = GetExecutorForMethod("CustomAwaitableWithICriticalNotifyCompletion"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[0]); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - Assert.Equal("Used UnsafeOnCompleted", (string)result); - } - - [Fact] - public async void TargetMethodReturningAwaitableWithoutICriticalNotifyCompletion_UsesOnCompleted() - { - // Arrange - var executor = GetExecutorForMethod("CustomAwaitableWithoutICriticalNotifyCompletion"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[0]); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - Assert.Equal("Used OnCompleted", (string)result); - } - - [Fact] - public async void TargetMethodReturningValueTaskOfValueType_CanBeInvokedViaExecute() - { - // Arrange - var executor = GetExecutorForMethod("ValueTaskOfValueType"); - - // Act - var result = await (ValueTask)executor.Execute(_targetObject, new object[] { 123 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(int), executor.AsyncResultType); - Assert.Equal(123, result); - } - - [Fact] - public async void TargetMethodReturningValueTaskOfReferenceType_CanBeInvokedViaExecute() - { - // Arrange - var executor = GetExecutorForMethod("ValueTaskOfReferenceType"); - - // Act - var result = await (ValueTask)executor.Execute(_targetObject, new object[] { "test result" }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - Assert.Equal("test result", result); - } - - [Fact] - public async void TargetMethodReturningValueTaskOfValueType_CanBeInvokedViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("ValueTaskOfValueType"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[] { 123 }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(int), executor.AsyncResultType); - Assert.NotNull(result); - Assert.Equal(123, (int)result); - } - - [Fact] - public async void TargetMethodReturningValueTaskOfReferenceType_CanBeInvokedViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("ValueTaskOfReferenceType"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[] { "test result" }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - Assert.Equal("test result", result); - } - - [Fact] - public async void TargetMethodReturningFSharpAsync_CanBeInvokedViaExecute() - { - // Arrange - var executor = GetExecutorForMethod("FSharpAsyncMethod"); - - // Act - var fsharpAsync = (FSharpAsync)executor.Execute(_targetObject, new object[] { "test result" }); - var result = await FSharpAsync.StartAsTask(fsharpAsync, - FSharpOption.None, - FSharpOption.None); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - Assert.Equal("test result", result); - } - - [Fact] - public async void TargetMethodReturningFailingFSharpAsync_CanBeInvokedViaExecute() - { - // Arrange - var executor = GetExecutorForMethod("FSharpAsyncFailureMethod"); - - // Act - var fsharpAsync = (FSharpAsync)executor.Execute(_targetObject, new object[] { "test result" }); - var resultTask = FSharpAsync.StartAsTask(fsharpAsync, - FSharpOption.None, - FSharpOption.None); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - - var exception = await Assert.ThrowsAsync(async () => await resultTask); - Assert.IsType(exception.InnerException); - Assert.Equal("Test exception", exception.InnerException.Message); - } - - [Fact] - public async void TargetMethodReturningFSharpAsync_CanBeInvokedViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("FSharpAsyncMethod"); - - // Act - var result = await executor.ExecuteAsync(_targetObject, new object[] { "test result" }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - Assert.Equal("test result", result); - } - - [Fact] - public async void TargetMethodReturningFailingFSharpAsync_CanBeInvokedViaExecuteAsync() - { - // Arrange - var executor = GetExecutorForMethod("FSharpAsyncFailureMethod"); - - // Act - var resultTask = executor.ExecuteAsync(_targetObject, new object[] { "test result" }); - - // Assert - Assert.True(executor.IsMethodAsync); - Assert.Same(typeof(string), executor.AsyncResultType); - - var exception = await Assert.ThrowsAsync(async () => await resultTask); - Assert.IsType(exception.InnerException); - Assert.Equal("Test exception", exception.InnerException.Message); - } - - private ObjectMethodExecutor GetExecutorForMethod(string methodName) - { - var method = typeof(TestObject).GetMethod(methodName); - return ObjectMethodExecutor.Create(method, targetTypeInfo); - } - - private ObjectMethodExecutor GetExecutorForMethod(string methodName, object[] parameterDefaultValues) - { - var method = typeof(TestObject).GetMethod(methodName); - return ObjectMethodExecutor.Create(method, targetTypeInfo, parameterDefaultValues); - } - - public class TestObject - { - public string value; - public int ValueMethod(int i, int j) - { - return i + j; - } - - public void VoidValueMethod(int i) - { - - } - - public TestObject ValueMethodWithReturnType(int i) - { - return new TestObject() { value = "Hello" }; ; - } - - public TestObject ValueMethodWithReturnTypeThrowsException(TestObject i) - { - throw new NotImplementedException("Not Implemented Exception"); - } - - public TestObject ValueMethodUpdateValue(TestObject parameter) - { - parameter.value = "HelloWorld"; - return parameter; - } - - public Task ValueMethodAsync(int i, int j) - { - return Task.FromResult(i + j); - } - - public async Task VoidValueMethodAsync(int i) - { - await ValueMethodAsync(3, 4); - } - public Task ValueMethodWithReturnTypeAsync(int i) - { - return Task.FromResult(new TestObject() { value = "Hello" }); - } - - public async Task ValueMethodWithReturnVoidThrowsExceptionAsync(TestObject i) - { - await Task.CompletedTask; - throw new NotImplementedException("Not Implemented Exception"); - } - - public async Task ValueMethodWithReturnTypeThrowsExceptionAsync(TestObject i) - { - await Task.CompletedTask; - throw new NotImplementedException("Not Implemented Exception"); - } - - public Task ValueMethodUpdateValueAsync(TestObject parameter) - { - parameter.value = "HelloWorld"; - return Task.FromResult(parameter); - } - - public TestAwaitable CustomAwaitableOfReferenceTypeAsync( - string input1, - int input2) - { - return new TestAwaitable(new TestObject - { - value = $"{input1} {input2}" - }); - } - - public TestAwaitable CustomAwaitableOfValueTypeAsync( - int input1, - int input2) - { - return new TestAwaitable(input1 + input2); - } - - public TestAwaitableWithICriticalNotifyCompletion CustomAwaitableWithICriticalNotifyCompletion() - { - return new TestAwaitableWithICriticalNotifyCompletion(); - } - - public TestAwaitableWithoutICriticalNotifyCompletion CustomAwaitableWithoutICriticalNotifyCompletion() - { - return new TestAwaitableWithoutICriticalNotifyCompletion(); - } - - public ValueTask ValueTaskOfValueType(int result) - { - return new ValueTask(result); - } - - public ValueTask ValueTaskOfReferenceType(string result) - { - return new ValueTask(result); - } - - public void MethodWithMultipleParameters(int valueTypeParam, string referenceTypeParam) - { - } - - public FSharpAsync FSharpAsyncMethod(string parameter) - { - return FSharpAsync.AwaitTask(Task.FromResult(parameter)); - } - - public FSharpAsync FSharpAsyncFailureMethod(string parameter) - { - return FSharpAsync.AwaitTask( - Task.FromException(new InvalidOperationException("Test exception"))); - } - } - - public class TestAwaitable - { - private T _result; - private bool _isCompleted; - private List _onCompletedCallbacks = new List(); - - public TestAwaitable(T result) - { - _result = result; - - // Simulate a brief delay before completion - ThreadPool.QueueUserWorkItem(_ => - { - Thread.Sleep(100); - SetCompleted(); - }); - } - - private void SetCompleted() - { - _isCompleted = true; - - foreach (var callback in _onCompletedCallbacks) - { - callback(); - } - } - - public TestAwaiter GetAwaiter() - { - return new TestAwaiter(this); - } - - public struct TestAwaiter : INotifyCompletion - { - private TestAwaitable _owner; - - public TestAwaiter(TestAwaitable owner) : this() - { - _owner = owner; - } - - public bool IsCompleted => _owner._isCompleted; - - public void OnCompleted(Action continuation) - { - if (_owner._isCompleted) - { - continuation(); - } - else - { - _owner._onCompletedCallbacks.Add(continuation); - } - } - - public T GetResult() - { - return _owner._result; - } - } - } - - public class TestAwaitableWithICriticalNotifyCompletion - { - public TestAwaiterWithICriticalNotifyCompletion GetAwaiter() - => new TestAwaiterWithICriticalNotifyCompletion(); - } - - public class TestAwaitableWithoutICriticalNotifyCompletion - { - public TestAwaiterWithoutICriticalNotifyCompletion GetAwaiter() - => new TestAwaiterWithoutICriticalNotifyCompletion(); - } - - public class TestAwaiterWithICriticalNotifyCompletion - : CompletionTrackingAwaiterBase, ICriticalNotifyCompletion - { - } - - public class TestAwaiterWithoutICriticalNotifyCompletion - : CompletionTrackingAwaiterBase, INotifyCompletion - { - } - - public class CompletionTrackingAwaiterBase - { - private string _result; - - public bool IsCompleted { get; private set; } - - public string GetResult() => _result; - - public void OnCompleted(Action continuation) - { - _result = "Used OnCompleted"; - IsCompleted = true; - continuation(); - } - - public void UnsafeOnCompleted(Action continuation) - { - _result = "Used UnsafeOnCompleted"; - IsCompleted = true; - continuation(); - } - } - } -} diff --git a/src/Shared/test/Shared.Tests/PropertyActivatorTest.cs b/src/Shared/test/Shared.Tests/PropertyActivatorTest.cs deleted file mode 100644 index a5cb1605b3..0000000000 --- a/src/Shared/test/Shared.Tests/PropertyActivatorTest.cs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Reflection; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class PropertyActivatorTest - { - [Fact] - public void Activate_InvokesValueAccessorWithExpectedValue() - { - // Arrange - var instance = new TestClass(); - var typeInfo = instance.GetType().GetTypeInfo(); - var property = typeInfo.GetDeclaredProperty("IntProperty"); - var invokedWith = -1; - var activator = new PropertyActivator( - property, - valueAccessor: (val) => - { - invokedWith = val; - return val; - }); - - // Act - activator.Activate(instance, 123); - - // Assert - Assert.Equal(123, invokedWith); - } - - [Fact] - public void Activate_SetsPropertyValue() - { - // Arrange - var instance = new TestClass(); - var typeInfo = instance.GetType().GetTypeInfo(); - var property = typeInfo.GetDeclaredProperty("IntProperty"); - var activator = new PropertyActivator(property, valueAccessor: (val) => val + 1); - - // Act - activator.Activate(instance, 123); - - // Assert - Assert.Equal(124, instance.IntProperty); - } - - [Fact] - public void GetPropertiesToActivate_RestrictsActivatableProperties() - { - // Arrange - var instance = new TestClass(); - var typeInfo = instance.GetType().GetTypeInfo(); - var expectedPropertyInfo = typeInfo.GetDeclaredProperty("ActivatableProperty"); - - // Act - var propertiesToActivate = PropertyActivator.GetPropertiesToActivate( - type: typeof(TestClass), - activateAttributeType: typeof(TestActivateAttribute), - createActivateInfo: - (propertyInfo) => new PropertyActivator(propertyInfo, valueAccessor: (val) => val + 1)); - - // Assert - Assert.Collection( - propertiesToActivate, - (activator) => - { - Assert.Equal(expectedPropertyInfo, activator.PropertyInfo); - }); - } - - [Fact] - public void GetPropertiesToActivate_CanCreateCustomPropertyActivators() - { - // Arrange - var instance = new TestClass(); - var typeInfo = instance.GetType().GetTypeInfo(); - var expectedPropertyInfo = typeInfo.GetDeclaredProperty("IntProperty"); - - // Act - var propertiesToActivate = PropertyActivator.GetPropertiesToActivate( - type: typeof(TestClass), - activateAttributeType: typeof(TestActivateAttribute), - createActivateInfo: - (propertyInfo) => new PropertyActivator(expectedPropertyInfo, valueAccessor: (val) => val + 1)); - - // Assert - Assert.Collection( - propertiesToActivate, - (activator) => - { - Assert.Equal(expectedPropertyInfo, activator.PropertyInfo); - }); - } - - [Fact] - public void GetPropertiesToActivate_ExcludesNonPublic() - { - // Arrange - var instance = new TestClassWithPropertyVisiblity(); - var typeInfo = instance.GetType().GetTypeInfo(); - var expectedPropertyInfo = typeInfo.GetDeclaredProperty("Public"); - - // Act - var propertiesToActivate = PropertyActivator.GetPropertiesToActivate( - typeof(TestClassWithPropertyVisiblity), - typeof(TestActivateAttribute), - (propertyInfo) => new PropertyActivator(propertyInfo, valueAccessor: (val) => val)); - - // Assert - Assert.Single(propertiesToActivate); - Assert.Single(propertiesToActivate, p => p.PropertyInfo == expectedPropertyInfo); - } - - [Fact] - public void GetPropertiesToActivate_IncludesNonPublic() - { - // Arrange - var instance = new TestClassWithPropertyVisiblity(); - var typeInfo = instance.GetType().GetTypeInfo(); - - // Act - var propertiesToActivate = PropertyActivator.GetPropertiesToActivate( - typeof(TestClassWithPropertyVisiblity), - typeof(TestActivateAttribute), - (propertyInfo) => new PropertyActivator(propertyInfo, valueAccessor: (val) => val), - includeNonPublic: true); - - // Assert - Assert.Equal(5, propertiesToActivate.Length); - } - - private class TestClass - { - public int IntProperty { get; set; } - - [TestActivate] - public int ActivatableProperty { get; set; } - - [TestActivate] - public int NoSetterActivatableProperty { get; } - - [TestActivate] - public int this[int something] // Not activatable - { - get - { - return 0; - } - } - - [TestActivate] - public static int StaticActivatablProperty { get; set; } - } - - private class TestClassWithPropertyVisiblity - { - [TestActivate] - public int Public { get; set; } - - [TestActivate] - protected int Protected { get; set; } - - [TestActivate] - internal int Internal { get; set; } - - [TestActivate] - protected internal int ProtectedInternal {get; set; } - - [TestActivate] - private int Private { get; set; } - } - - [AttributeUsage(AttributeTargets.Property)] - private class TestActivateAttribute : Attribute - { - } - - private class ActivationInfo - { - public string Name { get; set; } - } - } -} diff --git a/src/Shared/test/Shared.Tests/PropertyHelperTest.cs b/src/Shared/test/Shared.Tests/PropertyHelperTest.cs deleted file mode 100644 index 1c43dc880b..0000000000 --- a/src/Shared/test/Shared.Tests/PropertyHelperTest.cs +++ /dev/null @@ -1,863 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class PropertyHelperTest - { - [Fact] - public void PropertyHelper_ReturnsNameCorrectly() - { - // Arrange - var anonymous = new { foo = "bar" }; - var property = PropertyHelper.GetProperties(anonymous.GetType()).First().Property; - - // Act - var helper = new PropertyHelper(property); - - // Assert - Assert.Equal("foo", property.Name); - Assert.Equal("foo", helper.Name); - } - - [Fact] - public void PropertyHelper_ReturnsValueCorrectly() - { - // Arrange - var anonymous = new { bar = "baz" }; - var property = PropertyHelper.GetProperties(anonymous.GetType()).First().Property; - - // Act - var helper = new PropertyHelper(property); - - // Assert - Assert.Equal("bar", helper.Name); - Assert.Equal("baz", helper.GetValue(anonymous)); - } - - [Fact] - public void PropertyHelper_ReturnsGetterDelegate() - { - // Arrange - var anonymous = new { bar = "baz" }; - var property = PropertyHelper.GetProperties(anonymous.GetType()).First().Property; - - // Act - var helper = new PropertyHelper(property); - - // Assert - Assert.NotNull(helper.ValueGetter); - Assert.Equal("baz", helper.ValueGetter(anonymous)); - } - - [Fact] - public void SetValue_SetsPropertyValue() - { - // Arrange - var expected = "new value"; - var instance = new BaseClass { PropA = "old value" }; - var helper = PropertyHelper.GetProperties( - instance.GetType()).First(prop => prop.Name == "PropA"); - - // Act - helper.SetValue(instance, expected); - - // Assert - Assert.Equal(expected, instance.PropA); - } - - [Fact] - public void PropertyHelper_ReturnsSetterDelegate() - { - // Arrange - var expected = "new value"; - var instance = new BaseClass { PropA = "old value" }; - var helper = PropertyHelper.GetProperties( - instance.GetType()).First(prop => prop.Name == "PropA"); - - // Act and Assert - Assert.NotNull(helper.ValueSetter); - helper.ValueSetter(instance, expected); - - // Assert - Assert.Equal(expected, instance.PropA); - } - - [Fact] - public void PropertyHelper_ReturnsValueCorrectly_ForValueTypes() - { - // Arrange - var anonymous = new { foo = 32 }; - var property = PropertyHelper.GetProperties(anonymous.GetType()).First().Property; - - // Act - var helper = new PropertyHelper(property); - - // Assert - Assert.Equal("foo", helper.Name); - Assert.Equal(32, helper.GetValue(anonymous)); - } - - [Fact] - public void PropertyHelper_ReturnsCachedPropertyHelper() - { - // Arrange - var anonymous = new { foo = "bar" }; - - // Act - var helpers1 = PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo()); - var helpers2 = PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo()); - - // Assert - Assert.Single(helpers1); - Assert.Same(helpers1, helpers2); - Assert.Same(helpers1[0], helpers2[0]); - } - - [Fact] - public void PropertyHelper_DoesNotChangeUnderscores() - { - // Arrange - var anonymous = new { bar_baz2 = "foo" }; - - // Act + Assert - var helper = Assert.Single(PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo())); - Assert.Equal("bar_baz2", helper.Name); - } - - [Fact] - public void PropertyHelper_DoesNotFindPrivateProperties() - { - // Arrange - var anonymous = new PrivateProperties(); - - // Act + Assert - var helper = Assert.Single(PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo())); - Assert.Equal("Prop1", helper.Name); - } - - [Fact] - public void PropertyHelper_DoesNotFindStaticProperties() - { - // Arrange - var anonymous = new Static(); - - // Act + Assert - var helper = Assert.Single(PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo())); - Assert.Equal("Prop5", helper.Name); - } - -#if NETSTANDARD || NETCOREAPP - [Fact] - public void PropertyHelper_RefStructProperties() - { - // Arrange - var obj = new RefStructProperties(); - - // Act + Assert - var helper = Assert.Single(PropertyHelper.GetProperties(obj.GetType().GetTypeInfo())); - Assert.Equal("Prop5", helper.Name); - } -#elif NET46 || NET461 -#else -#error Unknown TFM - update the set of TFMs where we test for ref structs -#endif - - [Fact] - public void PropertyHelper_DoesNotFindSetOnlyProperties() - { - // Arrange - var anonymous = new SetOnly(); - - // Act + Assert - var helper = Assert.Single(PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo())); - Assert.Equal("Prop6", helper.Name); - } - - [Theory] - [InlineData(typeof(int?))] - [InlineData(typeof(DayOfWeek?))] - public void PropertyHelper_WorksForNullablePrimitiveAndEnumTypes(Type nullableType) - { - // Act - var properties = PropertyHelper.GetProperties(nullableType); - - // Assert - Assert.Empty(properties); - } - - [Fact] - public void PropertyHelper_UnwrapsNullableTypes() - { - // Arrange - var myType = typeof(MyStruct?); - - // Act - var properties = PropertyHelper.GetProperties(myType); - - // Assert - var property = Assert.Single(properties); - Assert.Equal("Foo", property.Name); - } - - [Fact] - public void PropertyHelper_WorksForStruct() - { - // Arrange - var anonymous = new MyProperties(); - - anonymous.IntProp = 3; - anonymous.StringProp = "Five"; - - // Act + Assert - var helper1 = Assert.Single(PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo()).Where(prop => prop.Name == "IntProp")); - var helper2 = Assert.Single(PropertyHelper.GetProperties(anonymous.GetType().GetTypeInfo()).Where(prop => prop.Name == "StringProp")); - Assert.Equal(3, helper1.GetValue(anonymous)); - Assert.Equal("Five", helper2.GetValue(anonymous)); - } - - [Fact] - public void PropertyHelper_ForDerivedClass() - { - // Arrange - var derived = new DerivedClass { PropA = "propAValue", PropB = "propBValue" }; - - // Act - var helpers = PropertyHelper.GetProperties(derived.GetType().GetTypeInfo()).ToArray(); - - // Assert - Assert.NotNull(helpers); - Assert.Equal(2, helpers.Length); - - var propAHelper = Assert.Single(helpers.Where(h => h.Name == "PropA")); - var propBHelper = Assert.Single(helpers.Where(h => h.Name == "PropB")); - - Assert.Equal("propAValue", propAHelper.GetValue(derived)); - Assert.Equal("propBValue", propBHelper.GetValue(derived)); - } - - [Fact] - public void PropertyHelper_ForDerivedClass_WithNew() - { - // Arrange - var derived = new DerivedClassWithNew { PropA = "propAValue" }; - - // Act - var helpers = PropertyHelper.GetProperties(derived.GetType().GetTypeInfo()).ToArray(); - - // Assert - Assert.NotNull(helpers); - Assert.Equal(2, helpers.Length); - - var propAHelper = Assert.Single(helpers.Where(h => h.Name == "PropA")); - var propBHelper = Assert.Single(helpers.Where(h => h.Name == "PropB")); - - Assert.Equal("propAValue", propAHelper.GetValue(derived)); - Assert.Equal("Newed", propBHelper.GetValue(derived)); - } - - [Fact] - public void PropertyHelper_ForDerived_WithVirtual() - { - // Arrange - var derived = new DerivedClassWithOverride { PropA = "propAValue", PropB = "propBValue" }; - - // Act - var helpers = PropertyHelper.GetProperties(derived.GetType().GetTypeInfo()).ToArray(); - - // Assert - Assert.NotNull(helpers); - Assert.Equal(2, helpers.Length); - - var propAHelper = Assert.Single(helpers.Where(h => h.Name == "PropA")); - var propBHelper = Assert.Single(helpers.Where(h => h.Name == "PropB")); - - Assert.Equal("OverridenpropAValue", propAHelper.GetValue(derived)); - Assert.Equal("propBValue", propBHelper.GetValue(derived)); - } - - [Fact] - public void PropertyHelper_ForInterface_ReturnsExpectedProperties() - { - // Arrange - var expectedNames = new[] { "Count", "IsReadOnly" }; - - // Act - var helpers = PropertyHelper.GetProperties(typeof(ICollection)); - - // Assert - Assert.Collection( - helpers.OrderBy(helper => helper.Name, StringComparer.Ordinal), - helper => { Assert.Equal(expectedNames[0], helper.Name, StringComparer.Ordinal); }, - helper => { Assert.Equal(expectedNames[1], helper.Name, StringComparer.Ordinal); }); - } - - [Fact] - public void PropertyHelper_ForDerivedInterface_ReturnsAllProperties() - { - // Arrange - var expectedNames = new[] { "Count", "IsReadOnly", "Keys", "Values" }; - - // Act - var helpers = PropertyHelper.GetProperties(typeof(IDictionary)); - - // Assert - Assert.Collection( - helpers.OrderBy(helper => helper.Name, StringComparer.Ordinal), - helper => { Assert.Equal(expectedNames[0], helper.Name, StringComparer.Ordinal); }, - helper => { Assert.Equal(expectedNames[1], helper.Name, StringComparer.Ordinal); }, - helper => { Assert.Equal(expectedNames[2], helper.Name, StringComparer.Ordinal); }, - helper => { Assert.Equal(expectedNames[3], helper.Name, StringComparer.Ordinal); }); - } - - [Fact] - public void GetProperties_ExcludesIndexersAndPropertiesWithoutPublicGetters() - { - // Arrange - var type = typeof(DerivedClassWithNonReadableProperties); - - // Act - var result = PropertyHelper.GetProperties(type).ToArray(); - - // Assert - Assert.Equal(3, result.Length); - Assert.Equal("Visible", result[0].Name); - Assert.Equal("PropA", result[1].Name); - Assert.Equal("PropB", result[2].Name); - } - - [Fact] - public void GetVisibleProperties_NoHiddenProperty() - { - // Arrange - var type = typeof(string); - - // Act - var result = PropertyHelper.GetVisibleProperties(type).ToArray(); - - // Assert - var property = Assert.Single(result); - Assert.Equal("Length", property.Name); - Assert.Equal(typeof(int), property.Property.PropertyType); - } - - [Fact] - public void GetVisibleProperties_HiddenProperty() - { - // Arrange - var type = typeof(DerivedHiddenProperty); - - // Act - var result = PropertyHelper.GetVisibleProperties(type).ToArray(); - - // Assert - Assert.Equal(2, result.Length); - Assert.Equal("Id", result[0].Name); - Assert.Equal(typeof(string), result[0].Property.PropertyType); - Assert.Equal("Name", result[1].Name); - Assert.Equal(typeof(string), result[1].Property.PropertyType); - } - - [Fact] - public void GetVisibleProperties_HiddenProperty_TwoLevels() - { - // Arrange - var type = typeof(DerivedHiddenProperty2); - - // Act - var result = PropertyHelper.GetVisibleProperties(type).ToArray(); - - // Assert - Assert.Equal(2, result.Length); - Assert.Equal("Id", result[0].Name); - Assert.Equal(typeof(Guid), result[0].Property.PropertyType); - Assert.Equal("Name", result[1].Name); - Assert.Equal(typeof(string), result[1].Property.PropertyType); - } - - [Fact] - public void GetVisibleProperties_NoHiddenPropertyWithTypeInfoInput() - { - // Arrange - var type = typeof(string); - - // Act - var result = PropertyHelper.GetVisibleProperties(type.GetTypeInfo()).ToArray(); - - // Assert - var property = Assert.Single(result); - Assert.Equal("Length", property.Name); - Assert.Equal(typeof(int), property.Property.PropertyType); - } - - [Fact] - public void GetVisibleProperties_HiddenPropertyWithTypeInfoInput() - { - // Arrange - var type = typeof(DerivedHiddenProperty); - - // Act - var result = PropertyHelper.GetVisibleProperties(type.GetTypeInfo()).ToArray(); - - // Assert - Assert.Equal(2, result.Length); - Assert.Equal("Id", result[0].Name); - Assert.Equal(typeof(string), result[0].Property.PropertyType); - Assert.Equal("Name", result[1].Name); - Assert.Equal(typeof(string), result[1].Property.PropertyType); - } - - [Fact] - public void GetVisibleProperties_HiddenProperty_TwoLevelsWithTypeInfoInput() - { - // Arrange - var type = typeof(DerivedHiddenProperty2); - - // Act - var result = PropertyHelper.GetVisibleProperties(type.GetTypeInfo()).ToArray(); - - // Assert - Assert.Equal(2, result.Length); - Assert.Equal("Id", result[0].Name); - Assert.Equal(typeof(Guid), result[0].Property.PropertyType); - Assert.Equal("Name", result[1].Name); - Assert.Equal(typeof(string), result[1].Property.PropertyType); - } - - [Fact] - public void MakeFastPropertySetter_SetsPropertyValues_ForPublicAndNobPublicProperties() - { - // Arrange - var instance = new BaseClass(); - var typeInfo = instance.GetType().GetTypeInfo(); - var publicProperty = typeInfo.GetDeclaredProperty("PropA"); - var protectedProperty = typeInfo.GetDeclaredProperty("PropProtected"); - var publicPropertySetter = PropertyHelper.MakeFastPropertySetter(publicProperty); - var protectedPropertySetter = PropertyHelper.MakeFastPropertySetter(protectedProperty); - - // Act - publicPropertySetter(instance, "TestPublic"); - protectedPropertySetter(instance, "TestProtected"); - - // Assert - Assert.Equal("TestPublic", instance.PropA); - Assert.Equal("TestProtected", instance.GetPropProtected()); - } - - [Fact] - public void MakeFastPropertySetter_SetsPropertyValues_ForOverridenProperties() - { - // Arrange - var instance = new DerivedClassWithOverride(); - var typeInfo = instance.GetType().GetTypeInfo(); - var property = typeInfo.GetDeclaredProperty("PropA"); - var propertySetter = PropertyHelper.MakeFastPropertySetter(property); - - // Act - propertySetter(instance, "Test value"); - - // Assert - Assert.Equal("OverridenTest value", instance.PropA); - } - - [Fact] - public void MakeFastPropertySetter_SetsPropertyValues_ForNewedProperties() - { - // Arrange - var instance = new DerivedClassWithNew(); - var typeInfo = instance.GetType().GetTypeInfo(); - var property = typeInfo.GetDeclaredProperty("PropB"); - var propertySetter = PropertyHelper.MakeFastPropertySetter(property); - - // Act - propertySetter(instance, "Test value"); - - // Assert - Assert.Equal("NewedTest value", instance.PropB); - } - - [Fact] - public void MakeFastPropertyGetter_ReferenceType_ForNullObject_Throws() - { - // Arrange - var property = PropertyHelper - .GetProperties(typeof(BaseClass)) - .Single(p => p.Name == nameof(BaseClass.PropA)); - - var accessor = PropertyHelper.MakeFastPropertyGetter(property.Property); - - // Act & Assert - Assert.Throws(() => accessor(null)); - } - - [Fact] - public void MakeFastPropertyGetter_ValueType_ForNullObject_Throws() - { - // Arrange - var property = PropertyHelper - .GetProperties(typeof(MyProperties)) - .Single(p => p.Name == nameof(MyProperties.StringProp)); - - var accessor = PropertyHelper.MakeFastPropertyGetter(property.Property); - - // Act & Assert - Assert.Throws(() => accessor(null)); - } - - [Fact] - public void MakeNullSafeFastPropertyGetter_ReferenceType_Success() - { - // Arrange - var property = PropertyHelper - .GetProperties(typeof(BaseClass)) - .Single(p => p.Name == nameof(BaseClass.PropA)); - - var accessor = PropertyHelper.MakeNullSafeFastPropertyGetter(property.Property); - - // Act - var value = accessor(new BaseClass() { PropA = "Hi" }); - - // Assert - Assert.Equal("Hi", value); - } - - [Fact] - public void MakeNullSafeFastPropertyGetter_ValueType_Success() - { - // Arrange - var property = PropertyHelper - .GetProperties(typeof(MyProperties)) - .Single(p => p.Name == nameof(MyProperties.StringProp)); - - var accessor = PropertyHelper.MakeNullSafeFastPropertyGetter(property.Property); - - // Act - var value = accessor(new MyProperties() { StringProp = "Hi" }); - - // Assert - Assert.Equal("Hi", value); - } - - [Fact] - public void MakeNullSafeFastPropertyGetter_ReferenceType_ForNullObject_ReturnsNull() - { - // Arrange - var property = PropertyHelper - .GetProperties(typeof(BaseClass)) - .Single(p => p.Name == nameof(BaseClass.PropA)); - - var accessor = PropertyHelper.MakeNullSafeFastPropertyGetter(property.Property); - - // Act - var value = accessor(null); - - // Assert - Assert.Null(value); - } - - [Fact] - public void MakeNullSafeFastPropertyGetter_ValueType_ForNullObject_ReturnsNull() - { - // Arrange - var property = PropertyHelper - .GetProperties(typeof(MyProperties)) - .Single(p => p.Name == nameof(MyProperties.StringProp)); - - var accessor = PropertyHelper.MakeNullSafeFastPropertyGetter(property.Property); - - // Act - var value = accessor(null); - - // Assert - Assert.Null(value); - } - - public static TheoryData> IgnoreCaseTestData - { - get - { - return new TheoryData> - { - { - new - { - selected = true, - SeLeCtEd = false - }, - new KeyValuePair("selected", false) - }, - { - new - { - SeLeCtEd = false, - selected = true - }, - new KeyValuePair("SeLeCtEd", true) - }, - { - new - { - SelECTeD = false, - SeLECTED = true - }, - new KeyValuePair("SelECTeD", true) - } - }; - } - } - - [Theory] - [MemberData(nameof(IgnoreCaseTestData))] - public void ObjectToDictionary_IgnoresPropertyCase(object testObject, - KeyValuePair expectedEntry) - { - // Act - var result = PropertyHelper.ObjectToDictionary(testObject); - - // Assert - var entry = Assert.Single(result); - Assert.Equal(expectedEntry, entry); - } - - [Fact] - public void ObjectToDictionary_WithNullObject_ReturnsEmptyDictionary() - { - // Arrange - object value = null; - - // Act - var dictValues = PropertyHelper.ObjectToDictionary(value); - - // Assert - Assert.NotNull(dictValues); - Assert.Equal(0, dictValues.Count); - } - - [Fact] - public void ObjectToDictionary_WithPlainObjectType_ReturnsEmptyDictionary() - { - // Arrange - var value = new object(); - - // Act - var dictValues = PropertyHelper.ObjectToDictionary(value); - - // Assert - Assert.NotNull(dictValues); - Assert.Equal(0, dictValues.Count); - } - - [Fact] - public void ObjectToDictionary_WithPrimitiveType_LooksUpPublicProperties() - { - // Arrange - var value = "test"; - - // Act - var dictValues = PropertyHelper.ObjectToDictionary(value); - - // Assert - Assert.NotNull(dictValues); - Assert.Equal(1, dictValues.Count); - Assert.Equal(4, dictValues["Length"]); - } - - [Fact] - public void ObjectToDictionary_WithAnonymousType_LooksUpProperties() - { - // Arrange - var value = new { test = "value", other = 1 }; - - // Act - var dictValues = PropertyHelper.ObjectToDictionary(value); - - // Assert - Assert.NotNull(dictValues); - Assert.Equal(2, dictValues.Count); - Assert.Equal("value", dictValues["test"]); - Assert.Equal(1, dictValues["other"]); - } - - [Fact] - public void ObjectToDictionary_ReturnsCaseInsensitiveDictionary() - { - // Arrange - var value = new { TEST = "value", oThEr = 1 }; - - // Act - var dictValues = PropertyHelper.ObjectToDictionary(value); - - // Assert - Assert.NotNull(dictValues); - Assert.Equal(2, dictValues.Count); - Assert.Equal("value", dictValues["test"]); - Assert.Equal(1, dictValues["other"]); - } - - [Fact] - public void ObjectToDictionary_ReturnsInheritedProperties() - { - // Arrange - var value = new ThreeDPoint() { X = 5, Y = 10, Z = 17 }; - - // Act - var dictValues = PropertyHelper.ObjectToDictionary(value); - - // Assert - Assert.NotNull(dictValues); - Assert.Equal(3, dictValues.Count); - Assert.Equal(5, dictValues["X"]); - Assert.Equal(10, dictValues["Y"]); - Assert.Equal(17, dictValues["Z"]); - } - - private class Point - { - public int X { get; set; } - public int Y { get; set; } - } - - private class ThreeDPoint : Point - { - public int Z { get; set; } - } - - private class Static - { - public static int Prop2 { get; set; } - public int Prop5 { get; set; } - } - -#if NETSTANDARD || NETCOREAPP - private class RefStructProperties - { - public Span Span => throw new NotImplementedException(); - public MyRefStruct UserDefined => throw new NotImplementedException(); - - public int Prop5 { get; set; } - } - - private readonly ref struct MyRefStruct - { - } -#elif NET46 || NET461 -#else -#error Unknown TFM - update the set of TFMs where we test for ref structs -#endif - private struct MyProperties - { - public int IntProp { get; set; } - public string StringProp { get; set; } - } - - private class SetOnly - { - public int Prop2 { set { } } - public int Prop6 { get; set; } - } - - private class PrivateProperties - { - public int Prop1 { get; set; } - protected int Prop2 { get; set; } - private int Prop3 { get; set; } - } - - public class BaseClass - { - public string PropA { get; set; } - - protected string PropProtected { get; set; } - - public string GetPropProtected() - { - return PropProtected; - } - } - - public class DerivedClass : BaseClass - { - public string PropB { get; set; } - } - - public class BaseClassWithVirtual - { - public virtual string PropA { get; set; } - public string PropB { get; set; } - } - - public class DerivedClassWithNew : BaseClassWithVirtual - { - private string _value = "Newed"; - - public new string PropB - { - get { return _value; } - set { _value = "Newed" + value; } - } - } - - public class DerivedClassWithOverride : BaseClassWithVirtual - { - private string _value = "Overriden"; - - public override string PropA - { - get { return _value; } - set { _value = "Overriden" + value; } - } - } - - private class DerivedClassWithNonReadableProperties : BaseClassWithVirtual - { - public string this[int index] - { - get { return string.Empty; } - set { } - } - - public int Visible { get; set; } - - private string NotVisible { get; set; } - - public string NotVisible2 { private get; set; } - - public string NotVisible3 - { - set { } - } - - public static string NotVisible4 { get; set; } - } - - private struct MyStruct - { - public string Foo { get; set; } - } - - private class BaseHiddenProperty - { - public int Id { get; set; } - } - - private class DerivedHiddenProperty : BaseHiddenProperty - { - public new string Id { get; set; } - - public string Name { get; set; } - } - - private class DerivedHiddenProperty2 : DerivedHiddenProperty - { - public new Guid Id { get; set; } - - public new string Name { get; private set; } - } - } -} diff --git a/src/Shared/test/Shared.Tests/Readme.txt b/src/Shared/test/Shared.Tests/Readme.txt deleted file mode 100644 index b818bd8148..0000000000 --- a/src/Shared/test/Shared.Tests/Readme.txt +++ /dev/null @@ -1,4 +0,0 @@ -NOTE: -1. The tests for 'ExceptionDetailProvider' and 'StackTraceHelper' in project 'Microsoft.Extensions.StackTrace.Sources' are located in Diagnostics - repo. This is because they refer to some packages from FileSystem repo which causes a circular reference and breaks the - build. \ No newline at end of file diff --git a/src/Shared/test/Shared.Tests/SecurityHelperTests.cs b/src/Shared/test/Shared.Tests/SecurityHelperTests.cs deleted file mode 100644 index 8e7515ad36..0000000000 --- a/src/Shared/test/Shared.Tests/SecurityHelperTests.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Linq; -using System.Security.Claims; -using System.Security.Principal; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class SecurityHelperTests - { - [Fact] - public void AddingToAnonymousIdentityDoesNotKeepAnonymousIdentity() - { - var user = SecurityHelper.MergeUserPrincipal(new ClaimsPrincipal(), new GenericPrincipal(new GenericIdentity("Test1", "Alpha"), new string[0])); - - Assert.NotNull(user); - Assert.Equal("Alpha", user.Identity.AuthenticationType); - Assert.Equal("Test1", user.Identity.Name); - Assert.IsAssignableFrom(user); - Assert.IsAssignableFrom(user.Identity); - Assert.Single(user.Identities); - } - - [Fact] - public void AddingExistingIdentityChangesDefaultButPreservesPrior() - { - ClaimsPrincipal user = new GenericPrincipal(new GenericIdentity("Test1", "Alpha"), null); - - Assert.Equal("Alpha", user.Identity.AuthenticationType); - Assert.Equal("Test1", user.Identity.Name); - - user = SecurityHelper.MergeUserPrincipal(user, new GenericPrincipal(new GenericIdentity("Test2", "Beta"), new string[0])); - - Assert.Equal("Beta", user.Identity.AuthenticationType); - Assert.Equal("Test2", user.Identity.Name); - - user = SecurityHelper.MergeUserPrincipal(user, new GenericPrincipal(new GenericIdentity("Test3", "Gamma"), new string[0])); - - Assert.Equal("Gamma", user.Identity.AuthenticationType); - Assert.Equal("Test3", user.Identity.Name); - - Assert.Equal(3, user.Identities.Count()); - Assert.Equal("Test3", user.Identities.Skip(0).First().Name); - Assert.Equal("Test2", user.Identities.Skip(1).First().Name); - Assert.Equal("Test1", user.Identities.Skip(2).First().Name); - } - - [Fact] - public void AddingPreservesNewIdentitiesAndDropsEmpty() - { - var existingPrincipal = new ClaimsPrincipal(new ClaimsIdentity()); - var identityNoAuthTypeWithClaim = new ClaimsIdentity(); - identityNoAuthTypeWithClaim.AddClaim(new Claim("identityNoAuthTypeWithClaim", "yes")); - existingPrincipal.AddIdentity(identityNoAuthTypeWithClaim); - var identityEmptyWithAuthType = new ClaimsIdentity("empty"); - existingPrincipal.AddIdentity(identityEmptyWithAuthType); - - Assert.False(existingPrincipal.Identity.IsAuthenticated); - - var newPrincipal = new ClaimsPrincipal(); - var newEmptyIdentity = new ClaimsIdentity(); - var identityTwo = new ClaimsIdentity("yep"); - newPrincipal.AddIdentity(newEmptyIdentity); - newPrincipal.AddIdentity(identityTwo); - - var user = SecurityHelper.MergeUserPrincipal(existingPrincipal, newPrincipal); - - // Preserve newPrincipal order - Assert.False(user.Identity.IsAuthenticated); - Assert.Null(user.Identity.Name); - - Assert.Equal(4, user.Identities.Count()); - Assert.Equal(newEmptyIdentity, user.Identities.Skip(0).First()); - Assert.Equal(identityTwo, user.Identities.Skip(1).First()); - Assert.Equal(identityNoAuthTypeWithClaim, user.Identities.Skip(2).First()); - Assert.Equal(identityEmptyWithAuthType, user.Identities.Skip(3).First()); - - // This merge should drop newEmptyIdentity since its empty - user = SecurityHelper.MergeUserPrincipal(user, new GenericPrincipal(new GenericIdentity("Test3", "Gamma"), new string[0])); - - Assert.Equal("Gamma", user.Identity.AuthenticationType); - Assert.Equal("Test3", user.Identity.Name); - - Assert.Equal(4, user.Identities.Count()); - Assert.Equal("Test3", user.Identities.Skip(0).First().Name); - Assert.Equal(identityTwo, user.Identities.Skip(1).First()); - Assert.Equal(identityNoAuthTypeWithClaim, user.Identities.Skip(2).First()); - Assert.Equal(identityEmptyWithAuthType, user.Identities.Skip(3).First()); - } - } -} diff --git a/src/Shared/test/Shared.Tests/StackTraceHelperTest.cs b/src/Shared/test/Shared.Tests/StackTraceHelperTest.cs deleted file mode 100644 index 657a310b6e..0000000000 --- a/src/Shared/test/Shared.Tests/StackTraceHelperTest.cs +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.Extensions.StackTrace.Sources; -using ThrowingLibrary; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class StackTraceHelperTest - { - [Fact] - public void StackTraceHelper_IncludesLineNumbersForFiles() - { - // Arrange - Exception exception = null; - try - { - // Throwing an exception in the current assembly always seems to populate the full stack - // trace regardless of symbol type. Crossing assembly boundaries ensures PortablePdbReader gets used - // on desktop. - Thrower.Throw(); - } - catch (Exception ex) - { - exception = ex; - } - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - Assert.Collection(stackFrames, - frame => - { - Assert.Contains("Thrower.cs", frame.FilePath); - Assert.Equal(17, frame.LineNumber); - }, - frame => - { - Assert.Contains("StackTraceHelperTest.cs", frame.FilePath); - }); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForGenericMethods() - { - // Arrange - var exception = Record.Exception(() => GenericMethod(null)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.GenericMethod(T val)", methods[0]); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithOutParameters() - { - // Arrange - var exception = Record.Exception(() => MethodWithOutParameter(out var value)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.MethodWithOutParameter(out int value)", methods[0]); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithGenericOutParameters() - { - // Arrange - var exception = Record.Exception(() => MethodWithGenericOutParameter("Test", out int value)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.MethodWithGenericOutParameter(string a, out TVal value)", methods[0]); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithRefParameters() - { - // Arrange - var value = 0; - var exception = Record.Exception(() => MethodWithRefParameter(ref value)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.MethodWithRefParameter(ref int value)", methods[0]); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithGenericRefParameters() - { - // Arrange - var value = 0; - var exception = Record.Exception(() => MethodWithGenericRefParameter(ref value)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.MethodWithGenericRefParameter(ref TVal value)", methods[0]); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithNullableParameters() - { - // Arrange - var value = 0; - var exception = Record.Exception(() => MethodWithNullableParameter(value)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.MethodWithNullableParameter(Nullable value)", methods[0]); - } - - [Fact] - public void StackTraceHelper_PrettyPrintsStackTraceForMethodsOnGenericTypes() - { - // Arrange - var exception = Record.Exception(() => new GenericClass().Throw(0)); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest+GenericClass.Throw(T parameter)", methods[0]); - } - - [Fact] - public void StackTraceHelper_ProducesReadableOutput() - { - // Arrange - var expectedCallStack = new List() - { - "Microsoft.Extensions.Internal.StackTraceHelperTest.Iterator()+MoveNext()", - "string.Join(string separator, IEnumerable values)", - "Microsoft.Extensions.Internal.StackTraceHelperTest+GenericClass.GenericMethod(ref V value)", - "Microsoft.Extensions.Internal.StackTraceHelperTest.MethodAsync(int value)", - "Microsoft.Extensions.Internal.StackTraceHelperTest.MethodAsync(TValue value)", - "Microsoft.Extensions.Internal.StackTraceHelperTest.Method(string value)", - "Microsoft.Extensions.Internal.StackTraceHelperTest.StackTraceHelper_ProducesReadableOutput()", - }; - - Exception exception = null; - try - { - Method("test"); - } - catch (Exception ex) - { - exception = ex; - } - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - var methodNames = stackFrames.Select(stackFrame => stackFrame.MethodDisplayInfo.ToString()).ToArray(); - - // Assert - Assert.Equal(expectedCallStack, methodNames); - } - - [Fact] - public void StackTraceHelper_DoesNotIncludeInstanceMethodsOnTypesWithStackTraceHiddenAttribute() - { - // Arrange - var exception = Record.Exception(() => InvokeMethodOnTypeWithStackTraceHiddenAttribute()); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.ThrowCore()", methods[0]); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.InvokeMethodOnTypeWithStackTraceHiddenAttribute()", methods[1]); - } - - [Fact] - public void StackTraceHelper_DoesNotIncludeStaticMethodsOnTypesWithStackTraceHiddenAttribute() - { - // Arrange - var exception = Record.Exception(() => InvokeStaticMethodOnTypeWithStackTraceHiddenAttribute()); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.ThrowCore()", methods[0]); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.InvokeStaticMethodOnTypeWithStackTraceHiddenAttribute()", methods[1]); - } - - [Fact] - public void StackTraceHelper_DoesNotIncludeMethodsWithStackTraceHiddenAttribute() - { - // Arrange - var exception = Record.Exception(() => new TypeWithMethodWithStackTraceHiddenAttribute().Throw()); - - // Act - var stackFrames = StackTraceHelper.GetFrames(exception); - - // Assert - var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray(); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest.ThrowCore()", methods[0]); - Assert.Equal("Microsoft.Extensions.Internal.StackTraceHelperTest+TypeWithMethodWithStackTraceHiddenAttribute.Throw()", methods[1]); - } - - [Fact] - public void GetFrames_DoesNotFailForDynamicallyGeneratedAssemblies() - { - // Arrange - var action = (Action)Expression.Lambda( - Expression.Throw( - Expression.New(typeof(Exception)))).Compile(); - var exception = Record.Exception(action); - - // Act - var frames = StackTraceHelper.GetFrames(exception).ToArray(); - - // Assert - var frame = frames[0]; - Assert.Null(frame.FilePath); - Assert.Equal($"lambda_method(Closure )", frame.MethodDisplayInfo.ToString()); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - async Task MethodAsync(int value) - { - await Task.Delay(0); - return GenericClass.GenericMethod(ref value); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - async Task MethodAsync(TValue value) - { - return await MethodAsync(1); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - string Method(string value) - { - return MethodAsync(value).GetAwaiter().GetResult(); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - static IEnumerable Iterator() - { - yield return "Success"; - throw new Exception(); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void MethodWithOutParameter(out int value) => throw new Exception(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void MethodWithGenericOutParameter(string a, out TVal value) => throw new Exception(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void MethodWithRefParameter(ref int value) => throw new Exception(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void MethodWithGenericRefParameter(ref TVal value) => throw new Exception(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void MethodWithNullableParameter(int? value) => throw new Exception(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void InvokeMethodOnTypeWithStackTraceHiddenAttribute() => new TypeWithStackTraceHiddenAttribute().Throw(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - void InvokeStaticMethodOnTypeWithStackTraceHiddenAttribute() => TypeWithStackTraceHiddenAttribute.ThrowStatic(); - - class GenericClass - { - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public static string GenericMethod(ref V value) - { - var returnVal = ""; - for (var i = 0; i < 10; i++) - { - returnVal += string.Join(", ", Iterator()); - } - return returnVal; - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public void Throw(T parameter) => throw new Exception(); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - private void GenericMethod(T val) where T : class => throw new Exception(); - - private class StackTraceHiddenAttribute : Attribute - { - } - - [StackTraceHidden] - private class TypeWithStackTraceHiddenAttribute - { - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public void Throw() => ThrowCore(); - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public static void ThrowStatic() => ThrowCore(); - } - - private class TypeWithMethodWithStackTraceHiddenAttribute - { - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - [StackTraceHidden] - public void MethodWithStackTraceHiddenAttribute() - { - ThrowCore(); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - public void Throw() => MethodWithStackTraceHiddenAttribute(); - } - - [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] - private static void ThrowCore() => throw new Exception(); - } -} diff --git a/src/Shared/test/Shared.Tests/WebEncodersTests.cs b/src/Shared/test/Shared.Tests/WebEncodersTests.cs deleted file mode 100644 index 5c71403fd6..0000000000 --- a/src/Shared/test/Shared.Tests/WebEncodersTests.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using Xunit; - -namespace Microsoft.Extensions.Internal -{ - public class WebEncodersTests - { - [Theory] - [InlineData("", 1, 0)] - [InlineData("", 0, 1)] - [InlineData("0123456789", 9, 2)] - [InlineData("0123456789", Int32.MaxValue, 2)] - [InlineData("0123456789", 9, -1)] - public void Base64UrlDecode_BadOffsets(string input, int offset, int count) - { - // Act & assert - Assert.ThrowsAny(() => - { - var retVal = WebEncoders.Base64UrlDecode(input, offset, count); - }); - } - - [Theory] - [InlineData("x")] - [InlineData("(x)")] - public void Base64UrlDecode_MalformedInput(string input) - { - // Act & assert - Assert.Throws(() => - { - var retVal = WebEncoders.Base64UrlDecode(input); - }); - } - - [Theory] - [InlineData("", "")] - [InlineData("123456qwerty++//X+/x", "123456qwerty--__X-_x")] - [InlineData("123456qwerty++//X+/xxw==", "123456qwerty--__X-_xxw")] - [InlineData("123456qwerty++//X+/xxw0=", "123456qwerty--__X-_xxw0")] - public void Base64UrlEncode_And_Decode(string base64Input, string expectedBase64Url) - { - // Arrange - byte[] input = new byte[3].Concat(Convert.FromBase64String(base64Input)).Concat(new byte[2]).ToArray(); - - // Act & assert - 1 - string actualBase64Url = WebEncoders.Base64UrlEncode(input, 3, input.Length - 5); // also helps test offsets - Assert.Equal(expectedBase64Url, actualBase64Url); - - // Act & assert - 2 - // Verify that values round-trip - byte[] roundTripped = WebEncoders.Base64UrlDecode("xx" + actualBase64Url + "yyy", 2, actualBase64Url.Length); // also helps test offsets - string roundTrippedAsBase64 = Convert.ToBase64String(roundTripped); - Assert.Equal(roundTrippedAsBase64, base64Input); - } - - [Theory] - [InlineData("", "")] - [InlineData("123456qwerty++//X+/x", "123456qwerty--__X-_x")] - [InlineData("123456qwerty++//X+/xxw==", "123456qwerty--__X-_xxw")] - [InlineData("123456qwerty++//X+/xxw0=", "123456qwerty--__X-_xxw0")] - public void Base64UrlEncode_And_Decode_WithBufferOffsets(string base64Input, string expectedBase64Url) - { - // Arrange - var input = new byte[3].Concat(Convert.FromBase64String(base64Input)).Concat(new byte[2]).ToArray(); - var buffer = new char[30]; - var output = new char[30]; - for (var i = 0; i < buffer.Length; i++) - { - buffer[i] = '^'; - output[i] = '^'; - } - - // Act 1 - var numEncodedChars = - WebEncoders.Base64UrlEncode(input, offset: 3, output: output, outputOffset: 4, count: input.Length - 5); - - // Assert 1 - var encodedString = new string(output, startIndex: 4, length: numEncodedChars); - Assert.Equal(expectedBase64Url, encodedString); - - // Act 2 - var roundTripInput = new string(output); - var roundTripped = - WebEncoders.Base64UrlDecode(roundTripInput, offset: 4, buffer: buffer, bufferOffset: 5, count: numEncodedChars); - - // Assert 2, verify that values round-trip - var roundTrippedAsBase64 = Convert.ToBase64String(roundTripped); - Assert.Equal(roundTrippedAsBase64, base64Input); - } - - [Theory] - [InlineData(0, 1, 0)] - [InlineData(0, 0, 1)] - [InlineData(10, 9, 2)] - [InlineData(10, Int32.MaxValue, 2)] - [InlineData(10, 9, -1)] - public void Base64UrlEncode_BadOffsets(int inputLength, int offset, int count) - { - // Arrange - byte[] input = new byte[inputLength]; - - // Act & assert - Assert.ThrowsAny(() => - { - var retVal = WebEncoders.Base64UrlEncode(input, offset, count); - }); - } - } -} diff --git a/src/Shared/test/testassets/ThrowingLibrary/Thrower.cs b/src/Shared/test/testassets/ThrowingLibrary/Thrower.cs deleted file mode 100644 index babe2387c6..0000000000 --- a/src/Shared/test/testassets/ThrowingLibrary/Thrower.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Runtime.CompilerServices; - -namespace ThrowingLibrary -{ - // Throwing an exception in the current assembly always seems to populate the full stack - // trace regardless of symbol type. This type exists to simulate an exception thrown - // across assemblies which is the typical use case for StackTraceHelper. - public static class Thrower - { - [MethodImpl(MethodImplOptions.NoInlining)] - public static void Throw() - { - throw new DivideByZeroException(); - } - } -} diff --git a/src/Shared/test/testassets/ThrowingLibrary/ThrowingLibrary.csproj b/src/Shared/test/testassets/ThrowingLibrary/ThrowingLibrary.csproj deleted file mode 100644 index 2b2900911a..0000000000 --- a/src/Shared/test/testassets/ThrowingLibrary/ThrowingLibrary.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - netstandard2.0 - portable - false - - -