یک نکتهی تکمیلی: امکان فراخوانی کدهای #C از طریق کدهای جاوااسکریپت، در برنامههای Blazor
در مطلب جاری، روش فراخوانی توابع جاوااسکریپتی را از طریق کدهای #C برنامههای Blazor بررسی کردیم؛ عکس آن نیز میسر است و یکی از کاربردهای آن، ارسال نتایج کتابخانههای جاوااسکریپتی، به کدهای یک کامپوننت است. برای مثال کاربری در یک کامپوننت تقویم باز شده، روزی را انتخاب میکند. میخواهیم نتیجهی این انتخاب او را که در سمت کدهای جاوااسکریپتی رخداده، به نحوی به کدهای #C یک کامپوننت منتقل کنیم و یا حتی محاسباتی را در سمت کدهای #C انجام دهیم و به کدهای جاوااسکریپتی منتقل کنیم.
الف) فراخوانی متدهای استاتیک #C از طریق کدهای جاوااسکریپتی
فرض کنید متد استاتیک HelpMessage را میخواهیم از طریق کدهای جاوااسکریپتی فراخوانی کنیم. برای این منظور، یک چنین تابعی باید به ویژگی JSInvokable مزین شود:
@page "/js-sample"
<button class="btn btn-primary" onclick="JsFunctionHelper.invokeDotnetStaticFunction()">Invoke Static Method</button>
@code
{
[JSInvokable]
public static Task<string> HelpMessage()
{
return Task.FromResult("Help text from C# static function");
}
}
در اینجا یک دکمه را هم مشاهده میکنید که از ویژگی onclick استاندارد HTML استفاده کردهاست. یعنی متدی را که فراخوانی میکند، در حقیقت یک کد جاوا اسکریپتی است و نه یک متد #C واقع در کامپوننت جاری.
سپس در سمت در فایل Client\wwwroot\main.js برای فراخوانی متد HelpMessage خواهیم داشت:
window.JsFunctionHelper = {
invokeDotnetStaticFunction: function () {
DotNet.invokeMethodAsync("BlazorRazorSample.Client", "HelpMessage").then(
(data) => {
console.log(data);
}
);
}
};
در اینجا تابع سراسری جدیدی به نام invokeDotnetStaticFunction تعریف شدهاست (همان تابعی که توسط دکمهی قرار گرفته در کامپوننت فراخوانی میشود). این تابع با استفاده از متد DotNet.invokeMethodAsync استاندارد Blazor، کار فراخوانی متد استاتیک HelpMessage واقع در فضای نام BlazorRazorSample.Client را انجام میدهد. چون این فراخوانی async است، نتیجهی نهایی را از طریق یک callback دریافت کرده و لاگ میکند.
ب) فراخوانی متدهای غیر استاتیک #C از طریق کدهای جاوااسکریپتی
فراخوانی instance methodهای کامپوننتها از طریق کدهای #C، کمی پیچیدهتر است:
@page "/js-sample"
@implements IDisposable
@inject IJSRuntime jSRuntime
<button class="btn btn-primary" @onclick="CallInstanceMethod">Invoke Instance Method</button>
@code
{
private DotNetObjectReference<JsSample> objectReference;
[JSInvokable]
public string GetAddress()
{
return "123 Main Street";
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender)
{
objectReference = DotNetObjectReference.Create(this);
}
}
private async Task CallInstanceMethod()
{
await jSRuntime.InvokeVoidAsync("JsFunctionHelper.invokeDotnetInstanceFunction", objectReference);
}
public void Dispose()
{
objectReference?.Dispose();
}
}
- در این حالت نیاز است ارجاعی از وهلهی کامپوننت جاری را به متد جاوااسکریپتی ارسال کرد. به همین جهت در ابتدا توسط متد DotNetObjectReference.Create، این ارجاع را ایجاد کرده و سپس توسط متد jSRuntime.InvokeVoidAsync آنرا به سمت کدهای جاوا اسکریپتی ارسال میکنیم. در مثال فوق، JsSample همان نام کامپوننت جاری است.
- همچنین در اینجا onclick تعریف شده، به متدی داخل همین کامپوننت اشاره میکند.
- این ارجاع نیز باید در پایان کار کامپوننت، Dispose شود. به همین جهت implements IDisposable@ را مشاهده میکنید.
اکنون کدهای جاوا اسکریپتی که از این وهلهی دریافتی استفاده میکند، به صورت زیر خواهد بود. در این کدها addressProvider همان objectReference دریافتی است که توسط آن میتوان متد غیراستاتیک GetAddress کامپوننت را فراخوانی کرد:
window.JsFunctionHelper = {
invokeDotnetInstanceFunction: function (addressProvider) {
addressProvider.invokeMethodAsync("GetAddress").then((data) => {
console.log(data);
});
}
};