KHÔNG GIAN HỌC TẬP / IJSRuntime
Danh mục bài học Blazor Server .NET 10
BÀI 06Component và trạng thái

IJSRuntime

Kết nối C# với JavaScript: gọi hàm, nhận kết quả và quản lý JavaScript module trong component.

Giải thích, ví dụ & thực hành Tất cả bài học

Thử hai cách gọi JavaScript bên dưới: hàm toàn cục và ES module. Kết quả xuất hiện ngay trong mỗi khối; mở Xem code để đối chiếu lời gọi C# với hàm JavaScript tương ứng.

Bắt đầu từ một lời gọi đơn giản. Chọn Get Current Time để nhận dữ liệu từ JavaScript. Sau đó chuyển sang Init Module, thử phép cộng và bấm Dispose Module để quan sát trạng thái module.

01. Global JS — gọi hàm toàn cục

Global Result: none

Cách này dùng khi hàm JavaScript được khai báo toàn cục (ví dụ trong window hoặc file JS load trực tiếp vào page).

Xem code
Razor (Pages/IJSRuntimeDemo.razor)

<button class="btn btn-primary" @onclick="Global_ShowAlert">Alert</button>
<button class="btn btn-success" @onclick="Global_GetBrowserInfo">Get Browser Info</button>
<button class="btn btn-warning" @onclick="Global_GetCurrentTime">Get Current Time</button>

<p><b>Global Result:</b> @GlobalResult</p>

@code {
    private string GlobalResult = "none";

    private async Task Global_ShowAlert()
    {
        await JS.InvokeVoidAsync("blazorGlobal.showAlert", "Hello from Blazor (Global JS)");
        GlobalResult = "✅ Alert đã được gọi";
    }

    private async Task Global_GetBrowserInfo()
    {
        GlobalResult = await JS.InvokeAsync<string>("blazorGlobal.getBrowserInfo");
    }

    private async Task Global_GetCurrentTime()
    {
        GlobalResult = await JS.InvokeAsync<string>("blazorGlobal.getCurrentTime");
    }
}
JavaScript global (wwwroot/js/ijsruntime-global-demo.js)

window.blazorGlobal = {
    showAlert: function (message) {
        alert(message);
    },

    getBrowserInfo: function () {
        return `UserAgent: ${navigator.userAgent}`;
    },

    getCurrentTime: function () {
        return new Date().toLocaleTimeString();
    }
};

02. JS Module — import rồi gọi hàm

Module Ready: False
Module Result: none

Cách này dùng với file ES module. Đây là cách hiện đại hơn, gọn scope và dễ quản lý hơn so với global function.

Xem code
Razor (Pages/IJSRuntimeDemo.razor)
@inject IJSRuntime JS
@implements IAsyncDisposable

<button class="btn btn-dark" @onclick="Module_Init">Init Module</button>

<button class="btn btn-info text-white" @onclick="Module_AddNumbers">Add 10 + 20</button>

<button class="btn btn-secondary" @onclick="Module_FormatMessage">Format Message</button>

<button class="btn btn-outline-danger" @onclick="Module_Dispose">Dispose Module</button>

<p><b>Module Ready:</b> @ModuleReady</p>
<p><b>Module Result:</b> @ModuleResult</p>



@code {
private IJSObjectReference? _module;
private string ModuleResult = "none";
private bool ModuleReady = false;

private async Task EnsureModuleAsync()
{
    if (_module is null)
    {
        _module = await JS.InvokeAsync<IJSObjectReference>(
            "import",
            "./js/ijsruntime-module-demo.js");

        ModuleReady = true;
    }
}

private async Task Module_Init()
{
    await EnsureModuleAsync();
    ModuleResult = "Module initialized";
}

private async Task Module_AddNumbers()
{
    await EnsureModuleAsync();
    var result = await _module!.InvokeAsync<int>("addNumbers", 10, 20);
    ModuleResult = $"10 + 20 = {result}";
}

private async Task Module_FormatMessage()
{
    await EnsureModuleAsync();
    ModuleResult = await _module!.InvokeAsync<string>(
        "formatMessage",
        "Hello from Blazor Module");
}

private async Task Module_Dispose()
{
    if (_module is not null)
    {
        await _module.DisposeAsync();
        _module = null;
        ModuleReady = false;
        ModuleResult = "Module disposed";
    }
}

public async ValueTask DisposeAsync()
{
    if (_module is not null)
    {
        await _module.DisposeAsync();
    }
}
}
JavaScript module (wwwroot/js/ijsruntime-module-demo.js)

export function addNumbers(a, b) {
    return a + b;
}

export function formatMessage(message) {
    return `[Module] ${message} at ${new Date().toLocaleTimeString()}`;
}

03. Chọn Global hay Module?

  • Global JS: gọi nhanh, phù hợp demo nhỏ hoặc code cũ, nhưng dễ làm ô nhiễm global scope.
  • JS Module: hiện đại hơn, tách scope rõ ràng, dễ bảo trì và nên ưu tiên trong dự án lớn.
  • Khi dùng module, nhớ dispose IJSObjectReference nếu component có thể bị hủy nhiều lần.


04. JavaScript gọi ngược về C#

Result: none

JavaScript có thể gọi trực tiếp method C# bằng [JSInvokable].

Xem code
Razor

<button @onclick="CallJsToInvokeDotNet">
    JS gọi C#
</button>

<p><b>Result:</b> @DotNetResult</p>
C#

private string DotNetResult = "none";

private async Task CallJsToInvokeDotNet()
{
    await JS.InvokeVoidAsync("blazorGlobal.callDotNet");
}

[JSInvokable]
public static string DotNetHello()
{
    return "Hello from C#";
}
JavaScript

window.blazorGlobal.callDotNet = async function () {

    const result = await DotNet.invokeMethodAsync(
        'BlazorSample',
        'DotNetHello'
    );

    alert(result);
}

Điểm cần nhớ

Dùng InvokeVoidAsync khi không cần nhận kết quả, InvokeAsync<T> khi có dữ liệu trả về. Với module, giữ tham chiếu trong lúc dùng và giải phóng khi component kết thúc.

Web hosting by Somee.com