Blazor 0.5.0 experimental release now available - Printable Version +- Sick Gaming (https://www.sickgaming.net) +-- Forum: Programming (https://www.sickgaming.net/forum-76.html) +--- Forum: C#, Visual Basic, & .Net Frameworks (https://www.sickgaming.net/forum-79.html) +--- Thread: Blazor 0.5.0 experimental release now available (/thread-85793.html) |
Blazor 0.5.0 experimental release now available - xSicKxBot - 07-26-2018 Blazor 0.5.0 experimental release now available <div style="margin: 5px 5% 10px 5%;"><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available.png" width="360" height="332" title="" alt="" /></div><div><p>Blazor 0.5.0 is now available! This release explores scenarios where Blazor is run in a separate process from the rendering process. Specifically, Blazor 0.5.0 enables the option to run Blazor on the server and then handle all UI interactions over a SignalR connection. This release also adds some very early support for debugging your Blazor .NET code in the browser!</p> <p>New features in this release:</p> <ul> <li>Server-side Blazor</li> <li>Startup model aligned with ASP.NET Core</li> <li>JavaScript interop improvements <ul> <li>Removed requirement to preregister JavaScript methods</li> <li>Invoke .NET instance method from JavaScript</li> <li>Pass .NET objects to JavaScript by reference</li> </ul> </li> <li>Add Blazor to any HTML file using a normal script tag</li> <li>Render raw HTML</li> <li>New component parameter snippet</li> <li>Early support for in-browser debugging</li> </ul> <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.5.0">Blazor 0.5.0 release notes</a>.</p> <h2 id="get-blazor-0-5-0">Get Blazor 0.5.0</h2> <p>To get setup with Blazor 0.5.0:</p> <ol> <li>Install the <a href="https://go.microsoft.com/fwlink/?linkid=873092">.NET Core 2.1 SDK</a> (2.1.300 or later).</li> <li>Install <a href="https://go.microsoft.com/fwlink/?linkid=873093">Visual Studio 2017</a> (15.7 or later) with the <em>ASP.NET and web development</em> workload selected.</li> <li>Install the latest <a href="https://go.microsoft.com/fwlink/?linkid=870389">Blazor Language Services extension</a> from the Visual Studio Marketplace.</li> <li> <p>Install the Blazor templates on the command-line:</p> <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> </code></pre> </li> </ol> <p>You can find getting started instructions, docs, and tutorials for Blazor at <a href="https://blazor.net">https://blazor.net</a>.</p> <h2 id="upgrade-an-existing-project-to-blazor-0-5-0">Upgrade an existing project to Blazor 0.5.0</h2> <p>To upgrade an existing Blazor project from 0.4.0 to 0.5.0:</p> <ul> <li>Install all of the required bits listed above.</li> <li> <p>Update your Blazor package and .NET CLI tool references to 0.5.0. Your upgraded Blazor project file should look like this:</p> <pre><code class="lang-xml"><span class="hljs-tag"><<span class="hljs-name">Project</span> <span class="hljs-attr">Sdk</span>=<span class="hljs-string">"Microsoft.NET.Sdk.Web"</span>></span> <span class="hljs-tag"><<span class="hljs-name">PropertyGroup</span>></span> <span class="hljs-tag"><<span class="hljs-name">TargetFramework</span>></span>netstandard2.0<span class="hljs-tag"></<span class="hljs-name">TargetFramework</span>></span> <span class="hljs-tag"><<span class="hljs-name">RunCommand</span>></span>dotnet<span class="hljs-tag"></<span class="hljs-name">RunCommand</span>></span> <span class="hljs-tag"><<span class="hljs-name">RunArguments</span>></span>blazor serve<span class="hljs-tag"></<span class="hljs-name">RunArguments</span>></span> <span class="hljs-tag"><<span class="hljs-name">LangVersion</span>></span>7.3<span class="hljs-tag"></<span class="hljs-name">LangVersion</span>></span> <span class="hljs-tag"></<span class="hljs-name">PropertyGroup</span>></span> <span class="hljs-tag"><<span class="hljs-name">ItemGroup</span>></span> <span class="hljs-tag"><<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.5.0"</span> /></span> <span class="hljs-tag"><<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.5.0"</span> /></span> <span class="hljs-tag"><<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.5.0"</span> /></span> <span class="hljs-tag"></<span class="hljs-name">ItemGroup</span>></span> <span class="hljs-tag"></<span class="hljs-name">Project</span>></span> </code></pre> </li> <li> <p>Update <em>index.html</em> to replace the <code>blazor-boot</code> script tag with a normal script tag that references <em>_framework/blazor.webassembly.js</em>..</p> <p><em>index.html</em></p> <pre><code class="lang-html"><span class="hljs-meta"><!DOCTYPE html></span> <span class="hljs-tag"><<span class="hljs-name">html</span>></span> <span class="hljs-tag"><<span class="hljs-name">head</span>></span> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /></span> <span class="hljs-tag"><<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width"</span>></span> <span class="hljs-tag"><<span class="hljs-name">title</span>></span>BlazorApp1<span class="hljs-tag"></<span class="hljs-name">title</span>></span> <span class="hljs-tag"><<span class="hljs-name">base</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span> /></span> <span class="hljs-tag"><<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"css/bootstrap/bootstrap.min.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> /></span> <span class="hljs-tag"><<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"css/site.css"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> /></span> <span class="hljs-tag"></<span class="hljs-name">head</span>></span> <span class="hljs-tag"><<span class="hljs-name">body</span>></span> <span class="hljs-tag"><<span class="hljs-name">app</span>></span>Loading...<span class="hljs-tag"></<span class="hljs-name">app</span>></span> <span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"_framework/blazor.webassembly.js"</span>></span><span class="undefined" /><span class="hljs-tag"></<span class="hljs-name">script</span>></span> <span class="hljs-tag"></<span class="hljs-name">body</span>></span> <span class="hljs-tag"></<span class="hljs-name">html</span>></span> </code></pre> </li> <li> <p>Add a <code>Startup</code> class to your project and update <em>Program.cs</em> to setup the Blazor host.</p> <p><em>Program.cs</em></p> <pre><code class="lang-csharp">@<span class="hljs-keyword">using</span> <span class="hljs-keyword">using</span> Microsoft.AspNetCore.Blazor.Hosting; <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>{ CreateHostBuilder(args).Build().Run(); } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IWebAssemblyHostBuilder <span class="hljs-title">CreateHostBuilder</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>=> BlazorWebAssemblyHost.CreateDefaultBuilder() .UseBlazorStartup<Startup>(); } </code></pre> <p><em>Startup.cs</em></p> <pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.AspNetCore.Blazor.Builder; <span class="hljs-keyword">using</span> Microsoft.Extensions.DependencyInjection; <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>) </span>{ } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IBlazorApplicationBuilder app</span>) </span>{ app.AddComponent<App>(<span class="hljs-string">"app"</span>); } } </code></pre> </li> <li> <p>Update to the new JavaScript interop model. The changes to the JavaScript interop model are covered in the “JavaScript interop changes” section below.</p> </li> </ul> <h2 id="what-is-server-side-blazor-">What is server-side Blazor?</h2> <p>Blazor is principally a client-side web framework intended to run in a browser where the component logic and DOM interactions all happen in the same process. </p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available.png" alt="Blazor client-side" /></p> <p>However, Blazor was built to be flexible enough to handle scenarios where the Blazor app runs apart from the rendering process. For example, you might run Blazor in a Web Worker thread so that it runs separately from the UI thread. Events would get pushed from the UI thread to the Blazor worker thread, and Blazor would push UI updates to the UI thread as needed. This scenario isn’t supported yet, but it’s something Blazor was designed to handle.</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-1.png" alt="Blazor web worker" /></p> <p>Another potential use case for running Blazor in a separate process is writing desktop applications with Electron. The Blazor component logic could run in a normal .NET Core process, while the UI updates are handled in the Electron rendering process.</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-2.png" alt="Blazor Electron" /></p> <p>We have a working <a href="https://github.com/stevesandersonms/blazorelectronexperiment.sample">prototype</a> that you can try out of using Blazor with Electron in this way.</p> <p>Blazor 0.5.0 takes the out-of-process model for Blazor and <em>streeeetches</em> it over a network connection so that you can run Blazor on the server. With Blazor 0.5.0 you can run your Blazor components server-side on .NET Core while UI updates, event handling, and JavaScript interop calls are handled over a SignalR connection. </p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-3.png" alt="Blazor server-side" /></p> <p>There are a number of benefits to running Blazor on the server in this way:</p> <ul> <li>You can still write your entire app with .NET and C# using the Blazor component model.</li> <li>Your app still has a rich interactive feel and avoids unnecessary page refreshes.</li> <li>Your app download size is significantly smaller and the initial app load time is much faster.</li> <li>Your Blazor component logic can take full advantage of server capabilities including using any .NET Core compatible APIs.</li> <li>Because you’re running on .NET Core on the server existing .NET tooling, like debugging, just works.</li> <li>Works with thin clients (ex browsers that don’t support WebAssembly, resource constrained devices, etc.).</li> </ul> <p>Of course there are some downsides too:</p> <ul> <li>Latency: every user interaction now involves a network hop.</li> <li>No offline support: if the client connection goes down the app stops working.</li> <li>Scalability: the server must manage multiple client connections and handle client state.</li> </ul> <p>While our primary goal for Blazor remains to provide a rich client-side web development experience, enough developers expressed interest in the server-side model that we decided to experiment with it. And because server-side Blazor uses the exact same component model as running Blazor on the client, it is well aligned with our client-side efforts.</p> <h3 id="get-started-with-server-side-blazor">Get started with server-side Blazor</h3> <p>To create your first server-side Blazor app use the new server-side Blazor project template. </p> <pre><code>dotnet <span class="hljs-keyword">new</span> <span class="hljs-type">blazorserverside</span> -o BlazorApp1 </code></pre> <p>Build and run the app from the <em>BlazorApp1.Server</em> directory to see it in action:</p> <pre><code>cd BlazorApp1.<span class="hljs-built_in">Server</span> dotnet <span class="hljs-built_in">run</span> </code></pre> <p>You can also create a server-side Blazor app from Visual Studio.</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-4.png" alt="Blazor server-side template" /></p> <p>When you run the Blazor server-side app it looks like a normal Blazor app, but the download size is significantly smaller (under 100KB), because there is no need to download a .NET runtime, the app assembly, or any of its dependencies.</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-5.png" alt="Blazor server-side running app" /></p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-6.png" alt="Blazor server-side download size" /></p> <p>You’re also free to run the app under the debugger (F5) as all the .NET logic is running on .NET Core on the server.</p> <p>The template creates a solution with two projects: an ASP.NET Core host project, and a project for your server-side Blazor app. In a future release we hope to merge these two projects into one, but for now the separation is necessary due to the differences in the Blazor compilation model.</p> <p>The server-side Blazor app contains all of your component logic, but instead of running client-side in the browser the logic is run server-side in the ASP.NET Core host application. The Blazor app uses a different bootstrapping script (<em>blazor.server.js</em> instead of <em>blazor.webassembly.js</em>), which establishes a SignalR connection with the server and handles applying UI updates and forwarding events. Otherwise the Blazor programming model is the same. </p> <p>The ASP.NET Core app hosts the Blazor app and sets up the SignalR endpoint. Because the Blazor app runs on the server, the event handling logic can directly access server resources and services. For example, the <code>FetchData</code> page no longer needs to issue an HTTP request to retrieve the weather forecast data, but can instead use a service configured on the server:</p> <pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">OnParametersSetAsync</span>(<span class="hljs-params" />) </span>{ forecasts = <span class="hljs-keyword">await</span> ForecastService.GetForecastAsync(StartDate); } </code></pre> <p>The <code>WeatherForecastService</code> in the template generates the forecast data in memory, but it could just as easily pull the data from a database using EF Core, or use other server resources. </p> <h3 id="startup-model">Startup model</h3> <p>All Blazor projects in 0.5.0 now use a new startup model that is similar to the startup model in ASP.NET Core. Each Blazor project has a <code>Startup</code> class with a <code>ConfigureServices</code> method for configuring the services for your Blazor app, and a <code>Configure</code> method for configuring the root components of the application. </p> <pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>) </span>{ } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IBlazorApplicationBuilder app</span>) </span>{ app.AddComponent<App>(<span class="hljs-string">"app"</span>); } } </code></pre> <p>The app entry point in <em>Program.cs</em> creates a Blazor host that is configured to use the <code>Startup</code> class.</p> <pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>{ CreateHostBuilder(args).Build().Run(); } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> IWebAssemblyHostBuilder <span class="hljs-title">CreateHostBuilder</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>) </span>=> BlazorWebAssemblyHost.CreateDefaultBuilder() .UseBlazorStartup<Startup>(); } </code></pre> <p>In server-side Blazor apps the entry point comes from the host ASP.NET Core app, which references the Blazor <code>Startup</code> class to both add the server-side Blazor services and to add the Blazor app to the request handling pipeline:</p> <pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Startup</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ConfigureServices</span>(<span class="hljs-params">IServiceCollection services</span>) </span>{ ... services.AddServerSideBlazor<App.Startup>(); } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Configure</span>(<span class="hljs-params">IApplicationBuilder app, IHostingEnvironment env</span>) </span>{ ... app.UseServerSideBlazor<App.Startup>(); } } </code></pre> <p>While the server-side Blazor project may also have a Program class, it is not used when running on the server. However it would be used if you switched to client-side (WebAssembly) execution just by changing the <code><script></code> tag in <em>index.html</em> to load <em>blazor.webassembly.js</em> instead of <em>blazor.server.js</em>.</p> <p>The Blazor app and the ASP.NET Core app share the same service provider. Services added in either <code>ConfigureServices</code> methods are visible to both apps. Scoped services are scoped to the client connection.</p> <h3 id="state-management">State management</h3> <p>When running Blazor on the server the UI state is all managed server-side. The initial state is established with the client connects to the server and is maintained in memory as the user interacts with the app. If the client connection is lost then the server-side app state will be lost, unless it is otherwise persisted and restored by the app. For example, you could maintain your app state in an <code>AppState</code> class that you serialize into session state periodically and then initialize the app state from session state when it is available. While this process is currently completely manual in the future we hope to make server-side state management easier and more integrated.</p> <h2 id="javascript-interop-changes">JavaScript interop changes</h2> <p>You can use JavaScript interop libraries when using server-side Blazor. The Blazor runtime handles sending the JavaScript calls to the browser and then sending the results back to the server. To accommodate out-of-process usage of JavaScript interop the JavaScript interop model was significantly revised and expanded upon in this release.</p> <h3 id="calling-javascript-from-net">Calling JavaScript from .NET</h3> <p>To call into JavaScript from .NET use the new <code>IJSRuntime</code> abstraction, which is accessible from <code>JSRuntime.Current</code>. The <code>InvokeAsync<T></code> method on <code>IJSRuntime</code> takes an identifier for the JavaScript function you wish to invoke along with any number of JSON serializable arguments. The function identifier is relative to the global scope (<code>window</code>). For example, if you wish to call <code>window.someScope.someFunction</code> then the identifier would be <code>someScope.someFunction</code>. There is no longer any need to register the function before it can be called. The return type <code>T</code> must also be JSON serializable.</p> <p><em>exampleJsInterop.js</em></p> <pre><code class="lang-js">window.exampleJsFunctions = { showPrompt: <span class="hljs-keyword">function</span> <span class="hljs-title" />(message) { <span class="hljs-keyword">return</span> <span class="hljs-type">prompt(message,</span> <span class="hljs-symbol">'Type</span> anything here'); } }; </code></pre> <p><em>ExampleJsInterop.cs</em></p> <pre><code class="lang-csharp"><span class="hljs-keyword">using</span> Microsoft.JSInterop; <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ExampleJsInterop</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Task<<span class="hljs-keyword">string</span>> <span class="hljs-title">Prompt</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> message</span>) </span>{ <span class="hljs-comment">// Implemented in exampleJsInterop.js</span> <span class="hljs-keyword">return</span> JSRuntime.Current.InvokeAsync<<span class="hljs-keyword">string</span>>( <span class="hljs-string">"exampleJsFunctions.showPrompt"</span>, message); } } </code></pre> <p>The <code>IJSRuntime</code> abstraction is async to allow for out-of-process scenarios. However, if you are running in-process and want to invoke a JavaScript function synchronously you can downcast to <code>IJSInProcessRuntime</code> and call <code>Invoke<T></code> instead. We recommend that most JavaScript interop libraries should use the async APIs to ensure the libraries can be used in all Blazor scenarios, client-side or server-side.</p> <h3 id="calling-net-from-javascript">Calling .NET from JavaScript</h3> <p>To invoke a static .NET method from JavaScript use the <code>DotNet.invokeMethod</code> or <code>DotNet.invokeMethodAsync</code> functions passing in the identifier of the static method you wish to call, the name of the assembly containing the function, and any arguments. Again, the async version is required to support out-of-process scenarios. To be invokable from JavaScript, the .NET method must be public, static, and attributed with <code>[JSInvokable]</code>. By default, the method identifier is the method name, but you can specify a different identifier using the <code>JSInvokableAttribute</code> constructor. Calling open generic methods is not currently supported.</p> <p><em>JavaScriptInteroperable.cs</em></p> <pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> JavaScriptInvokable { [JSInvokable] <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">Task</span><<span class="hljs-keyword">int</span>[]> ReturnArrayAsync() { <span class="hljs-built_in">return</span> <span class="hljs-built_in">Task</span>.FromResult(<span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[] { <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span> }); } } </code></pre> <p><em>dotnetInterop.js</em></p> <pre><code class="lang-js"><span class="hljs-type">DotNet</span>.invokeMethodAsync(assemblyName, '<span class="hljs-type">ReturnArrayAsync'</span>).<span class="hljs-keyword">then</span>(<span class="hljs-class"><span class="hljs-keyword">data</span> => ...)</span> </code></pre> <p>New in Blazor 0.5.0, you can also call .NET instance methods from JavaScript. To invoke a .NET instance method from JavaScript you first pass the .NET instance to JavaScript by wrapping it in a <code>DotNetObjectRef</code> instance. The .NET instance will then be passed by reference to JavaScript and you can invoke .NET instance methods on the instance using the <code>invokeMethod</code> or <code>invokeMethodAsync</code> functions. The .NET instance can also be passed as an argument when invoking other .NET methods from JavaScript.</p> <p><em>ExampleJsInterop.cs</em></p> <pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ExampleJsInterop</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Task <span class="hljs-title">SayHello</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name</span>) </span>{ <span class="hljs-keyword">return</span> JSRuntime.Current.InvokeAsync<<span class="hljs-keyword">object</span>>( <span class="hljs-string">"exampleJsFunctions.sayHello"</span>, <span class="hljs-keyword">new</span> DotNetObjectRef(<span class="hljs-keyword">new</span> HelloHelper(name))); } } </code></pre> <p><em>exampleJsInterop.js</em></p> <pre><code class="lang-js"><span class="hljs-built_in">window</span>.exampleJsFunctions = { <span class="hljs-attr">sayHello</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">dotnetHelper</span>) </span>{ <span class="hljs-keyword">return</span> dotnetHelper.invokeMethodAsync(<span class="hljs-string">'SayHello'</span>) .then(<span class="hljs-function"><span class="hljs-params">r</span> =></span> <span class="hljs-built_in">console</span>.log®); } }; </code></pre> <p><em>HelloHelper.cs</em></p> <pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">HelloHelper</span> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HelloHelper</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name</span>) </span>{ Name = name; } <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } [JSInvokable] <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> <span class="hljs-title">SayHello</span>(<span class="hljs-params" />) </span>=> <span class="hljs-string">$"Hello, <span class="hljs-subst">{Name}</span>!"</span>; } </code></pre> <p><em>Output</em></p> <pre><code>Hello, Blazor! </code></pre> <h2 id="add-blazor-to-any-html-file">Add Blazor to any HTML file</h2> <p>In previous Blazor releases the project build modified <em>index.html</em> to replace the <code>blazor-boot</code> script tag with a real script tag that handled downloading the starting up the runtime. This setup made it difficult to use Blazor in arbitrary HTML files. </p> <p>In Blazor 0.5.0 this mechanism has been replaced. For client-side projects add a script tag that references the <em>_framework/blazor.webassembly.js</em> script (which is generated as part of the build). For server-side projects you reference <em>_framework/blazor.server.js</em>. You can add this script to any HTML file, including server generated content.</p> <p>For example, instead of using the static <em>index.html</em> file from the Blazor client project you could add a Razor Page to your ASP.NET Core host project and then add the Blazor script tag there along with any server-side rendering logic.</p> <h2 id="render-raw-html">Render raw HTML</h2> <p>Blazor normally renders strings using DOM text nodes, which means that any markup they may contain will be ignored and treated as literal text. This new feature lets you render special <code>MarkupString</code> values that will be parsed as HTML or SVG and then inserted into the DOM.</p> <p>WARNING: Rendering raw HTML constructed from any untrusted source is a <strong>major security risk</strong>!</p> <p>Use the <code>MarkupString</code> type to add blocks of static HTML content.</p> <pre><code class="lang-html">@((MarkupString)myMarkup) @functions { string myMarkup = "<span class="hljs-tag"><<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">'markup'</span>></span>This is a <span class="hljs-tag"><<span class="hljs-name">em</span>></span>markup string<span class="hljs-tag"></<span class="hljs-name">em</span>></span>.<span class="hljs-tag"></<span class="hljs-name">p</span>></span>"; } </code></pre> <h2 id="component-parameter-snippet">Component parameter snippet</h2> <p>Thanks to a community contribution from Benjamin Vertonghen (<a href="https://github.com/vertonghenb">vertonghenb</a>) we now have a Visual Studio snippet for adding component parameters. Just type <code>para</code> and then hit <code>Tab</code> twice to add a parameter to your component.</p> <h2 id="debugging">Debugging</h2> <p>Blazor 0.5.0 introduces some <em>very</em> basic debugging support in Chrome for client-side Blazor apps running on WebAssembly. While this initial debugging support is very limited and unpolished it does show the basic debugging infrastructure coming together.</p> <p>To debug your client-side Blazor app in Chrome:</p> <ul> <li>Build a Blazor app in <code>Debug</code> configuration (the default for non-published apps)</li> <li>Run the Blazor app in Chrome</li> <li>With the keyboard focus on the app (not in the dev tools, which you should probably close as it’s less confusing that way), press the following Blazor specific hotkey: <ul> <li>Shift+Alt+D on Windows/Linux</li> <li>Shift+Cmd+D on macOS</li> </ul> </li> </ul> <p>You need to run Chrome with remote debugging enabled to debug your Blazor app. If you don’t, you will get an error page with instructions for running Chrome with the debugging port open so that the Blazor debugging proxy can connect to it. You will need to <em>close all Chrome instances</em> and then restart Chrome as instructed.</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-7.png" alt="Blazor debugging error page" /></p> <p>Once you have Chrome running with remote debugging enabled, hitting the debugging hotkey will open a new debugger tab. After a brief moment the <em>Sources</em> tab will show a list of the .NET assemblies in the app. You can expand each assembly and find the <em>.cs</em>/<em>.cshtml</em> source files you want to debug. You can then set breakpoints, switch back to your app’s tab, and cause the breakpoints to be hit. You can then single-step (F10) or resume (F8).</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-8.png" alt="Blazor debugging" /></p> <p>How does this work? Blazor provides a debugging proxy that implements the <a href="https://chromedevtools.github.io/devtools-protocol/">Chrome DevTools Protocol</a> and augments the protocol with .NET specific information. When you hit the debugging hotkey, Blazor points the Chrome DevTools at the proxy, which in turn connects to the browser window you are trying to debug (hence the need for enabling remote debugging).</p> <p>You might be wondering why we don’t just use browser source maps. Source maps allow the browser to map compiled files back to their original source files. However, Blazor does not map C# directly to JS/WASM (at least not yet). Instead, Blazor does IL interpretation within the browser, so source maps are not relevant.</p> <p>NOTE: The debugger capabilities are <strong>very limited.</strong> You can currently only:</p> <ul> <li>Single-step through the current method (F10) or resume (F8)</li> <li>In the <em>Locals</em> display, observe the values of any local variables of type <code>int</code>/<code>string</code>/<code>bool</code></li> <li>See the call stack, including call chains that go from JavaScript into .NET and vice-versa</li> </ul> <p>That’s it! You <em>cannot</em> step into child methods (i.e., F11), observe the values of any locals that aren’t an <code>int</code>/<code>string</code>/<code>bool</code>, observe the values of any class properties or fields, hover over variables to see their values, evaluate expressions in the console, step across async calls, or do basically anything else.</p> <p>Our friends on the Mono team have done some great work tackling some of the hardest technical problems to enable source viewing, breakpoints, and stepping, but please be patient as completing the long tail of debugger features remains a significant ongoing task.</p> <h3 id="community">Community</h3> <p>The Blazor community has produced a number of great Blazor extensions, libraries, sample apps, articles, and videos.<br />You can find out about these community projects on the <a href="https://blazor.net/community.html">Blazor Community page</a>. Recent additions include a <a href="https://github.com/BlazorExtensions/SignalR">Blazor SignalR client</a>, <a href="https://dworthen.github.io/BlazorRealm/docs/quickstart.html">Redux integration</a>, and various community authored samples (<a href="https://github.com/RemiBou/Toss.Blazor">Toss</a>, <a href="https://github.com/Lupusa87/LupusaBlazorProjects">Clock</a>, <a href="https://github.com/conficient/BlazorChatSample">Chat</a>). If you have a Blazor related project that you’d like to share on the community page let us know by sending us a pull request to the <a href="https://github.com/aspnet/Blazor.Docs">Blazor.Docs</a> repo.</p> <h3 id="give-feedback">Give feedback</h3> <p>We hope you enjoy this latest preview release of Blazor. As with previous releases, your feedback is important to us. 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’ve tried out Blazor for a while please also let us know what you think by taking our in-product survey. Click the survey link shown on the app home page when running one of the Blazor project templates:</p> <p><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/07/blazor-0-5-0-experimental-release-now-available-9.png" alt="Blazor survey" /></p> <p>Thanks for trying out Blazor!</p> <p> </p> </div> |