{"id":13015,"date":"2018-04-12T10:24:30","date_gmt":"2018-04-12T17:24:30","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=13015"},"modified":"2023-12-18T08:55:08","modified_gmt":"2023-12-18T16:55:08","slug":"asp-net-core-2-1-0-preview2-now-available","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-2-1-0-preview2-now-available\/","title":{"rendered":"ASP.NET Core 2.1.0-preview2 now available"},"content":{"rendered":"<p>Today we&#8217;re very happy to announce that the second preview of the next minor release of ASP.NET Core and .NET Core is now available for you to try out. This second preview includes many refinements based on feedback we received from the <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-2-1-0-preview1-now-available\/\">first preview<\/a> we released back in February.<\/p>\n<p>You can read about <a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2018\/04\/11\/announcing-net-core-2-1-preview-2\/\">.NET Core 2.1.0-preview2 over on their blog<\/a>.<\/p>\n<p>You can also read about <a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2018\/04\/11\/announcing-entity-framework-core-2-1-preview-2\/\">Entity Framework Core 2.1.0-preview2 on their blog<\/a>.<\/p>\n<h2 id=\"howdoigetit\">How do I get it?<\/h2>\n<p>You can download the new .NET Core SDK for 2.1.0-preview2 (which includes ASP.NET Core 2.1.0-preview2) from <a href=\"https:\/\/www.microsoft.com\/net\/download\/dotnet-core\/sdk-2.1.300-preview2\">https:\/\/www.microsoft.com\/net\/download\/dotnet-core\/sdk-2.1.300-preview2<\/a><\/p>\n<h3 id=\"vs2017versionreqs\">Visual Studio 2017 version requirements<\/h3>\n<p>Customers using Visual Studio 2017 should also install (in addition to the SDK above) and use the <a href=\"https:\/\/www.visualstudio.com\/vs\/preview\/\">Preview channel<\/a> (15.7 Preview 3 at the time of writing) when working with .NET Core and ASP.NET Core 2.1 projects. .NET Core 2.1 projects require Visual Studio 2017 15.7 or greater.<\/p>\n<h3 id=\"impacttomachines\">Impact to machines<\/h3>\n<p>Please note that given this is a preview release there are likely to be known issues and as-yet-to-be-discovered bugs. While .NET Core SDK and runtime installs are side-by-side on your machine, your default SDK will become the latest version, which in this case will be the preview. If you run into issues working on existing projects using earlier versions of .NET Core after installing the preview SDK, you can force specific projects to use an earlier installed version of the SDK using a global.json file as <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/core\/tools\/global-json\">documented here<\/a>. Please <a href=\"https:\/\/github.com\/dotnet\/cli\/issues\">log an issue<\/a> if you run into such cases as SDK releases are intended to be backwards compatible.<\/p>\n<p>Already published applications running on earlier versions of .NET Core and ASP.NET Core shouldn&#8217;t be impacted by installing the preview. That said, we don&#8217;t recommend installing previews on machines running critical workloads.<\/p>\n<h2 id=\"announcementsandreleasenotes\">Announcements and release notes<\/h2>\n<p>You can see all the announcements published pertaining to this release at <a href=\"https:\/\/github.com\/aspnet\/Announcements\/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.1.0-preview2\">https:\/\/github.com\/aspnet\/Announcements\/issues?q=is%3Aopen+is%3Aissue+milestone%3A2.1.0-preview2<\/a><\/p>\n<p>Release notes, including known issues, are available at <a href=\"https:\/\/github.com\/aspnet\/Home\/releases\/tag\/2.1.0-preview2\">https:\/\/github.com\/aspnet\/Home\/releases\/tag\/2.1.0-preview2<\/a><\/p>\n<h2 id=\"givingfeedback\">Giving feedback<\/h2>\n<p>The main purpose of providing previews like this is to solicit feedback from customers such that we can refine and improve the changes in time for the final release. We intend to ship a release candidate in about a month (with &#8220;go-live&#8221; license and support) before the final RTW release.<\/p>\n<p>Please provide feedback by logging issues in the appropriate repository at <a href=\"https:\/\/github.com\/aspnet\">https:\/\/github.com\/aspnet<\/a> or <a href=\"https:\/\/github.com\/dotnet\">https:\/\/github.com\/dotnet<\/a>. The posts on specific topics above will provide direct links to the most appropriate place to log issues for the features detailed.<\/p>\n<h2 id=\"newfeatures\">New features<\/h2>\n<p>You can see a summary of the new features planned in 2.1 in the <a href=\"https:\/\/blogs.msdn.microsoft.com\/webdev\/2018\/02\/02\/asp-net-core-2-1-roadmap\/\">roadmap post<\/a> we published previously.<\/p>\n<p>Following are details of additions and changes in preview2 itself.<\/p>\n<h3><a href=\"#improvements-to-razor-ui-libraries\" id=\"user-content-improvements-to-razor-ui-libraries\" class=\"anchor\"><\/a>Improvements to Razor UI libraries<\/h3>\n<p>New in ASP.NET Core 2.1 is support for building <a href=\"https:\/\/blogs.msdn.microsoft.com\/webdev\/2018\/03\/01\/asp-net-core-2-1-razor-ui-in-class-libraries\/\">Razor UI in class libraries<\/a>. In Preview 2 we&#8217;ve made various improvements to simplify authoring Razor UI in class libraries through the introduction of the new Razor SDK.<\/p>\n<p>To create a Razor UI class library, start with a .NET Standard class library and then update the SDK in the .csproj file to be <code>Microsoft.NET.SDK.Razor<\/code>. The Razor SDK adds the necessary build targets and properties so that Razor files can be included in the build.<\/p>\n<p>To create your own Razor UI class library:<\/p>\n<ol>\n<li>Create a .NET Standard class library\n<pre><code>dotnet new classlib -o ClassLibrary1\r\n<\/code><\/pre>\n<\/li>\n<li>Add a reference from the class library to <code>Microsoft.AspNetCore.Mvc<\/code>\n<pre><code>dotnet add ClassLibrary1 package Microsoft.AspNetCore.Mvc -v 2.1.0-preview2-final\r\n<\/code><\/pre>\n<\/li>\n<li>Open <code>ClassLibrary1.csproj<\/code> and change the SDK to be <code>Microsoft.NET.SDK.Razor<\/code>\n<div class=\"highlight highlight-text-xml\">\n<pre>&lt;<span class=\"pl-ent\">Project<\/span> <span class=\"pl-e\">Sdk<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Microsoft.NET.Sdk.Razor<span class=\"pl-pds\">\"<\/span><\/span>&gt;\r\n\r\n  &lt;<span class=\"pl-ent\">PropertyGroup<\/span>&gt;\r\n    &lt;<span class=\"pl-ent\">TargetFramework<\/span>&gt;netstandard2.0&lt;\/<span class=\"pl-ent\">TargetFramework<\/span>&gt;\r\n  &lt;\/<span class=\"pl-ent\">PropertyGroup<\/span>&gt;\r\n\r\n  &lt;<span class=\"pl-ent\">ItemGroup<\/span>&gt;\r\n    &lt;<span class=\"pl-ent\">PackageReference<\/span> <span class=\"pl-e\">Include<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Microsoft.AspNetCore.Mvc<span class=\"pl-pds\">\"<\/span><\/span> <span class=\"pl-e\">Version<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>2.1.0-preview2-final<span class=\"pl-pds\">\"<\/span><\/span> \/&gt;\r\n  &lt;\/<span class=\"pl-ent\">ItemGroup<\/span>&gt;\r\n\r\n&lt;\/<span class=\"pl-ent\">Project<\/span>&gt;<\/pre>\n<\/div>\n<\/li>\n<li>Add a Razor page and a view imports file to the class library\n<pre><code>dotnet new page -n Test -na ClassLibrary1.Pages -o ClassLibrary1\/Pages\r\ndotnet new viewimports -na ClassLibrary1.Pages -o ClassLibrary1\/Pages\r\n<\/code><\/pre>\n<\/li>\n<li>Update the Razor page to add some markup\n<div class=\"highlight highlight-text-html-basic\">\n<pre>@page\r\n\r\n&lt;<span class=\"pl-ent\">h1<\/span>&gt;Hello from a Razor UI class library!&lt;\/<span class=\"pl-ent\">h1<\/span>&gt;<\/pre>\n<\/div>\n<\/li>\n<li>Build the class library to ensure there are no build errors\n<pre><code>dotnet build ClassLibrary1\r\n<\/code><\/pre>\n<p>In the build output you should see both <code>ClassLibrary1.dll<\/code> and <code>ClassLibrary1.Views.dll<\/code>, where the latter contains the compiled Razor content.<\/li>\n<\/ol>\n<p>Now let&#8217;s use our Razor UI library from an ASP.NET Core web app.<\/p>\n<ol>\n<li>Create a ASP.NET Core Web Application\n<pre><code>dotnet new razor -o WebApplication1\r\n<\/code><\/pre>\n<\/li>\n<li>Create a solution file and add both projects to the solution\n<pre><code>dotnet new sln\r\ndotnet sln add WebApplication1\r\ndotnet sln add ClassLibrary1\r\n<\/code><\/pre>\n<\/li>\n<li>Add a reference from the web application to the class library\n<pre><code>dotnet add WebApplication1 reference ClassLibrary1\r\n<\/code><\/pre>\n<\/li>\n<li>Build and run the web app\n<pre><code>cd WebApplication1\r\ndotnet run\r\n<\/code><\/pre>\n<\/li>\n<li>Browse to <code>\/test<\/code> to see your page from your Razor UI class library<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/63f47dcfb772c2c6616cdc948a6dd0b745843248\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f72617a6f722d75692d636c6173736c69622e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Razor UI class library\" style=\"max-width: 100%\" \/><\/a><\/li>\n<\/ol>\n<p>Looks great! Now we can package up our Razor UI class library and share it with others.<\/p>\n<ol>\n<li>Create a package for the Razor UI class library\n<pre><code>cd ..\r\ndotnet pack ClassLibrary1\r\n<\/code><\/pre>\n<\/li>\n<li>Create a new web app and add a package reference to our Razor UI class library package\n<pre><code>dotnet new razor -o WebApplication2\r\ndotnet add WebApplication2 package ClassLibrary1 --source &lt;current path&gt;\/ClassLibrary1\/bin\/Debug\r\n<\/code><\/pre>\n<\/li>\n<li>Run the new app with the package reference\n<pre><code>cd WebApplication2\r\ndotnet run\r\n<\/code><\/pre>\n<\/li>\n<li>Browse to <code>\/test<\/code> for the new app to see that your package is getting used.<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/1c960c4ee1827ce0e3bfc0164e6b2f2a86f118f9\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f72617a6f722d75692d636c6173736c6962322e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Razor UI class library package\" style=\"max-width: 100%\" \/><\/a><\/li>\n<\/ol>\n<p>Publish your package to NuGet to share your handiwork with everyone.<\/p>\n<h3><a href=\"#razor-compilation-on-build\" id=\"user-content-razor-compilation-on-build\" class=\"anchor\"><\/a>Razor compilation on build<\/h3>\n<p>Razor compilation is now part of every build. This means that Razor compilation issues are caught at design time instead of when the app is first run. Compiling the Razor views and pages also significantly speeds up startup time. And even though your view and pages are built up front, you can still modify your Razor files at runtime and see them updated without having to restart the app.<\/p>\n<h3><a href=\"#scaffold-identity-into-an-existing-project\" id=\"user-content-scaffold-identity-into-an-existing-project\" class=\"anchor\"><\/a>Scaffold identity into an existing project<\/h3>\n<p>The latest preview of Visual Studio 2017 (15.7 Preview 3) supports scaffolding identity into an existing application and overriding specific pages from the <a href=\"https:\/\/blogs.msdn.microsoft.com\/webdev\/2018\/03\/02\/aspnetcore-2-1-identity-ui\/\" rel=\"nofollow\">default identity UI<\/a>.<\/p>\n<p>To scaffold identity into an existing application:<\/p>\n<ol>\n<li>Right-click on the project in the solution explorer and select <code>Add -&gt; New Scaffolded Item...<\/code><\/li>\n<li>Select the Identity scaffolder and click Add.<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/e67d2ff5bc98ee491fbd30a512c394222bc91009\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f6164642d73636166666f6c642d6964656e746974792e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Add Scaffold Identity\" style=\"max-width: 100%\" \/><\/a><\/li>\n<li>The Add Identity dialog appears. Leave the layout unspecified. Check the checkbox in the override file list for &#8220;LoginPartial&#8221;. Also click the &#8220;+&#8221; button to create a new data context class and a custom identity user class. Click Add to run the identity scaffolder.<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/7e15ae3beb984377f6440a3049fae9319e642e12\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f6164642d6964656e746974792d64656661756c74312e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Add default Identity\" style=\"max-width: 100%\" \/><\/a>The scaffolder will add an Identity area to your application that configures identity and also will update the layout to include the login partial.<\/li>\n<li>Update the <code>Configure<\/code> method in <code>Startup.cs<\/code> to add the database error page when in development and also the authentication middleware before invoking MVC.\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">public<\/span> <span class=\"pl-k\">void<\/span> <span class=\"pl-en\">Configure<\/span>(<span class=\"pl-en\">IApplicationBuilder<\/span> <span class=\"pl-smi\">app<\/span>, <span class=\"pl-en\">IHostingEnvironment<\/span> <span class=\"pl-smi\">env<\/span>)\r\n{\r\n    <span class=\"pl-k\">if<\/span> (env.IsDevelopment())\r\n    {\r\n        app.UseDeveloperExceptionPage();\r\n        app.UseDatabaseErrorPage();\r\n    }\r\n    <span class=\"pl-k\">else<\/span>\r\n    {\r\n        app.UseExceptionHandler(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>\/Error<span class=\"pl-pds\">\"<\/span><\/span>);\r\n        app.UseHsts();\r\n    }\r\n\r\n    app.UseHttpsRedirection();\r\n    app.UseStaticFiles();\r\n    app.UseCookiePolicy();\r\n\r\n    app.UseAuthentication();\r\n\r\n    app.UseMvc();\r\n}<\/pre>\n<\/div>\n<\/li>\n<li>The generated <code>_ViewStart.cshtml<\/code> in this preview release contains an unfortunate typo in the specified layout path. Fixup the layout path to be <code>\/Pages\/Shared\/_Layout.cshtml<\/code>. This will be fixed in the next release.<\/li>\n<li>Select <code>Tools -&gt; NuGet Package Manager -&gt; Package Manager Console<\/code> and run the following commands to add an EF migration and create the database.\n<pre><code>Add-Migration Initial\r\nUpdate-Database\r\n<\/code><\/pre>\n<\/li>\n<li>Build and run the application. You should now be able to register and login users.<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/fca85cd6bb51a4777cd6883e4b8678788308a9ed\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f7765622d6170702d6c6f67696e2e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Web app login\" style=\"max-width: 100%\" \/><\/a><\/li>\n<\/ol>\n<h3><a href=\"#customize-default-identity-ui\" id=\"user-content-customize-default-identity-ui\" class=\"anchor\"><\/a>Customize default Identity UI<\/h3>\n<p>The identity scaffolder can also scaffold individual pages to override the default identity UI. For example, you can use a custom user type and update the identity UI to add additional user properties.<\/p>\n<ol>\n<li>In the solution explorer right-click on the project you added Identity to in the previous section and select <code>Add -&gt; New Scaffolded Item...<\/code><\/li>\n<li>Select the Identity scaffolder and click Add.<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/e67d2ff5bc98ee491fbd30a512c394222bc91009\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f6164642d73636166666f6c642d6964656e746974792e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Add Scaffold Identity\" style=\"max-width: 100%\" \/><\/a><\/li>\n<li>The Add Identity dialog appears. Again leave the layout unspecified. Check the checkbox for the <code>AccountManageIndex<\/code> file. For the data context select the data context we created in the previous section. Click Add to run the identity scaffolder.<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/2a4218380351bbb89d190688c64f715c7c58241d\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f6f766572726964652d6d616e6167652e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Override Manage\" style=\"max-width: 100%\" \/><\/a><\/li>\n<li>Fixup the layout path in <code>_ViewStart.cshtml<\/code> as we did previously.<\/li>\n<li>Open the generated <code>\/Areas\/Identity\/Pages\/Account\/Manage\/Index.cshtml.cs<\/code> file and replace references <code>IdentityUser<\/code> with your custom user type (<code>ScaffoldIdentityWebAppUser<\/code>). This manual edit is necessary in this preview, but will be handled by the identity scaffolder in a future update.<\/li>\n<li>Update <code>ScaffoldIdentityWebAppUser<\/code> to add an <code>Age<\/code> property.\n<div class=\"highlight highlight-source-cs\">\n<pre>    <span class=\"pl-k\">public<\/span> <span class=\"pl-k\">class<\/span> <span class=\"pl-en\">ScaffoldIdentityWebAppUser<\/span> : <span class=\"pl-en\">IdentityUser<\/span>\r\n    {\r\n        <span class=\"pl-k\">public <\/span><span class=\"pl-k\">int<\/span> <span class=\"pl-en\">Age<\/span> { <span class=\"pl-k\">get<\/span>; <span class=\"pl-k\">set<\/span>; }\r\n    }<\/pre>\n<\/div>\n<\/li>\n<li>Update the <code>InputModel<\/code> in <code>\/Areas\/Identity\/Pages\/Account\/Manage\/Index.cshtml.cs<\/code> to add a new <code>Age<\/code> property.\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">public<\/span> <span class=\"pl-k\">class<\/span> <span class=\"pl-en\">InputModel<\/span>\r\n{\r\n    [Required]\r\n    [EmailAddress]\r\n    <span class=\"pl-k\">public <\/span><span class=\"pl-k\">string<\/span> <span class=\"pl-en\">Email<\/span> { <span class=\"pl-k\">get<\/span>; <span class=\"pl-k\">set<\/span>; }\r\n\r\n    [Phone]\r\n    [Display(Name = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Phone number<span class=\"pl-pds\">\"<\/span><\/span>)]\r\n    <span class=\"pl-k\">public <\/span><span class=\"pl-k\">string<\/span> <span class=\"pl-en\">PhoneNumber<\/span> { <span class=\"pl-k\">get<\/span>; <span class=\"pl-k\">set<\/span>; }\r\n    \r\n    [Range(<span class=\"pl-c1\">0<\/span>, <span class=\"pl-c1\">120<\/span>)]\r\n    <span class=\"pl-k\">public <\/span><span class=\"pl-k\">int<\/span> <span class=\"pl-en\">Age<\/span> { <span class=\"pl-k\">get<\/span>; <span class=\"pl-k\">set<\/span>; }\r\n}<\/pre>\n<\/div>\n<\/li>\n<li>Update <code>\/Areas\/Identity\/Pages\/Account\/Manage\/Index.cshtml<\/code> to add a field for setting the Age property. You can the field below the existing phone number field.\n<div class=\"highlight highlight-text-html-basic\">\n<pre>&lt;<span class=\"pl-ent\">div<\/span> <span class=\"pl-e\">class<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>form-group<span class=\"pl-pds\">\"<\/span><\/span>&gt;\r\n    &lt;<span class=\"pl-ent\">label<\/span> <span class=\"pl-e\">asp-for<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Input.Age<span class=\"pl-pds\">\"<\/span><\/span>&gt;&lt;\/<span class=\"pl-ent\">label<\/span>&gt;\r\n    &lt;<span class=\"pl-ent\">input<\/span> <span class=\"pl-e\">asp-for<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Input.Age<span class=\"pl-pds\">\"<\/span><\/span> <span class=\"pl-e\">class<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>form-control<span class=\"pl-pds\">\"<\/span><\/span> \/&gt;\r\n    &lt;<span class=\"pl-ent\">span<\/span> <span class=\"pl-e\">asp-validation-for<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Input.Age<span class=\"pl-pds\">\"<\/span><\/span> <span class=\"pl-e\">class<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>text-danger<span class=\"pl-pds\">\"<\/span><\/span>&gt;&lt;\/<span class=\"pl-ent\">span<\/span>&gt;\r\n&lt;\/<span class=\"pl-ent\">div<\/span>&gt;<\/pre>\n<\/div>\n<\/li>\n<li>Update the <code>OnPostAsync<\/code> method in <code>\/Areas\/Identity\/Pages\/Account\/Manage\/Index.cshtml.cs<\/code> to save the user&#8217;s age to the database:\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">if<\/span> (<span class=\"pl-en\">Input.Age<\/span> &gt;= 0 &amp;&amp; Input.Age &lt; 120)\r\n{\r\n    user.Age = Input.Age;\r\n    <span class=\"pl-k\">await<\/span> _userManager.UpdateAsync(user);\r\n}<\/pre>\n<\/div>\n<\/li>\n<li>Update the <code>OnGetAsync<\/code> method in to initialize the <code>InputModel<\/code> with the user&#8217;s age from the database:\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-en\">Input<\/span> = new InputModel\r\n{\r\n    Email = user.Email,\r\n    PhoneNumber = user.PhoneNumber,\r\n    Age = user.Age\r\n};<\/pre>\n<\/div>\n<\/li>\n<li>Select <code>Tools -&gt; NuGet Package Manager -&gt; Package Manager Console<\/code> and run the following commands to add an EF migration and update the database.\n<pre><code>Add-Migration UserAge\r\nUpdate-Database\r\n<\/code><\/pre>\n<\/li>\n<li>Build and run the app. Register a user and then set the user&#8217;s age on the manage page:<a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/43c3254be1d1574222b2c806e945765642e61d40\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f7765622d6170702d6d616e6167652e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Web app manage\" style=\"max-width: 100%\" \/><\/a><\/li>\n<\/ol>\n<h3><a href=\"#improvements-to-apicontroller-parameter-binding\" id=\"user-content-improvements-to-apicontroller-parameter-binding\" class=\"anchor\"><\/a>Improvements to [ApiController] parameter binding<\/h3>\n<p>Applying <code>[ApiController]<\/code> to your controller sets up convenient conventions for how parameters get bound to request data. In Preview 2 we&#8217;ve made a number of improvements to how these conventions work based on feedback:<\/p>\n<ul>\n<li><code>[FromBody]<\/code> will no longer be inferred for complex types with specific semantics, like <code>CancellationToken<\/code><\/li>\n<li>Multiple <code>[FromBody]<\/code> parameters will result in an exception<\/li>\n<li>When there are multiple routes for an action parameters that match <em>any<\/em> route value will be considered <code>[FromRoute]<\/code><\/li>\n<\/ul>\n<h3><a href=\"#provide-constructed-model-type-to-the-partial-tag-helper\" id=\"user-content-provide-constructed-model-type-to-the-partial-tag-helper\" class=\"anchor\"><\/a>Provide constructed model type to the partial tag helper<\/h3>\n<p>The partial tag helper now supports passing a model instance through the new <code>model<\/code> attribute.<\/p>\n<div class=\"highlight highlight-text-html-basic\">\n<pre>&lt;<span class=\"pl-ent\">partial<\/span> <span class=\"pl-e\">name<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>MovieView<span class=\"pl-pds\">\"<\/span><\/span> <span class=\"pl-e\">model<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>new Movie() { Name=\"Ghostsmashers\" }<span class=\"pl-pds\">'<\/span><\/span> \/&gt;<\/pre>\n<\/div>\n<p>The <code>asp-for<\/code> attribute was also renamed to <code>for<\/code>.<\/p>\n<h3><a href=\"#analyzer-to-warn-about-using-htmlpartial-usage\" id=\"user-content-analyzer-to-warn-about-using-htmlpartial-usage\" class=\"anchor\"><\/a>Analyzer to warn about using Html.Partial usage<\/h3>\n<p>Starting in this preview, calls to <code>Html.Partial<\/code> will result in an analyzer warning due to the potential for deadlocks.<\/p>\n<p><a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/ef0a1511ce45ea61356d952ca79da18af45a404d\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f7061727469616c2d7761726e696e672e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Html.Partial warning\" style=\"max-width: 100%\" \/><\/a><\/p>\n<p>Calls to <code>@Html.Partial(...)<\/code> should be replaced by <code>@await Html.PartialAsync(...)<\/code> or use the partial tag helper instead (<code>&lt;partial name=\"...\" \/&gt;<\/code>).<\/p>\n<h3><a href=\"#option-to-opt-out-of-https\" id=\"user-content-option-to-opt-out-of-https\" class=\"anchor\"><\/a>Option to opt-out of HTTPS<\/h3>\n<p>HTTPS is enabled by default in ASP.NET Core 2.1 and the out of the box templates include support for handling HTTPS redirects and HSTS. But in some backend services where HTTPS is being handled externally at the edge using HTTPS at each node is not needed.<\/p>\n<p>In Preview 2 you can disable HTTPS when creating new ASP.NET Core projects by passing the <code>--no-https<\/code> option at the command-line. In Visual Studio this option is surfaced from the new ASP.NET Core Web Application dialog.<\/p>\n<p><a target=\"_blank\" href=\"https:\/\/camo.githubusercontent.com\/ceface9e24a38d8e0db6a525a874ef3b3c9a8b56\/68747470733a2f2f6d73646e7368617265642e626c6f622e636f72652e77696e646f77732e6e65742f6d656469612f323031382f30342f64697361626c652d68747470732e706e67\" rel=\"noopener\"><img decoding=\"async\" src=\"\" alt=\"Disable HTTPS\" style=\"max-width: 100%\" \/><\/a><\/p>\n<h3><a href=\"#razor-pages-handling-of-head-requests\" id=\"user-content-razor-pages-handling-of-head-requests\" class=\"anchor\"><\/a>Razor Pages handling of HEAD requests<\/h3>\n<p>Razor Pages will now fall back to calling a matching GET page handler if no HEAD page handler is defined.<\/p>\n<h3><a href=\"#updated-to-jsonnet-11\" id=\"user-content-updated-to-jsonnet-11\" class=\"anchor\"><\/a>Updated to Json.NET 11<\/h3>\n<p>We&#8217;ve updated to Json.NET 11 to benefit from the latest Json.NET features and improvements.<\/p>\n<h3><a href=\"#added-web-api-client-to-aspnet-core-meta-packages\" id=\"user-content-added-web-api-client-to-aspnet-core-meta-packages\" class=\"anchor\"><\/a>Added Web API Client to ASP.NET Core meta-packages<\/h3>\n<p>The <a href=\"https:\/\/nuget.org\/packages\/Microsoft.AspNet.WebApi.Client\" rel=\"nofollow\">Web API Client<\/a> is now included by the ASP.NET Core meta-packages for your convenience. This package provides convenient methods for handling formatting and deserialization when calling web APIs.<\/p>\n<h3><a href=\"#viewdata-backed-properties\" id=\"user-content-viewdata-backed-properties\" class=\"anchor\"><\/a>ViewData backed properties<\/h3>\n<p>Properties decorated with <code>[ViewData]<\/code> on controllers, page models, and Razor Pages provide a convenient way to add data that can be read by views and pages.<\/p>\n<p>For example, to specify the title for a page and have it show up in the page layout you can define a property on your page model that is decorated with <code>[ViewData]<\/code>:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">public<\/span> <span class=\"pl-k\">class<\/span> <span class=\"pl-en\">AboutModel<\/span> : <span class=\"pl-en\">PageModel<\/span>\r\n{\r\n    [ViewData]\r\n    <span class=\"pl-k\">public <\/span><span class=\"pl-k\">string<\/span> <span class=\"pl-en\">Title<\/span> { <span class=\"pl-k\">get<\/span>; } = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>About<span class=\"pl-pds\">\"<\/span><\/span>;\r\n}<\/pre>\n<\/div>\n<p>The title can be accessed from the about page as a model property:<\/p>\n<div class=\"highlight highlight-text-html-basic\">\n<pre>@page\r\n@model AboutModel\r\n\r\n&lt;<span class=\"pl-ent\">h2<\/span>&gt;@Model.Title&lt;\/<span class=\"pl-ent\">h2<\/span>&gt;<\/pre>\n<\/div>\n<p>Then, in the layout, the title can be read from the <code>ViewData<\/code> dictionary:<\/p>\n<div class=\"highlight highlight-text-html-basic\">\n<pre>&lt;!DOCTYPE html&gt;\r\n&lt;<span class=\"pl-ent\">html<\/span>&gt;\r\n&lt;<span class=\"pl-ent\">head<\/span>&gt;\r\n    &lt;<span class=\"pl-ent\">meta<\/span> <span class=\"pl-e\">charset<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>utf-8<span class=\"pl-pds\">\"<\/span><\/span> \/&gt;\r\n    &lt;<span class=\"pl-ent\">meta<\/span> <span class=\"pl-e\">name<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>viewport<span class=\"pl-pds\">\"<\/span><\/span> <span class=\"pl-e\">content<\/span>=<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>width=device-width, initial-scale=1.0<span class=\"pl-pds\">\"<\/span><\/span> \/&gt;\r\n    &lt;<span class=\"pl-ent\">title<\/span>&gt;@ViewData[\"Title\"] - WebApplication2&lt;\/<span class=\"pl-ent\">title<\/span>&gt;\r\n...<\/pre>\n<\/div>\n<h3><a href=\"#prebuilt-ui-libraries-for-azure-ad-and-azure-ad-b2c\" id=\"user-content-prebuilt-ui-libraries-for-azure-ad-and-azure-ad-b2c\" class=\"anchor\"><\/a>Prebuilt UI libraries for Azure AD and Azure AD B2C<\/h3>\n<p>The UI and components required for setting up authentication with Azure AD or Azure AD B2C are now available in this preview as prebuilt packages:<\/p>\n<ul>\n<li><a href=\"https:\/\/nuget.org\/packages\/Microsoft.AspNetCore.Authentication.AzureAD.UI\" rel=\"nofollow\">Microsoft.AspNetCore.Authentication.AzureAD.UI<\/a><\/li>\n<li><a href=\"https:\/\/nuget.org\/packages\/Microsoft.AspNetCore.Authentication.AzureADB2C.UI\" rel=\"nofollow\">Microsoft.AspNetCore.Authentication.AzureADB2C.UI<\/a><\/li>\n<\/ul>\n<p>These packages can be used to setup authentication with Azure AD or Azure AD B2C in any project.<\/p>\n<h3><a href=\"#updates-to-launchsettingsjson\" id=\"user-content-updates-to-launchsettingsjson\" class=\"anchor\"><\/a>Updates to launchSettings.json<\/h3>\n<p>The <code>applicationUrl<\/code> property in <code>launchSettings.json<\/code> can now be used to specify a semicolon separated list of server URLs.<\/p>\n<div class=\"highlight highlight-source-json\">\n<pre><span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>WebApplication1<span class=\"pl-pds\">\"<\/span><\/span>: {\r\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>commandName<span class=\"pl-pds\">\"<\/span><\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Project<span class=\"pl-pds\">\"<\/span><\/span>,\r\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>launchBrowser<span class=\"pl-pds\">\"<\/span><\/span>: <span class=\"pl-c1\">true<\/span>,\r\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>applicationUrl<span class=\"pl-pds\">\"<\/span><\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>https:\/\/localhost:5001;http:\/\/localhost:5000<span class=\"pl-pds\">\"<\/span><\/span>,\r\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>environmentVariables<span class=\"pl-pds\">\"<\/span><\/span>: {\r\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>ASPNETCORE_ENVIRONMENT<span class=\"pl-pds\">\"<\/span><\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Development<span class=\"pl-pds\">\"<\/span><\/span>\r\n  }\r\n}<\/pre>\n<\/div>\n<h3><a href=\"#deprecating-aspnetcore-and-aspnetcore-build-docker-images\" id=\"user-content-deprecating-aspnetcore-and-aspnetcore-build-docker-images\" class=\"anchor\"><\/a>Deprecating aspnetcore and aspnetcore-build Docker images<\/h3>\n<p>Starting with .NET Core 2.1.0-preview2, we intend to migrate from using the <code>microsoft\/aspnetcore-build<\/code> and <code>microsoft\/aspnetcore<\/code> Docker repos to the <code>microsoft\/dotnet<\/code> Docker repo. We will continue to ship patches and security fixes for the existing aspnetcore images but any new images for 2.1 and higher will be pushed to <code>microsoft\/dotnet<\/code>.<\/p>\n<p>Dockerfiles using microsoft\/aspnetcore:&lt;version&gt; should change to microsoft\/dotnet:&lt;version&gt;-aspnetcore-runtime.<\/p>\n<p>Dockerfiles using microsoft\/aspnetcore-build:&lt;version&gt; that do not require Node should change to microsoft\/dotnet:&lt;version&gt;-sdk.<\/p>\n<p>Dockerfiles using microsoft\/aspnetcore-build that require Node will need to handle that in their own images, either with a multi-stage build or by installing Node themselves.<\/p>\n<p>For more details on the change, including some example Dockerfiles and a link to a discussion issue, you can see the announcement here: <a href=\"https:\/\/github.com\/aspnet\/Announcements\/issues\/298\">https:\/\/github.com\/aspnet\/Announcements\/issues\/298<\/a><\/p>\n<h3>Kestrel support for SNI<\/h3>\n<p>Server Name Indication (SNI) can be used to allow hosting multiple domains on the same IP address and port. It does this by sending the expected host name in the TLS handshake so that the server can provide the correct certificate. Kestrel now supports this via the ServerCertificateSelector callback. This is invoked once per connection to allow you to inspect the host name and select the most appropriate certificate.<\/p>\n<pre>WebHost.CreateDefaultBuilder()\r\n    .UseKestrel((context, options) =&gt;\r\n    {\r\n        options.ListenAnyIP(5005, listenOptions =&gt;\r\n        {\r\n            listenOptions.UseHttps(httpsOptions =&gt;\r\n            {\r\n                var localhostCert = CertificateLoader.LoadFromStoreCert(\"localhost\", \"My\", StoreLocation.CurrentUser, allowInvalid: true);\r\n                var exampleCert = CertificateLoader.LoadFromStoreCert(\"example.com\", \"My\", StoreLocation.CurrentUser, allowInvalid: true);\r\n                var subExampleCert = CertificateLoader.LoadFromStoreCert(\"sub.example.com\", \"My\", StoreLocation.CurrentUser, allowInvalid: true);\r\n                var certs = new Dictionary(StringComparer.OrdinalIgnoreCase);\r\n                certs[\"localhost\"] = localhostCert;\r\n                certs[\"example.com\"] = exampleCert;\r\n                certs[\"sub.example.com\"] = subExampleCert;\r\n\r\n                httpsOptions.ServerCertificateSelector = (features, name) =&gt;\r\n                {\r\n                    if (name != null &amp;&amp; certs.TryGetValue(name, out var cert))\r\n                    {\r\n                        return cert;\r\n                    }\r\n\r\n                    return exampleCert;\r\n                };\r\n            });\r\n        });\r\n    });\r\n<\/pre>\n<p>SNI support requires running on netcoreapp2.1. On netcoreapp2.0 and net461 the callback will be invoked but the name will always be null. The name will also be null if the client did not provide this optional parameter.<\/p>\n<h3>HTTPClient Factory and Polly<\/h3>\n<p>As we discussed in our Preview1 post on HttpClient factory, we had planned to provide a package that integrates Polly with HTTPClient factory. In Preview2 the majority of that integration is now available. In order to try this out you need to add the Polly integration NuGet package Microsoft.Extensions.Http.Polly:<\/p>\n<pre>&lt;ItemGroup&gt;\r\n &lt;PackageReference Include=\"Microsoft.AspNetCore.App\" Version=\"2.1.0-preview2-final\" \/&gt;\r\n &lt;PackageReference Include=\"Microsoft.Extensions.Http.Polly\" Version=\"2.1.0-preview2-final\" \/&gt;\r\n&lt;\/ItemGroup&gt;\r\n<\/pre>\n<p>Then you can write code like the following:<\/p>\n<pre>services.AddHttpClient(client =&gt; client.BaseAddress = new Uri(Configuration[\"ValuesServiceUri\"]))\r\n        .AddTransientHttpErrorPolicy(policyBuilder =&gt; policyBuilder.RetryAsync(2));\r\n<\/pre>\n<p>With this code we would automatically retry twice before failing any requests made using the ValuesClient, the ValuesClient here being the same as the one we showed in the Preview1 post. For more information on Polly and what policies are available, you can read the <a href=\"https:\/\/github.com\/App-vNext\/Polly\/wiki\">Polly docs here<\/a><\/p>\n<p>The Polly.PolicyBuilder provided to AddTransientHttpErrorPolicy has been preconfigured to handle errors in the following categories:<\/p>\n<ul>\n<li>Network failures (System.Net.Http.HttpRequestException)<\/li>\n<li>HTTP 5XX status codes (server errors)<\/li>\n<li>HTTP 408 status code (request timeout)<\/li>\n<\/ul>\n<p>You can use the more general AddPolicyHandler method to add a Policy that handles different conditions. In general AddTransientHttpErrorPolicy is good for reactive policies (Retry, CircuitBreaker, Fallback), which we think are likely to be the most commonly used. However, the AddPollyHandler API can be used to add any Polly policy handling any conditions that you want.<\/p>\n<p>The policy will be cached indefinitely per named client, which allows policies such as CircuitBreaker to function.<\/p>\n<p>If you want to share a single Policy across multiple named clients then you should create a Policy and then pass it into multiple calls, for example:<\/p>\n<pre>var retryPolicy = Policy.Handle&lt;HttpRequestException&gt;()\r\n                        .OrResult&lt;HttpResponseMessage&gt;(message =&gt; !message.IsSuccessStatusCode)\r\n                        .WaitAndRetry(new[]\r\n                        {\r\n                           TimeSpan.FromSeconds(1),\r\n                           TimeSpan.FromSeconds(2),\r\n                           TimeSpan.FromSeconds(3)\r\n                         });\r\n\r\nservices.AddHttpClient()\r\n        .AddPolicyHandler(retryPolicy);\r\n\r\nservices.AddHttpClient(\"otherClient\")\r\n        .AddPolicyHandler(retryPolicy);\r\n<\/pre>\n<p>With this code we will Retry all HttpRequestExceptions and non success status codes 3 times, with a slightly longer pause between each try. We could change to an exponential backoff retry policy by changing the code slightly:<\/p>\n<pre>var retryPolicy = Policy.Handle&lt;HttpRequestException&gt;()\r\n                        .OrResult&lt;HttpResponseMessage&gt;(message =&gt; !message.IsSuccessStatusCode)\r\n                        .WaitAndRetryAsync(3, retryAttempt =&gt; \r\n                          TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) \r\n                        );\r\n<\/pre>\n<p>For documentation on Polly and the policies available you can read the <a href=\"https:\/\/github.com\/App-vNext\/Polly\/wiki\">Polly wiki<\/a>.<\/p>\n<h2 id=\"migrating\">Migrating an ASP.NET Core 2.0.x project to 2.1.0-preview2<\/h2>\n<p>Follow these steps to migrate an existing ASP.NET Core 2.0.x project to 2.1.0-preview2:<\/p>\n<ol>\n<li>Open the project&#8217;s CSPROJ file and change the value of the <code>&lt;TargetFramework&gt;<\/code> element to <code>netcoreapp2.1<\/code>\n<ul>\n<li>Projects targeting .NET Framework rather than .NET Core, e.g. <code>net471<\/code>, don&#8217;t need to do this<\/li>\n<\/ul>\n<\/li>\n<li>In the same file, update the versions of the various <code>&lt;PackageReference&gt;<\/code> elements for any <code>Microsoft.AspNetCore<\/code>, <code>Microsoft.Extensions<\/code>, and <code>Microsoft.EntityFrameworkCore<\/code> packages to <code>2.1.0-preview2-final<\/code><\/li>\n<li>In the same file, remove any references to <code>&lt;DotNetCliToolReference&gt;<\/code> elements for any <code>Microsoft.AspNetCore<\/code>, <code>Microsoft.VisualStudio<\/code>, and <code>Microsoft.EntityFrameworkCore<\/code> packages. These tools are now deprecated and are replaced by global tools.<\/li>\n<\/ol>\n<p>That should be enough to get the project building and running against 2.1.0-preview2. The following steps will change your project to use new code-based idioms that are recommended in 2.1<\/p>\n<ol>\n<li>Open the <code>Program.cs<\/code> file<\/li>\n<li>Rename the <code>BuildWebHost<\/code> method to <code>CreateWebHostBuilder<\/code>, change its return type to <code>IWebHostBuilder<\/code>, and remove the call to <code>.Build()<\/code> in its body<\/li>\n<li>Update the call in <code>Main<\/code> to call the renamed <code>CreateWebHostBuilder<\/code> method like so: <code>CreateWebHostBuilder(args).Build().Run();<\/code><\/li>\n<li>Open the <code>Startup.cs<\/code> file<\/li>\n<li>In the <code>ConfigureServices<\/code> method, change the call to add MVC services to set the compatibility version to 2.1 like so: <code>services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);<\/code><\/li>\n<li>In the <code>Configure<\/code> method, add a call to add the HSTS middleware <strong>after<\/strong> the exception handler middleware: <code>app.UseHsts();<\/code><\/li>\n<li>Staying in the <code>Configure<\/code> method, add a call to add the HTTPS redirection middleware <strong>before<\/strong> the static files middleware: <code>app.UseHttpsRedirection();<\/code><\/li>\n<li>Open the project propery pages (right-mouse click on project in Visual Studio Solution Explorer and select &#8220;Properties&#8221;)<\/li>\n<li>Open the &#8220;Debug&#8221; tab and in the IIS Express profile, check the &#8220;Enable SSL&#8221; checkbox and save the changes\n<ul><\/ul>\n<\/li>\n<\/ol>\n<p>Note that some projects might require more steps depending on the options selected when the project was created, or packages added since. You might like to try creating a new project targeting 2.1.0-preview2 (in Visual Studio or using <code>dotnet new<\/code> at the cmd line) with the same options to see what other things have changed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re very happy to announce that the second preview of the next minor release of ASP.NET Core and .NET Core is now available for you to try out. This second preview includes many refinements based on feedback we received from the first preview we released back in February. You can read about .NET Core [&hellip;]<\/p>\n","protected":false},"author":693,"featured_media":21382,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509],"tags":[7556],"class_list":["post-13015","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-asp-net-core-2-1-0-preview2"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re very happy to announce that the second preview of the next minor release of ASP.NET Core and .NET Core is now available for you to try out. This second preview includes many refinements based on feedback we received from the first preview we released back in February. You can read about .NET Core [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/13015","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\/693"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=13015"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/13015\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21382"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=13015"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=13015"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=13015"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}