Closed leecow closed 2 years ago
Doc issue: https://github.com/dotnet/docs/issues/25066
We added support for implicit namespace imports for C# projects to reduce the amount of boilerplate in project templates by reducing the using statements needed in each C# file.
For example, an empty web app looked like this:
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapGet("/", () => "Hello World!");
app.Run();
but now it's simplified to:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.MapGet("/", () => "Hello World!");
app.Run();
We added support to System.IO.Compression.ZipFile
to capture Unix file permissions during create and set the file permissions when extracting zip archives on Unix. This allows for executable files to be "round tripped" through a zip archive, and it means you no longer have to modify the file permissions to make files executable anymore after extracting a zip archive. It also respects the read/write permissions for user, group, and other as well.
If a zip archive doesn't contain file permissions (because it was created on Windows, or using a tool which didn't capture the permissions, like an earlier version of .NET) extracted files get the default file permissions, just like any other newly created file. This behavior didn't change.
The Unix file permissions work with other zip archive tools as well, including:
We added new native memory allocation APIs exposed via System.Runtime.InteropServices.NativeMemory
: https://github.com/dotnet/runtime/pull/54006. These APIs represent equivalents to the malloc
, free
, realloc
, and calloc
C APIs and also includes APIs for doing aligned allocations.
These features make it much easier to customize the behavior of JSON objects. Previously, this functionality required implementing a custom converter.
Notifications for (de)serialization are useful for defaulting values and validation. To use them, implement one or more of the interfaces IJsonOnDeserialized
, IJsonOnDeserializing
, IJsonOnSerialized
or IJsonOnSerializing
from the System.Text.Json.Serialization
namespace.
Here's an example that validates during both JsonSerializer.Serialize()
and JsonSerializer.Deserialize()
to ensure a FirstName
property is not null
.
public class Person : IJsonOnDeserialized, IJsonOnSerializing
{
public string FirstName{ get; set; }
void IJsonOnDeserialized.OnDeserialized() => Validate(); // Call after deserialization
void IJsonOnSerializing.OnSerializing() => Validate(); // Call before serialization
private void Validate()
{
if (FirstName is null)
{
throw new InvalidOperationException("The 'FirstName' property cannot be 'null'.");
}
}
}
The order properties are serialized in can now be controlled by applying the System.Text.Json.Serialization.JsonPropertyOrderAttribute
with an integer specifying the order. Smaller numbers are serialized first; properties that have no attribute have a default ordering value of 0. Previously, the order was determined by reflection order which is not deterministic.
Here's an example that specifies JSON should be serialized in the order Id, City, FirstName, LastName
:
public class Person
{
public string City { get; set; } // No order defined (has the default ordering value of 0)
[JsonPropertyOrder(1)] // Serialize after other properties that have default ordering
public string FirstName { get; set; }
[JsonPropertyOrder(2)] // Serialize after FirstName
public string LastName { get; set; }
[JsonPropertyOrder(-1)] // Serialize before other properties that have default ordering
public int Id { get; set; }
}
@tannergooding should there be something about https://github.com/dotnet/runtime/pull/55776 here? although it's a little special.
Yes. I will be adding it and working on the related blog post when I get back from vacation.
Oops, didn't realize you were on vacation. 😺
Developers will be able to control how distributed tracing information is propagated
Introduced DistributedContextPropagator
abstract class which determines if and how distributed context information is encoded and decoded as it traverses the network.
The encoding can be transported over any network protocol that supports string key-value pairs. For example, when using HTTP, each key value pair is an HTTP header.
DistributedContextPropagator inject values into and extracts values from carriers as string key/value pairs.
DistributedContextPropagator propagator = DistributedContextPropagator.Current;
propagator.Inject(activity, carrier, (object theCarrier, string fieldName, string value) =>
{
// Extract the context from the activity then inject it to the carrier.
});
// Set the current propagation behavior to not transmit any distributed context information in outbound network messages.
DistributedContextPropagator.Current = DistributedContextPropagator.CreateNoOutputPropagator();
CC @noahfalk @shirhatti
.NET Core has been supporting the Globalization Invariant Mode for a while. This mode used to support only ASCII range characters case mapping in operations like String.ToUpper
, String.ToLower
, and strings comparing and searching with Ignore Casing option. Now the full Unicode characters set case mapping fully supported in the Globalization Invariant Mode.
When mentioning the improvement to Globalization Invariant Mode above it might be an opportunity to note the breaking change https://github.com/dotnet/docs/issues/24849
@danmoseley the doc I linked is the published breaking change doc.
@tarekgh ah my bad, I had forgotten they were both in the same breaking change doc.
The runtime now has a mode in which it doesn't create any memory pages that are writeable and executable at the same time. All executable memory is mapped as read-execute only. This was already supported on macOS ARM64 before preview 7, because it is not allowed to create memory mappings that are writeable and executable at the same time on that platform at all. Preview 7 adds that for all the remaining platform. On these platforms, executable code generation / modification is done via separate read-write memory mappings. This is true for both JITted code and runtime generated helpers. These mappings are created at virtual memory addresses that are different from the executable code address and exist only for a very brief period of time when the writing is performed. For example, JIT now generates code into a scratch buffer that is copied into the executable memory using a single memory copy function call after the whole method is jitted. And the writeable mapping lifetime spans only the time of the memory copy.
This new feature is disabled by default and it can be enabled by setting the environment variable DOTNET_EnableWriteXorExecute
(or COMPlus_EnableWriteXorExecute
) to 1. The reason is that there is a slightly worse startup performance (around 10% in the ASP.Net benchmark tests with R2R enabled) caused by this feature and we want to look into improving that (post .NET 6) before we enable it by default. However, the steady state performance was measured to be the same with and without the feature enabled. So for applications where the startup performance doesn't matter much, it might be interesting to try to enable it now.
The .NET encryption and decryption routines were designed around streaming, with no real concession for when the payload is already in memory. The new Encrypt- and Decrypt- methods on SymmetricAlgorithm
accelerate the already-in-memory case, and are intended to provide clarity to the caller and the code reviewer. Additionally, they support reading from and writing to spans.
Previous versions:
private static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
{
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
// These are the defaults, but let's set them anyways.
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
using (MemoryStream destination = new MemoryStream())
using (ICryptoTransform transform = aes.CreateDecryptor())
using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(ciphertext, 0, ciphertext.Length);
cryptoStream.FlushFinalBlock();
return destination.ToArray();
}
}
}
With the new simplified methods:
private static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
{
using (Aes aes = Aes.Create())
{
aes.Key = key;
return aes.DecryptCbc(ciphertext, iv);
}
}
With the new Encrypt- and Decrypt-methods only the key property is used from the SymmetricAlgorithm instance. The new DecryptCbc method does support choosing the padding algorithm, but PKCS#7 is used with CBC so often that it's a default argument. If you like the clarity, just specify it:
private static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
{
using (Aes aes = Aes.Create())
{
aes.Key = key;
return aes.DecryptCbc(ciphertext, iv, PaddingMode.PKCS7);
}
}
dynamic
is removed.As discussed in https://github.com/dotnet/runtime/issues/53195, the "dynamic" feature in C# is considered somewhat stale and adding a dependency to a new JsonNode
API (which was added in Preview 4) is not considered a good practice.
If a newer, more modern version of "dynamic" is introduced, this support will be reconsidered.
See also the breaking change issue .
The "dynamic" keyword could be used to get and set properties on the new JsonObject
class such as:
dynamic obj = JsonNode.Parse("{\"A\":42}");
int i = (int)obj.A;
The property name must be specified as a string, and "dynamic" not used:
JsonNode obj = JsonNode.Parse("{\"A\":42}");
int i = (int)obj["A"];
https://github.com/dotnet/templating/issues/3359
We updated .NET SDK templates to use latest C# language idioms when creating the project targeting .NET 6 framework. The following language features will be used or enabled by default in the SDK-included project templates as applicable:
console
template prior to .NET 6using System;
namespace Company.ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
console
template// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
The users may encounter difficulty if the following scenarios which used to work before: • Use a .NET 6 template and then change the target framework to previous version • Use a .NET 6 template and then add different TFM to multi-target
More information on this breaking change is available here.
Runtime Issue: https://github.com/dotnet/runtime/issues/29723
namespace System.Reflection
{
public sealed class NullabilityInfoContext
{
public NullabilityInfo Create(ParameterInfo parameterInfo);
public NullabilityInfo Create(PropertyInfo propertyInfo);
public NullabilityInfo Create(EventInfo eventInfo);
public NullabilityInfo Create(FieldInfo parameterInfo);
}
public sealed class NullabilityInfo
{
public Type Type { get; }
// ReadState and WriteState could be different in case the member has nullability attribute affecting them
// For example for a non null property [MaybeNull] attribute makes ReadState nullable
public NullabilityState ReadState { get; }
// For example for a nulllable property [DisallowNull] attribute makes WriteState not null
public NullabilityState WriteState { get; }
// if the member is an array, then the nullability of the array elements null otherwise
public NullabilityInfo? ElementType { get; }
// if the member has generic argument(s) then nullability of each argument, else empty array
public NullabilityInfo[] GenericTypeArguments { get; }
}
public enum NullabilityState
{
Unknown, // Nullability not enabled
NotNull, // Not nullable value or reference type
Nullable // Nulable value or reference type
}
}
private NullabilityInfoContext _nullabilityContext = new NullabilityInfoContext();
private void DeserializePropertyValue(PropertyInfo p, object instance, object? value)
{
if (value == null)
{
var nullabilityInfo = _nullabilityContext.Create(p);
if (nullabilityInfo.WriteState != NullabilityState.Nullable)
throw new MySerializerException($"Property '{p.GetType().Name}.{p.Name}'' cannot be set to null.");
}
p.SetValue(instance, value);
}
class Data
{
public string?[] ArrayField;
public Tuple<string?, object> TupleField;
}
private void Print()
{
Type type = typeof(Data);
FieldInfo arrayField = type.GetField("ArrayField");
FieldInfo tupleField = type.GetField("TupleField");
NullabilityInfoContext context = new ();
NullabilityInfo arrayInfo = context.Create(arrayField);
Console.WriteLine(arrayInfo.ReadState ); // NotNull
Console.WriteLine(arrayInfo.Element.State); // Nullable
NullabilityInfo tupleInfo = context.Create(tupleField);
Console.WriteLine(tupleInfo.ReadState); // NotNull
Console.WriteLine(tupleInfo.GenericTypeArguments [0].State); // Nullable
Console.WriteLine(tupleInfo.GenericTypeArguments [1].State); // NotNull
}
We are previewing (as in they will not ship as "stable" with .NET 6) several new interfaces which enable operators to be used with generics:
public static TSelf Sum<TSelf>(IEnumerable<TSelf> values)
where TSelf : INumber<TSelf>
{
TSelf result = TSelf.Zero;
foreach (var value in values)
{
result += value;
}
return result;
}
This is powered by a new feature which allows static abstract
members to be declared in interfaces. This enables interfaces to expose operators and other static methods, such as Parse
or Create
, and for those to be implemented by a derived type. Please see our associated blog post for more details!
There are scenarios where customers want to integrate existing, "raw" JSON payloads when writing new JSON payloads with Utf8JsonWriter.
Sample code:
JsonWriterOptions writerOptions = new() { WriteIndented = true, };
using MemoryStream ms = new();
using UtfJsonWriter writer = new(ms, writerOptions);
writer.WriteStartObject();
writer.WriteString("dataType", "CalculationResults");
writer.WriteStartArray("data");
foreach (CalculationResult result in results)
{
writer.WriteStartObject();
writer.WriteString("measurement", result.Measurement);
writer.WritePropertyName("value");
// Write raw JSON numeric value
byte[] formattedValue = FormatNumberValue(result.Value);
writer.WriteRawValue(formattedValue, skipValidation: true);
writer.WriteEndObject();
}
writer.WriteEndArray();
writer.WriteEndObject();
JsonSerializer
(https://github.com/dotnet/runtime/issues/1574)In many scenarios, users need to serialize and deserialize JSON data to/from a stream in a synchronous manner. We've added new APIs on JsonSerializer
to support this. Overloads that take source-generated content are also provided.
using MemoryStream ms = GetMyStream();
MyPoco poco = JsonSerializer.Deserialize<MyPoco>(ms);
From @SingleAccretion:
Gosh @SingleAccretion did a lot!
One of them is listed twice but still hell of a job!
@EgorBo - Feel free to add some performance improvement graphs for dynamic PGO/inline changes.
One of them is listed twice but still hell of a job!
Thanks for catching it. Deleted the line.
What's new in .NET 6 Preview 7
This issue is for teams to highlight work for the community that will release .NET 6 Preview 7.
To add content, use a new conversation entry. The entry should include the team name and feature title as the first line as shown in the template below.
Preview 1: https://github.com/dotnet/core/issues/5853 Preview 2: https://github.com/dotnet/core/issues/5889 Preview 3: https://github.com/dotnet/core/issues/5890 Preview 4: https://github.com/dotnet/core/issues/6098 Preview 5: https://github.com/dotnet/core/issues/6099 Preview 6: https://github.com/dotnet/core/issues/6325