Blazor WebAssembly provides JavaScript glue code for WebAssembly that is common web architecture.
Blazor aims to provide almost of all features of .NET Core to modern web browser, So JavaScript glue code of Blazor webassembly can interoperate with JavaScript ecosystem that is used in exsisting usage.
This article describes the Blazor provides WebAssembly and Blazor WebAssembly calls JavaScript method, it is sample as leverage the Razor syntax template writing that provides high productivity, and reusing JavaScript ecosystem. As addition, the Blazor webassembly acquires some icons from external web app by browser of local.
In next article [JavaScript colors SVG images that are acquired by Blazor WebAssembly], these icons rendered by the Razor template then JavaScript colors them.
>>Blazor webassembly sample project of this article
・Create Blazor Webassembly project
.NET framework provides many templates variety for creation of apps, there are several kind of web apps, native apps and so on. it is also provided for Blazor WebAssembly and it has host type and stand alone type (as default).
The [dotnet new –list] command shows all of templates and the [dotnet new blazorwasm -h] shows parameters of Blazor WebAssembly. So put the command [dotnet new blazorwasm] create base files of Blazor WebAssembly project that is not hosted by Blazor server. Blazor server provides progressive web apps feature.
The directory of created project includes many files. There is the [Program.cs] file as application entrypoint, and the [App.razor] file as routing deefinition.
HTTP request is tranfer from the [App.razor] file to the [Shared\MainLayout.razor] file then the [Shared\MainLayout.razor] makes output that combines the [Shared\NavMenu.razor] file with requested ([/] : as root) page of the [Pages] folder.
The page files of the [Pages] folder has the [@page] directive. It is routing mechanizm of Razor syntax.
@page "/" <PageTitle>Index</PageTitle> <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" />
At first as one fifths, put command [dotnet run] in the [Integrated terminal] (put the [ctrl] key + the [@] key for show the [Integrated terminal] : to confirm shortcut key on your keybord type, show shortcut key list using the [ctrl] key + the [k] key + the [s] key) . When the result output after compile, put the [ctrl] key + click the link (http://localhost:5078 for below figure) to launch browser with display index page content.
・Acquiring SVG images from external web
As next : two fifths step, create temporaly contents as whole structure at the [Index.razor] file. Create some content in case of that some value is null ([<p><em>Loading…</em></p>] for below figure), and create some content when some value is not null.
Prepare the [SVGIcon] object for SVG image. Use the [MarkupString] type to a property that is used for output string for HTML. The [image] tag of HTML has the [src] attribute that is able to accept inline SVG.
Three fifths step, acquire one svg file from external web site [Icon Fonts], and display it. Modify only in the [@code] statements.
for HTML (same as temporaly contents as whole structure above)
<h1>List of the [Icon Fonts]</h1> <div>Icon made from <a href="http://www.onlinewebfonts.com/icon" target="new">Icon Fonts</a> is licensed by CC BY 3.0</div> @if (SVGs.URL == null) { <p><em>Loading...</em></p> } else { <div style="display:inline-block;"> <img id="@SVGs.URL" src='@SVGs.imgSrc' style="width:100px;" onclick="selectImg(this)"> </div> }
for Code
private SVGIcon SVGs = new SVGIcon(); protected override async Task OnInitializedAsync() { HttpClient httpClient = new HttpClient(); Uri requestURL = new Uri("http://cdn.onlinewebfonts.com/svg/download_155117.svg"); var res = await httpClient.GetStringAsync(requestURL); if (string.IsNullOrEmpty(res)) { @* some code *@ } else { var xml = new System.Xml.XmlDocument(); xml.LoadXml(res); var content = ""; if(xml.LastChild != null){ content = xml.LastChild.OuterXml; } SVGs = new SVGIcon() { URL="http://cdn.onlinewebfonts.com/svg/download_155117.svg", XML= new MarkupString(content) }; } }
[describe]
Use the [OnInitializedAsync] task to run code when HTML on loading.
The step of four fifths, modify the [OnInitializedAsync] that is task to run code when HTML on loading. Change feature that acquires one SVG file to acquire ten SVG files as sampling. So change the [SVGs] variable from single object to the List objects.
private SVGIcon SVGs = new SVGIcon(); to private List SVGs = new List();
Since change the [SVGs] variable to the List objects, HTML part also change to render List objects.
@if (SVGs.URL == null) { <p><em>Loading...</em></p> } else { <div style="display:inline-block;"> <img id="@SVGs.URL" src='@SVGs.imgSrc' style="width:100px;" onclick="selectImg(this)"> </div> } to @if (SVGs.FirstOrDefault() == null) { <p><em>Loading...</em></p> } else { @foreach (var svg in SVGs) { <div style="display:inline-block;"> <img id="@svg.URL" src='@svg.imgSrc' style="width:100px;" onclick="selectImg(this)"> </div> } } [describe] The [SVGs.FirstOrDefault()] statement is return null when the [SVGs] variable items count is zero, on otherhand the [SVGs.First()] statement return the [InvalidOperationException] type exception. If create exception handler that corresponds all exceptions, it is better use this [System.Linq.Enumerable.First Method].
>>System.Linq.Enumerable.First Method
・Call JavaScript from Blazor WebAssembly
Five fifths step is modifing the [wwwroot/index.html] file because JavaScript has to define in HTML file. However, this contents is vavigated by the [Shared/MainLayout.razor] file and includes the [Pages/Index.razor] component. So add the [SignIn] part on the [Shared/MainLayout.razor] file as simple procedures of calling JavaScript from Blazor. The Blazor method [SignIn()] is called use injected razor syntax of HTML [A] tag (<a href=”#” @onclick=”SignIn”>@SignedText</a>), then the Blazor method [SignIn()] calls the JavaSript method [SetSignInText] as implimentation of the [IJSRuntime] Interface.
The below code is whole of the [Shared/MainLayout.razor] file.
@inherits LayoutComponentBase @inject IJSRuntime JS <div class="page"> <div class="sidebar"> <NavMenu /> </div> <main> <div class="top-row px-4"> <a href="#" @onclick="SignIn">@SignedText</a> <span> | </span> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> </div> <article class="content px-4"> @Body </article> </main> </div> @code{ public MarkupString SignedText { get; set; } = (MarkupString)"<span style='color:#ff0000'>SignIn</span>"; public async Task SignIn() { SignedText = new (await JS.InvokeAsync("SetSignInText")); } } [describe] It's important that define the [@inject IJSRuntime JS] statement at head part of the [Shared/MainLayout.razor] file. As addition, implementation of the [IJSRuntime] interface is asyncronise, so the task define as async and await calling the [SetSignInText] JavaScript method. The [IJSRuntime] interface has also the [InvokeVoidAsync] method, thus if JavaSctipt returns some value, use the [InvokeAsync] method. These methods create an instance of ValueTask value type that is able to convert to Task reference type. So it is good that await a method returns value type, then construct new the MarkupString using it.
If the ValueTask value type is awaited, the instanse of Task reference type is executed, it is onetime. This mechanism effects to decleasing number of instance allocating times.
A reference type needs explicit instancing, and await end of instancing, furthermore, await end of processing that throw value of the processing to Blazor object. Long time and external processting of reference type task as await ansyncronously needs instancing a struct that has multiple fields.
The [SetSignInText] JavaScript has to defines as HTML, so it is good which on the [Shared/MainLayout.razor] file or on the [wwwroot/index.html] file (excludes the [Pages/Index.razor] file). If the reason is that it is share function for all pages, so define on the [Shared/MainLayout.razor] file. Or the reason is that want to bunch JavaScript functions at head of HTML file, define on the [Pages/Index.razor] file.
In this article, JavaScript functions are defined on the [wwwroot/index.html] file.
<script> window.SetSignInText = () =>{ var res = prompt("Please put login name."); if(res == null){ res="<span style='color:#ff0000'>SignIn</span>"; } return res; } </script> [describe] Though this code sample is dummy code of JavaScript that it does not login really, it is able to confirm that Blazor calls JavaScript method real. And can confirm that Blazor can await JavaScript method and acquire string that JavaScript object take and transfer.
If want to save the project until so far of this article to GitHub temporarily, create gitignore file use .NET template, and initialise git repository use the [Integrated terminal] of Visual Studio Code.
Put [dotnet new gitignore] command in the [Integrated terminal] to create gitignore file, and Put [git init] command to initialise git repository.
No responses yet