Gọi .NET code từ JavaScript trong Blazor apps

Mã JavaScript có thể chạy một method .NET được xác định trong mã Blazor của bạn bằng cách sử dụng DotNet utility class. Class này là một phần của JS interop library. Class DotNet exposes các hàm trợ giúp invokeMethod và invokeMethodAsync. Sử dụng invokeMethod để chạy một phương thức và đợi kết quả và sử dụng invokeMethodAsync để gọi phương thức không đồng bộ. Phương thức invokeMethodAsync trả về một JavaScript Promise.

Để duy trì khả năng đáp ứng trong các ứng dụng của bạn, hãy định nghĩa phương thức .NET là không đồng bộ và gọi nó bằng cách sử dụng invokeMethodAsync từ JavaScript.

Phương thức .NET đang được gọi phải được  JSInvokable attribute. Phương thức phải public và mọi tham số phải có thể tuần tự hóa dưới dạng JSON. Ngoài ra, đối với một phương thức không đồng bộ, kiểu trả về phải là void, một Task hoặc một đối tượng Task<T> object trong đó T là kiểu có thể tuần tự hóa JSON.

Trong .NET, một phương thức thuộc về một lớp (static method) hoặc một đối tượng (một instance method). Để gọi một phương thức tĩnh, bạn cung cấp tên của .NET assembly chứa lớp, mã định danh (identifier) cho phương thức và bất kỳ tham số nào mà phương thức chấp nhận làm đối số cho các hàm invokeMethod hoặc invokeMethodAsync. Theo mặc định, mã định danh phương thức giống như tên của phương thức, nhưng bạn có thể chỉ định một giá trị khác bằng thuộc tính JsInvokable.

Ví dụ: Gọi phương thức .NET tĩnh từ trình xử lý sự kiện JavaScript

Đoạn mã sau đây hiển thị một ví dụ dựa trên dữ liệu dự báo thời tiết trong trang FetchData.razor từ mẫu Ứng dụng máy chủ Blazor. Phương pháp CalculAverageAsync tính toán trung bình cho nhiệt độ Fahrenheit và Centigrade trong mảng dự báo.

Trong ví dụ này, mảng dự báo đã được thay đổi thành static để làm cho nó có thể truy cập trực tiếp từ một phương thức tĩnh (static). Tuy nhiên, thay đổi này gây ra một bug  chỉ xuất hiện khi Ứng dụng máy chủ Blazor được triển khai tới môi trường máy chủ và được chạy đồng thời bởi nhiều người dùng. Bạn sẽ sớm thấy cách sửa lỗi này.

@code {
private static WeatherForecast[] forecasts; // NOTE CHANGE TO STATIC - CAUSES A BUG

...

[JSInvokable]
public static async Task<decimal[]> CalculateAveragesAsync()
{
var forecastTemperatures = from f in forecasts
select (f.TemperatureF, f.TemperatureC);

var avgF = await Task.FromResult(forecastTemperatures.Average(t => t.TemperatureF));
var avgC = await Task.FromResult(forecastTemperatures.Average(t => t.TemperatureC));

return new[] { (decimal)avgF, (decimal)avgC };
}
}

Để minh họa phương pháp này hoạt động, hãy thêm chân trang sau vào <table> trên trang FetchData.razor:

...
<table class="table">
<thead>
...
</thead>
<tbody>
...
</tbody>
<tfoot>
<tr>
<td><button onclick="calculateAverages()">Averages</button></td>
<td></td>
<td id="avgC"></td>
<td></td>
<td id="avgF"></td>
<td></td>
<td></td>
</tr>
</tfoot>
</table>
...
Footer này chứa một nút chạy calculateAverages JavaScript function (hiển thị tiếp theo) khi nó được nhấp vào. Footer  cũng bao gồm một cặp trường có tên avgC và avgF sẽ được sử dụng để hiển thị nhiệt độ trung bình.
Bạn có thể thêm hàm tính toán trong JavaScript được hiển thị bên dưới vào phần tử <script> trên tệp Pages / _Host.cshtml. Thay thế WebApplicationAssemblyName trong lệnh gọi đến DotNet.invokeMethodAsync bằng tên của ứng dụng Blazor của bạn (tên này phải giống với tên của assembly chứa mã Blazor của bạn):
<script>
...

window.calculateAverages = async () => {
var averages = await DotNet.invokeMethodAsync('WebApplicationAssemblyName', 'CalculateAveragesAsync');
$('#avgF').html(averages[0]);
$('#avgC').html(averages[1]);
};
</script>
Hàm calculateAverages chạy tính toán trung bình và nhận kết quả trong một mảng có tên trung bình. Các câu lệnh tiếp theo hiển thị các giá trị trong mảng này trong trường avgF và avgC. Nếu bạn chạy ứng dụng và truy cập trang Tìm nạp Dữ liệu, bạn có thể nhấp vào nút Averages và kết quả sẽ được hiển thị trong chân trang của bảng:
blazor-fetch-data-page-averages

Gọi một .NET instance method từ JavaScript

Để chạy một instance method, JavaScript yêu cầu một tham chiếu đối tượng trỏ đến instance đó. JS interop cung cấp loại DotNetReference chung mà bạn có thể sử dụng để tạo tham chiếu đối tượng(object reference) trong mã .NET của mình. Mã của bạn phải cung cấp tham chiếu đối tượng này cho JavaScript. Sau đó, mã JavaScript có thể gọi invokeMethodAsync với tên của phương thức .NET và bất kỳ tham số nào mà phương thức yêu cầu. Để tránh rò rỉ bộ nhớ, mã .NET của bạn nên loại bỏ tham chiếu đối tượng khi nó không còn cần thiết nữa.
Ví dụ: Gọi một phương thức .NET instance từ JavaScript
Trong ví dụ trước, mã JavaScript chạy một phương thức tĩnh (static), phương thức này tính toán các giá trị trung bình cho một tập dữ liệu tĩnh (static). Làm cho mọi thứ (static) không phải là một cách tiếp cận có thể mở rộng trong một hệ thống nhiều người dùng. Tất cả người dùng sẽ phải làm việc với cùng một dữ liệu được chia sẻ, có thể làm hỏng kết quả.
Giải pháp là chuyển trở lại dữ liệu thể hiện (instance data), dữ liệu này chỉ có thể truy cập được thông qua phương thức thể hiện (nstance method) hoặc tham chiếu đối tượng (object reference) từ phương thức tĩnh. Để đạt được điều này, bạn phải cung cấp một tham chiếu đối tượng đến phiên bản hiện tại của đối tượng FetchData cho mã JavaScript của bạn. Trong mã JavaScript trên trang Pages / _Host.cshtml, hãy thêm biến và hàm được hiển thị bên dưới:
<script>
...
var objectRef;

window.populateObjectRef = (ref) => {
objectRef = ref;
};

...
</script>
Hàm populateObjectRef nhận một tham chiếu đối tượng và lưu nó vào bộ nhớ cache trong biến objectRef. Sau đó, bạn có thể sửa đổi hàm calculateAverages  để gọi phương thức calculateAverages trong .NET bằng cách sử dụng tham chiếu đối tượng này, như được hiển thị bên dưới:
<script>
...
window.calculateAverages = async () => {
var averages = await objectRef.invokeMethodAsync('CalculateAveragesAsync');
$('#avgF').html(averages[0]);
$('#avgC').html(averages[1]);
};
</script>
Bước cuối cùng là tạo tham chiếu đối tượng trong mã .NET và chuyển nó sang JavaScript. Sử dụng phương thức JS.InvokeVoidAsync của JS interop để thực hiện việc này. Bạn cũng nên đảm bảo rằng tham chiếu đối tượng được xử lý khi đối tượng FetchData bị xóa khỏi bộ nhớ bằng cách triển khai giao diện IDisposable và thêm phương thức Dispose.
Đoạn mã sau làm nổi bật các bổ sung cho mã FetchData trên trang FetchData.razor. Thành phần sử dụng sự kiện OnAfterRender để tạo tham chiếu đối tượng và gọi hàm populateObjectRef. Như đã mô tả trước đó, thời gian là quan trọng. Nếu bạn thực hiện các thao tác này trước khi kết xuất rendering, thì JS interop sẽ chưa khả dụng:
...
@implements IDisposable

<h1>Weather forecast</h1>
...

@code {
...
private DotNetObjectReference<FetchData> objRef;

...

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
objRef = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("populateObjectRef", objRef);
}
}

...

public void Dispose()
{
objRef?.Dispose();
}
}
Theo : https://docs.microsoft.com/en-us/learn/modules/blazor-build-rich-interactive-components/2-create-user-interfaces-blazor-components

Leave a Reply

Your email address will not be published.