{"id":47523,"date":"2023-09-12T10:06:00","date_gmt":"2023-09-12T17:06:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=47523"},"modified":"2023-10-10T09:34:05","modified_gmt":"2023-10-10T16:34:05","slug":"asp-net-core-updates-in-dotnet-8-rc-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-updates-in-dotnet-8-rc-1\/","title":{"rendered":"ASP.NET Core updates in .NET 8 Release Candidate 1"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-rc1\">.NET 8 Release Candidate 1 (RC1) is now available<\/a> and includes many great new improvements to ASP.NET Core!<\/p>\n<p>This is the first of two release candidates that we plan to share before the final .NET 8 release later this year. Most of the planned features and changes for .NET 8 are part of this release candidate and are ready for you to try out. You can find the full list of <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/release-notes\/aspnetcore-8.0\">what&#8217;s new in ASP.NET Core in .NET 8<\/a> in the docs. A few areas (particularly Blazor) still have some significant changes pending. We expect to complete those changes for the next .NET 8 release candidate.<\/p>\n<p>Here&#8217;s a summary of what&#8217;s new in this preview release:<\/p>\n<ul>\n<li><a href=\"#servers\">Servers &amp; middleware<\/a>\n<ul>\n<li>HTTP\/3 disabled by default<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#apis\">API authoring<\/a>\n<ul>\n<li>Support for keyed services in minimal APIs, MVC, and SignalR<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#blazor\">Blazor<\/a>\n<ul>\n<li>Blazor Web App template updates<\/li>\n<li>Discover components from additional assemblies for static server rendering<\/li>\n<li>Routing improvements<\/li>\n<li>Trigger a page refresh<\/li>\n<li>Pass through arbitrary attributes to <code>QuickGrid<\/code><\/li>\n<li>Determine if a form field is valid<\/li>\n<li>Configure the .NET WebAssembly runtime<\/li>\n<li>Trim .NET IL after ahead-of-time (AOT) compilation<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#identity\">Identity<\/a>\n<ul>\n<li>Removed <code>username<\/code> property<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#spa\">Single page apps (SPA)<\/a>\n<ul>\n<li>Standard .NET template options<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#metrics\">Metrics<\/a><\/li>\n<\/ul>\n<p>For more details on the ASP.NET Core work planned for .NET 8 see the full <a href=\"https:\/\/aka.ms\/aspnet\/roadmap\">ASP.NET Core roadmap for .NET 8<\/a> on GitHub.<\/p>\n<h2>Get started<\/h2>\n<p>To get started with ASP.NET Core in .NET 8 RC1, <a href=\"https:\/\/dotnet.microsoft.com\/next\">install the .NET 8 SDK<\/a>.<\/p>\n<p>If you&#8217;re on Windows using Visual Studio, we recommend installing the latest <a href=\"https:\/\/visualstudio.com\/preview\">Visual Studio 2022 preview<\/a>. If you&#8217;re using Visual Studio Code, you can try out the new <a href=\"https:\/\/devblogs.microsoft.com\/visualstudio\/announcing-csharp-dev-kit-for-visual-studio-code\/\">C# Dev Kit<\/a>.<\/p>\n<h2>Upgrade an existing project<\/h2>\n<p>To upgrade an existing ASP.NET Core app from .NET 8 Preview 7 to .NET 8 RC1:<\/p>\n<ul>\n<li>Update the target framework of your app to <code>net8.0<\/code>.<\/li>\n<li>Update all Microsoft.AspNetCore.* package references to <code>8.0.0-rc.1.*<\/code>.<\/li>\n<li>Update all Microsoft.Extensions.* package references to <code>8.0.0-rc.1.*<\/code>.<\/li>\n<\/ul>\n<p>See also the full list of <a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/compatibility\/8.0#aspnet-core\">breaking changes<\/a> in ASP.NET Core for .NET 8.<\/p>\n<p><a id=\"servers\"><\/a><\/p>\n<h2>Servers &amp; middleware<\/h2>\n<h3>HTTP\/3 disabled by default<\/h3>\n<p>HTTP\/3 is no longer enabled by default in Kestrel. This change returns the Kestrel HTTP protocol behavior back to its .NET 7 state, but differs from all .NET 8 previews.<\/p>\n<p>We reverted to the .NET 7 behavior because enabling HTTP\/3 caused some anti-virus software to prompt whether network access is allowed when an app is launched with debugging. This isn&#8217;t a good experience, so we turned HTTP\/3 off by default until we can improve the developer experience.<\/p>\n<p>You can re-enable HTTP\/3 per endpoint by setting the protocols your endpoint allows:<\/p>\n<pre><code class=\"language-csharp\">var builder = WebApplication.CreateBuilder(args);\n\nbuilder.WebHost.ConfigureKestrel((context, options) =&gt;\n{\n    options.ListenAnyIP(5001, listenOptions =&gt;\n    {\n        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;\n        listenOptions.UseHttps();\n    });\n});<\/code><\/pre>\n<p>Or, by configuring the default protocols:<\/p>\n<pre><code class=\"language-csharp\">var builder = WebApplication.CreateBuilder(args);\n\nbuilder.WebHost.ConfigureKestrel((context, options) =&gt;\n{\n    options.ConfigureEndpointDefaults(listenOptions =&gt;\n    {\n        listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;\n        listenOptions.UseHttps();\n    });\n});<\/code><\/pre>\n<p>See <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/servers\/kestrel\/http3\">Use HTTP\/3 with the ASP.NET Core Kestrel web server<\/a> for more information about HTTP\/3 requirements and configuration.<\/p>\n<p><a id=\"apis\"><\/a><\/p>\n<h2>API authoring<\/h2>\n<h3>Support for keyed services in minimal APIs, MVC, and SignalR<\/h3>\n<p>In .NET 8 Preview 7, we introduced support for <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-dotnet-8-preview-7\/#keyed-services-support-in-microsoft-extensions-dependencyinjection\">keyed services in DI<\/a>. Starting in .NET 8 RC1, it&#8217;s now possible to use keyed services in apps using minimal APIs, controller-based APIs, and SignalR hubs. To leverage the new keyed services support, annotate the target parameter with the <code>[FromKeyedServices(\"keyName\")]<\/code> attribute.<\/p>\n<blockquote>\n<p>Note: <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/50687\">Resolving keyed services in the constructor of an MVC controller or SignalR hub<\/a> is not currently supported.<\/p>\n<\/blockquote>\n<p>The following sample showcases this support in minimal APIs and controllers:<\/p>\n<pre><code class=\"language-csharp\">using Microsoft.AspNetCore.Mvc;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddKeyedSingleton&lt;ICache, BigCache&gt;(\"big\");\nbuilder.Services.AddKeyedSingleton&lt;ICache, SmallCache&gt;(\"small\");\nbuilder.Services.AddControllers();\n\nvar app = builder.Build();\n\napp.MapGet(\"\/big\", ([FromKeyedServices(\"big\")] ICache bigCache) =&gt; bigCache.Get(\"date\"));\n\napp.MapGet(\"\/small\", ([FromKeyedServices(\"small\")] ICache smallCache) =&gt; smallCache.Get(\"date\"));\n\napp.MapControllers();\n\napp.Run();\n\npublic interface ICache\n{\n    object Get(string key);\n}\npublic class BigCache : ICache\n{\n    public object Get(string key) =&gt; $\"Resolving {key} from big cache.\";\n}\n\npublic class SmallCache : ICache\n{\n    public object Get(string key) =&gt; $\"Resolving {key} from small cache.\";\n}\n\n[ApiController]\n[Route(\"\/cache\")]\npublic class CustomServicesApiController : Controller\n{\n    [HttpGet(\"big-cache\")]\n    public ActionResult&lt;object&gt; GetOk([FromKeyedServices(\"big\")] ICache cache)\n    {\n        return cache.Get(\"data-mvc\");\n    }\n}\n\npublic class MyHub : Hub\n{\n    public void Method([FromKeyedServices(\"small\")] ICache cache)\n    {\n        Console.WriteLine(cache.Get(\"signalr\"));\n    }\n}<\/code><\/pre>\n<p><a id=\"blazor\"><\/a><\/p>\n<h2>Blazor<\/h2>\n<h3>Blazor Web App template updates<\/h3>\n<p>In .NET 8 we&#8217;ve been adding capabilities to Blazor so that you can use Blazor components full stack for all of your web UI needs. You can now render Blazor components statically from the server in response to requests, progressively enhance the experience with enhanced navigation &amp; form handling, stream server-rendered updates, and add rich interactivity where it&#8217;s needed using Blazor Server or Blazor WebAssembly. To optimize the app load time, Blazor can also auto-select whether to use Blazor Server or Blazor WebAssembly at runtime.<\/p>\n<p>These new Blazor capabilities are now all setup for you by the Blazor Web App project template. In this release, the Blazor Web App template has been cleaned up and improved with several new options to configure different scenarios.<\/p>\n<p>The Blazor Web App now has the following options:<\/p>\n<ul>\n<li><strong>Use interactive WebAssembly components<\/strong>: Enables support for the interactive WebAssembly render mode, based on Blazor WebAssembly.<\/li>\n<li><strong>Use interactive Server components<\/strong>: Enables support for the interactive Server render mode, based on Blazor Server.<\/li>\n<li><strong>Include sample pages<\/strong>: If this option is selected, the project will include sample pages and a layout based on Bootstrap styling. Disable this option if you just want an empty project to start with.<\/li>\n<\/ul>\n<p>If both the WebAssembly and Server render modes are selected, then the template will use the Auto render mode. The Auto render model will initially use the Server mode while the .NET runtime and app bundle is download to the browser. Once the runtime is download, Auto will switch to start using the WebAssembly render mode instead.<\/p>\n<p>By default, the Blazor Web App template will enable both static and interactive server rendering using a single project. If you also enable the WebAssembly render mode, then the project will include an additional client project for your WebAssembly-based components. The built output from the client project will be downloaded to the browser and executed on the client. Any components using the WebAssembly or Auto render modes must be built from the client project. <\/p>\n<p>The Blazor Web App template has a cleaned up folder structure:<\/p>\n<ul>\n<li>The new <em>Components<\/em> folder contains all the components in the server project.<\/li>\n<li>The <em>Components\/Layout<\/em> folder contains the app layout.<\/li>\n<li>The <em>Components\/Pages<\/em> folder contains the routable page components.<\/li>\n<\/ul>\n<p>The component names and content have been cleaned up to match their function:<\/p>\n<ul>\n<li><em>Index.razor<\/em> -&gt; <em>Home.razor<\/em><\/li>\n<li><em>Counter.razor<\/em> is unchanged<\/li>\n<li><em>FetchData.razor<\/em> -&gt; <em>Weather.razor<\/em><\/li>\n<\/ul>\n<p>The <code>App<\/code> component is now clean and simple:<\/p>\n<pre><code class=\"language-html\">&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n\n&lt;head&gt;\n    &lt;meta charset=\"utf-8\" \/&gt;\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" \/&gt;\n    &lt;base href=\"\/\" \/&gt;\n    &lt;link rel=\"stylesheet\" href=\"bootstrap\/bootstrap.min.css\" \/&gt;\n    &lt;link rel=\"stylesheet\" href=\"app.css\" \/&gt;\n    &lt;link rel=\"stylesheet\" href=\"BlazorApp51.styles.css\" \/&gt;\n    &lt;link rel=\"icon\" type=\"image\/png\" href=\"favicon.png\" \/&gt;\n    &lt;HeadOutlet \/&gt;\n&lt;\/head&gt;\n\n&lt;body&gt;\n    &lt;Routes \/&gt;\n    &lt;script src=\"_framework\/blazor.web.js\"&gt;&lt;\/script&gt;\n&lt;\/body&gt;\n\n&lt;\/html&gt;<\/code><\/pre>\n<p>We made several change to the <code>App<\/code> component to clear it up:<\/p>\n<ul>\n<li>We removed the Bootstrap icons and switched to custom SVG icons instead.<\/li>\n<li>We moved the Blazor router to the new <code>Routes<\/code> component and removed its <code>NotFound<\/code> parameter as it is never used.<\/li>\n<li>We moved the default Blazor error UI to the <code>MainLayout<\/code> component.<\/li>\n<li>We removed the <code>surpress-error<\/code> attribute on the <code>script<\/code> tag for the Blazor script, as it is no longer required.<\/li>\n<\/ul>\n<p>The new <code>Routes<\/code> component in the template simplifies making the entire app interactive: simply apply the desired render mode to the <code>Routes<\/code> and <code>HeadOutlet<\/code> components. The root <code>App<\/code> component needs to be static, because it renders the Blazor script and script tags cannot be dynamically removed. You also can&#8217;t make the Blazor router directly interactive from the <code>App<\/code> component, because it has parameters that are render fragments, which are not serializable. Interactive components rendered from static components must have serializable parameters. The <code>Routes<\/code> component provides an appropriate boundary for enabling interactivity.<\/p>\n<h3>Discover components from additional assemblies for static server rendering<\/h3>\n<p>You can now configure additional assemblies to use for discovering routable Blazor components for static server rendering using the <code>AddAdditionalAssemblies()<\/code> method:<\/p>\n<pre><code class=\"language-csharp\">app.MapRazorComponents&lt;App&gt;()\n    .AddAdditionalAssemblies(typeof(Counter).Assembly);<\/code><\/pre>\n<h3>Routing improvements<\/h3>\n<p>We&#8217;ve unified the Blazor routing implementation with ASP.NET Core routing. This unification adds to the Blazor router support for the following features:<\/p>\n<ul>\n<li><a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/routing#complex-segments\">Complex segments<\/a> (<code>\"\/a{b}c{d}\"<\/code>)<\/li>\n<li>Default values (<code>\"\/{tier=free}\"<\/code>)<\/li>\n<li>All built-in <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/fundamentals\/routing#route-constraints\">route constraints<\/a><\/li>\n<\/ul>\n<h3>Trigger a page refresh<\/h3>\n<p>You can now call <code>NavigationManager.Refresh()<\/code> to trigger a page refresh. This will refresh the page using an enhanced page navigation if possible. Otherwise, it will trigger a full page refresh. To force a full page refresh, use <code>NavigationManager.Refresh(forceReload: true)<\/code>.<\/p>\n<h3>Pass through arbitrary attributes to <code>QuickGrid<\/code><\/h3>\n<p>The <code>QuickGrid<\/code> component will now pass through any additional attributes to the the rendered <code>table<\/code> element:<\/p>\n<pre><code class=\"language-razor\">&lt;QuickGrid Items=\"@FilteredPeople\" custom-attribute=\"somevalue\" class=\"custom-class-attribute\"&gt;<\/code><\/pre>\n<p>Thank you <a href=\"https:\/\/github.com\/ElderJames\">@ElderJames<\/a> for this contribution!<\/p>\n<h3>Determine if a form field is valid<\/h3>\n<p>The new <code>EditContext.IsValid(FieldIdentifier)<\/code> API can be used to determine if a field is valid without having to get the validation messages.<\/p>\n<p>Thank you <a href=\"https:\/\/github.com\/ElderJames\">@ElderJames<\/a> for this contribution!<\/p>\n<h3>Configure the .NET WebAssembly runtime<\/h3>\n<p>You can now configure various .NET runtime options during <a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/blazor\/fundamentals\/startup\">startup<\/a> when running on WebAssembly using the <code>configureRuntime<\/code> function:<\/p>\n<pre><code class=\"language-html\">&lt;script src=\"_framework\/blazor.webassembly.js\" autostart=\"false\"&gt;&lt;\/script&gt;\n&lt;script&gt;\n  Blazor.start({\n    configureRuntime: dotnet =&gt; {\n        dotnet.withEnvironmentVariable(\"CONFIGURE_RUNTIME\", \"true\");\n    }\n  });\n&lt;\/script&gt;<\/code><\/pre>\n<p>The .NET runtime instance can now accessed from <code>Blazor.runtime<\/code>.<\/p>\n<p>For more details on the .NET runtime options and APIs when running on WebAssembly, see https:\/\/github.com\/dotnet\/runtime\/blob\/main\/src\/mono\/wasm\/runtime\/dotnet.d.ts.<\/p>\n<h3>Trim .NET IL after ahead-of-time (AOT) compilation<\/h3>\n<p>The new <code>WasmStripILAfterAOT<\/code> MSBuild option enables removing the .NET IL for compiled methods after performing ahead-of-time (AOT) compilation to WebAssembly. This new stripping mode reduces the size of _framework folder by 1.7% &#8211; 4.2% based on our tests.<\/p>\n<pre><code class=\"language-xml\">&lt;PropertyGroup&gt;\n  &lt;RunAOTCompilation&gt;true&lt;\/RunAOTCompilation&gt;\n  &lt;WasmStripILAfterAOT&gt;true&lt;\/WasmStripILAfterAOT&gt;\n&lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>This setting will trim away the IL code for most compiled methods, including methods from libraries and methods in the app. Not all compiled methods can be trimmed, as some are still needed by the .NET interpreter at runtime.<\/p>\n<p>If you hit any issues using this new trimming option for AOT compiled WebAssembly apps, let us know by <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/new\/choose\">opening issues on GitHub in the dotnet\/runtime repo<\/a>.<\/p>\n<p><a id=\"identity\"><\/a><\/p>\n<h2>Identity<\/h2>\n<h3>Removed <code>username<\/code> property from Identity API JSON payloads<\/h3>\n<p>To simplify <code>MapIdentityApi&lt;TUser&gt;()<\/code> and align more closely with the existing Identity UIs, the <code>username<\/code> property has been removed from request and response JSON payloads. Username and email are now the same and the field will be named <code>Email<\/code> moving forward (or <code>NewEmail<\/code> in the case of registering a user).<\/p>\n<p><a id=\"spa\"><\/a><\/p>\n<h2>Single page apps (SPA)<\/h2>\n<h3>Standard .NET template options<\/h3>\n<p>The Visual Studio templates for using ASP.NET Core with popular frontend JavaScript frameworks like Angular, React, and Vue now support the standard .NET template options, including specifying a target .NET framework version, enabling OpenAPI support, and much more.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/10\/spa-dotnet-template-options.png\" alt=\"Visual Studio SPA template options for .NET\" \/><\/p>\n<p><a id=\"metrics\"><\/a><\/p>\n<h2>Metrics<\/h2>\n<p>In .NET 8 RC1, we&#8217;ve renamed new metrics to follow the <a href=\"https:\/\/github.com\/open-telemetry\/semantic-conventions\/blob\/main\/docs\/README.md\">OpenTelemetry Semantic Conventions<\/a>. This change is based on feedback from users and library authors about what to name their own counters. OpenTelemetry is an existing established standard, and it is beneficial for .NET&#8217;s built-in metrics and the broader .NET ecosystem to follow that standard.<\/p>\n<ul>\n<li>ASP.NET Core&#8217;s primary HTTP metrics now exactly match OpenTelemetry&#8217;s <a href=\"https:\/\/github.com\/open-telemetry\/semantic-conventions\/blob\/main\/docs\/http\/http-metrics.md#metric-httpserverrequestduration\"><code>http.server.request.duration<\/code><\/a> and <a href=\"https:\/\/github.com\/open-telemetry\/semantic-conventions\/blob\/main\/docs\/http\/http-metrics.md#metric-httpserveractive_requests\"><code>http.server.active_requests<\/code><\/a> counters.<\/li>\n<li>Other counters in ASP.NET Core use the semantic convention&#8217;s naming standard. For example, the rate-limiting middleware has metrics that record the number of HTTP requests waiting for a lease and lease duration.\n<ul>\n<li>Renamed the lease queue length counter from <code>rate-limiting-current-queued-requests<\/code> to <code>aspnetcore.rate_limiting.queued_requests<\/code>.<\/li>\n<li>Renamed the lease queue duration counter from <code>rate-limiting-queued-request-duration<\/code> to <code>aspnetcore.rate_limiting.request.time_in_queue<\/code>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>After updating to .NET 8 RC1, you may need to update to use the names in dashboards and alerts that use them.<\/p>\n<p>For more information about available metrics in .NET 8, including a complete list of the counters available and their names, see <a href=\"https:\/\/github.com\/lmolkova\/semantic-conventions\/blob\/dotnet8-metrics\/docs\/dotnet\/README.md\">Semantic Conventions for .NET metrics<\/a>.<\/p>\n<h2>Known Issues<\/h2>\n<h3>ASP.NET Redis-based output-cache<\/h3>\n<p>There is a known regression in the Redis-based output-cache for ASP.NET (new in .NET 8, announced in Preview 6); this feature will not work in RC1. The cause has been identified and resolved for RC2.<\/p>\n<h3>Blazor Web App template creates multiple counter components<\/h3>\n<p>The Blazor Web App uses an unnecessary workaround when enabling interactive WebAssembly components. The template generates two <code>Counter<\/code> components: 1. A <code>Counter<\/code> component in the client project with the render mode attribute, and 2. A <code>Counter<\/code> page in the server project that uses the <code>Counter<\/code> from the client. This workaround is unnecessary. The <code>Counter<\/code> component in the server project can be removed after copying its <code>@page<\/code> directive to the <code>Counter<\/code> in the client project. Then call <code>AddAdditionalAssemblies(typeof(Counter).Assembly)<\/code> in <em>Program.cs<\/em> so that the <code>Counter<\/code> component can be discovered.<\/p>\n<h2>Give feedback<\/h2>\n<p>We hope you enjoy this preview release of ASP.NET Core in .NET 8. Let us know what you think about these new improvements by filing issues on <a href=\"https:\/\/github.com\/dotnet\/aspnetcore\/issues\/new\">GitHub<\/a>.<\/p>\n<p>Thanks for trying out ASP.NET Core!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 Release Candidate 1 is now available! Check out what&#8217;s new in ASP.NET Core in this update.<\/p>\n","protected":false},"author":417,"featured_media":48260,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,197,7509,7251],"tags":[7701],"class_list":["post-47523","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-aspnet","category-aspnetcore","category-blazor","tag-dotnet-8"],"acf":[],"blog_post_summary":"<p>.NET 8 Release Candidate 1 is now available! Check out what&#8217;s new in ASP.NET Core in this update.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/47523","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\/417"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=47523"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/47523\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/48260"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=47523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=47523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=47523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}