Blazor JavaScript Interop

Wprowadzenie

Myślę, że wsparcie wykorzystywania istniejących bibliotek JavaScript w Blazorze w przyszłości zaważy na tym, czy ten framework odniesie sukces, czy nie. Bogactwo różnorodnych bibliotek w JavaScript zapewnia bardzo duży wybór. Za każdym razem, gdy czegoś potrzebowałem, to pytanie nie brzmiało: „czy jest jakaś biblioteka, która to zrobi?”, tylko: „którą z 20 dostępnych bibliotek wykorzystać?”.

Twórcy Blazora pomyśleli o tym, aby łatwo można było z poziomu C# wywoływać kod JavaScript. W tym wpisie rozbudujemy przykładową aplikację właśnie o wywołanie metody z JavaScriptu. Co fajne, już w tym momencie powstają różne wrapery (np. Blazor Redux), które umożliwiają korzystanie z bibliotek JavaScript bezpośrednio z poziomu C# i Blazora.

Eksport pliku CSV

Kolejną rzeczą, którą lubię w Blazorze, jest to, że jak coś potrzebuję zrobić po stronie frontendu, to nie muszę szukać rozwiązania na to w JavaScripcie, tylko korzystam ze znanej mi biblioteki ze świata backendu.

Tak jak w przykładzie do tego wpisu: chcę wyeksportować plik CSV z danymi, to korzystam z biblioteki CsvHelper, której użyłbym po stronie Web API. Bibliotekę opisywałem jakiś czas temu; jeśli jej nie znasz, to zapraszam do lektury wpisu o CsvHelper.

Co ważne, w przykładzie chcę zrobić wszystko po stronie przeglądarki, czyli nie chcę wysyłać żądania do serwera, który wygeneruje plik CSV, który następnie pobierze użytkownik. Skoro mam wszystkie dane po stronie przeglądarki, to czemu nie wygenerować pliku w niej?

W tym wpisie dodamy eksport pliku CSV do projektu z poprzedniego wpisu o użyciu Web API w Blazorze. Najpierw dodamy do projektu pakiet CsvHelper z nugeta, a następnie zmienimy widok FetchData.razor:

@page "/fetchdata"
@using CsvHelper
@using System.IO
@using System.Text
@inject IWeatherForecastService Service
@inject IFileService FileService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<button onclick="@Download">Download</button>
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@functions {
WeatherForecast[] forecasts;
protected override async Task OnInitAsync()
{
forecasts = await Service.GetAsync();
}
void Download()
{
using (var writer = new StringWriter())
{
using (var csv = new CsvWriter(writer))
{
csv.WriteRecords(forecasts);
FileService.SaveAsAsync("data.csv", Encoding.ASCII.GetBytes(writer.ToString()));
}
}
}
}

W stosunku do wcześniejszego wpisu w pliku pojawiło się kilka zmian (poniżej numery linii):

  • 6 – wstrzyknięcie nowej usługi do pracy z plikami – jej kod będzie później we wpisie,
  • 18 – dodanie przycisku Download, który w momencie naciśnięcia wykonuje metodę Download,
  • 50–61 – metoda Download.

Metoda Download generuje zawartość pliku CSV do stringa i następnie korzysta z metody SaveAsAsync z FileService. Metoda ta właśnie za pomocą JavaScriptu wyświetla okno pobrania wygenerowanego pliku w przeglądarce.

Darmowy kurs Visual Studio

Pracując z setkami programistów, zauważyłem, że większość osób nie pracuje efektywnie w Visual Studio. W skrajnych przypadkach korzystali z kopiowania z wykorzystaniem menu Edit. Wiem, że to dziwne, ale naprawdę niektórzy tak pracują. Dlatego postanowiłem stworzyć kurs Visual Studio – aby pomóc koleżankom i kolegom w efektywniejszej pracy.

Przygotowałem 30 lekcji e-mail, w których pokażę Ci, w jaki sposób pracować efektywniej i szybciej w Visual Studio. Poznasz dodatki, bez których nie wyobrażam sobie pracy w tym IDE.

Po więcej informacji zapraszam na dedykowaną stronę kursu: Darmowy Kurs Visual Studio.

Quiz C#

Ostatnio przygotowałem również quiz C#, w którym możesz sprawdzić swoją wiedzę. Podejmiesz wyzwanie?

Blazor JavaScript Interop

Kluczowym elementem tego wpisu jest klasa FileService:

public class FileService : IFileService
{
private IJSRuntime _jsRuntime;
public FileService(IJSRuntime jsRuntime)
{
_jsRuntime = jsRuntime;
}
public Task SaveAsAsync(string filename, byte[] data)
{
return _jsRuntime.InvokeAsync<object>(
"saveAsFile",
filename,
Convert.ToBase64String(data));
}
}
public interface IFileService
{
Task SaveAsAsync(string filename, byte[] data);
}
view raw FileService.cs hosted with ❤ by GitHub

Klasa nie jest jakoś mocno skomplikowana. Wstrzykujemy do niej interfejs IJSRuntime, za pomocą którego możemy wywoływać funkcje z JavaScript. Takie wywołanie znajduje się w metodzie SaveAsAsync usługi.

IJSRuntime udostępnia generyczną metodę InvokeAsync, której pierwszy parametr określa nazwę metody, którą chcemy wywołać. Natomiast kolejnymi parametrami są poszczególne parametry wywoływanej metody z JavaScript. W tym przypadku metoda saveAsFile oczekuje dwóch parametrów. Pierwszy to nazwa pliku, drugi to jego zawartość. Dlatego do metody InvokeAsync jako drugi parametr przekazujemy nazwę pliku, a jako trzeci – zawartość.

Parametr generyczny metody określa typ, który funkcja JavaScript zwraca. W tym przykładzie funkcja nic nie zwraca, dlatego mamy typ object, a sama metoda SaveAsAsync zwraca klasę Task.

Samą metodę SaveAsFile dodałem do pliku index.html z folderu wwwroot i wygląda ona tak:

<script type="text/javascript">
function saveAsFile(filename, bytesBase64) {
var link = document.createElement('a');
link.download = filename;
link.href = "data:application/octet-stream;base64," + bytesBase64;
document.body.appendChild(link); // Needed for Firefox
link.click();
document.body.removeChild(link);
}
</script>
view raw index.html hosted with ❤ by GitHub

Nie jestem specem z JavaScriptu, dlatego metodę pobrałem ze Stack Overflow, więc może nie być idealna. 😉

Jak widać, wywołanie metody JavaScript z poziomu C# i Blazora nie jest trudne.

Klasa FileService została zarejestrowana w kontenerze w klasie Startup.cs. Podobnie jak to było z klasą WeatherForecastService z poprzedniego wpisu.

Test przykładu

Po pobraniu oraz uruchomieniu przykładu należy przejść pod adres http://localhost:52531/fetchdata i tam po chwili pojawi się tabelka z danymi, a nad nią przycisk Download. Po jego naciśnięciu nastąpi pobranie pliku CSV z danymi.

Poniżej znajduje się zrzut ekranu, w którym widać okno przeglądarki z załadowaną stroną oraz pobranym plikiem. Widać również narzędzie developerskie Chrome’a z zakładką Network, w której widać, że podczas eksportowania pliku nie nastąpiło wysłanie żądania do serwera po plik CSV. Cały eksport wykonał się w aplikacji działającej w przeglądarce.

blazor generate csv

Przykład

Jak wspomniałem wcześniej, w tym wpisie rozbudowałem przykład z wpisu z ubiegłego tygodnia. Zmodyfikowany przykład znajduje się w repozytorium: https://github.com/danielplawgo/BlazorWithApi. Po pobraniu przykładu można go od razu uruchomić i przetestować eksport pliku CSV.

Podsumowanie

Możliwość korzystania z istniejących bibliotek JavaScript będzie ważnym elementem, który zaważy na tym, czy Blazor odniesie jakiś sukces i będzie w przyszłości popularny. Osobiście bardzo na to liczę, bo wizja tworzenia frontendu w C# w tych samych narzędziach co Web API jest bardzo kusząca. 🙂

Cieszy mnie z jednej strony to, że łatwo można wywołać funkcje JavaScript z poziomu C#, a drugiej strony to, że powstają już wrapery popularnych bibliotek JavaScript. Myślę, że dzięki temu Blazor ma szansę zaistnieć w przyszłości jako framework do tworzenia frontendu.

Zainteresowany Blazorem? Jak tak to zapraszam na stronę prezentacji Front-end in C#? Yes – Blazor, gdzie znajdziesz więcej materiałów.

Szkolenie C# i .NET 5

Szkolenie C# i .NET 5

Zainteresował Ciebie ten temat? A może chcesz więcej? Jak tak to zapraszam na moje autorskie szkolenie o C# oraz .NET.

3 thoughts on “Blazor JavaScript Interop

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.