Aracılığıyla paylaş


.NET 10 için .NET kitaplıklarındaki yenilikler

Bu makalede .NET 10 için .NET kitaplıklarındaki yeni özellikler açıklanmaktadır.

Şifreleme

SHA-1 dışındaki parmak izine göre sertifikaları bulma

Sertifikaları parmak iziyle benzersiz olarak bulmak oldukça yaygın bir işlemdir, ancak X509Certificate2Collection.Find(X509FindType, Object, Boolean) yöntem (mod için FindByThumbprint ) yalnızca SHA-1 parmak izi değerini arar.

Bu karma algoritmaların uzunlukları aynı olduğundan SHA-2-256 ("SHA256") ve SHA-3-256 parmak izlerini bulmak için Find yöntemini kullanma riski vardır.

Bunun yerine. .NET 10, eşleştirme için kullanılacak karma algoritmasının adını kabul eden yeni bir yöntem tanıtır.

X509Certificate2Collection coll = store.Certificates.FindByThumbprint(HashAlgorithmName.SHA256, thumbprint);
Debug.Assert(coll.Count < 2, "Collection has too many matches, has SHA-2 been broken?");
return coll.SingleOrDefault();

ASCII/UTF-8'de PEM ile kodlanmış verileri bulma

PEM kodlaması (başlangıçta Gizlilik Artırılmış Posta, ancak şimdi e-posta dışında yaygın olarak kullanılır), "metin" için tanımlanır; bu da PemEncoding sınıfının String ve ReadOnlySpan<char>üzerinde çalışacak şekilde tasarlandığı anlamına gelir. Ancak, ASCII (dize) kodlaması kullanan bir dosyada yazılmış bir sertifikaya benzer bir şey olması yaygındır (özellikle Linux'ta). Geçmişte bu, PemEncodingkullanabilmeniz için dosyayı açmanız ve baytları karakterlere (veya dizeye) dönüştürmeniz gerektiği anlamına geliyordu.

Yeni PemEncoding.FindUtf8(ReadOnlySpan<Byte>) yöntem, PEM'in yalnızca 7 bit ASCII karakterleri için tanımlandığı ve bu 7 bit ASCII'nin tek bayt UTF-8 değerleriyle mükemmel bir çakışmaya sahip olması gerçeğinden yararlanır. Bu yeni yöntemi çağırarak UTF-8/ASCII-to-char dönüştürmesini atlayabilir ve dosyayı doğrudan okuyabilirsiniz.

byte[] fileContents = File.ReadAllBytes(path);
-char[] text = Encoding.ASCII.GetString(fileContents);
-PemFields pemFields = PemEncoding.Find(text);
+PemFields pemFields = PemEncoding.FindUtf8(fileContents);

-byte[] contents = Base64.DecodeFromChars(text.AsSpan()[pemFields.Base64Data]);
+byte[] contents = Base64.DecodeFromUtf8(fileContents.AsSpan()[pemFields.Base64Data]);

PKCS#12/PFX dışarı aktarma için şifreleme algoritması

ExportPkcs12 üzerindeki yeni yöntemler, çağıranların çıkışı üretmek için hangi şifreleme ve özet algoritmalarının kullanılacağını seçmesine izin verir.

  • Pkcs12ExportPbeParameters.Pkcs12TripleDesSha1 Windows XP dönemine ait de facto standardı gösterir. Eski bir şifreleme algoritması seçerek PKCS#12/PFX okumayı destekleyen hemen her kitaplık ve platform tarafından desteklenen bir çıkış üretir.
  • Pkcs12ExportPbeParameters.Pbes2Aes256Sha256 AES'nin 3DES yerine (ve SHA-1 yerine SHA-2-256) kullanılması gerektiğini gösterir, ancak çıkış tüm okuyucular tarafından anlaşılamayabilir (Windows XP gibi).

Daha fazla denetim istiyorsanız, bir kabul eden PbeParameters kullanabilirsiniz.

Kuantum sonrası şifreleme (PQC)

.NET 10 üç yeni asimetrik algoritma için destek içerir: ML-KEM (FIPS 203), ML-DSA (FIPS 204) ve SLH-DSA (FIPS 205). Yeni türler şunlardır:

Çok az fayda sağladığı için bu yeni türler AsymmetricAlgorithm'den türetilmez. Nesne oluşturma ve ardından bir anahtarı içeri aktarma veya yeni bir anahtar oluşturma yaklaşımı yerine AsymmetricAlgorithm , yeni türlerin tümü bir anahtar oluşturmak veya içeri aktarmak için statik yöntemler kullanır:

using System;
using System.IO;
using System.Security.Cryptography;

private static bool ValidateMLDsaSignature(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, string publicKeyPath)
{
    string publicKeyPem = File.ReadAllText(publicKeyPath);

    using (MLDsa key = MLDsa.ImportFromPem(publicKeyPem))
    {
        return key.VerifyData(data, signature);
    }
}

Nesne özelliklerini ayarlayıp bir anahtarın ortaya çıkmasını sağlamak yerine, bu yeni türlerde anahtar üretimi, ihtiyaç duyduğu tüm seçenekleri alır.

using (MLKem key = MLKem.GenerateKey(MLKemAlgorithm.MLKem768))
{
    string publicKeyPem = key.ExportSubjectPublicKeyInfoPem();
    ...
}

Bu algoritmaların tümü, algoritmanın geçerli sistemde desteklenip desteklenmediğini belirtmek için statik IsSupported bir özelliğe sahip olma deseniyle devam eder.

.NET 10, Windows Şifreleme API'sini içerir: Kuantum Sonrası Şifreleme (PQC) için Yeni Nesil (CNG) desteği, bu algoritmaları PQC desteğine sahip Windows sistemlerinde kullanılabilir hale getirir. Örneğin:

using System;
using System.IO;
using System.Security.Cryptography;

private static bool ValidateMLDsaSignature(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, string publicKeyPath)
{
    string publicKeyPem = File.ReadAllText(publicKeyPath);

    using MLDsa key = MLDsa.ImportFromPem(publicKeyPem);
    return key.VerifyData(data, signature);
}

PQC algoritmaları, sistem şifreleme kitaplıklarının OpenSSL 3.5 (veya daha yeni) veya PQC desteğine sahip Windows CNG olduğu sistemlerde kullanılabilir. Tür MLKem olarak [Experimental] işaretlenmemiştir, ancak bazı metotları işaretlenmiştir (ve böyle kalacaktır, ta ki temel alınan standartlar sonlanana kadar). Geliştirme tamamlanana kadar MLDsa, SlhDsa ve CompositeMLDsa sınıfları tanılama altında [Experimental] olarak SYSLIB5006 ile işaretlenmiştir.

ML-DSA

sınıfı, MLDsa yaygın kod desenlerini basitleştiren kullanım kolaylığı özellikleri içerir:

private static byte[] SignData(string privateKeyPath, ReadOnlySpan<byte> data)
{
    using (MLDsa signingKey = MLDsa.ImportFromPem(File.ReadAllBytes(privateKeyPath)))
    {
-       byte[] signature = new byte[signingKey.Algorithm.SignatureSizeInBytes];
-       signingKey.SignData(data, signature);
+       return signingKey.SignData(data);
-       return signature;
    }
}

Buna ek olarak, .NET 10 bunu "saf" ML-DSA'dan ayırt etmeye yardımcı olmak için "PreHash" olarak adlandırılan HashML-DSA desteği ekler. Temel belirtim Nesne Tanımlayıcısı (OID) değeriyle etkileşime geçerken, bu [Experimental] türdeki SignPreHash ve VerifyPreHash yöntemleri noktalı ondalık OID'yi dize olarak alır. Bu, HashML-DSA kullanan daha fazla senaryo iyi tanımlandığında gelişebilir.

private static byte[] SignPreHashSha3_256(MLDsa signingKey, ReadOnlySpan<byte> data)
{
    const string Sha3_256Oid = "2.16.840.1.101.3.4.2.8";
    return signingKey.SignPreHash(SHA3_256.HashData(data), Sha3_256Oid);
}

RC 1'den başlayarak, ML-DSA gelişmiş şifreleme senaryoları için ek esneklik sağlayan "dış" mu değerinden oluşturulan ve doğrulanan imzaları da destekler:

private static byte[] SignWithExternalMu(MLDsa signingKey, ReadOnlySpan<byte> externalMu)
{
    return signingKey.SignMu(externalMu);
}

private static bool VerifyWithExternalMu(MLDsa verifyingKey, ReadOnlySpan<byte> externalMu, ReadOnlySpan<byte> signature)
{
    return verifyingKey.VerifyMu(externalMu, signature);
}

Bileşik ML-DSA

.NET 10, ietf-lamps-pq-composite-sigs (.NET 10 GA itibarıyla taslak 8'de), ve CompositeMLDsa türleri dahil olmak üzere CompositeMLDsaAlgorithm RSA varyantları için temel yöntemlerin uygulanmasıyla birlikte yeni türler sunar.

var algorithm = CompositeMLDsaAlgorithm.MLDsa65WithRSA4096Pss;
using var privateKey = CompositeMLDsa.GenerateKey(algorithm);

byte[] data = [42];
byte[] signature = privateKey.SignData(data);

using var publicKey = CompositeMLDsa.ImportCompositeMLDsaPublicKey(algorithm, privateKey.ExportCompositeMLDsaPublicKey());
Console.WriteLine(publicKey.VerifyData(data, signature)); // True

signature[0] ^= 1; // Tamper with signature
Console.WriteLine(publicKey.VerifyData(data, signature)); // False

Doldurmalı AES KeyWrap (IETF RFC 5649)

AES-KWP, içeriğin bir kez şifrelendiği ancak şifre çözme anahtarının her biri ayrı bir gizli formda olmak üzere birden çok tarafa dağıtılması gereken Şifreleme İletiSi Sözdizimi (CMS) EnvelopedData gibi yapılarda zaman zaman kullanılan bir algoritmadır.

.NET artık sınıfındaki örnek yöntemleri aracılığıyla AES-KWP algoritmasını Aes destekliyor:

private static byte[] DecryptContent(ReadOnlySpan<byte> kek, ReadOnlySpan<byte> encryptedKey, ReadOnlySpan<byte> ciphertext)
{
    using (Aes aes = Aes.Create())
    {
        aes.SetKey(kek);

        Span<byte> dek = stackalloc byte[256 / 8];
        int length = aes.DecryptKeyWrapPadded(encryptedKey, dek);

        aes.SetKey(dek.Slice(0, length));
        return aes.DecryptCbc(ciphertext);
    }
}

Genelleştirme ve tarih/saat

DateOnly türü için ISOWeek'te yeni yöntem aşırı yüklemeleri

ISOWeek sınıfı başlangıçta DateTime türü mevcut olmadan önce tanıtıldığı gibi yalnızca DateOnlyile çalışacak şekilde tasarlanmıştır. artık DateOnly kullanıma sunulduğuna göre, ISOWeek de bunu desteklemesi mantıklıdır. Aşağıdaki aşırı yüklemeler yenidir:

Dize karşılaştırması için sayısal sıralama

Sayısal dize karşılaştırması, dizeleri sözcük bilimi yerine sayısal olarak karşılaştırmak için yüksek düzeyde istenen bir özelliktir. Örneğin, 210'den küçük olduğundan, sayısal olarak sıralandığında "2" önce "10" görünmelidir. Benzer şekilde, "2" ve "02" sayısal olarak eşittir. Yeni NumericOrdering seçenekle, artık şu tür karşılaştırmalar yapmak mümkündür:

StringComparer numericStringComparer = StringComparer.Create(CultureInfo.CurrentCulture, CompareOptions.NumericOrdering);

Console.WriteLine(numericStringComparer.Equals("02", "2"));
// Output: True

foreach (string os in new[] { "Windows 8", "Windows 10", "Windows 11" }.Order(numericStringComparer))
{
    Console.WriteLine(os);
}

// Output:
// Windows 8
// Windows 10
// Windows 11

HashSet<string> set = new HashSet<string>(numericStringComparer) { "007" };
Console.WriteLine(set.Contains("7"));
// Output: True

Bu seçenek şu dizin tabanlı dize işlemleri için geçerli değildir: IndexOf, LastIndexOf, StartsWith, EndsWith, IsPrefixve IsSuffix.

Tek parametreli yeni TimeSpan.FromMilliseconds aşırı yükleme

TimeSpan.FromMilliseconds(Int64, Int64) yöntemi daha önce tek bir parametre alan bir aşırı yükleme eklemeden tanıtılmıştı.

İkinci parametre isteğe bağlı olduğundan bu işe yarasa da, aşağıdaki gibi bir LINQ ifadesinde kullanıldığında derleme hatasına neden olur:

Expression<Action> a = () => TimeSpan.FromMilliseconds(1000);

LINQ ifadeleri isteğe bağlı parametreleri işleyemediğinden bu sorun ortaya çıkar. Bu sorunu çözmek için, .NET 10 tek bir parametre alan yeni bir aşırı yükleme tanıtır. Ayrıca ikinci parametreyi zorunlu hale getirmek için mevcut yöntemi değiştirir.

Dize

Karakter aralığıyla çalışmak için dize normalleştirme API'leri

Unicode dize normalleştirmesi uzun süredir destekleniyor, ancak var olan API'ler yalnızca dize türüyle çalıştı. Bu, karakter dizileri veya yayılma alanları gibi farklı biçimlerde depolanan verileri olan çağıranların bu API'leri kullanmak için yeni bir dize ayırması gerektiği anlamına gelir. Ayrıca, normalleştirilmiş bir dize döndüren API'ler her zaman normalleştirilmiş çıkışı temsil etmek için yeni bir dize ayırır.

.NET 10, dize türlerinin ötesinde normalleştirmeyi genişleten ve gereksiz ayırmaları önlemeye yardımcı olan karakter aralıklarıyla çalışan yeni API'ler ekler:

Onaltılık dize dönüştürme için UTF-8 desteği

UTF-8 desteği, .NET 10 uygulamasında hex-string dönüşüm işlemleri için Convert sınıfına eklenir. Bu yeni yöntemler, ara dize tahsislerine gerek kalmadan UTF-8 bayt dizileri ile onaltılık gösterimler arasında dönüştürmenin verimli yollarını sunar.

Bu yöntemler, string ile çalışan mevcut aşırı yüklemeleri yansıtır, ancak zaten UTF-8 kodlamalı baytlarla çalıştığınız senaryolarda iyileştirilmiş performans için doğrudan UTF-8 kodlamalı baytlar üzerinde çalışır.

Koleksiyonlar

TryAdd için ilave TryGetValue ve OrderedDictionary<TKey, TValue> yükleri

OrderedDictionary<TKey,TValue>, diğer TryAdd uygulamaları gibi ekleme ve alma için TryGetValue ve IDictionary<TKey, TValue> sağlar. Ancak, daha fazla işlem gerçekleştirmek isteyebileceğiniz senaryolar vardır, bu nedenle girişe bir dizin döndüren yeni aşırı yüklemeler eklenir:

Bu dizin, girişe hızlı erişim sağlamak için GetAt ve SetAt ile kullanılabilir. Yeni TryAdd aşırı yüklemenin örnek kullanımlarından biri, sıralı sözlükte bir anahtar-değer çifti eklemek veya güncelleştirmektir:

// Try to add a new key with value 1.
if (!orderedDictionary.TryAdd(key, 1, out int index))
{
    // Key was present, so increment the existing value instead.
    int value = orderedDictionary.GetAt(index).Value;
    orderedDictionary.SetAt(index, value + 1);
}

Bu yeni API zaten JsonObject'de kullanılıyor ve özellikleri güncelleme performansını %10-20%oranında artırıyor.

Seri -leştirme

JsonSourceGenerationOptions'de ReferenceHandler belirtmeye izin ver

JSON serileştirmesi için kaynak oluşturucuları kullandığınızda, döngüler seri hale getirildiğinde veya seri durumdan çıkarıldığında, oluşturulan bağlam bir hata fırlatır. Artık ReferenceHandler içinde JsonSourceGenerationOptionsAttribute öğesini belirterek bu davranışı özelleştirebilirsiniz. aşağıda JsonKnownReferenceHandler.Preservekullanan bir örnek verilmişti:

public static void MakeSelfRef()
{
    SelfReference selfRef = new SelfReference();
    selfRef.Me = selfRef;

    Console.WriteLine(JsonSerializer.Serialize(selfRef, ContextWithPreserveReference.Default.SelfReference));
    // Output: {"$id":"1","Me":{"$ref":"1"}}
}

[JsonSourceGenerationOptions(ReferenceHandler = JsonKnownReferenceHandler.Preserve)]
[JsonSerializable(typeof(SelfReference))]
internal partial class ContextWithPreserveReference : JsonSerializerContext
{
}

internal class SelfReference
{
    public SelfReference Me { get; set; } = null!;
}

Yinelenen JSON özelliklerini yasaklama seçeneği

JSON belirtimi, bir JSON yükünü seri durumdan çıkarırken yinelenen özelliklerin nasıl işleneceğini belirtmez. Bu, beklenmeyen sonuçlara ve güvenlik açıklarına yol açabilir. .NET 10, yinelenen JSON özelliklerine izin vermeme seçeneğini tanıtır JsonSerializerOptions.AllowDuplicateProperties:

string json = """{ "Value": 1, "Value": -1 }""";
Console.WriteLine(JsonSerializer.Deserialize<MyRecord>(json).Value); // -1

JsonSerializerOptions options = new() { AllowDuplicateProperties = false };
JsonSerializer.Deserialize<MyRecord>(json, options);                // throws JsonException
JsonSerializer.Deserialize<JsonObject>(json, options);              // throws JsonException
JsonSerializer.Deserialize<Dictionary<string, int>>(json, options); // throws JsonException

JsonDocumentOptions docOptions = new() { AllowDuplicateProperties = false };
JsonDocument.Parse(json, docOptions);   // throws JsonException

record MyRecord(int Value);

Seri durumdan çıkarma sırasında bir değerin birden fazla kez atanıp atanmadığı kontrol edilerek yinelemeler tespit edilir; bu nedenle büyük/küçük harf duyarlılığı ve adlandırma ilkesi gibi diğer seçeneklerle beklendiği gibi çalışır.

Katı JSON serileştirme seçenekleri

JSON serileştirici, serileştirme ve seri durumdan çıkarma işlemlerini özelleştirmek için birçok seçenek kabul eder, ancak varsayılan ayarlar bazı uygulamalar için çok esnek olabilir. .NET 10, aşağıdaki seçenekleri ekleyerek en iyi yöntemleri izleyen yeni JsonSerializerOptions.Strict bir ön ayar ekler:

Bu seçenekler, JsonSerializerOptions.Default ile okuma uyumludur - JsonSerializerOptions.Default ile serileştirilmiş bir nesne, JsonSerializerOptions.Strict ile seri durumdan çıkarılabilir.

JSON serileştirmesi hakkında daha fazla bilgi için bkz . System.Text.Json'a genel bakış.

JSON seri hale getiricisi için PipeReader desteği

JsonSerializer.Deserialize PipeReaderartık mevcut PipeWriter desteği tamamlayarak destekler. Daha önce, gerekli bir PipeReader seri durumdan çıkarılarak bir öğesine dönüştürülüyor Streamancak yeni aşırı yüklemeler doğrudan seri hale getiriciye tümleştirerek PipeReader bu adımı ortadan kaldırıyor. Bir bonus olarak, elinizdekilerden dönüştürmek zorunda kalmak bazı verimlilik avantajları sağlayabilir.

Bu, temel kullanımı gösterir:

using System;
using System.IO.Pipelines;
using System.Text.Json;
using System.Threading.Tasks;

var pipe = new Pipe();

// Serialize to writer
await JsonSerializer.SerializeAsync(pipe.Writer, new Person("Alice"));
await pipe.Writer.CompleteAsync();

// Deserialize from reader
var result = await JsonSerializer.DeserializeAsync<Person>(pipe.Reader);
await pipe.Reader.CompleteAsync();

Console.WriteLine($"Your name is {result.Name}.");
// Output: Your name is Alice.

record Person(string Name);

Öbekler halinde belirteçler üreten bir üretici ve bunları alan ve görüntüleyen bir tüketici örneği aşağıda verilmiştir:

using System;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Text.Json;
using System.Threading.Tasks;

var pipe = new Pipe();

// Producer writes to the pipe in chunks.
var producerTask = Task.Run(async () =>
{
    async static IAsyncEnumerable<Chunk> GenerateResponse()
    {
        yield return new Chunk("The quick brown fox", DateTime.Now);
        await Task.Delay(500);
        yield return new Chunk(" jumps over", DateTime.Now);
        await Task.Delay(500);
        yield return new Chunk(" the lazy dog.", DateTime.Now);
    }

    await JsonSerializer.SerializeAsync<IAsyncEnumerable<Chunk>>(pipe.Writer, GenerateResponse());
    await pipe.Writer.CompleteAsync();
});

// Consumer reads from the pipe and outputs to console.
var consumerTask = Task.Run(async () =>
{
    var thinkingString = "...";
    var clearThinkingString = new string("\b\b\b");
    var lastTimestamp = DateTime.MinValue;

    // Read response to end.
    Console.Write(thinkingString);
    await foreach (var chunk in JsonSerializer.DeserializeAsyncEnumerable<Chunk>(pipe.Reader))
    {
        Console.Write(clearThinkingString);
        Console.Write(chunk.Message);
        Console.Write(thinkingString);
        lastTimestamp = DateTime.Now;
    }

    Console.Write(clearThinkingString);
    Console.WriteLine($" Last message sent at {lastTimestamp}.");

    await pipe.Reader.CompleteAsync();
});

await producerTask;
await consumerTask;

record Chunk(string Message, DateTime Timestamp);

Bunların tümü JSON Pipe olarak seri hale getirilir (okunabilirlik için burada biçimlendirilir):

[
    {
        "Message": "The quick brown fox",
        "Timestamp": "2025-08-01T18:37:27.2930151-07:00"
    },
    {
        "Message": " jumps over",
        "Timestamp": "2025-08-01T18:37:27.8594502-07:00"
    },
    {
        "Message": " the lazy dog.",
        "Timestamp": "2025-08-01T18:37:28.3753669-07:00"
    }
]

Sistem.Sayılar

Diğer sol elle kullanılan matris dönüştürme yöntemleri

.NET 10, pano ve kısıtlanmış billboard matrisleri için sol elle dönüştürme matrisleri oluşturmak için kalan API'leri ekler. Bunun yerine bir sol elle koordinat sistemi kullanırken, mevcut sağ elle kullanılan karşılıkları CreateBillboard(Vector3, Vector3, Vector3, Vector3)gibi bu yöntemleri kullanabilirsiniz:

Tensor geliştirmeleri

System.Numerics.Tensors alanı artık Lengths ve Strides gibi işlemleri gerçekleştirmek için, IReadOnlyTensor adı verilen genel olmayan bir arabirim içerir. Dilim işlemleri artık verileri kopyalamaz ve bu da performansı artırır. Buna ek olarak, performans kritik olmadığında verileri genel olmayan bir şekilde object ile kutulama yaparak erişebilirsiniz.

Tensor API'leri artık kararlıdır ve artık deneysel olarak işaretlenmemektedir. API'ler hala System.Numerics.Tensors NuGet paketine başvurmayı gerektirse de, .NET 10 sürümü için kapsamlı bir şekilde gözden geçirilmiş ve sonlandırılmıştır. Türler, temel alınan tür T işlemi desteklediğinde aritmetik işlemler sağlamak için C# 14 uzantı işleçlerinden yararlanir. Eğer T ilgili genel matematik arabirimlerini, örneğin IAdditionOperators<TSelf, TOther, TResult> veya INumber<TSelf>, uygularsa işlem desteklenir. Örneğin, tensor + tensor için Tensor<int> kullanılabilir, ancak Tensor<bool> için mevcut değil.

Seçenekler doğrulaması

ValidationContext için yeni AOT güvenli oluşturucu

Seçenek doğrulaması sırasında kullanılan ValidationContext sınıfı, displayName parametresini açıkça kabul eden yeni bir oluşturucu aşırı yüklemesi içerir.

ValidationContext(Object, String, IServiceProvider, IDictionary<Object,Object>)

Görünen ad, AOT güvenliğini sağlar ve uyarı olmadan yerel derlemelerde kullanılmasını sağlar.

Tanılama

ActivitySource ve Meter içindeki telemetri şeması URL'leri için destek

ActivitySource ve Meter şimdi oluşturma sırasında OpenTelemetry belirtimleriyle uyumlu bir telemetri şeması URL'si belirtmeyi destekliyor. Telemetri şeması, izleme ve ölçüm verileri için tutarlılık ve uyumluluk sağlar. Ayrıca, .NET 10, birden çok yapılandırma seçeneği (ActivitySourceOptions dahil) ile ActivitySource örneklerinin oluşturulmasını basitleştiren öğesini tanıtır.

Yeni API'ler şunlardır:

sınıfı, Activity hizmetler veya bileşenler arasında işlem akışını izleyerek dağıtılmış izlemeyi etkinleştirir. .NET, olay kaynağı sağlayıcısı aracılığıyla bu izleme verilerini işlem dışı olarak serileştirmeyi Microsoft-Diagnostics-DiagnosticSource destekler. Bir Activity, ActivityLink ve ActivityEvent gibi ek meta veriler içerebilir. .NET 10, bu bağlantıları ve olayları seri hale getirme desteğini ekler, dolayısıyla dış işlem izleme verileri artık bu bilgileri içerir. Örneğin:

Events->"[(TestEvent1,​2025-03-27T23:34:10.6225721+00:00,​[E11:​EV1,​E12:​EV2]),​(TestEvent2,​2025-03-27T23:34:11.6276895+00:00,​[E21:​EV21,​E22:​EV22])]"
Links->"[(19b6e8ea216cb2ba36dd5d957e126d9f,​98f7abcb3418f217,​Recorded,​null,​false,​[alk1:​alv1,​alk2:​alv2]),​(2d409549aadfdbdf5d1892584a5f2ab2,​4f3526086a350f50,​None,​null,​false)]"

Hız sınırı izleme örnekleme desteği

Dağıtılmış izleme verileri olay kaynağı sağlayıcısı aracılığıyla Microsoft-Diagnostics-DiagnosticSource işlem dışı olarak seri hale getirildiğinde, kaydedilen tüm etkinlikler yayılabilir veya izleme oranına göre örnekleme uygulanabilir.

Hız Sınırlama Örneklemesi adlı yeni örnekleme seçeneği, saniye başına seri hale getirilen kök etkinliklerin sayısını kısıtlar. Bu, veri hacmini daha hassas bir şekilde denetlemeye yardımcı olur.

Harici işlem izleme veri toplayıcıları, FilterAndPayloadSpecs seçeneğini belirterek bu örneklemeyi etkinleştirebilir ve yapılandırabilir. Örneğin, aşağıdaki ayar serileştirmeyi tüm ActivitySource örneklerde saniyede 100 kök etkinlikle sınırlar:

[AS]*/-ParentRateLimitingSampler(100)

ZIP dosyaları

ZipArchive performansı ve bellek geliştirmeleri

.NET 10, ZipArchiveperformansını ve bellek kullanımını geliştirir.

İlk olarak, ZipArchive modunda bir Update'a girişlerin yazılma şekli optimize edildi. Daha önce tüm ZipArchiveEntry örnekleri belleğe yüklenip yeniden yazılıyordu ve bu da yüksek bellek kullanımı ve performans sorunlarına yol açabiliyordu. İyileştirme, bellek kullanımını azaltır ve tüm girişleri belleğe yükleme gereksinimini ortadan kaldırarak performansı artırır.

İkincisi, ZipArchive girdilerinin ayıkılması artık paralelleştirilmiştir ve iç veri yapıları daha iyi bellek kullanımı için iyileştirilmiştir. Bu geliştirmeler performans sorunları ve yüksek bellek kullanımıyla ilgili sorunları ele alır ve özellikle büyük arşivlerle ilgilenirken ZipArchive daha verimli ve hızlı hale getirir.

Yeni zaman uyumsuz ZIP API'leri

.NET 10, ZIP dosyalarından okurken veya zip dosyalarına yazarken engellemeyen işlemler gerçekleştirmeyi kolaylaştıran yeni zaman uyumsuz API'ler getirir. Bu özellik topluluk tarafından yüksek oranda istendi.

ZIP arşivlerini ayıklamak, oluşturmak ve güncelleştirmek için yeni async yöntemler kullanılabilir. Bu yöntemler, geliştiricilerin özellikle G/Ç ile ilişkili işlemleri içeren senaryolarda büyük dosyaları verimli bir şekilde işlemesine ve uygulama yanıt hızını iyileştirmesine olanak tanır. Bu yöntemler şunlardır:

Bu API'leri kullanma örnekleri için Önizleme 4 blog gönderisine bakın.

Birleştirilmiş akışlar için GZipStream'de performans iyileştirmesi

Topluluk katkısı, birleştirilmiş GZip veri akışlarını işlerken GZipStream performansını geliştirdi. Daha önce, her yeni akış kesimi iç ZLibStreamHandle öğesini atar ve yeniden tahsis ederdi, bu da ek bellek ayırmaları ve başlatma ek yüküne neden olurdu. Bu değişiklikle, tutacak artık hem yönetilen hem de yönetilmeyen bellek ayırmalarını azaltmak ve çalışma süresini iyileştirmek için sıfırlanıp yeniden kullanılır. Çok sayıda küçük veri akışı işlenirken en büyük etki (yaklaşık 35% daha hızlı) görülür. Bu değişiklik:

  • Birleştirilmiş her akış için yaklaşık 64-80 bayt bellek ayırmayı ortadan kaldırır ve yönetilmeyen bellek tasarrufları sağlar.
  • Yürütme süresini birleştirilmiş akış başına yaklaşık 400 ns azaltır.

Windows işlem yönetimi

Yeni işlem grubunda Windows işlemlerini başlatma

Windows için artık ayrı bir işlem grubunda işlem başlatmak için kullanabilirsiniz ProcessStartInfo.CreateNewProcessGroup . Bu, alt işlemlere düzgün işleme olmadan ebeveyni indirebilecek yalıtılmış sinyaller göndermenizi sağlar. Sinyal göndermek, zorunlu sonlandırmayı önlemek için uygundur.

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        bool isChildProcess = args.Length > 0 && args[0] == "child";
        if (!isChildProcess)
        {
            var psi = new ProcessStartInfo
            {
                FileName = Environment.ProcessPath,
                Arguments = "child",
                CreateNewProcessGroup = true,
            };

            using Process process = Process.Start(psi)!;
            Thread.Sleep(5_000);

            GenerateConsoleCtrlEvent(CTRL_C_EVENT, (uint)process.Id);
            process.WaitForExit();

            Console.WriteLine("Child process terminated gracefully, continue with the parent process logic if needed.");
        }
        else
        {
            // If you need to send a CTRL+C, the child process needs to re-enable CTRL+C handling, if you own the code, you can call SetConsoleCtrlHandler(NULL, FALSE).
            // see https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw#remarks
            SetConsoleCtrlHandler((IntPtr)null, false);

            Console.WriteLine("Greetings from the child process!  I need to be gracefully terminated, send me a signal!");

            bool stop = false;

            var registration = PosixSignalRegistration.Create(PosixSignal.SIGINT, ctx =>
            {
                stop = true;
                ctx.Cancel = true;
                Console.WriteLine("Received CTRL+C, stopping...");
            });

            StreamWriter sw = File.AppendText("log.txt");
            int i = 0;
            while (!stop)
            {
                Thread.Sleep(1000);
                sw.WriteLine($"{++i}");
                Console.WriteLine($"Logging {i}...");
            }

            // Clean up
            sw.Dispose();
            registration.Dispose();

            Console.WriteLine("Thanks for not killing me!");
        }
    }

    private const int CTRL_C_EVENT = 0;
    private const int CTRL_BREAK_EVENT = 1;

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetConsoleCtrlHandler(IntPtr handler, [MarshalAs(UnmanagedType.Bool)] bool Add);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
}

WebSocket geliştirmeleri

WebSocketStream

.NET 10, .NET'teki en yaygın ve daha önce zahmetliWebSocketStream senaryolardan bazılarını basitleştirmek için tasarlanmış yeni bir API'yi kullanıma sunarWebSocket.

Geleneksel WebSocket API'ler düşük düzeydedir ve önemli bir ortak yapı gerektirir: arabelleğe alma ve çerçeveleme, iletileri yeniden oluşturma, kodlama/kod çözme işlemlerini yönetme ve akışlar, kanallar veya diğer aktarım soyutlamalarıyla tümleştirmek için özel sarmalayıcılar yazma. Bu karmaşıklıklar, özellikle akış veya metin tabanlı protokollere sahip uygulamalar ya da olay temelli işleyiciler için WebSockets'in aktarım olarak kullanılmasını zor hale getirir.

WebSocketStream Bir WebSocket üzerinden tabanlı bir Streamsoyutlama sağlayarak bu ağrı noktalarını giderir. Bu, ikili veya metin olsun, verileri okumak, yazmak ve ayrıştırmak için mevcut API'lerle sorunsuz tümleştirme sağlar ve el ile tesisat ihtiyacını azaltır.

WebSocketStream yaygın WebSocket tüketimi ve üretim desenleri için üst düzey, tanıdık API'leri etkinleştirir. Bu API'ler sürtünmeyi azaltır ve gelişmiş senaryoların uygulanmasını kolaylaştırır.

Yaygın kullanım desenleri

Tipik iş akışlarının WebSocketStream nasıl WebSocket basitleştirildiğinden birkaç örnek aşağıda verilmiştir:

Akış metin protokolü (örneğin, STOMP)
using System.IO;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

// Streaming text protocol (for example, STOMP).
using Stream transportStream = WebSocketStream.Create(
    connectedWebSocket, 
    WebSocketMessageType.Text,
    ownsWebSocket: true);
// Integration with Stream-based APIs.
// Don't close the stream, as it's also used for writing.
using var transportReader = new StreamReader(transportStream, leaveOpen: true); 
var line = await transportReader.ReadLineAsync(cancellationToken); // Automatic UTF-8 and new line handling.
transportStream.Dispose(); // Automatic closing handshake handling on `Dispose`.
akış ikili protokolü (örneğin, AMQP)
using System;
using System.IO;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

// Streaming binary protocol (for example, AMQP).
Stream transportStream = WebSocketStream.Create(
    connectedWebSocket,
    WebSocketMessageType.Binary,
    closeTimeout: TimeSpan.FromSeconds(10));
await message.SerializeToStreamAsync(transportStream, cancellationToken);
var receivePayload = new byte[payloadLength];
await transportStream.ReadExactlyAsync(receivePayload, cancellationToken);
transportStream.Dispose();
// `Dispose` automatically handles closing handshake.
Tek bir iletiyi akış olarak okuma (örneğin, JSON seri durumdan çıkarma)
using System.IO;
using System.Net.WebSockets;
using System.Text.Json;

// Reading a single message as a stream (for example, JSON deserialization).
using Stream messageStream = WebSocketStream.CreateReadableMessageStream(connectedWebSocket, WebSocketMessageType.Text);
// JsonSerializer.DeserializeAsync reads until the end of stream.
var appMessage = await JsonSerializer.DeserializeAsync<AppMessage>(messageStream);
Akış olarak tek bir ileti yazma (örneğin, ikili serileştirme)
using System;
using System.IO;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

// Writing a single message as a stream (for example, binary serialization).
public async Task SendMessageAsync(AppMessage message, CancellationToken cancellationToken)
{
    using Stream messageStream = WebSocketStream.CreateWritableMessageStream(_connectedWebSocket, WebSocketMessageType.Binary);
    foreach (ReadOnlyMemory<byte> chunk in message.SplitToChunks())
    {
        await messageStream.WriteAsync(chunk, cancellationToken);
    }
} // EOM sent on messageStream.Dispose().

TLS geliştirmeleri

macOS için TLS 1.3 (istemci)

.NET 10, Apple'ın Network.framework'lerini SslStream ve HttpClientile tümleştirerek macOS üzerinde istemci tarafı TLS 1.3 desteği ekler. Geçmişte, macOS TLS 1.3'i desteklemeyen Güvenli Aktarım'ı kullanıyordu; Network.framework'e katılmanız TLS 1.3'e olanak tanır.

Kapsam ve davranış

  • yalnızca macOS, bu sürümde istemci tarafı.
  • Kabul et. Mevcut uygulamalar etkin olmadığı sürece geçerli yığını kullanmaya devam ediyor.
  • Etkinleştirildiğinde, eski TLS sürümleri (TLS 1.0 ve 1.1) artık Network.framework üzerinden kullanılamayabilir.

Nasıl Etkinleştirilir

Kodda AppContext anahtarı kullanın:

// Opt in to Network.framework-backed TLS on Apple platforms.
AppContext.SetSwitch("System.Net.Security.UseNetworkFramework", true);

using var client = new HttpClient();
var html = await client.GetStringAsync("https://example.com");

Veya bir ortam değişkeni kullanın:

# Opt-in via environment variable (set for the process or machine as appropriate)
DOTNET_SYSTEM_NET_SECURITY_USENETWORKFRAMEWORK=1
# or
DOTNET_SYSTEM_NET_SECURITY_USENETWORKFRAMEWORK=true

Notes

  • TLS 1.3, üzerinde oluşturulan ve API'ler için SslStream geçerlidir (örneğin,HttpClient/HttpMessageHandler ).
  • Şifre paketleri, macOS tarafından Network.framework üzerinden denetleniyor.
  • Network.framework etkinleştirildiğinde temel alınan akış davranışı farklılık gösterebilir (örneğin arabelleğe alma, okuma/yazma tamamlama, iptal semantiği).
  • Semantik sıfır bayt okumaları için farklılık gösterebilir. Veri kullanılabilirliğini algılamak için sıfır uzunluklu okumalara güvenmekten kaçının.
  • Bazı uluslararası etki alanı adları (IDN) ana bilgisayar adları Network.framework tarafından reddedilebilir. ASCII/Punycode (A-label) konak adlarını tercih edin veya macOS/Network.framework kısıtlamalarına karşı adları doğrulayın.
  • Uygulamanız belirli SslStream bir edge-case davranışına bağlıysa, Network.framework altında doğrulayın.