使用 Blazor 專案在 JavaScript 內呼叫 C# 執行個體方法
當在進行 Blazor 專案程式設計的時候,原則上許多的功能是不需要自行設計相關 JavaScript 程式碼來進行呼叫,因為 Blazor 開發框架中已經具備了許多機制,例如 資料綁定、路由 等相關機制,輕鬆地就能做到原先要使用 JavaScript 程式語言能夠做到的事情。
不過,Blazor 存在的目的,並不是要完全取代掉不去使用 JavaScript 程式語言功能,有些時候,需要能夠執行某一 JavaScript 程式碼之後,緊接著要能夠在 JavaScript 內來呼叫 .NET C# 的程式碼,這樣的需求在 Blazor 可以完成的實現出來,而在這裡將會有兩種情境可以使用: 靜態 .NET 方法呼叫 與 實例方法呼叫
在這篇文章中,將會設計一個按鈕,該按鈕點選下去之後,將會執行所綁定 JavaScript,這部分的功能將會是最基本的 HTML 網頁設計功能,而在這個按鈕所綁定的 JavaScript 方法內 (這裡將會呼叫 showPrompt 方法),該 JavaScript 方法將會呼叫 prompt 函式,讓使用者輸入自己的姓名文字,接著將會透過在 .NET C# 所產生的 DotNetObjectReference 物件,在 JavaScript 使用這樣的敘述 DotNetObject.invokeMethodAsync('SayHello', result);
執行該物件所擁有的 SayHello 方法,當然,該方法是使用 C# 所設計的,並且會在 .NET 環境下執行。
透過這樣的機制,便可以將 JavaScript 所取得的字串,傳遞到 .NET C# 變數內,接著透過 Blazor 所提供的資料綁定機制,將這段字串顯示在網頁上。
不過,在這裡首先需要建立起 DotNetObjectReference 物件,在這裡需要指定所用到的執行個體型別,也就是 BindDotNetInstance ,接下來使用 objRef = DotNetObjectReference.Create(helloHelper);
敘述來建立起 DotNetObjectReference物件。
不過,要把這個 objRef 物件傳遞到 JavaScript 函式內,將這個物件設定為 JavaScript 的全域變數,這裡又有兩種方式選擇,可以使用一個按鈕或者使用 Blazor 生命週期的事件 ComponentBase.OnAfterRenderAsync來做到,此時要呼叫 await jsRuntime.InvokeVoidAsync("SetDotNetObjectJS", objRef);
即可。
另外,為了要讓這個 Blazor 元件取得傳遞於 JavaScript 環境中的字串,需要綁定一個委派方法到 helloHelper.HelloHandler
內。
現在來看看如何做出這樣的範例成程式碼。
這篇文章的原始碼位於 bzCallCsharpInstanceMethodFromJavaScript
建立測試用主控台應用程式專案
- 開啟 Visual Studio 2019
- 選擇右下方的 [建立新的專案] 按鈕
- 在 [建立新專案] 對話窗中
- 從右上方的專案類型下拉按鈕中,找到並選擇 [Web]
- 從可用專案範本清單內,找到並選擇 [Blazor Server 應用程式]
- 點選左下方 [下一步] 按鈕
- 在 [設定新的專案] 對話窗中
- 在 [專案名稱] 欄位中輸入
bzCallCsharpInstanceMethodFromJavaScript
- 點選左下方 [下一步] 按鈕
- 在 [其他資訊] 對話窗中
- 在 [目標 Framework] 下拉選單中,選擇 [.NET 5.0 (目前)]
- 點選左下方 [建立] 按鈕
加入客製化 JavaScript
- 滑鼠右擊 [bzCallCsharpInstanceMethodFromJavaScript] 專案下的 [wwwroot] 節點
- 從彈出功能表選擇 [加入] > [新增資料夾]
- 在新增的資料夾,設定該資料夾名稱為 js
- 接著,滑鼠右擊 [js] 資料夾節點
- 從彈出功能表選擇 [加入] > [新增項目]
- 當出現 [新增項目 - bzCallCsharpInstanceMethodFromJavaScript] 對話窗
- 在右方選擇 [已安裝] > [Visual C#] > [ASP.NET Core] > [Web] > [指令碼]
- 在中間部份選擇 [JavaScript 檔] 這個項目
- 在下方名稱欄位內輸入 [JavaScript.js]
- 最後點選右下方的 [新增] 按鈕
請將底下的 JavaScript 程式碼輸入到這個檔案內
var DotNetObject = {}
function showPrompt(text) {
var result = prompt(text, 'Type your name here');
//呼叫該 .NET 執行個體(由類別 BindDotNetInstance 所產生)的 SayHello 方法
DotNetObject.invokeMethodAsync('SayHello', result);
}
function SetDotNetObjectJS(dotnetHelper) {
//將該 .NET 執行個體設定成為 JavaScript 的全域變數
DotNetObject = dotnetHelper;
}
修正 _Host.cshtml 檔案
- 請在 [Pages] 資料夾內找到並且打開 [_Host.cshtml] 檔案
- 請找到
<script src="_framework/blazor.server.js"></script>
敘述 - 在其上方加入這個敘述
<script src="/js/JavaScript.js"></script>
修正 index.razor
- 請在 [Pages] 資料夾內找到並且打開 [index.razor] 檔案
- 把底下的程式碼替換掉原先的程式碼
@page "/"
@inject IJSRuntime jsRuntime
@implements IDisposable
<h1>Hello, Blazor 專案在 JavaScript 內呼叫 C# 執行個體方法!</h1>
<div>
<button class="btn btn-primary" @onclick="SetDotNetObject">設定物件</button>
</div>
<div>
<button type="button" class="btn btn-primary" onclick="showPrompt('請輸入你的名字')">
綁定按鈕事件到 JavaScript 上
</button>
</div>
<div>
<div class="text-success">@Name</div>
</div>
@code {
BindDotNetInstance helloHelper = new BindDotNetInstance();
DotNetObjectReference<BindDotNetInstance> objRef;
public string Name = "";
async Task SetDotNetObject()
{
// 進行綁定該執行個體的委派方法,以便進行 callback 呼叫
helloHelper.HelloHandler = x =>
{
//將 JavaScript 程式碼取得的文字內容,設定到該 Blazor 元件內的 C# 變數中
Name = x;
//通知 Blazor 重新產生最新狀態的 Render Tree
StateHasChanged();
};
objRef = DotNetObjectReference.Create(helloHelper);
await jsRuntime.InvokeAsync<string>(
"SetDotNetObjectJS", objRef);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender == true)
{
helloHelper.HelloHandler = x =>
{
Name = x;
StateHasChanged();
};
objRef = DotNetObjectReference.Create(helloHelper);
await jsRuntime.InvokeVoidAsync(
"SetDotNetObjectJS", objRef);
}
}
public void Dispose()
{
objRef?.Dispose();
}
class BindDotNetInstance
{
public Action<string> HelloHandler;
[JSInvokable]
public void SayHello(string message)
{
var result = $"你好, {message}!";
HelloHandler?.Invoke(result);
}
}
}
執行並且測試
按下 F5 開始執行這個專案
現在將會看到底下的畫面
請點選 [綁定按鈕事件到 JavaScript 上] 按鈕
最後點選確定按鈕,就會看到底下執行結果