ASP.NET Core Blazor의 JavaScript 함수에서 .NET 메서드 호출

이 문서에서는 JS(JavaScript)에서 .NET 메서드를 호출하는 방법을 설명합니다. .NET에서 JS 함수를 호출하는 방법에 대한 내용은 ASP.NET Core Blazor의 .NET 메서드에서 JavaScript 함수 호출을 참조하세요.

정적 .NET 메서드 호출

JavaScript(JS)에서 정적 .NET 메서드를 호출하려면 JS 함수 DotNet.invokeMethod 또는 DotNet.invokeMethodAsync를 사용합니다. 메서드를 포함하는 어셈블리의 이름, 정적 .NET 메서드 식별자 및 인수를 전달합니다.

다음 예제에서는

  • {ASSEMBLY NAME} 자리 표시자는 앱의 어셈블리 이름입니다.
  • {.NET METHOD ID} 자리 표시자는 .NET 메서드 식별자입니다.
  • {ARGUMENTS} 자리 표시자는 메서드에 전달할 쉼표로 구분된 선택적 인수이며 각 인수는 JS직렬화 가능해야 합니다.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});

DotNet.invokeMethod는 작업의 결과를 반환합니다. DotNet.invokeMethodAsync는 작업의 결과를 나타내는 JS Promise를 반환합니다.

이 비동기 함수(invokeMethodAsync)는 Blazor Server 시나리오를 지원하기 위해 동기 버전(invokeMethod)보다 우선적으로 적용됩니다.

.NET 메서드는 퍼블릭이고 정적이며 [JSInvokable] 특성이 있어야 합니다.

다음 예제에서는

  • {<T>} 자리 표시자는 값을 반환하는 메서드에만 필요한 반환 형식을 나타냅니다.
  • {.NET METHOD ID} 자리 표시자는 메서드 식별자입니다.
@code {
    [JSInvokable]
    public static Task{<T>} {.NET METHOD ID}()
    {
        ...
    }
}

개방형 제네릭 메서드를 호출하는 것은 정적 .NET 메서드에서 지원되지 않지만 이 문서의 뒷부분에서 설명되는 인스턴스 메서드를 사용하면 지원됩니다.

다음 CallDotNetExample1 구성 요소에서 ReturnArrayAsync C# 메서드는 int 배열을 반환합니다. [JSInvokable] 특성은 메서드에 적용되어 메서드를 JS에서 호출 가능하게 만듭니다.

Pages/CallDotNetExample1.razor:

@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

@code {
    [JSInvokable]
    public static Task<int[]> ReturnArrayAsync()
    {
        return Task.FromResult(new int[] { 1, 2, 3 });
    }
}
@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

@code {
    [JSInvokable]
    public static Task<int[]> ReturnArrayAsync()
    {
        return Task.FromResult(new int[] { 1, 2, 3 });
    }
}

<button> 요소의 onclick HTML 특성은 Blazor의 @onclick 지시문 특성이 아니라 click 이벤트를 처리하기 위한 JavaScript의 onclick 이벤트 처리기 할당입니다. returnArrayAsync JS 함수는 처리기로서 할당됩니다.

다음 returnArrayAsync JS 함수는 이전 CallDotNetExample1 구성 요소의 ReturnArrayAsync .NET 메서드를 호출하고 결과를 브라우저의 웹 개발자 도구 콘솔에 기록합니다. BlazorSample은 앱의 어셈블리 이름입니다.

wwwroot/index.html(Blazor WebAssembly) 또는 Pages/_Host.cshtml(Blazor Server)의 닫는 </body> 태그 내부:

<script>
  window.returnArrayAsync = () => {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
      .then(data => {
        console.log(data);
      });
    };
</script>

Trigger .NET static method 단추를 선택하면 브라우저의 개발자 도구 콘솔 출력이 배열 데이터를 표시합니다. 출력 형식은 브라우저마다 약간씩 다릅니다. 다음 출력은 Microsoft Edge에서 사용하는 형식을 보여 줍니다.

Array(3) [ 1, 2, 3 ]

기본적으로 JS 호출의 .NET 메서드 식별자는 .NET 메서드 이름이지만 [JSInvokable] 특성 생성자를 사용하여 다른 식별자를 지정할 수 있습니다. 다음 예제에서 DifferentMethodNameReturnArrayAsync 메서드에 대해 할당된 메서드 식별자입니다.

[JSInvokable("DifferentMethodName")]

DotNet.invokeMethod 또는 DotNet.invokeMethodAsync에 대한 호출에서 다음과 같이 DifferentMethodName을 호출하여 ReturnArrayAsync .NET 메서드를 실행합니다.

  • DotNet.invokeMethod('BlazorSample', 'DifferentMethodName');
  • DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');

참고

이 단원의 ReturnArrayAsync 메서드 예제에서는 명시적 C# asyncawait 키워드를 사용하지 않고 Task의 결과를 반환합니다. asyncawait를 사용하여 메서드를 코딩하는 방식은 await 키워드를 사용하여 비동기 작업의 값을 반환하는 메서드에서 일반적입니다.

asyncawait 키워드로 구성된 ReturnArrayAsync 메서드:

[JSInvokable]
public static async Task<int[]> ReturnArrayAsync()
{
    return await Task.FromResult(new int[] { 1, 2, 3 });
}

자세한 내용은 C# 가이드에서 async 및 await를 사용한 비동기 프로그래밍을 참조하세요.

인스턴스 .NET 메서드 호출

JavaScript(JS)에서 인스턴스 .NET 메서드를 호출하려면

  • DotNetObjectReference에서 인스턴스를 래핑하고 Create를 호출하여 .NET 인스턴스를 JS에 대한 참조로 전달합니다.
  • JS전달된 DotNetObjectReference에서 invokeMethod 또는 invokeMethodAsync를 사용하여 .NET 인스턴스 메서드를 호출합니다. JS에서 다른 .NET 메서드를 호출할 때 .NET 인스턴스를 인수로 전달할 수도 있습니다.
  • DotNetObjectReference를 삭제합니다.

구성 요소 인스턴스 예제

다음 sayHello1 JS 함수는 DotNetObjectReference를 수신하고 invokeMethodAsync를 호출하여 구성 요소의 GetHelloMethod .NET 메서드를 호출합니다.

wwwroot/index.html(Blazor WebAssembly) 또는 Pages/_Host.cshtml(Blazor Server)의 닫는 </body> 태그 내부:

<script>
  window.sayHello1 = (dotNetHelper) => {
    return dotNetHelper.invokeMethodAsync('GetHelloMessage');
  };
</script>

다음 CallDotNetExample2 구성 요소:

  • 구성 요소에는 GetHelloMessage라는 JS 호출 가능 .NET 메서드가 있습니다.
  • Trigger .NET instance method 단추를 선택하면 JS 함수 sayHello1DotNetObjectReference를 사용하여 호출됩니다.
  • sayHello1:
    • GetHelloMessage를 호출하고 메시지 결과를 받습니다.
    • 호출하는 TriggerDotNetInstanceMethod 메서드에 메시지 결과를 반환합니다.
  • resultsayHello1에서 반환된 메시지는 사용자에게 표시됩니다.
  • 메모리 누수를 방지하고 가비지 수집을 허용하기 위해 DotNetObjectReference에서 만든 .NET 개체 참조는 Dispose 메서드에서 삭제됩니다.

Pages/CallDotNetExample2.razor:

@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<CallDotNetExample2> objRef;

    public async Task TriggerDotNetInstanceMethod()
    {
        objRef = DotNetObjectReference.Create(this);
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {name}!";

    public void Dispose()
    {
        objRef?.Dispose();
    }
}
@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<CallDotNetExample2> objRef;

    public async Task TriggerDotNetInstanceMethod()
    {
        objRef = DotNetObjectReference.Create(this);
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {name}!";

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

인스턴스 메서드에 인수를 전달하려면 다음을 수행합니다.

  1. .NET 메서드 호출에 매개 변수를 추가합니다. 다음 예제에서는 이름이 메서드에 전달됩니다. 필요에 따라 목록에 추가 매개 변수를 추가합니다.

    <script>
      window.sayHello2 = (dotNetHelper, name) => {
        return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
      };
    </script>
    
  2. .NET 메서드에 매개 변수 목록을 제공합니다.

    Pages/CallDotNetExample3.razor:

    @page "/call-dotnet-example-3"
    @implements IDisposable
    @inject IJSRuntime JS
    
    <h1>Call .NET Example 3</h1>
    
    <p>
        <label>
            Name: <input @bind="name" />
        </label>
    </p>
    
    <p>
        <button @onclick="TriggerDotNetInstanceMethod">
            Trigger .NET instance method
        </button>
    </p>
    
    <p>
        @result
    </p>
    
    @code {
        private string name;
        private string result;
        private DotNetObjectReference<CallDotNetExample3> objRef;
    
        public async Task TriggerDotNetInstanceMethod()
        {
            objRef = DotNetObjectReference.Create(this);
            result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
        }
    
        [JSInvokable]
        public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
    
        public void Dispose()
        {
            objRef?.Dispose();
        }
    }
    
    @page "/call-dotnet-example-3"
    @implements IDisposable
    @inject IJSRuntime JS
    
    <h1>Call .NET Example 3</h1>
    
    <p>
        <label>
            Name: <input @bind="name" />
        </label>
    </p>
    
    <p>
        <button @onclick="TriggerDotNetInstanceMethod">
            Trigger .NET instance method
        </button>
    </p>
    
    <p>
        @result
    </p>
    
    @code {
        private string name;
        private string result;
        private DotNetObjectReference<CallDotNetExample3> objRef;
    
        public async Task TriggerDotNetInstanceMethod()
        {
            objRef = DotNetObjectReference.Create(this);
            result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
        }
    
        [JSInvokable]
        public string GetHelloMessage(string passedName) => $"Hello, {passedName}!";
    
        public void Dispose()
        {
            objRef?.Dispose();
        }
    }
    

클래스 인스턴스 예제

다음 sayHello1 JS 함수:

  • 전달된 DotNetObjectReference에 대해 GetHelloMessage .NET 메서드를 호출합니다.
  • GetHelloMessage에서 sayHello1 호출자로 메시지를 반환합니다.

wwwroot/index.html(Blazor WebAssembly) 또는 Pages/_Host.cshtml(Blazor Server)의 닫는 </body> 태그 내부:

<script>
  window.sayHello1 = (dotNetHelper) => {
    return dotNetHelper.invokeMethodAsync('GetHelloMessage');
  };
</script>

다음 HelloHelper 클래스에는 GetHelloMessage이라는 JS 호출 가능 .NET 메서드가 있습니다. HelloHelper가 만들어지면 Name 속성의 이름이 GetHelloMessage에서 메시지를 반환하는 데 사용됩니다.

HelloHelper.cs:

using Microsoft.JSInterop;

public class HelloHelper
{
    public HelloHelper(string name)
    {
        Name = name;
    }

    public string Name { get; set; }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;

public class HelloHelper
{
    public HelloHelper(string name)
    {
        Name = name;
    }

    public string Name { get; set; }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}

다음 JsInteropClasses3 클래스의 CallHelloHelperGetHelloMessage 메서드는 HelloHelper의 새 인스턴스를 사용하여 JS 함수 sayHello1를 호출합니다.

JsInteropClasses3.cs:

using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses3 : IDisposable
{
    private readonly IJSRuntime js;
    private DotNetObjectReference<HelloHelper> objRef;

    public JsInteropClasses3(IJSRuntime js)
    {
        this.js = js;
    }

    public ValueTask<string> CallHelloHelperGetHelloMessage(string name)
    {
        objRef = DotNetObjectReference.Create(new HelloHelper(name));

        return js.InvokeAsync<string>("sayHello1", objRef);
    }

    public void Dispose()
    {
        objRef?.Dispose();
    }
}
using System;
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses3 : IDisposable
{
    private readonly IJSRuntime js;
    private DotNetObjectReference<HelloHelper> objRef;

    public JsInteropClasses3(IJSRuntime js)
    {
        this.js = js;
    }

    public ValueTask<string> CallHelloHelperGetHelloMessage(string name)
    {
        objRef = DotNetObjectReference.Create(new HelloHelper(name));

        return js.InvokeAsync<string>("sayHello1", objRef);
    }

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

메모리 누수를 방지하고 가비지 수집을 허용하기 위해 DotNetObjectReference에서 만든 .NET 개체 참조는 Dispose 메서드에서 삭제됩니다.

다음 CallDotNetExample4 구성 요소에서 Trigger .NET instance method 단추를 선택하면 name 값을 사용하여 JsInteropClasses3.CallHelloHelperGetHelloMessage가 호출됩니다.

Pages/CallDotNetExample4.razor:

@page "/call-dotnet-example-4"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private JsInteropClasses3 jsInteropClasses;

    private async Task TriggerDotNetInstanceMethod()
    {
        jsInteropClasses = new JsInteropClasses3(JS);
        result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
    }

    public void Dispose()
    {
        jsInteropClasses?.Dispose();
    }
}
@page "/call-dotnet-example-4"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private JsInteropClasses3 jsInteropClasses;

    private async Task TriggerDotNetInstanceMethod()
    {
        jsInteropClasses = new JsInteropClasses3(JS);
        result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
    }

    public void Dispose()
    {
        jsInteropClasses?.Dispose();
    }
}

다음 그림은 Name 필드에 이름 Amy Pond가 있는 렌더링된 구성 요소를 보여 줍니다. 이 단추를 선택하면 Hello, Amy Pond!가 UI에 표시됩니다.

렌더링된 'CallDotNetExample4' 구성 요소 예제

JsInteropClasses3 클래스에 표시된 이전 패턴은 구성 요소에서 완전히 구현될 수도 있습니다.

Pages/CallDotNetExample5.razor:

@page "/call-dotnet-example-5"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<HelloHelper> objRef;

    public async Task TriggerDotNetInstanceMethod()
    {
        objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

    public void Dispose()
    {
        objRef?.Dispose();
    }
}
@page "/call-dotnet-example-5"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<HelloHelper> objRef;

    public async Task TriggerDotNetInstanceMethod()
    {
        objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

메모리 누수를 방지하고 가비지 수집을 허용하기 위해 DotNetObjectReference에서 만든 .NET 개체 참조는 Dispose 메서드에서 삭제됩니다.

Name 필드에 이름 Amy Pond가 제공된 경우 CallDotNetExample5 구성 요소에 의해 표시되는 출력은 Hello, Amy Pond!입니다.

위의 CallDotNetExample5 구성 요소에서 .NET 개체 참조는 삭제됩니다. 클래스 또는 구성 요소가 DotNetObjectReference를 삭제하지 않으면 전달된 DotNetObjectReference에서 dispose를 호출하여 클라이언트에서 삭제합니다.

window.jsFunction = (dotnetHelper) => {
  dotnetHelper.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}');
  dotnetHelper.dispose();
}

앞의 예제에서:

  • {ASSEMBLY NAME} 자리 표시자는 앱의 어셈블리 이름입니다.
  • {.NET METHOD ID} 자리 표시자는 .NET 메서드 식별자입니다.

구성 요소 인스턴스 .NET 메서드 도우미 클래스

도우미 클래스는 .NET 인스턴스 메서드를 Action으로 호출할 수 있습니다. 도우미 클래스는 다음과 같은 시나리오에서 유용합니다.

  • 동일한 형식의 여러 구성 요소가 동일한 페이지에 렌더링되는 경우
  • Blazor Server 앱에서 여러 사용자가 동시에 동일한 구성 요소를 사용하는 경우

다음 예제에서는

  • CallDotNetExample6 구성 요소에는 앱의 Shared 폴더에 있는 공유 구성 요소인 여러 ListItem 구성 요소가 포함되어 있습니다.
  • ListItem 구성 요소는 메시지와 단추로 구성됩니다.
  • ListItem 구성 요소 단추를 선택하면 해당 ListItemUpdateMessage 메서드가 목록 항목 텍스트를 변경하고 단추를 숨깁니다.

다음 MessageUpdateInvokeHelper 클래스는 클래스를 인스턴스화할 때 지정된 Action을 호출하기 위해 JS 호출 가능 .NET 메서드인 UpdateMessageCaller를 유지 관리합니다. BlazorSample은 앱의 어셈블리 이름입니다.

MessageUpdateInvokeHelper.cs:

using System;
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
    private Action action;

    public MessageUpdateInvokeHelper(Action action)
    {
        this.action = action;
    }

    [JSInvokable("BlazorSample")]
    public void UpdateMessageCaller()
    {
        action.Invoke();
    }
}
using System;
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
    private Action action;

    public MessageUpdateInvokeHelper(Action action)
    {
        this.action = action;
    }

    [JSInvokable("BlazorSample")]
    public void UpdateMessageCaller()
    {
        action.Invoke();
    }
}

다음 updateMessageCaller JS 함수는 UpdateMessageCaller .NET 메서드를 호출합니다. BlazorSample은 앱의 어셈블리 이름입니다.

wwwroot/index.html(Blazor WebAssembly) 또는 Pages/_Host.cshtml(Blazor Server)의 닫는 </body> 태그 내부:

<script>
  window.updateMessageCaller = (dotnetHelper) => {
    dotnetHelper.invokeMethodAsync('BlazorSample', 'UpdateMessageCaller');
    dotnetHelper.dispose();
  }
</script>

다음 ListItem 구성 요소는 부모 구성 요소에서 여러 번 사용할 수 있는 공유 구성 요소로, HTML 목록(<ul>...</ul> 또는 <ol>...</ol>)에 대해 목록 항목(<li>...</li>)을 만듭니다. 각 ListItem 구성 요소 인스턴스는 Action이 해당 UpdateMessage 메서드로 설정된 MessageUpdateInvokeHelper의 인스턴스를 설정합니다.

ListItem 구성 요소의 InteropCall 단추를 선택하면 MessageUpdateInvokeHelper 인스턴스에 대해 생성된 DotNetObjectReference를 사용하여 updateMessageCaller가 호출됩니다. 이렇게 하면 프레임워크가 해당 ListItemMessageUpdateInvokeHelper 인스턴스에서 UpdateMessageCaller를 호출할 수 있습니다. 전달된 DotNetObjectReference는 JS(dotnetHelper.dispose())에서 삭제됩니다.

Shared/ListItem.razor:

@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        await JS.InvokeVoidAsync("updateMessageCaller",
            DotNetObjectReference.Create(messageUpdateInvokeHelper));
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}
@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        await JS.InvokeVoidAsync("updateMessageCaller",
            DotNetObjectReference.Create(messageUpdateInvokeHelper));
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}

messageUpdateMessage에 설정된 경우 UI를 업데이트하기 위해 StateHasChanged가 호출됩니다. StateHasChanged가 호출되지 않은 경우에는 Action이 호출될 때 UI가 업데이트되어야 한다는 것을 Blazor에서 알 수 없습니다.

다음 CallDotNetExample6 부모 구성 요소에는 각각이 ListItem 구성 요소의 인스턴스인 4개의 목록 항목이 포함되어 있습니다.

Pages/CallDotNetExample6.razor:

@page "/call-dotnet-example-6"

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem />
    <ListItem />
    <ListItem />
    <ListItem />
</ul>
@page "/call-dotnet-example-6"

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem />
    <ListItem />
    <ListItem />
    <ListItem />
</ul>

다음 그림은 두 번째 InteropCall 단추를 선택한 후 렌더링된 CallDotNetExample6 부모 구성 요소를 보여 줍니다.

  • 두 번째 ListItem 구성 요소는 UpdateMessage Called! 메시지를 표시했습니다.
  • InteropCall 단추의 CSS display 속성이 none으로 설정되어 있기 때문에 두 번째 ListItem 구성 요소에 대한 단추는 표시되지 않습니다.

렌더링된 'CallDotNetExample6' 구성 요소 예제

JavaScript의 위치

JS interop 개요 문서에 설명된 접근 방식을 사용하여 JavaScript(JS) 코드를 로드합니다.

JS 모듈에서 스크립트를 분리하는 방법에 대한 내용은 Javascript 모듈의 Javascript 격리 섹션을 참조하세요.

경고

<script> 태그를 동적으로 업데이트할 수 없으므로 구성 요소 파일(.razor)에 <script> 태그를 넣지 마세요.

순환 개체 참조 방지

순환 참조를 포함하는 개체는 다음 중 하나에 대해 클라이언트에서 직렬화될 수 없습니다.

  • .NET 메서드 호출
  • 반환 형식에 순환 참조가 있는 경우 C#에서 JavaScript 메서드 호출

JavaScript interop 호출의 크기 제한

This section only applies to Blazor Server apps. In Blazor WebAssembly, the framework doesn't impose a limit on the size of JavaScript (JS) interop inputs and outputs.

In Blazor Server, JS interop calls are limited in size by the maximum incoming SignalR message size permitted for hub methods, which is enforced by HubOptions.MaximumReceiveMessageSize (default: 32 KB). JS to .NET SignalR messages larger than MaximumReceiveMessageSize throw an error. The framework doesn't impose a limit on the size of a SignalR message from the hub to a client.

When SignalR logging isn't set to Debug or Trace, a message size error only appears in the browser's developer tools console:

Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.

When SignalR server-side logging is set to Debug or Trace, server-side logging surfaces an InvalidDataException for a message size error.

appsettings.Development.json:

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.AspNetCore.SignalR": "Debug"
    }
  }
}

Error:

System.IO.InvalidDataException: The maximum message size of 32768B was exceeded. The message size can be configured in AddHubOptions.

Increase the limit by setting MaximumReceiveMessageSize in Startup.ConfigureServices. The following example sets the maximum receive message size to 64 KB (64 * 1024):

services.AddServerSideBlazor()
   .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

Increasing the SignalR incoming message size limit comes at the cost of requiring more server resources, and it exposes the server to increased risks from a malicious user. Additionally, reading a large amount of content in to memory as strings or byte arrays can also result in allocations that work poorly with the garbage collector, resulting in additional performance penalties.

One option for reading large payloads is to send the content in smaller chunks and process the payload as a Stream. This can be used when reading large JSON payloads or if data is available in JS as raw bytes. For an example that demonstrates sending large binary payloads in Blazor Server that uses techniques similar to the InputFile component, see the Binary Submit sample app.

참고

ASP.NET Core 참조 원본에 대한 설명서 링크는 ASP.NET Core의 다음 릴리스를 위한 제품 단위의 현재 개발을 나타내는 리포지토리의 main 분기를 로드합니다. 다른 릴리스에 대한 분기를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용하여 분기를 선택합니다. 예를 들어 release/5.0 ASP.NET Core 5.0 릴리스에 대한 분기를 선택합니다.

Consider the following guidance when developing code that transfers a large amount of data between JS and Blazor in Blazor Server apps:

  • Slice the data into smaller pieces, and send the data segments sequentially until all of the data is received by the server.
  • Don't allocate large objects in JS and C# code.
  • Don't block the main UI thread for long periods when sending or receiving data.
  • Free consumed memory when the process is completed or cancelled.
  • Enforce the following additional requirements for security purposes:
    • Declare the maximum file or data size that can be passed.
    • Declare the minimum upload rate from the client to the server.
  • After the data is received by the server, the data can be:
    • Temporarily stored in a memory buffer until all of the segments are collected.
    • Consumed immediately. For example, the data can be stored immediately in a database or written to disk as each segment is received.

JavaScript 모듈에서의 JavaScript 격리

Blazor에서는 표준 JavaScript 모듈(ECMAScript 사양)에서 JS(JavaScript) 격리를 사용하도록 설정합니다.

JS 격리는 다음과 같은 이점을 제공합니다.

  • 가져온 JS는 전역 네임스페이스를 더 이상 오염시키지 않습니다.
  • 라이브러리 및 구성 요소의 소비자는 관련 JS를 가져올 필요가 없습니다.

자세한 내용은 ASP.NET Core Blazor의 .NET 메서드에서 JavaScript 함수 호출를 참조하세요.

추가 자료