{"id":13075,"date":"2018-04-17T10:59:55","date_gmt":"2018-04-17T17:59:55","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=13075"},"modified":"2018-04-17T10:59:55","modified_gmt":"2018-04-17T17:59:55","slug":"blazor-0-2-0-release-now-available","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/blazor-0-2-0-release-now-available\/","title":{"rendered":"Blazor 0.2.0 release now available"},"content":{"rendered":"<p>Just a few weeks ago we <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/get-started-building-net-web-apps-in-the-browser-with-blazor\/\">announced<\/a> the first preview release of an experimental web UI framework called <a href=\"https:\/\/github.com\/aspnet\/blazor\">Blazor<\/a>. Blazor enables full-stack web development using C# and WebAssembly. So far thousands of web developers have taken on the challenge to try out Blazor and done some pretty remarkable things:<\/p>\n<ul>\n<li>Started using Blazor to build <a href=\"https:\/\/github.com\/torhovland\/blazor-realworld-example-app\">RealWorld<\/a> web apps<\/li>\n<li>Used Blazor to <a href=\"https:\/\/twitter.com\/bjorndaniel\/status\/980527041652117504\">control a Christmas tree from a Raspberry Pi<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/riipah\/vocadb-lyrics-blazor-proto\">Built a Blazor app<\/a> for looking up lyrics to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Vocaloid\">vocaloid<\/a> music<\/li>\n<li><a href=\"https:\/\/github.com\/torhovland\/blazor-redux\">Integrated Blazor with the Redux<\/a> DevTools to do time-traveling debugging<\/li>\n<\/ul>\n<p>The feedback and support from the community has been tremendous. Thank you for your support!<\/p>\n<p>Today we are happy to announce the release of Blazor 0.2.0. Blazor 0.2.0 includes a whole bunch of improvements and new goodies to play with. <\/p>\n<p>New features in this release include:<\/p>\n<ul>\n<li>Build your own reusable component libraries<\/li>\n<li>Improved syntax for event handling and data binding<\/li>\n<li>Build on save in Visual Studio<\/li>\n<li>Conditional attributes<\/li>\n<li>HttpClient improvements<\/li>\n<\/ul>\n<p>A full list of the changes in this release can be found in the <a href=\"https:\/\/github.com\/aspnet\/Blazor\/releases\/tag\/0.2.0\">Blazor 0.2.0 release notes<\/a>.<\/p>\n<p>Many of these improvements were contributed by our friends in the community, for which, again, we thank you!<\/p>\n<p>You can find getting started instructions, docs, and tutorials for this release on our new documentation site at <a href=\"http:\/\/blazor.net\">http:\/\/blazor.net<\/a>.<\/p>\n<h3 id=\"get-blazor-0-2-0\">Get Blazor 0.2.0<\/h3>\n<p>To get setup with Blazor 0.2.0:<\/p>\n<ol>\n<li>Install the <a href=\"https:\/\/www.microsoft.com\/net\/download\/dotnet-core\/sdk-2.1.300-preview2\">.NET Core 2.1 Preview 2 SDK<\/a>.\n<ul>\n<li>If you&#039;ve installed the .NET Core 2.1 Preview 2 SDK previously, make sure the version is 2.1.300-preview2-<strong>008533<\/strong> by running <code>dotnet --version<\/code>. If not, then you need to install it again to get the updated build.<\/li>\n<\/ul>\n<\/li>\n<li>Install the latest <em>preview<\/em> of <a href=\"https:\/\/www.visualstudio.com\/vs\/preview\">Visual Studio 2017 (15.7)<\/a> with the <em>ASP.NET and web development<\/em> workload.\n<ul>\n<li>You can install Visual Studio previews side-by-side with an existing Visual Studio installation without impacting your existing development environment.<\/li>\n<\/ul>\n<\/li>\n<li>Install the <a href=\"https:\/\/go.microsoft.com\/fwlink\/?linkid=870389\">ASP.NET Core Blazor Language Services extension<\/a> from the Visual Studio Marketplace.<\/li>\n<\/ol>\n<p>To install the Blazor templates on the command-line:<\/p>\n<pre><code>dotnet new -<span class=\"hljs-selector-tag\">i<\/span> Microsoft<span class=\"hljs-selector-class\">.AspNetCore<\/span><span class=\"hljs-selector-class\">.Blazor<\/span><span class=\"hljs-selector-class\">.Templates<\/span>\n<\/code><\/pre>\n<h3 id=\"upgrade-a-blazor-project\">Upgrade a Blazor project<\/h3>\n<p>To upgrade an existing Blazor project from 0.1.0 to 0.2.0:<\/p>\n<ul>\n<li>Install all of the required bits listed above<\/li>\n<li>Update your Blazor package and .NET CLI tool references to 0.2.0<\/li>\n<li>Update the package reference for <code>Microsoft.AspNetCore.Razor.Design<\/code> to 2.1.0-preview2-final.<\/li>\n<li>Update the SDK version in <code>global.json<\/code> to <code>2.1.300-preview2-008533<\/code><\/li>\n<li>For Blazor client app projects, update the <code>Project<\/code> element in the project file to <code>&lt;Project Sdk=&quot;Microsoft.NET.Sdk.Web&quot;&gt;<\/code><\/li>\n<li>Update to the new bind and event handling syntax<\/li>\n<\/ul>\n<p>Your upgraded Blazor project file should look like this:<\/p>\n<pre><code class=\"lang-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Project<\/span> <span class=\"hljs-attr\">Sdk<\/span>=<span class=\"hljs-string\">\"Microsoft.NET.Sdk.Web\"<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>netstandard2.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">RunCommand<\/span>&gt;<\/span>dotnet<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">RunCommand<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">RunArguments<\/span>&gt;<\/span>blazor serve<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">RunArguments<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Microsoft.AspNetCore.Razor.Design\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"2.1.0-preview2-final\"<\/span> <span class=\"hljs-attr\">PrivateAssets<\/span>=<span class=\"hljs-string\">\"all\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Microsoft.AspNetCore.Blazor.Browser\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"0.2.0\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PackageReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Microsoft.AspNetCore.Blazor.Build\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"0.2.0\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DotNetCliToolReference<\/span> <span class=\"hljs-attr\">Include<\/span>=<span class=\"hljs-string\">\"Microsoft.AspNetCore.Blazor.Cli\"<\/span> <span class=\"hljs-attr\">Version<\/span>=<span class=\"hljs-string\">\"0.2.0\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ItemGroup<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Project<\/span>&gt;<\/span>\n<\/code><\/pre>\n<h3 id=\"build-reusable-component-libraries\">Build reusable component libraries<\/h3>\n<p>Blazor components are reusable pieces of web UI that can maintain state and handle events. In this release we&#039;ve made it easy to build reusable component libraries that you can package and share.<\/p>\n<p>To create a new Blazor component library:<\/p>\n<ol>\n<li>\n<p>Install the Blazor templates on the command-line if you haven&#039;t already<\/p>\n<pre><code> dotnet new -<span class=\"hljs-selector-tag\">i<\/span> Microsoft<span class=\"hljs-selector-class\">.AspNetCore<\/span><span class=\"hljs-selector-class\">.Blazor<\/span><span class=\"hljs-selector-class\">.Templates<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Create a new Blazor library project<\/p>\n<pre><code> dotnet <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-type\">blazorlib<\/span> -o BlazorLib1\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Create a new Blazor app so we can try out our component.<\/p>\n<pre><code> dotnet <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-type\">blazor<\/span> -o BlazorApp1\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Add a reference from the Blazor app to the Blazor library.<\/p>\n<pre><code> dotnet <span class=\"hljs-keyword\">add <\/span><span class=\"hljs-keyword\">BlazorApp1 <\/span>reference <span class=\"hljs-keyword\">BlazorLib1<\/span>\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Edit the home page of the Blazor app (<code>\/Pages\/Index.cshtml<\/code>) to use the component from the component library.<\/p>\n<pre><code> <span class=\"hljs-variable\">@addTagHelper<\/span> *, BlazorLib1\n <span class=\"hljs-variable\">@using<\/span> BlazorLib1\n <span class=\"hljs-variable\">@page<\/span> <span class=\"hljs-string\">\"\/\"<\/span>\n\n &lt;h1&gt;Hello, world!&lt;\/h1&gt;\n\n Welcome to your new app.\n\n &lt;SurveyPrompt Title=<span class=\"hljs-string\">\"How is Blazor working for you?\"<\/span> \/&gt;\n\n &lt;Component1 \/&gt;\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Build and run the app to see the updated home page<\/p>\n<pre><code> cd BlazorApp1\n dotnet <span class=\"hljs-keyword\">run<\/span><span class=\"bash\"><\/span>\n<\/code><\/pre>\n<p> <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/04\/blazor-component-lib-1.png\" alt=\"Blazor component library\"><\/p>\n<\/li>\n<\/ol>\n<h3 id=\"javascript-interop\">JavaScript interop<\/h3>\n<p>Blazor apps can call browser APIs or JavaScript libraries through JavaScript interop. Library authors can create .NET wrappers for browser APIs or JavaScript libraries and share them as reusable class libraries.<\/p>\n<p>To call a JavaScript function from Blazor the function must first be registered by calling <code>Blazor.registerFunction<\/code>. In the Blazor library we just created <code>exampleJsInterop.js<\/code> registers a function to display a prompt.<\/p>\n<pre><code class=\"lang-js\">Blazor.registerFunction(<span class=\"hljs-symbol\">'BlazorLib1.ExampleJsInterop.Prompt<\/span>', <span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\"><\/span>(message) {\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-type\">prompt(message,<\/span> <span class=\"hljs-symbol\">'Type<\/span> anything here');\n});\n<\/code><\/pre>\n<p>To call a registered function from C# use the <code>RegisteredFunction.Invoke<\/code> method as shown in <code>ExampleJsInterop.cs<\/code><\/p>\n<pre><code class=\"lang-csharp\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ExampleJsInterop<\/span>\n{\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">string<\/span> <span class=\"hljs-title\">Prompt<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span> message<\/span>)\n    <\/span>{\n        <span class=\"hljs-keyword\">return<\/span> RegisteredFunction.Invoke&lt;<span class=\"hljs-keyword\">string<\/span>&gt;(\n            <span class=\"hljs-string\">\"BlazorLib1.ExampleJsInterop.Prompt\"<\/span>,\n            message);\n    }\n}\n<\/code><\/pre>\n<p>In the Blazor app we can now update the <code>Counter<\/code> component in <code>\/Pages\/Counter.cshtml<\/code> to display a prompt whenever the button is clicked.<\/p>\n<pre><code class=\"lang-html\"><span class=\"hljs-meta\">@using<\/span> BlazorLib1\n<span class=\"hljs-meta\">@page<\/span> <span class=\"hljs-string\">\"\/counter\"<\/span>\n\n<span class=\"hljs-variable\">&lt;h1&gt;<\/span>Counter<span class=\"hljs-variable\">&lt;\/h1&gt;<\/span>\n\n<span class=\"hljs-variable\">&lt;p&gt;<\/span>Current count: <span class=\"hljs-meta\">@currentCount&lt;\/p&gt;<\/span>\n\n<span class=\"hljs-variable\">&lt;button onclick=\"@IncrementCount\"&gt;<\/span>Click me<span class=\"hljs-variable\">&lt;\/button&gt;<\/span>\n\n<span class=\"hljs-meta\">@functions<\/span> {\n    int currentCount = 0;\n\n    void IncrementCount()\n    {\n        currentCount++;\n        ExampleJsInterop.Prompt(<span class=\"hljs-string\">\"+1!\"<\/span>);\n    }\n}\n<\/code><\/pre>\n<p>Build and run the app and click the counter button to see the prompt.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/04\/blazor-jsinterop-prompt-1.png\" alt=\"Counter prompt\"><\/p>\n<p>We can now package our Blazor library as a NuGet package and share it with <em>the world!<\/em><\/p>\n<pre><code><span class=\"hljs-function\"><span class=\"hljs-title\">cd<\/span><\/span> ..\/BlazorLib1\ndotnet pack\n<\/code><\/pre>\n<h3 id=\"improved-event-handling\">Improved event handling<\/h3>\n<p>To handle events Blazor components can register C# delegates that should be called when UI events occur. In the previous release of Blazor components could register delegates using a specialized syntax (ex <code>&lt;button @onclick(Foo)&gt;<\/code> or <code>&lt;button onclick=@{ Foo(); }&gt;<\/code>) that only worked for specific cases and for specific types. In Blazor 0.2.0 we&#039;ve replaced the old syntax with a new syntax that is much more powerful and flexible.<\/p>\n<p>To register an event handler add an attribute of the form <code>on[event]<\/code> where <code>[event]<\/code> is the name of the event you wish to handle. The value of the attribute should be the delegate you wish to register preceded by an <code>@<\/code> sign. For example:<\/p>\n<pre><code class=\"lang-html\">&lt;button onclick=<span class=\"hljs-string\">\"@OnClick\"<\/span> \/&gt;\n<span class=\"hljs-meta\">@functions<\/span> {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">OnClick<\/span><span class=\"hljs-params\">(UIMouseEventArgs e)<\/span>\n    <\/span>{\n        Console.WriteLine(<span class=\"hljs-string\">\"hello, world\"<\/span>);\n    }\n}\n<\/code><\/pre>\n<p>or using a lambda:<\/p>\n<pre><code class=\"lang-html\">&lt;<span class=\"hljs-keyword\">button<\/span> <span class=\"hljs-keyword\">onclick<\/span>=<span class=\"hljs-string\">\"@(e =&gt; Console.WriteLine(\"<\/span>hello, world<span class=\"hljs-string\">\"))\"<\/span>\n<\/code><\/pre>\n<p>If you don&#039;t need access to the <code>UIEventArgs<\/code> in the delegate you can just leave it out.<\/p>\n<pre><code class=\"lang-html\">&lt;button onclick=<span class=\"hljs-string\">\"@OnClick\"<\/span> \/&gt;\n<span class=\"hljs-meta\">@functions<\/span> {\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">OnClick<\/span><span class=\"hljs-params\">()<\/span>\n    <\/span>{\n        Console.WriteLine(<span class=\"hljs-string\">\"hello, world\"<\/span>);\n    }\n}\n<\/code><\/pre>\n<p>With the new syntax you can register a handler for any event, including custom ones. The new syntax also enables better support for tool tips and completions for specific event types.<\/p>\n<p>The new syntax also allows for normal HTML style event handling attributes. If the value of the attribute is a string without a leading <code>@<\/code> character then the attribute is treated as normal HTML.<\/p>\n<p>For some events we define event specific event argument types (ex <code>UIMouseEventArgs<\/code> as shown above). We only have a limited set of these right now, but we expect to have the majority of events covered in the future.<\/p>\n<h3 id=\"improved-data-binding\">Improved data binding<\/h3>\n<p>Data binding allows you to populate the DOM using some component state and then also update the component state based on DOM events. In this release we are replacing the previous <code>@bind(...)<\/code> syntax with something more first class and that works better with tooling.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/04\/blazor-bind-1.png\" alt=\"Bind tooling\"><\/p>\n<p>To create setup a data binding you use the <code>bind<\/code> attribute.<\/p>\n<pre><code class=\"lang-html\">&lt;input bind=<span class=\"hljs-string\">\"@CurrentValue\"<\/span> \/&gt;\n@<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span><span class=\"hljs-title\">s<\/span> <\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-built_in\">string<\/span> CurrentValue { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n<\/code><\/pre>\n<p>The C# expression provided to <code>bind<\/code> should be something that can be assigned (i.e. an <strong>LValue<\/strong>).<\/p>\n<p>Using the <code>bind<\/code> attribute is essentially equivalent to the following:<\/p>\n<pre><code class=\"lang-html\"><span class=\"hljs-params\">&lt;input value=\"@CurrentValue\" onchange=\"@((UIValueEventArgs __e) =&gt;<\/span> CurrentValue = __e.Value)\/&gt;\n@<span class=\"hljs-class\">functions <\/span>{\n    public string <span class=\"hljs-class\">CurrentValue <\/span>{ get; set; }\n}\n<\/code><\/pre>\n<p>When the component is rendered the <code>value<\/code> of the input element will come from the <code>CurrentValue<\/code> property. When the user types in the text box the <code>onchange<\/code> is fired and the  <code>CurrentValue<\/code> property is set to the changed value. In reality the code generation is a little more complex because <code>bind<\/code> deals with a few cases of type conversions. But, in principle, <code>bind<\/code> will associate the current value of an expression with a <em>value<\/em> attribute, and will handle changes using the registered handler.<\/p>\n<p>Data binding is frequently used with <code>input<\/code> elements of various types. For example, binding to a checkbox looks like this:<\/p>\n<pre><code class=\"lang-html\">&lt;input <span class=\"hljs-keyword\">type<\/span>=<span class=\"hljs-string\">\"checkbox\"<\/span> bind=<span class=\"hljs-string\">\"@IsSelected\"<\/span> \/&gt;\n@<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span><span class=\"hljs-title\">s<\/span> <\/span>{\n    <span class=\"hljs-keyword\">public<\/span> bool IsSelected { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n<\/code><\/pre>\n<p>Blazor has a set of mappings between the structure of input tags and the attributes that need to be set on the generated DOM elements. Right now this set is pretty minimal, but we plan to provide a complete set of mappings in the future. <\/p>\n<p>There is also limited support for type conversions (<code>string<\/code>, <code>int<\/code>, <code>DataTime<\/code>) and error handling is limited right now. This is another area that we plan to improve in the future.<\/p>\n<h3 id=\"binding-format-strings\">Binding format strings<\/h3>\n<p>You can use the <code>format-...<\/code> attribute to provide a format string to specify how .NET values should be bound to attribute values. <\/p>\n<pre><code>&lt;input bind=<span class=\"hljs-string\">\"@StartDate\"<\/span> format-<span class=\"hljs-keyword\">value<\/span>=<span class=\"hljs-string\">\"MM\/dd\/yyyy\"<\/span> \/&gt;\n@functions {\n    <span class=\"hljs-keyword\">public<\/span> DateTime StartDate { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n<\/code><\/pre>\n<p>Currently you can define a format string for <em>any type you want<\/em> &#8230; as long as it&#039;s a <code>DateTime<\/code> ;). Adding better support for formating and conversions is another area we plan to address in the future.<\/p>\n<h3 id=\"binding-to-components\">Binding to components<\/h3>\n<p>You can use <code>bind-...<\/code> to bind to component parameters that follow a specific pattern:<\/p>\n<pre><code class=\"lang-html\">@* <span class=\"hljs-keyword\">in<\/span> Counter.cshtml *@\n&lt;div&gt;...html omitted <span class=\"hljs-keyword\">for<\/span> brevity...&lt;\/div&gt;\n@functions {\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> Value { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; } = <span class=\"hljs-number\">1<\/span>;\n    <span class=\"hljs-keyword\">public<\/span> Action&lt;<span class=\"hljs-keyword\">int<\/span>&gt; ValueChanged { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n\n@* <span class=\"hljs-keyword\">in<\/span> another file *@\n&lt;Counter bind-Value=<span class=\"hljs-string\">\"@CurrentValue\"<\/span> \/&gt;\n@functions {\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> CurrentValue { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n<\/code><\/pre>\n<p>The <code>Value<\/code> parameter is bindable because it has a companion <code>ValueChanged<\/code> event that matches the type of the <code>Value<\/code> parameter.<\/p>\n<h3 id=\"build-on-save\">Build on save<\/h3>\n<p>The typical development workflow for many web developers is to edit the code, save it, and then refresh the browser. This workflow is made possible by the interpreted nature of JavaScript, HTML, and CSS. Blazor is a bit different because it is based on compiling C# and Razor code to .NET assemblies. <\/p>\n<p>To enable the standard web development workflow with Blazor, Visual Studio will now watch for file changes in your Blazor project and rebuild and restart your app as things are changed. You can then refresh the browser to see the changes without having to manually rebuild.<\/p>\n<h3 id=\"conditional-attributes\">Conditional attributes<\/h3>\n<p>Blazor will now handle conditionally rendering attributes based on the .NET value they are bound to. If the value you&#039;re binding to is <code>false<\/code> or <code>null<\/code>, then Blazor won&#039;t render the attribute. If the value is <code>true<\/code>, then the attribute is rendered minimized.<\/p>\n<p>For example:<\/p>\n<pre><code class=\"lang-html\">&lt;input type=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-keyword\">checked<\/span>=<span class=\"hljs-string\">\"@IsCompleted\"<\/span> \/&gt;\n@functions {\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">bool<\/span> IsCompleted { <span class=\"hljs-keyword\">get<\/span>; <span class=\"hljs-keyword\">set<\/span>; }\n}\n\n@* <span class=\"hljs-keyword\">if<\/span> IsCompleted <span class=\"hljs-keyword\">is<\/span> <span class=\"hljs-literal\">true<\/span>, render <span class=\"hljs-keyword\">as<\/span>: *@\n&lt;input type=<span class=\"hljs-string\">\"checkbox\"<\/span> <span class=\"hljs-keyword\">checked<\/span> \/&gt;\n\n@* <span class=\"hljs-keyword\">if<\/span> IsCompleted <span class=\"hljs-keyword\">is<\/span> <span class=\"hljs-literal\">false<\/span>, render <span class=\"hljs-keyword\">as<\/span>: *@\n&lt;input type=<span class=\"hljs-string\">\"checkbox\"<\/span> \/&gt;\n<\/code><\/pre>\n<h3 id=\"httpclient-improvements\">HttpClient improvements<\/h3>\n<p>Thanks to a number of contributions from the community, there are a number of improvements in using <code>HttpClient<\/code> in Blazor apps:<\/p>\n<ul>\n<li>Support deserialization of structs from JSON<\/li>\n<li>Support specifying arbitrary fetch API arguments using the HttpRequestMessage property bag.<\/li>\n<li>Including cookies by default for same-origin requests<\/li>\n<\/ul>\n<h3 id=\"summary\">Summary<\/h3>\n<p>We hope you enjoy this updated preview of Blazor. Your feedback is especially important to us during this experimental phase for Blazor. If you run into issues or have questions while trying out Blazor please <a href=\"https:\/\/github.com\/aspnet\/blazor\/issues\">file issues on GitHub<\/a>. You can also chat with us and the Blazor community on <a href=\"https:\/\/gitter.im\/aspnet\/blazor\">Gitter<\/a> if you get stuck or to share how Blazor is working for you. After you&#039;ve tried out Blazor for a while please also let us know what you think by taking our in-product survey. Just click the survey link shown on the app home page when running one of the Blazor project templates:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2018\/04\/blazor-survey.png\" alt=\"Blazor survey\"><\/p>\n<p>Have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just a few weeks ago we announced the first preview release of an experimental web UI framework called Blazor. Blazor enables full-stack web development using C# and WebAssembly. So far thousands of web developers have taken on the challenge to try out Blazor and done some pretty remarkable things: Started using Blazor to build RealWorld [&hellip;]<\/p>\n","protected":false},"author":417,"featured_media":21392,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509,7251],"tags":[31,32,7205],"class_list":["post-13075","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","category-blazor","tag-asp-net","tag-asp-net-core","tag-blazor"],"acf":[],"blog_post_summary":"<p>Just a few weeks ago we announced the first preview release of an experimental web UI framework called Blazor. Blazor enables full-stack web development using C# and WebAssembly. So far thousands of web developers have taken on the challenge to try out Blazor and done some pretty remarkable things: Started using Blazor to build RealWorld [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/13075","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=13075"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/13075\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21392"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=13075"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=13075"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=13075"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}