Microsoft.JSInterop.JSException: Could not find '<method>' in 'window'

Viewed 8268

oof what a day, trying to figure out dynamically injecting sdk.js and create button tag with src = some url.

I have added all my js code into a file scripting to inject sdk based on params and kept under wwwroot, but for somereason my function is not able detect by server.js

Exception that am getting is - Error: Microsoft.JSInterop.JSException: Could not find 'initializeSDK' in 'window'.

here's the js code i have

    window.initializeSDK = {

    ejectInjectSdk: function (action, environment) {
        var script = document.createElement('script');
        if (action == "inject") {
            if (self === top) {
                var antiClickjack = document.getElementById("antiClickjack");
                antiClickjack.parentNode.removeChild(antiClickjack);
            } else {
                top.location = self.location;
            }


            if (environment == 'Sandbox') {

                script.type = 'text/javascript';
                script.src = "https://sandbox-assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js";
                document.body.append(script);
            } else if (environment == 'live') {
                script.type = 'text/javascript';
                script.src = "https://assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js";
                document.body.append(script);
            }

        } else if (action == "eject") {
            if (environment == 'Sandbox') {
                $("script[src='https://sandbox-assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js']").remove();
            } else if (environment == 'live') {
                $("script[src='https://assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js']").remove();
            }

        }
        $("#vcoholder").hide();
    },

    ejectInjectBtn: function (initpayload) {
        $("#vcoholder").append("<img alt='Visa Checkout' class='v-button' role='button' src='https://sandbox.secure.checkout.visa.com/wallet-services-web/xo/button.png' />");
        onVisaCheckoutReady(initpayload);
        $("#vcoholder").show();

    },

    onVisaCheckoutReady: function (initpayload) {

        console.log(initpayload);
        V.init(initpayload);
        V.on("payment.success", function (payment) {
            console.log(payment);
            var obj = {};
            obj.isLive = false;
            obj.apikey = $.trim($("#apikey").val());
            obj.sharedsecretkey = $.trim($("#sharedsecretkey").val());
            obj.encapikey = $.trim($("#encapikey").val());
            obj.encsharedsecretkey = $.trim($("#encsharedsecretkey").val());
            obj.encKey = payment.encKey;
            obj.encPaymentData = payment.encPaymentData;
            obj.vInitRequest = payment.vInitRequest;
            obj.callid = payment.callid;

            console.log("Payload sending to server " + JSON.stringify(obj));

            $.ajax({
                type: "POST",
                url: '../api/Restful/Getresultsv2',
                data: JSON.stringify(obj),
                dataType: "json",
                success: function (result) {
                    console.log(result);
                    $("#displayJson").jsonViewer(result, {
                        collapsed: false,
                        withQuotes: true
                    })
                }
            });

        });
        V.on("payment.cancel", function (payment) {
            console.log(JSON.stringify(payment));
        });
        V.on("payment.error", function (payment, error) {
            console.log(JSON.stringify(error));
        });
    }
};

And complete razor page below-

@page "/ClicktoPay"
@using Microsoft.AspNetCore.Authorization
@using Zapy.Server.ViewModels
@using Zapy.Server.Servcies
@using Zapy.Server.Models.Clicktopay;
@using Newtonsoft.Json;
@inject CheckoutService Checkoutservice
@inject IJSRuntime JSRuntime
@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration


<h3>Component1</h3>

<div id="nonsegmentedkeys" class="row">

    <div class="col">
        <div class="card" style="height: 560px;">
            <div class="card-body">
                <EditForm Model="@clicktoPayViewModel">
                    <div id="segmentedkeys">
                        <div class="form-group">
                            <label for="encryptionapikey">Encryption's Apikey</label>
                            <InputText class="form-control form-control-sm" id="encryptionapikey" @bind-Value="clicktoPayViewModel.EncryptionKey" />
                        </div>
                        <div class="form-group">
                            <label for="encryptionsharedsecretkey">Encryptions's Sharedsecret</label>
                            <InputText class="form-control form-control-sm" id="encryptionsharedsecretkey" @bind-Value="clicktoPayViewModel.EncryptionSharedsecret" />
                        </div>
                        <div class="form-group ">
                            <label for="inboundapikey">Inbound Apikey</label>
                            <InputText class="form-control form-control-sm" id="inboundapikey" @bind-Value="clicktoPayViewModel.InboundApikey" />
                        </div>
                        <div class="form-group">
                            <label for="inboundsharedsecret">Inbound Sharedsecret</label>
                            <InputText class="form-control form-control-sm" id="inboundsharedsecret" @bind-Value="clicktoPayViewModel.InboundSharedsecret" />
                        </div>

                    </div>
                </EditForm>
                <div id="vcoholder">
                </div>

            </div>
            <div class="card-footer">
                <button class="btn btn-primary" @onclick="CreateClicktopay">Initialize ClicktoPay</button>
            </div>
        </div>
    </div>

    <div class="col">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">Initialize parameters here</h5>
                <textarea id="displayJson" value="@clicktoPayViewModel.InitParameters" style="width: 550px; height: 480px;" rows="10"></textarea>
            </div>
        </div>
    </div>

</div>


@code {
    private ClicktoPayViewModel clicktoPayViewModel = new ClicktoPayViewModel();

    protected override async Task OnInitializedAsync()
    {

        clicktoPayViewModel = await Checkoutservice.GetClicktoPayDefaultAsync();

    }

    public async Task CreateClicktopay()
    {

        await JSRuntime.InvokeVoidAsync("initializeSDK.ejectInjectSdk", "inject", "Sandbox");
        await JSRuntime.InvokeVoidAsync("initializeSDK.ejectInjectBtn", clicktoPayViewModel.InitParameters);

    }
}
2 Answers

i don't know if you are still troubled by this.

But i also stumbled upon similar problem, where i already declared my script inside the enclosing <body> of _Layout.cshtml (I'm on Blazor Server), but i can't invoke it, the error said 'not defined'.

So what i do is basically JS Isolation (MS Docs) :

  1. put the said script inside a separate .js file, export the functions
  2. Prepare an IJSObjectReference as a C# object reference.
  3. Inside your component's @code or component's code-behind class, override OnAfterRenderAsync(), check if it is firstRender. It needs to be inside OnAfterRender or OnInitialized, async or not, because in Blazor (server at least) @inject-ed or [Inject]-ed object only available, at least after the component is rendered.
  4. load your .js script into the JS object reference using the injected IJSRuntime.
  5. Then you can use it in the scope of that current component.

Here is the minimum example i can muster out

@using Microsoft.JSInterop;
@inject IJSRuntime jsInvoker
@page "/ThePage"

<h1>Hello<h1>
<Button @onClick=Consoom>Text</Button>

@code {
    private IJSObjectReference? jsModule;
    protected override async Task OnAfterRenderAsync(bool firstRender) {
        if (firstRender)
        {
            jsModule = await jsInvoker.InvokeAsync<IJSObjectReference>("import", "./script/CWriter.js");
        }
        await base.OnAfterRenderAsync(firstRender);
    }
    private async Task<bool> Consoom() {
        await jsModule.InvokeVoidAsync("someFunc", "someArgs");
    }
}

This works for me, and i am on Blazor Server w/ .NET 6.

there's a thing to note, IJSObjectReference has DisposeAsync() but no synchronous, the usual, Dispose() , so you have to mind about its life-cycle too, maybe make your component also implement IAsyncDisposable.

Something to keep in mind is the official Microsoft documentation, although I was following it I did not notice that I was reading the ASP Core 6.0 documentation instead of ASP Core 5.0, in the top left menu you can select this. In my case for ASP Core 5.0 it should be noted that <script> should go in _Host.cshtml and in ASP Core 6.0 <script> goes in _Layoult.cshtml

enter image description here

Related