{"id":48250,"date":"2023-10-10T10:20:00","date_gmt":"2023-10-10T17:20:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=48250"},"modified":"2024-12-13T14:18:32","modified_gmt":"2024-12-13T22:18:32","slug":"announcing-dotnet-8-rc2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-rc2\/","title":{"rendered":"Announcing .NET 8 Release Candidate 2"},"content":{"rendered":"<p>.NET 8 RC2 is now available. This is our last release candidate. This release includes new NuGet package READMEs for .NET packages, simple CLI-based project evaluation for MSBuild, publishing containers to tar.gz archives, and Tensor Primitives for .NET.<\/p>\n<p>The dates for <a href=\"https:\/\/dotnetconf.net\/\">.NET Conf 2023<\/a> have been announced! Join us November 14-16, 2023 to celebrate the .NET 8 release!<\/p>\n<p><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">Download .NET 8 RC2<\/a> for Linux, macOS, and Windows.<\/p>\n<ul>\n<li><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">Installers and binaries<\/a><\/li>\n<li><a href=\"https:\/\/hub.docker.com\/_\/microsoft-dotnet-aspnet\/\">Container images<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/tree\/main\/release-notes\/8.0\">Release notes<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/compatibility\/8.0?toc=%2Fdotnet%2Ffundamentals%2Ftoc.json&amp;bc=%2Fdotnet%2Fbreadcrumb%2Ftoc.json\">Breaking changes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/8.0\/known-issues.md\">Known issues<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\">GitHub issue tracker<\/a><\/li>\n<\/ul>\n<blockquote>\n<p>\u26a0\ufe0fIMPORTANT\n.NET SDK 8.0.100-rc.2 <em>must<\/em> be used with Visual Studio 17.8 Preview 3 due to a dependency error with Razor tooling. See <a href=\"https:\/\/github.com\/dotnet\/sdk\/issues\/35810\">this SDK Announcement<\/a> for more details.<\/p>\n<\/blockquote>\n<p>There are several exciting posts you should check out as well:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-rc-2\">ASP.NET Core Updates in .NET 8 RC2<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-maui-in-dotnet-8-rc-2\">.NET MAUI Updates in .NET 8 RC2<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/visual-studio-2022-17-8-preview-3-is-here\/\">Visual Studio 2022 17.8 Preview 3<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-ef8-rc2\">Entity Framework Updates in .NET 8 RC2<\/a><\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/whats-new\/dotnet-8\">What&#8217;s New in .NET 8<\/a> describes all the new features in .NET 8. For a broader view of the platform, read <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/why-dotnet\/\">Why .NET?<\/a>.<\/li>\n<\/ul>\n<h2>New package READMEs for .NET Libraries<\/h2>\n<p>One of the top customer problems that package consumers face is lack of documentation. As such, we are driving an effort to increase the adoption and quality of NuGet package READMEs.<\/p>\n<p>The README file is an essential part of your package as it provides important information to users and helps them understand what the package is and what it does quickly. Also, README is the first things for users when they view your package on NuGet.org and soon other tooling. It is crucial for package authors to write and include high-quality READMEs for their packages.<\/p>\n<p>Now there are READMEs for the following Microsoft packages:<\/p>\n<table>\n<thead>\n<tr>\n<th style=\"text-align: left\">Package<\/th>\n<th style=\"text-align: center\">Status<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.DependencyInjection<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Logging<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.DependencyInjection.Abstractions<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Hosting<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Hosting.WindowsServices<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Logging.Abstractions<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Http<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.IO.Ports<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Data.OleDb<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Options<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Management<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Options.ConfigurationExtensions<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Caching.Memory<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Logging.Console<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Hosting.Abstractions<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Text.Encoding.CodePages<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Bcl.AsyncInterfaces<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.DirectoryServices.AccountManagement<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Speech<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.DirectoryServices<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Logging.Debug<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Net.Http.Json<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Data.Odbc<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Primitives<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Bcl.Numerics (new package)<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Bcl.TimeProvider (new package)<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Configuration<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Configuration.Abstractions<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Configuration.Binder<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">Microsoft.Extensions.Logging.EventLog<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Diagnostics.EventLog<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Net.Http.WinHttpHandler<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Text.Json<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<tr>\n<td style=\"text-align: left\">System.Threading.Channels<\/td>\n<td style=\"text-align: center\">\u2705<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>MSBuild: Simple CLI-based project evaluation<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/msbuild\/issues\/3911#issuecomment-1478468822\">Issue<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/msbuild\/pull\/9138\">PR<\/a><\/li>\n<\/ul>\n<p>MSBuild is a very powerful platform, and is great at integrating data and tools from other ecosystems into its view of the world.  It&#8217;s historically not been so good at making the data that it has available to the broader worlds of scripting and tools.  In the past, tools authors would have to do things like injecting their own MSBuild code to read certain Properties, Items, or Target Outputs into files, and then parse those files. This is work that is very error prone. In .NET 8, the MSBuild team has shipped a new feature that makes it easier to incorporate data from MSBuild into your scripts or tools. Let&#8217;s take a look at a sample to see what I mean.<\/p>\n<pre><code class=\"language-shell\">&gt;dotnet publish --getProperty:OutputPath\r\nbin\\Release\\net8.0\\<\/code><\/pre>\n<p>In this simple example, we&#8217;ve used the <code>--getProperty<\/code> flag to request the value of the <code>OutputPath<\/code> property after the <code>publish<\/code> command has run, and MSBuild has written that single property&#8217;s value to the standard out of my terminal. This is very useful for tooling like CI pipelines &#8211; where before you might have hard-coded an output path, now you can be data-driven! Let&#8217;s look at a more complex example, where we fetch multiple properties. In this example we&#8217;re publishing a Container Image for a project using the .NET SDK, and we want to use some properties of the container that are generated during that process:<\/p>\n<pre><code class=\"language-shell\">&gt;dotnet publish -p PublishProfile=DefaultContainer --getProperty:GeneratedContainerDigest --getProperty:GeneratedContainerConfiguration\r\n{\r\n  \"Properties\": {\r\n    \"GeneratedContainerDigest\": \"sha256:ef880a503bbabcb84bbb6a1aa9b41b36dc1ba08352e7cd91c0993646675174c4\",\r\n    \"GeneratedContainerConfiguration\": \"{\\u0022config\\u0022:{\\u0022ExposedPorts\\u0022:{\\u00228080\/tcp\\u0022:{}},\\u0022Labels\\u0022:{\\u0022org.opencontainers.image.created\\u0022:\\u00222023-10-02T18:20:01.6356453Z\\u0022,\\u0022org.opencontainers.artifact.created\\u0022:\\u00222023-10-02T18:20:01.6356453Z\\u0022,\\u0022org.opencontainers.artifact.description\\u0022:\\u0022A project that demonstrates publishing to various container registries using just\\\\r\\\\n      the .NET SDK\\u0022,\\u0022org.opencontainers.image.description\\u0022:\\u0022A project that demonstrates publishing to various container registries using just\\\\r\\\\n      the .NET SDK\\u0022,\\u0022org.opencontainers.image.authors\\u0022:\\u0022Chet Husk\\u0022,\\u0022org.opencontainers.image.url\\u0022:\\u0022https:\/\/github.com\/baronfel\/sdk-container-demo\\u0022,\\u0022org.opencontainers.image.documentation\\u0022:\\u0022https:\/\/github.com\/baronfel\/sdk-container-demo\\u0022,\\u0022org.opencontainers.image.version\\u0022:\\u00221.0.0\\u0022,\\u0022org.opencontainers.image.licenses\\u0022:\\u0022MIT\\u0022,\\u0022org.opencontainers.image.title\\u0022:\\u0022.NET SDK 7 Container Demo\\u0022,\\u0022org.opencontainers.image.base.name\\u0022:\\u0022mcr.microsoft.com\/dotnet\/aspnet:8.0.0-rc.1\\u0022},\\u0022Env\\u0022:[\\u0022PATH=\/usr\/local\/sbin:\/usr\/local\/bin:\/usr\/sbin:\/usr\/bin:\/sbin:\/bin\\u0022,\\u0022APP_UID=1654\\u0022,\\u0022ASPNETCORE_HTTP_PORTS=8080\\u0022,\\u0022DOTNET_RUNNING_IN_CONTAINER=true\\u0022,\\u0022DOTNET_VERSION=8.0.0-rc.1.23419.4\\u0022,\\u0022ASPNET_VERSION=8.0.0-rc.1.23421.29\\u0022],\\u0022WorkingDir\\u0022:\\u0022\/app\\u0022,\\u0022Entrypoint\\u0022:[\\u0022dotnet\\u0022,\\u0022sdk-container-demo.dll\\u0022],\\u0022User\\u0022:\\u00221654\\u0022},\\u0022created\\u0022:\\u00222023-10-02T18:20:04.6914310Z\\u0022,\\u0022rootfs\\u0022:{\\u0022type\\u0022:\\u0022layers\\u0022,\\u0022diff_ids\\u0022:[\\u0022sha256:d310e774110ab038b30c6a5f7b7f7dd527dbe527854496bd30194b9ee6ea496e\\u0022,\\u0022sha256:379caff0dd639afb033e114cb8da17c334a36d0c6c01bb4cf5f2d1a811968742\\u0022,\\u0022sha256:80627b9413613b9703eec6adc7a3a751ac1b7571041c77899456345f823ef63a\\u0022,\\u0022sha256:6231bc2ccd45860760c09a50d6d059aa4b6aa357e41e6d06f4394f24176f203d\\u0022,\\u0022sha256:56fa0b94fd5e406124a3d070ec79998698ddea2e635bf53bbf106dc86aeaa240\\u0022,\\u0022sha256:272eedde5582036a7f26fe5d069f4ba328ba7a5c6be30f6dcbee9838224df148\\u0022,\\u0022sha256:4b8ab71658cccccfaf8979b1025f3ed1b12e936a448dcd13b9ab4f7709f31357\\u0022]},\\u0022architecture\\u0022:\\u0022amd64\\u0022,\\u0022os\\u0022:\\u0022linux\\u0022,\\u0022history\\u0022:[{\\u0022created\\u0022:\\u00222023-09-20T04:55:40.8154909Z\\u0022,\\u0022created_by\\u0022:\\u0022\/bin\/sh -c #(nop) ADD file:a1398394375faab8dd9e1e8d584eea96c750fb57ae4ffd2b14624f1cf263561b in \/ \\u0022},{\\u0022created\\u0022:\\u00222023-09-20T04:55:41.1203677Z\\u0022,\\u0022created_by\\u0022:\\u0022\/bin\/sh -c #(nop)  CMD [\\\\u0022bash\\\\u0022]\\u0022,\\u0022empty_layer\\u0022:true},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:34.5265068Z\\u0022,\\u0022created_by\\u0022:\\u0022ENV APP_UID=1654 ASPNETCORE_HTTP_PORTS=8080 DOTNET_RUNNING_IN_CONTAINER=true\\u0022,\\u0022empty_layer\\u0022:true},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:34.5265068Z\\u0022,\\u0022created_by\\u0022:\\u0022RUN \/bin\/sh -c apt-get update     \\\\u0026\\\\u0026 apt-get install -y --no-install-recommends         ca-certificates                 libc6         libgcc-s1         libicu72         libssl3         libstdc\\\\u002B\\\\u002B6         tzdata         zlib1g     \\\\u0026\\\\u0026 rm -rf \/var\/lib\/apt\/lists\/* # buildkit\\u0022},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:34.8536814Z\\u0022,\\u0022created_by\\u0022:\\u0022RUN \/bin\/sh -c groupadd         --gid=$APP_UID         app     \\\\u0026\\\\u0026 useradd -l         --uid=$APP_UID         --gid=$APP_UID         --create-home         app # buildkit\\u0022},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:36.8764982Z\\u0022,\\u0022created_by\\u0022:\\u0022ENV DOTNET_VERSION=8.0.0-rc.1.23419.4\\u0022,\\u0022empty_layer\\u0022:true},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:36.8764982Z\\u0022,\\u0022created_by\\u0022:\\u0022COPY \/dotnet \/usr\/share\/dotnet # buildkit\\u0022},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:37.1287440Z\\u0022,\\u0022created_by\\u0022:\\u0022RUN \/bin\/sh -c ln -s \/usr\/share\/dotnet\/dotnet \/usr\/bin\/dotnet # buildkit\\u0022},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:39.8264990Z\\u0022,\\u0022created_by\\u0022:\\u0022ENV ASPNET_VERSION=8.0.0-rc.1.23421.29\\u0022,\\u0022empty_layer\\u0022:true},{\\u0022comment\\u0022:\\u0022buildkit.dockerfile.v0\\u0022,\\u0022created\\u0022:\\u00222023-09-20T12:13:39.8264990Z\\u0022,\\u0022created_by\\u0022:\\u0022COPY \/shared\/Microsoft.AspNetCore.App \/usr\/share\/dotnet\/shared\/Microsoft.AspNetCore.App # buildkit\\u0022},{\\u0022author\\u0022:\\u0022.NET SDK\\u0022,\\u0022created\\u0022:\\u00222023-10-02T18:20:04.6914069Z\\u0022,\\u0022created_by\\u0022:\\u0022.NET SDK Container Tooling, version 8.0.100-dev\\u0022}]}\"\r\n  }\r\n}<\/code><\/pre>\n<p>Here we&#8217;ve requested two properties, and received a JSON object with a <code>Properties<\/code> property containing the two properties we requested (both of which MSBuild has stored as strings). From here, we can use any JSON tooling for the CLI or the language of our choice to parse this data and use it.<\/p>\n<p>The same behavior holds for MSBuild Items, which can be requested by Item Type using the <code>--getItem:&lt;ITEMTYPE&gt;<\/code> flag. MSBuild will return these as JSON objects in an array under a key of the Item name, all under the <code>\"Items\"<\/code> key, like in this example where we request all of the Image Tags published for an image:<\/p>\n<pre><code class=\"language-shell\">&gt;dotnet publish -p PublishProfile=DefaultContainer --getItem:ContainerImageTags\r\n{\r\n  \"Items\": {\r\n    \"ContainerImageTags\": [\r\n      {\r\n        \"Identity\": \"latest\",\r\n        .... other MSBuild Item Metadata elided ....\r\n    ]\r\n  }\r\n}<\/code><\/pre>\n<p>Finally, we also support retrieving the outputs of a given Target that&#8217;s been run using <code>--getTargetResults:&lt;TARGETNAME&gt;<\/code>. These outputs are returned under the <code>TargetResults<\/code> property, like in this example where we get the final image name used by a generated SDK Container Image:<\/p>\n<pre><code class=\"language-shell\">&gt;dotnet publish -p PublishProfile=DefaultContainer --getTargetResult:ComputeContainerBaseImage\r\n{\r\n  \"TargetResults\": {\r\n    \"ComputeContainerBaseImage\": {\r\n      \"Result\": \"Success\",\r\n      \"Items\": [\r\n        {\r\n          \"Identity\": \"mcr.microsoft.com\/dotnet\/aspnet:8.0.0-rc.1\",\r\n          .... other MSBuild Item Metadata elided ....\r\n        }\r\n      ]\r\n    }\r\n  }\r\n}<\/code><\/pre>\n<p>We think this will really make it easier for MSBuild to integrate into other tooling, so we&#8217;re excited to see what you all do with it!<\/p>\n<h2>SDK Container Publish: Publish to tar.gz archive<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/sdk-container-builds\/issues\/283\">Issue<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/sdk\/pull\/35151\">PR<\/a><\/li>\n<\/ul>\n<p>The SDK has been able to publish containers to local container tools like Docker and Podman, as well as Remote Container Registries like Azure Container Registry, Amazon&#8217;s Elastic Container Registry, and Docker Hub for quite some time now. However, not all workflows are so straightforward. Some teams may prefer to run scanning tools over their images before pushing them, for example. To help support these workflows, community member @Danielku15 implemented an awesome new feature for the SDK Container Publish tooling &#8211; the ability to create a container directly as a tar.gz archive. Once this archive is made, it can be moved, scanned, or loaded into a local Docker toolchain &#8211; whatever your needs may be! Let&#8217;s take a look at how simple it is:<\/p>\n<pre><code class=\"language-shell\">&gt;dotnet publish -p PublishProfile=DefaultContainer -p ContainerArchiveOutputPath=.\/images\/sdk-container-demo.tar.gz\r\nMSBuild version 17.8.0+6cdef4241 for .NET\r\n  Determining projects to restore...\r\n  All projects are up-to-date for restore.\r\nC:\\Program Files\\dotnet\\sdk\\8.0.100-rc.2.23477.19\\Sdks\\Microsoft.NET.Sdk\\targets\\Microsoft.NET.RuntimeIdentifierInference.targets(311,5): message NETSDK1057: You are using a preview version of .NET. See: http\r\ns:\/\/aka.ms\/dotnet-support-policy [D:\\code\\sdk-container-demo\\src\\sdk-container-demo\\sdk-container-demo.csproj]\r\n  sdk-container-demo -&gt; D:\\code\\sdk-container-demo\\src\\sdk-container-demo\\bin\\Release\\net8.0\\sdk-container-demo.dll\r\n  sdk-container-demo -&gt; D:\\code\\sdk-container-demo\\src\\sdk-container-demo\\bin\\Release\\net8.0\\publish\\\r\n  Building image 'sdk-container-demo' with tags 'latest' on top of base image 'mcr.microsoft.com\/dotnet\/aspnet:8.0.0-rc.1'.\r\n  Pushed image 'sdk-container-demo:latest' to local archive at 'D:\\code\\sdk-container-demo\\src\\sdk-container-demo\\images\\sdk-container-demo.tar.gz'.<\/code><\/pre>\n<p>Here I&#8217;ve added one new property to my publish command: <code>ContainerArchiveOutputPath<\/code>. When this property is specified, instead of pushing the image to Docker or to a remote registry, the tooling instead created the file I chose. In this case I specified a file name explicitly, but if you want you can also just specify a folder to push the image into. If you do that, the generated tar.gz will be named after the image (so in this example the generated name would have been <code>sdk-container-demo.tar.gz<\/code>).<\/p>\n<p>Once you have a tar.gz, you can move it wherever you need, or simply load it into Docker using <code>docker load<\/code>:<\/p>\n<pre><code class=\"language-shell\">&gt;docker load --input .\\images\\sdk-container-demo.tar.gz\r\n5d6d1d62da4b: Loading layer [==================================================&gt;]  9.442MB\/9.442MB\r\nLoaded image: sdk-container-demo:latest<\/code><\/pre>\n<p>Just like that my image is available for me to run via Docker. We hope this new capability enables new workflows for more teams &#8211; let us know what you think at <a href=\"https:\/\/github.com\/dotnet\/sdk-container-builds\">our repo<\/a>!<\/p>\n<h2>Introducing Tensor Primitives for .NET<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/89639\">Issue<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/92219\">PR<\/a><\/li>\n<\/ul>\n<p>Over the past few years, .NET has made significant refinements to numeric support in an effort to optimize data-intensive workloads like those of AI and Machine Learning.<\/p>\n<p>Starting with the addition of hardware intrinsics in .NET Core 3, we provided .NET developers with access to hardware specific instructions. This enabled .NET applications to utilize modern hardware capabilities like vector instructions which are critical to AI workloads. <\/p>\n<p>The next step in this effort was Generic Math, which was introduced in .NET 6 as a preview feature and marked stable in .NET 7. Generic Math provides more type-safe simplified numeric operations. This feature eliminates the need for creating numerous nearly identical implementations to cater to different numeric types, thus simplifying the code and making it more maintainable.<\/p>\n<p>Tensor Primitives is the next step in the evolution of Numerics for AI in .NET by building on top of hardware intrinsics and Generic Math, and this set of features is included in .NET 8 starting with RC2.<\/p>\n<p>Tensor Primitives is short for <code>System.Numerics.Tensors.TensorPrimitives<\/code>, a new set of APIs which introduce support for tensor operations. The <code>TensorPrimitives<\/code> APIs are delivered through a standalone <code>System.Numerics.Tensors<\/code> NuGet package. The contents of this package supplant the previous <code>System.Numerics.Tensors<\/code> package, which had only shipped as preview. With .NET 8, <code>System.Numerics.Tensors<\/code> will be marked stable.<\/p>\n<p>For more details, see the <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/89639\">Future of Numerics and AI proposal<\/a>.<\/p>\n<h3>Semantic search example<\/h3>\n<p>AI workloads, such as semantic search or Retrieval Augmented Generation (RAG), enhance the natural language capabilities of Large Language Models like ChatGPT by incorporating relevant data into prompts. In these tasks, operations on vectors, such as cosine similarity, are essential for identifying the most relevant data to answer a question.<\/p>\n<p>Let&#8217;s imagine you have a movie database which contains movie titles and embeddings. <a href=\"https:\/\/learn.microsoft.com\/azure\/ai-services\/openai\/concepts\/understand-embeddings\">Embeddings<\/a> are beyond the scope of this post, but they&#8217;re ways of encoding semantic information as an array of numbers. In this case, they represent a brief synopsis of these movie plots and they&#8217;ve been precomputed. However, if you&#8217;d like you can use models like those from <a href=\"https:\/\/learn.microsoft.com\/azure\/ai-services\/openai\/how-to\/embeddings?tabs=csharp\">Azure OpenAI to generate embeddings<\/a>.<\/p>\n<pre><code class=\"language-csharp\">var movies = new [] {\r\n    new {Title=\"The Lion King\", Embedding= new [] {0.10022575f, -0.23998135f}},\r\n    new {Title=\"Inception\", Embedding= new [] {0.10327095f, 0.2563685f}},\r\n    new {Title=\"Toy Story\", Embedding= new [] {0.095857024f, -0.201278f}},\r\n    new {Title=\"Pulp Function\", Embedding= new [] {0.106827796f, 0.21676421f}},\r\n    new {Title=\"Shrek\", Embedding= new [] {0.09568083f, -0.21177962f}}\r\n};<\/code><\/pre>\n<p>Let&#8217;s say that you wanted to search for family-friendly movies using the search term &#8220;A movie that&#8217;s fun for the whole family&#8221;. The embedding for that query might look as follows. <\/p>\n<pre><code class=\"language-csharp\">var queryEmbedding = new[] {0.12217915f, -0.034832448f };<\/code><\/pre>\n<p>At this point, to see which movies in the database more closely match my query, I can compute the distance using a distance function like cosine similarity.\n\u00a0<\/p>\n<h4>Before Tensor Primitives<\/h4>\n<p>Before <code>TensorPrimitives<\/code>, if you needed to apply any operations such as cosine similarity to your tensor-shaped data, you had two options:<\/p>\n<ol>\n<li>Use external dependencies<\/li>\n<li>Implement your own operations<\/li>\n<\/ol>\n<h5>Using external dependencies<\/h5>\n<p>The easiest way for you to use any of these operations was to use existing libraries such as TorchSharp, TensorFlow.NET, Math.NET Numerics, ML.NET, or Semantic Kernel. If the application you were building heavily relied on the functionality provided by those libraries, it made sense to add them to your project. However, if all you needed was a handful of methods from those libraries, taking a dependency on those libraries introduced additional overhead. <\/p>\n<pre><code class=\"language-csharp\">using TorchSharp;\r\nusing static TorchSharp.torch.nn.functional;\r\n\r\nvar top3MoviesTorchSharp = \r\n    movies\r\n        .Select(movie =&gt; \r\n            new {\r\n                Title=movie.Title, \r\n                Embedding=movie.Embedding, \r\n                Similarity=cosine_similarity(torch.tensor(queryEmbedding), torch.tensor(movie.Embedding), 0L).item&lt;float&gt;()})\r\n        .OrderByDescending(movies =&gt; movies.Similarity)\r\n        .Take(3);<\/code><\/pre>\n<p>This is what the code might look like for measuring the similarity of my query to my movie collection. After sorting by most similar (higher is more similar) and taking the top 3 movies most likely to be &#8220;family-friendly&#8221;, the output is the following:<\/p>\n<table>\n<thead>\n<tr>\n<th>Title<\/th>\n<th>Similarity<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Toy Story<\/td>\n<td>0.66102695<\/td>\n<\/tr>\n<tr>\n<td>Shrek<\/td>\n<td>0.6457999<\/td>\n<\/tr>\n<tr>\n<td>The Lion King<\/td>\n<td>0.62360466<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As you can see from this example, movies such as Pulp Fiction and Inception are not part of the results because they&#8217;re not considered &#8220;family-friendly&#8221; movies. <\/p>\n<p>While TorchSharp makes it easy for you to calculate cosine similarity, adding it as a dependency for this one function may not make sense. <\/p>\n<h5>Writing your own implementation<\/h5>\n<p>If you didn&#8217;t want to take on another external dependency just to use a few operations in your application, the other alternative was to implement your own. This is what many of the libraries mentioned previously have done. While this is a viable path that offers you the most control over your code, this meant you were writing framework-level code rather than focusing on the competitive advantages of your application or business. Most likely your code might&#8217;ve been a naive implementation of the operation which didn&#8217;t take full advantage of the runtime&#8217;s capabilities for hardware optimizations.  <\/p>\n<pre><code class=\"language-csharp\">public float CosineSimilarityCustom(ReadOnlySpan&lt;float&gt; vector1, ReadOnlySpan&lt;float&gt; vector2)\r\n{\r\n    if (vector1.Length != vector2.Length)\r\n        throw new ArgumentException(\"Vectors must have the same length\");\r\n\r\n    float dotProduct = 0f;\r\n    float magnitude1 = 0f;\r\n    float magnitude2 = 0f;\r\n\r\n    for (int i = 0; i &lt; vector1.Length; i++)\r\n    {\r\n        dotProduct += vector1[i] * vector2[i];\r\n        magnitude1 += vector1[i] * vector1[i];\r\n        magnitude2 += vector2[i] * vector2[i];\r\n    }\r\n\r\n    magnitude1 = MathF.Sqrt(magnitude1);\r\n    magnitude2 = MathF.Sqrt(magnitude2);\r\n\r\n    if (magnitude1 == 0 || magnitude2 == 0)\r\n        return 0;  \/\/ handle the case where one or both vectors have zero magnitude\r\n\r\n    return dotProduct \/ (magnitude1 * magnitude2);\r\n}<\/code><\/pre>\n<p>This is what a custom implementation of cosine similarity might look like. You&#8217;d then use this as follows. <\/p>\n<pre><code class=\"language-csharp\">var top3MoviesCustom = \r\n    movies\r\n        .Select(movie =&gt; \r\n            new {\r\n                Title=movie.Title, \r\n                Embedding=movie.Embedding, \r\n                Similarity=CosineSimilarityCustom(queryEmbedding, movie.Embedding)})\r\n        .OrderByDescending(movies =&gt; movies.Similarity)\r\n        .Take(3);<\/code><\/pre>\n<p>The results of this code are the same as those from the TorchSharp example. While there are no external dependencies in this case, cosine similarity now becomes a set of framework-level code you need to maintain. <\/p>\n<h4>After Tensor Primitives<\/h4>\n<p><code>TensorPrimitives<\/code> simplifies these choices. If you just need a handful of operations, you don&#8217;t need to take on a large external dependency into your project. <\/p>\n<pre><code class=\"language-csharp\">using System.Numerics.Tensors;\r\n\r\nvar top3MoviesTensorPrimitives = \r\n    movies\r\n        .Select(movie =&gt; \r\n            new {\r\n                Title=movie.Title, \r\n                Embedding=movie.Embedding, \r\n                Similarity=TensorPrimitives.CosineSimilarity(queryEmbedding, movie.Embedding)})\r\n        .OrderByDescending(movies =&gt; movies.Similarity)\r\n        .Take(3);<\/code><\/pre>\n<p>Similarly, for libraries who make use of these operations such as Semantic Kernel and ML.NET, they can replace many of their existing implementation with <code>TensorPrimitives<\/code> so they can focus on their competitive advantages and deliver features faster. <\/p>\n<h3>Current State<\/h3>\n<p>Currently, <code>TensorPrimitives<\/code> provides vectorized implementations for operations like:<\/p>\n<ul>\n<li>CosineSimilarity<\/li>\n<li>SoftMax<\/li>\n<li>Sigmoid<\/li>\n<li>Tanh<\/li>\n<li>Sinh<\/li>\n<li>Norm (L2)<\/li>\n<li>SumOfSquares<\/li>\n<li>ProductOfSums<\/li>\n<\/ul>\n<p>For a complete list of operations, see <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/92219\">Tensor Primitives work items tracking issue<\/a>.<\/p>\n<h3>Suggested Usage<\/h3>\n<p>In initial tests, we&#8217;ve observed that the performance efficiencies this package introduces are more noticeable on tensors with a large number of elements. <\/p>\n<h3>What&#8217;s next?<\/h3>\n<p>Over the next few months, we plan to:<\/p>\n<ul>\n<li>Provide more comprehensive coverage of tensor operations.<\/li>\n<li>Replace existing implementations of these operations in libraries like ML.NET and Semantic Kernel with the Tensor Primitives implementations.<\/li>\n<\/ul>\n<h3>Get started with Tensor Primitives today<\/h3>\n<p>In your .NET project, add a reference to the latest <code>System.Numeric.Tensors<\/code> NuGet package.<\/p>\n<pre><code class=\"language-dotnet\">dotnet add package System.Numeric.Tensors --prerelease<\/code><\/pre>\n<p>Give us feedback and file any issues in the <a href=\"https:\/\/github.com\/dotnet\/runtime\">dotnet\/runtime<\/a> repo.<\/p>\n<h2>Community Contributor<\/h2>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/10\/community-spotlight.jpg\" alt=\"Florian Verdonck\" \/><\/p>\n<p>I\u2019m Florian Verdonck and I live in <a href=\"https:\/\/www.britishlegion.org.uk\/get-involved\/remembrance\/about-remembrance\/in-flanders-field\">Flanders Fields<\/a> in Belgium.\u202f <\/p>\n<p>My first programming experience was at the age of 18. <a href=\"http:\/\/vb.net\/\">VB.NET<\/a> was my first programming language and near the end of my higher education, I favoured C# as my go-to language. I quickly took an interest in web development \u2013 without specializing in front-end or back-end development. As my career has progressed, I\u2019ve always been eager to learn new software and practices. After getting the hang of C# and object-oriented programming, I learned about function programming during a <a href=\"https:\/\/www.meetup.com\/socratesbe\/\">local meetup<\/a> and had to try it out. <\/p>\n<p>Exploring functional programming was quite an eye-opener for me. It broadened my perspective on many things in the software industry such as how working too long with a popular programming language can make you oblivious to what else is out there. And why it is important to come out of your comfort zone from time to time. <\/p>\n<p>Exploring F# to learn about functional programming was a logical step for me as I had a strong familiarity with .NET. I liked how concise F# code can be and how there is no need to go fully functional from day one, you can start with what you know and gradually apply new techniques as you learn them. F# also has a treasure glove of small features and hidden gems which makes it unique. I was in love.\u202f <\/p>\n<p>As F# was my first indentation-based programming language, it took me some time to adjust to the syntax. One thing that was missing for me, coming as I did from other languages, was a code formatter.\u202f <\/p>\n<p>I value code style consistency when I\u2019m about to add new code to a shared codebase, and always do my best to be considerate of my predecessors. When I started, F# didn\u2019t have any out-of-the-box solution to the problem of multiple collaborators, sometimes with their own styles, that can\u2019t share code because it simply isn\u2019t formatted in a universally understood fashion. That is why I began contributing to the <a href=\"https:\/\/fsprojects.github.io\/fantomas\/\">Fantomas project<\/a>, as a part of the <a href=\"https:\/\/fsharp.org\/mentorship\/\">F# Foundation mentorship<\/a> program. My mentor, <a href=\"https:\/\/anthonylloyd.github.io\/\">Anthony Lloyd<\/a>, and I revived the project after it had lost its main maintainer.\u202f\u202f <\/p>\n<p>Contributing to Fantomas has been instrumental in my career. Not only was it great for some real-world F# work experience, but it also led me to pursue other interests like public speaking, product ownership and community building. Maintaining Fantomas was my contribution to the F# ecosystem and, in the process, I found personal meaning and a sense of belonging.\u202f <\/p>\n<p>My enthusiasm for Fantomas had its practical side, I was working on it in my spare time as most individual open-source maintainers do, and it still wasn\u2019t really a reliable or stable tool at the time. Frustrating bugs would still lurk behind every corner, adoption was still limited and there were upstream shortages in the F# compiler (Fantomas uses the parser from the F# compiler internally). <\/p>\n<p>What elevated Fantomas was the support of a London fintech firm called G-Research. The open-source division of G-Research saw potential in the project and decided to sponsor me financially to work on Fantomas. This made it possible to formally work on Fantomas on a weekly basis. <\/p>\n<p>G-Research\u2019s sponsorship granted me the time to tackle more challenging problems in the codebase and led me to start contributing to the F# compiler. With the help of <a href=\"https:\/\/github.com\/baronfel\">Chet Husk<\/a>, I was able to land <a href=\"https:\/\/github.com\/dotnet\/fsharp\/pull\/10769\">my first pull request<\/a> where we addressed a lack of information after parsing. Once I got over that initial mental roadblock of contributing to the compiler, I started doing it again and again. The F# team has been appreciative and helpful to all my contributions, and I encourage everyone to contribute!\u202f <\/p>\n<p>Last year, I joined the open-source team at G-Research full-time. Not to work just on Fantomas, but to tackle bigger problems in the F# compiler and tooling. It is a firm willing to actively contribute back to the software and tools it uses. I\u2019m very fortunate to have the privilege to work on these interesting projects and get the opportunity to work on the very heart of the F# ecosystem.<\/p>\n<h2>Importance of Feedback<\/h2>\n<p>Lastly, we want to highlight the importance of your feedback through these .NET 8 preview and RC releases. Your feedback is instrumental in helping shape new .NET experiences. Here are a few examples to illustrate the importance of your voice:<\/p>\n<ul>\n<li><strong>ASP.NET Core.<\/strong> <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/50131\">Reconsidered enabling HTTP\/3 by default in .NET 8.<\/a><\/li>\n<li><strong>Blazor.<\/strong> <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/49079\">Changed their entire plan around project structure and TFMs for Blazor WebAssembly.<\/a><\/li>\n<li><strong>Runtime.<\/strong> <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/89937\">Lit up newer ARM64 hardware capabilities<\/a> and <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/91981\">updated Marshal.QueryInterface.<\/a><\/li>\n<li><strong>SDK.<\/strong> <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-4\/#sdk-simplified-output-path-updates\">Improved simplified output paths<\/a> and polished the terminal logger.\n<img decoding=\"async\" src=\".\/modernbuildoutputdiagnostics.gif\" alt=\"Modern Terminal Logger\" \/><\/li>\n<li><strong>NuGet.<\/strong> <a href=\"https:\/\/github.com\/NuGet\/Home\/pull\/12310\">Improved the design of the new package vulnerability auditing feature.<\/a><\/li>\n<\/ul>\n<h2>Summary<\/h2>\n<p>In the journey towards the release of .NET 8, we extend our heartfelt gratitude to all the passionate .NET developers around the world who stepped up to explore and test the previews and release candidates. Your dedication to the .NET ecosystem has been invaluable, and your feedback has played a pivotal role in ensuring the reliability and robustness of this latest version. Thank you for being an essential part of this exciting journey, and we can&#8217;t wait to see what you&#8217;ll bring to life with .NET 8.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 RC2 is now available with new NuGet package READMEs for .NET packages, simple CLI-based project evaluation for MSBuild, publishing containers to tar.gz archives, and Tensor Primitives for .NET.<\/p>\n","protected":false},"author":551,"featured_media":48334,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685],"tags":[7701],"class_list":["post-48250","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","tag-dotnet-8"],"acf":[],"blog_post_summary":"<p>.NET 8 RC2 is now available with new NuGet package READMEs for .NET packages, simple CLI-based project evaluation for MSBuild, publishing containers to tar.gz archives, and Tensor Primitives for .NET.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/48250","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/551"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=48250"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/48250\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/48334"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=48250"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=48250"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=48250"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}