ASP.NET Core Blazor와의 상호 운용성(JavaScript [JSImport]/[JSExport] interop)

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

이 문서에서는 .NET 7 이상을 채택하는 앱용으로 릴리스된 JavaScript()/[JSImport][JSExport] interop API를 사용하여 클라이언트 쪽 구성 요소에서 JavaScriptJS(JS)와 상호 작용하는 방법을 설명합니다.

Blazor 는 인터페이스를 기반으로 하는 자체 JS interop 메커니즘을 IJSRuntime 제공합니다. Blazor'의 JS interop은 렌더링 모드 및 앱에서 BlazorBlazor Hybrid 균일하게 지원됩니다. IJSRuntime또한 라이브러리 작성자는 에코시스템 전체 Blazor 에서 공유할 interop 라이브러리를 빌드 JS 하고 interop에 권장 JS 되는 접근 방식을 다시 기본 수 있습니다Blazor. 다음 문서를 참조하세요.

이 문서에서는 WebAssembly에서 실행되는 클라이언트 쪽 구성 요소와 관련된 대체 JS interop 접근 방식을 설명합니다. 이러한 방법은 클라이언트 쪽 WebAssembly에서만 실행되도록 예상하는 경우에 적합합니다. 라이브러리 작성자는 이러한 방법을 사용하여 앱이 브라우저(OperatingSystem.IsBrowser)의 WebAssembly에서 실행되는 경우 코드 실행 중에 검사 interop을 최적화 JS 할 수 있습니다. 이 문서에서 설명하는 접근 방식은 .NET 7 이상으로 마이그레이션할 때 사용되지 않는 unmarshalled JS interop API를 대체하는 데 사용해야 합니다.

참고 항목

이 문서에서는 클라이언트 쪽 구성 요소의 interop에 중점을 JS 둡니다. JavaScript 앱에서 .NET을 호출하는 방법에 대한 지침은 JavaScript에서 .NET 실행을 참조하세요.

사용되지 않는 JavaScript interop API

API를 사용하는 IJSUnmarshalledRuntime unmarshalled JS interop는 .NET 7 이상의 ASP.NET Core에서 사용되지 않습니다. 이 문서의 지침에 따라 사용되지 않는 API를 바꿉니다.

필수 조건

시스템에 아직 설치되어 있지 않거나 시스템에 최신 버전이 설치되어 있지 않은 경우 .NET 7 이상을 다운로드하여 설치합니다.

네임스페이스

이 문서에 설명된 JS interop API는 System.Runtime.InteropServices.JavaScript 네임스페이스의 특성에 의해 제어됩니다.

안전하지 않은 블록 사용

앱의 프로젝트 파일에서 AllowUnsafeBlocks 속성을 사용하도록 설정하면 Roslyn 컴파일러의 코드 생성기가 JS interop에 대한 포인터를 사용할 수 있습니다.

<PropertyGroup>
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Warning

JS interop API를 사용하려면 AllowUnsafeBlocks를 사용하도록 설정해야 합니다. 보안 및 안정성 위험을 초래할 수 있는 .NET 앱에서 안전하지 않은 코드를 구현할 때는 주의해야 합니다. 자세한 내용은 안전하지 않은 코드, 포인터 형식 및 함수 포인터를 참조하세요.

.NET에서 JavaScript 호출

이 섹션에서는 .NET에서 JS 함수를 호출하는 방법을 설명합니다.

다음은 CallJavaScript1 구성 요소에 대한 설명입니다.

  • CallJavaScript1 모듈은 JSHost.ImportAsync를 사용하여 배치된 JS 파일에서 비동기적으로 가져옵니다.
  • 가져온 getMessageJS 함수는 GetWelcomeMessage에 의해 호출됩니다.
  • 반환된 시작 메시지 문자열은 message 필드를 통해 UI에 표시됩니다.

CallJavaScript1.razor:

@page "/call-javascript-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 1)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override async Task OnInitializedAsync()
    {
        await JSHost.ImportAsync("CallJavaScript1", 
            "../Components/Pages/CallJavaScript1.razor.js");

        message = GetWelcomeMessage();
    }
}
@page "/call-javascript-1"
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 1)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override async Task OnInitializedAsync()
    {
        await JSHost.ImportAsync("CallJavaScript1", 
            "../Pages/CallJavaScript1.razor.js");

        message = GetWelcomeMessage();
    }
}

참고 항목

interop이 JS 클라이언트에서 렌더링된 구성 요소에서만 호출되도록 코드 OperatingSystem.IsBrowser 에 조건부 검사 포함합니다. 이는 이 interop API에서 제공하는 코드를 실행할 수 없는 서버 쪽 구성 요소를 대상으로 하는 라이브러리/NuGet 패키지에 JS 중요합니다.

C#에서 호출하는 JS 함수를 가져오려면 JS 함수의 서명과 일치하는 C# 메서드 서명에서 [JSImport] 특성을 사용합니다. [JSImport] 특성의 첫 번째 매개 변수는 가져올 JS 함수의 이름이고 두 번째 매개 변수는 JS 모듈의 이름입니다.

다음 예제에서, getMessageCallJavaScript1라는 모듈에 대해 string를 반환하는 JS 함수입니다. C# 메서드 시그니처는 일치합니다. 매개 변수는 JS 함수에 전달되지 않으며, JS 함수는 string를 반환합니다. JS 함수는 C# 코드의 GetWelcomeMessage에서 호출됩니다.

CallJavaScript1.razor.cs:

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Components.Pages;

[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
    [JSImport("getMessage", "CallJavaScript1")]
    internal static partial string GetWelcomeMessage();
}

이전 CallJavaScript1 부분 클래스에 대한 앱의 네임스페이스는 BlazorSample입니다. 구성 요소의 네임스페이스는 BlazorSample.Components.Pages입니다. 로컬 테스트 앱에서 이전 구성 요소를 사용하는 경우 앱과 일치하도록 네임스페이스를 업데이트합니다. 예를 들어, 앱의 네임스페이스가 ContosoApp인 경우 네임스페이스는 ContosoApp.Components.Pages입니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Pages;

[SupportedOSPlatform("browser")]
public partial class CallJavaScript1
{
    [JSImport("getMessage", "CallJavaScript1")]
    internal static partial string GetWelcomeMessage();
}

이전 CallJavaScript1 부분 클래스에 대한 앱의 네임스페이스는 BlazorSample입니다. 구성 요소의 네임스페이스는 BlazorSample.Pages입니다. 로컬 테스트 앱에서 이전 구성 요소를 사용하는 경우 앱과 일치하도록 네임스페이스를 업데이트합니다. 예를 들어, 앱의 네임스페이스가 ContosoApp인 경우 네임스페이스는 ContosoApp.Pages입니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

가져온 메서드 서명에서 런타임에 의해 자동으로 마샬링되는 매개 변수 및 반환 값에 .NET 형식을 사용할 수 있습니다. JSMarshalAsAttribute<T>를 사용하여 가져온 메서드 매개 변수를 마샬링하는 방법을 제어합니다. 예를 들어, longSystem.Runtime.InteropServices.JavaScript.JSType.Number 또는 System.Runtime.InteropServices.JavaScript.JSType.BigInt로 마샬링 하도록 선택할 수 있습니다. 호출 가능한 JS 함수로 마샬링되는 매개 변수로 Action/Func<TResult> 콜백을 전달할 수 있습니다. JS 및 관리형 개체 참조를 모두 전달할 수 있으며, 프록시 개체로 마샬링되어 프록시가 가비지 수집될 때까지 경계를 넘어 개체를 활성 상태로 유지합니다. JS 약속으로 마샬링되는 Task 결과를 사용하여 비동기 메서드를 가져오고 내보낼 수도 있습니다. 마샬링된 형식의 대부분은 이 문서의 뒷부분에 나오는 JavaScript에서 .NET 호출 섹션에서 다루는 가져온 메서드와 내보낸 메서드 모두에서 매개 변수 및 반환 값으로 양방향으로 작동합니다.

다음 표에서는 지원되는 형식 매핑을 보여줍니다.

.NET JavaScript Nullable Task-Promise JSMarshalAs 선택사항 Array of
Boolean Boolean 지원됨 지원됨 지원됨 지원되지 않음
Byte Number 지원됨 지원됨 지원됨 지원됨
Char String 지원됨 지원됨 지원됨 지원되지 않음
Int16 Number 지원됨 지원됨 지원됨 지원되지 않음
Int32 Number 지원됨 지원됨 지원됨 지원됨
Int64 Number 지원됨 지원됨 지원되지 않음 지원되지 않음
Int64 BigInt 지원됨 지원됨 지원되지 않음 지원되지 않음
Single Number 지원됨 지원됨 지원됨 지원되지 않음
Double Number 지원됨 지원됨 지원됨 지원됨
IntPtr Number 지원됨 지원됨 지원됨 지원되지 않음
DateTime Date 지원됨 지원됨 지원되지 않음 지원되지 않음
DateTimeOffset Date 지원됨 지원됨 지원되지 않음 지원되지 않음
Exception Error 지원되지 않음 지원됨 지원됨 지원되지 않음
JSObject Object 지원되지 않음 지원됨 지원됨 지원됨
String String 지원되지 않음 지원됨 지원됨 지원됨
Object Any 지원되지 않음 지원됨 지원되지 않음 지원됨
Span<Byte> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Span<Int32> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Span<Double> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
ArraySegment<Byte> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
ArraySegment<Int32> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
ArraySegment<Double> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Task Promise 지원되지 않음 지원되지 않음 지원됨 지원되지 않음
Action Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Action<T1> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Action<T1, T2> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Action<T1, T2, T3> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<T1, TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<T1, T2, TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<T1, T2, T3, TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음

다음 조건은 형식 매핑 및 마샬링된 값에 적용됩니다.

  • Array of 열은 .NET 형식을 JSArray로 마샬링할 수 있는지를 나타냅니다. 예: Number의 JSArray에 매핑된C# int[](Int32).
  • 잘못된 형식의 값을 사용하여 C#에 JS 값을 전달할 때, 프레임워크는 대부분의 경우 예외를 throw합니다. 프레임워크는 JS에서 컴파일 시간 형식 검사를 수행하지 않습니다.
  • JSObject, Exception, Task, ArraySegmentGCHandle 및 프록시를 만듭니다. 개발자 코드에서 삭제를 트리거하거나 .NET GC(가비지 수집)가 나중에 개체를 삭제하도록 허용할 수 있습니다. 이러한 형식은 상당한 성능 오버헤드를 수행합니다.
  • Array: 배열을 마샬링하면 JS 또는 .NET에서 배열의 복사본이 만들어집니다.
  • MemoryView
    • MemoryViewSpanArraySegment를 마샬링하는 .NET WebAssembly 런타임에 대한 JS 클래스입니다.
    • 배열 마샬링과 달리 Span 또는 ArraySegment를 마샬링해도 기본 메모리의 복사본이 만들어지지 않습니다.
    • MemoryView는 .NET WebAssembly 런타임에서만 올바르게 인스턴스화할 수 있습니다. 따라서 Span 또는 ArraySegment의 매개 변수가 있는 .NET 메서드로 JS 함수를 가져올 수 없습니다.
    • Span에 대해 만들어진 MemoryView는 interop 호출 기간 동안에만 유효합니다. interop 호출 후에도 유지되지 않는 호출 스택에 Span이 할당되기 때문에, Span를 반환 하는 .NET 메서드를 내보낼 수 없습니다.
    • ArraySegment에 대해 만들어진 MemoryView는 interop 호출 후에 유지되며 버퍼를 공유하는 데 유용합니다. ArraySegment에 대해 만들어진 MemoryView에서 dispose()를 호출하면 프록시가 삭제되고 기본 .NET 배열의 고정이 해제됩니다. MemoryView에 대한 try-finally 블록에서 dispose()를 호출하는 것이 좋습니다.

다음 표에서는 지원되는 형식 매핑을 보여줍니다.

.NET JavaScript Nullable Task-Promise JSMarshalAs 선택사항 Array of
Boolean Boolean 지원됨 지원됨 지원됨 지원되지 않음
Byte Number 지원됨 지원됨 지원됨 지원됨
Char String 지원됨 지원됨 지원됨 지원되지 않음
Int16 Number 지원됨 지원됨 지원됨 지원되지 않음
Int32 Number 지원됨 지원됨 지원됨 지원됨
Int64 Number 지원됨 지원됨 지원되지 않음 지원되지 않음
Int64 BigInt 지원됨 지원됨 지원되지 않음 지원되지 않음
Single Number 지원됨 지원됨 지원됨 지원되지 않음
Double Number 지원됨 지원됨 지원됨 지원됨
IntPtr Number 지원됨 지원됨 지원됨 지원되지 않음
DateTime Date 지원됨 지원됨 지원되지 않음 지원되지 않음
DateTimeOffset Date 지원됨 지원됨 지원되지 않음 지원되지 않음
Exception Error 지원되지 않음 지원됨 지원됨 지원되지 않음
JSObject Object 지원되지 않음 지원됨 지원됨 지원됨
String String 지원되지 않음 지원됨 지원됨 지원됨
Object Any 지원되지 않음 지원됨 지원되지 않음 지원됨
Span<Byte> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Span<Int32> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Span<Double> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
ArraySegment<Byte> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
ArraySegment<Int32> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
ArraySegment<Double> MemoryView 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Task Promise 지원되지 않음 지원되지 않음 지원됨 지원되지 않음
Action Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Action<T1> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Action<T1, T2> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Action<T1, T2, T3> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<T1, TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<T1, T2, TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음
Func<T1, T2, T3, TResult> Function 지원되지 않음 지원되지 않음 지원되지 않음 지원되지 않음

다음 조건은 형식 매핑 및 마샬링된 값에 적용됩니다.

  • Array of 열은 .NET 형식을 JSArray로 마샬링할 수 있는지를 나타냅니다. 예: Number의 JSArray에 매핑된C# int[](Int32).
  • 잘못된 형식의 값을 사용하여 C#에 JS 값을 전달할 때, 프레임워크는 대부분의 경우 예외를 throw합니다. 프레임워크는 JS에서 컴파일 시간 형식 검사를 수행하지 않습니다.
  • JSObject, Exception, Task, ArraySegmentGCHandle 및 프록시를 만듭니다. 개발자 코드에서 삭제를 트리거하거나 .NET GC(가비지 수집)가 나중에 개체를 삭제하도록 허용할 수 있습니다. 이러한 형식은 상당한 성능 오버헤드를 수행합니다.
  • Array: 배열을 마샬링하면 JS 또는 .NET에서 배열의 복사본이 만들어집니다.
  • MemoryView
    • MemoryViewSpanArraySegment를 마샬링하는 .NET WebAssembly 런타임에 대한 JS 클래스입니다.
    • 배열 마샬링과 달리 Span 또는 ArraySegment를 마샬링해도 기본 메모리의 복사본이 만들어지지 않습니다.
    • MemoryView는 .NET WebAssembly 런타임에서만 올바르게 인스턴스화할 수 있습니다. 따라서 Span 또는 ArraySegment의 매개 변수가 있는 .NET 메서드로 JS 함수를 가져올 수 없습니다.
    • Span에 대해 만들어진 MemoryView는 interop 호출 기간 동안에만 유효합니다. interop 호출 후에도 유지되지 않는 호출 스택에 Span이 할당되기 때문에, Span를 반환 하는 .NET 메서드를 내보낼 수 없습니다.
    • ArraySegment에 대해 만들어진 MemoryView는 interop 호출 후에 유지되며 버퍼를 공유하는 데 유용합니다. ArraySegment에 대해 만들어진 MemoryView에서 dispose()를 호출하면 프록시가 삭제되고 기본 .NET 배열의 고정이 해제됩니다. MemoryView에 대한 try-finally 블록에서 dispose()를 호출하는 것이 좋습니다.

[JSImport] 특성의 모듈 이름과 JSHost.ImportAsync를 사용하여 구성 요소에서 모듈을 로드하는 호출은 앱에서 일치하고 고유해야 합니다. NuGet 패키지에서 배포할 라이브러리를 작성할 때는 NuGet 패키지 네임스페이스를 모듈 이름의 접두사로 사용하는 것이 좋습니다. 다음 예제에서 모듈 이름은 Contoso.InteropServices.JavaScript 패키지 및 사용자 메시지 interop 클래스(UserMessages)의 폴더를 반영합니다.

[JSImport("getMessage", 
    "Contoso.InteropServices.JavaScript.UserMessages.CallJavaScript1")]

전역 네임스페이스에서 액세스할 수 있는 함수는 함수 이름의 globalThis 접두사를 사용하고 모듈 이름을 제공하지 않고 [JSImport] 특성을 사용하여 가져올 수 있습니다. 다음 예제에서는 console.logglobalThis로 접두사를 지정합니다. 가져온 함수는 C# 문자열 메시지(message)를 수락하고 C# 문자열을 console.log에 대해 JSString에 마샬링하는 C# Log 메서드에 의해 호출됩니다.

[JSImport("globalThis.console.log")]
internal static partial void Log([JSMarshalAs<JSType.String>] string message);

구성 요소와 함께 배치되거나 파일의 다른 JavaScript 정적 자산 JS 과 함께 배치된 표준 JavaScript ES6 모듈에서 스크립트를 내보냅니다(예 JSwwwroot/js/{FILE NAME}.js: 정적 자산이 기본 앱의 wwwroot 폴더에 명명 js 된 폴더에 포함되고 {FILE NAME} 자리 표시자는 파일 이름임).

다음 예제에서 getMessage라는 JS 함수는 포르투갈어로 "Hello from Blazor!" 환영 메시지를 반환하는 정렬된 JS 파일에서 내보냅니다.

CallJavaScript1.razor.js:

export function getMessage() {
  return 'Olá do Blazor!';
}

JavaScript에서 .NET 호출

이 섹션에서는 JS에서 .NET 메서드를 호출하는 방법을 설명합니다.

다음 CallDotNet1 구성 요소는 DOM과 직접 상호 작용하여 환영 메시지 문자열을 렌더링하는 JS을 호출합니다.

  • CallDotNetJS 모듈은 이 구성 요소에 대한 정렬된 JS파일에서 비동기적으로 가져옵니다.
  • 가져온 setMessageJS 함수는 SetWelcomeMessage에 의해 호출됩니다.
  • 반환된 환영 메시지는 message 필드를 통해 setMessage에 의해 UI에 표시됩니다.

Important

이 섹션의 예제 JS 에서 interop는 구성 요소가 렌더링된 OnAfterRender후 데모 목적으로만 DOM 요소를 변경하는 데 사용됩니다. 일반적으로 개체가 Blazor와 상호 작용하지 않는 경우에만 DOM을 JS으로 변경해야 합니다. 이 섹션에 표시된 접근 방식은 Razor 구성 요소에서 타사 JS 라이브러리가 사용되는 경우와 유사합니다. 여기서 구성 요소는 JS interop을 통해 JS 라이브러리와 상호 작용하고, 타사 JS 라이브러리는 DOM의 일부와 상호 작용하며, Blazor은 DOM의 해당 부분에 대한 DOM 업데이트와 직접 관련되지 않습니다. 자세한 내용은 ASP.NET Core Blazor JavaScript 상호 운용성(JS)을 참조하세요.

CallDotNet1.razor:

@page "/call-dotnet-1"
@rendermode InteractiveWebAssembly
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call .NET Example 1)
</h1>

<p>
    <span id="result">.NET method not executed yet</span>
</p>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSHost.ImportAsync("CallDotNet1", 
                "../Components/Pages/CallDotNet1.razor.js");

            SetWelcomeMessage();
        }
    }
}
@page "/call-dotnet-1"
@using System.Runtime.InteropServices.JavaScript

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call .NET Example 1)
</h1>

<p>
    <span id="result">.NET method not executed yet</span>
</p>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSHost.ImportAsync("CallDotNet1", 
                "../Pages/CallDotNet1.razor.js");

            SetWelcomeMessage();
        }
    }
}

JS에서 호출할 수 있도록 .NET 메서드를 내보내려면 [JSExport] 특성을 사용합니다.

다음 예제에서

  • SetWelcomeMessagesetMessage으로 명명된 JS 함수를 호출합니다. JS 함수는 .NET을 호출하여 GetMessageFromDotnet에서 환영 메시지를 수신하고 UI에 메시지를 표시합니다.
  • GetMessageFromDotnet는 포르투갈어로 "Hello from Blazor!" 환영 메시지를 반환하는 [JSExport] 특성이 있는 .NET 메서드입니다.

CallDotNet1.razor.cs:

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Components.Pages;

[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
    [JSImport("setMessage", "CallDotNet1")]
    internal static partial void SetWelcomeMessage();

    [JSExport]
    internal static string GetMessageFromDotnet()
    {
        return "Olá do Blazor!";
    }
}

이전 CallDotNet1 부분 클래스에 대한 앱의 네임스페이스는 BlazorSample입니다. 구성 요소의 네임스페이스는 BlazorSample.Components.Pages입니다. 로컬 테스트 앱에서 이전 구성 요소를 사용하는 경우 앱과 일치하도록 앱의 네임스페이스를 업데이트합니다. 예를 들어, 앱의 네임스페이스가 ContosoApp인 경우 구성 요소 네임스페이스는 ContosoApp.Components.Pages입니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

다음 예제에서는 setMessage로 명명된 JS 함수를 배치된 JS 파일에서 가져옵니다.

setMessage 메서드는 다음 작업을 수행합니다.

  • 내보낸 .NET 메서드를 호출하기 위한 WebAssembly .NET 런타임 인스턴스를 노출하기 위해 globalThis.getDotnetRuntime(0)을 호출합니다.
  • 앱 어셈블리의 JS 내보내기를 가져옵니다. 다음 예제에서 앱 어셈블리의 이름은 BlazorSample입니다.
  • 내보내기(exports)에서 BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet 메서드를 호출합니다. 반환된 값(환영 메시지)은 CallDotNet1 구성 요소의 <span> 텍스트에 할당됩니다. 앱의 네임스페이스는 BlazorSample이고, CallDotNet1 구성 요소의 네임스페이스는 BlazorSample.Components.Pages입니다.

CallDotNet1.razor.js:

export async function setMessage() {
  const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
  var exports = await getAssemblyExports("BlazorSample.dll");

  document.getElementById("result").innerText = 
    exports.BlazorSample.Components.Pages.CallDotNet1.GetMessageFromDotnet();
}
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.Pages;

[SupportedOSPlatform("browser")]
public partial class CallDotNet1
{
    [JSImport("setMessage", "CallDotNet1")]
    internal static partial void SetWelcomeMessage();

    [JSExport]
    internal static string GetMessageFromDotnet()
    {
        return "Olá do Blazor!";
    }
}

이전 CallDotNet1 부분 클래스에 대한 앱의 네임스페이스는 BlazorSample입니다. 구성 요소의 네임스페이스는 BlazorSample.Pages입니다. 로컬 테스트 앱에서 이전 구성 요소를 사용하는 경우 앱과 일치하도록 앱의 네임스페이스를 업데이트합니다. 예를 들어, 앱의 네임스페이스가 ContosoApp인 경우 구성 요소 네임스페이스는 ContosoApp.Pages입니다. 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

다음 예제에서는 setMessage로 명명된 JS 함수를 배치된 JS 파일에서 가져옵니다.

setMessage 메서드는 다음 작업을 수행합니다.

  • 내보낸 .NET 메서드를 호출하기 위한 WebAssembly .NET 런타임 인스턴스를 노출하기 위해 globalThis.getDotnetRuntime(0)을 호출합니다.
  • 앱 어셈블리의 JS 내보내기를 가져옵니다. 다음 예제에서 앱 어셈블리의 이름은 BlazorSample입니다.
  • 내보내기(exports)에서 BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet 메서드를 호출합니다. 반환된 값(환영 메시지)은 CallDotNet1 구성 요소의 <span> 텍스트에 할당됩니다. 앱의 네임스페이스는 BlazorSample이고, CallDotNet1 구성 요소의 네임스페이스는 BlazorSample.Pages입니다.

CallDotNet1.razor.js:

export async function setMessage() {
  const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
  var exports = await getAssemblyExports("BlazorSample.dll");

  document.getElementById("result").innerText = 
    exports.BlazorSample.Pages.CallDotNet1.GetMessageFromDotnet();
}

참고 항목

내보내기를 가져오기 위한 호출 getAssemblyExports은 앱 전체에서 가용성을 위해 JavaScript 이니셜라이저에서 발생할 수 있습니다.

여러 모듈 가져오기 호출

JS 모듈을 로드한 후에는 사용자가 앱을 수동으로 다시 로드하지 않고도 앱이 브라우저 창이나 탭에서 실행되는 한 앱의 구성 요소 및 클래스에서 모듈의 JS 함수를 사용할 수 있습니다. JSHost.ImportAsync는 다음과 같은 경우 상당한 성능 저하 없이 동일한 모듈에서 여러 번 호출할 수 있습니다.

  • 사용자는 JSHost.ImportAsync를 호출하여 모듈을 가져오는 구성 요소를 방문하여 구성 요소에서 멀리 이동한 다음 동일한 모듈 가져오기를 위해 JSHost.ImportAsync가 다시 호출되는 구성 요소로 돌아갑니다.
  • 동일한 모듈은 서로 다른 구성 요소에서 사용되며 각 구성 요소의 JSHost.ImportAsync에 의해 로드됩니다.

구성 요소 간에 단일 JavaScript 모듈 사용

이 섹션의 지침을 따르기 전에 interop에 대한 일반적인 지침을 제공하는 이 문서의 .NET 및 JavaScript에서 .NET 호출 섹션을 [JSImport][JSExport]/읽어보세요.

이 섹션의 예제에서는 클라이언트 쪽 앱의 공유 JS 모듈에서 interop을 사용하는 JS 방법을 보여 있습니다. 이 섹션의 지침은 Razor 클래스 라이브러리(RCL)에 적용되지 않습니다.

다음 구성 요소, 클래스, C# 메서드 및 JS 함수가 사용됩니다.

  • Interop 클래스(Interop.cs): Interop으로 명명된 모듈의 [JSImport][JSExport] 특성을 사용하여 가져오기 및 내보내기 JS interop을 설정합니다.
    • GetWelcomeMessage: 가져온 getMessageJS 함수를 호출하는 .NET 메서드입니다.
    • SetWelcomeMessage: 가져온 setMessageJS 함수를 호출하는 .NET 메서드입니다.
    • GetMessageFromDotnet: JS에서 호출될 때 환영 메시지 문자열을 반환하는 내보낸 C# 메서드입니다.
  • wwwroot/js/interop.js 파일: JS 함수를 포함합니다.
    • getMessage: 구성 요소의 C# 코드에서 호출할 때 환영 메시지를 반환합니다.
    • setMessage: GetMessageFromDotnet C# 메서드를 호출하고 반환된 시작 메시지를 DOM <span> 요소에 할당합니다.
  • Program.csJSHost.ImportAsync를 호출하여 wwwroot/js/interop.js에서 모듈을 로드합니다.
  • CallJavaScript2 구성 요소(CallJavaScript2.razor): GetWelcomeMessage을 호출하고 구성 요소의 UI에 반환된 환영 메시지를 표시합니다.
  • CallDotNet2 구성 요소(CallDotNet2.razor): SetWelcomeMessage를 호출합니다.

Interop.cs:

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorSample.JavaScriptInterop;

[SupportedOSPlatform("browser")]
public partial class Interop
{
    [JSImport("getMessage", "Interop")]
    internal static partial string GetWelcomeMessage();

    [JSImport("setMessage", "Interop")]
    internal static partial void SetWelcomeMessage();

    [JSExport]
    internal static string GetMessageFromDotnet()
    {
        return "Olá do Blazor!";
    }
}

앞의 예제에서, 앱의 네임스페이스는 BlazorSample이고 C# interop 클래스의 전체 네임스페이스는 BlazorSample.JavaScriptInterop입니다.

wwwroot/js/interop.js:

export function getMessage() {
  return 'Olá do Blazor!';
}

export async function setMessage() {
  const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
  var exports = await getAssemblyExports("BlazorSample.dll");

  document.getElementById("result").innerText =
    exports.BlazorSample.JavaScriptInterop.Interop.GetMessageFromDotnet();
}

Program.cs 파일 맨 위에서 System.Runtime.InteropServices.JavaScript 네임스페이스를 사용할 수 있도록 합니다.

using System.Runtime.InteropServices.JavaScript;

WebAssemblyHost.RunAsync가 호출되기 전에 Program.cs에서 모듈을 로드합니다.

if (OperatingSystem.IsBrowser())
{
    await JSHost.ImportAsync("Interop", "../js/interop.js");
}

CallJavaScript2.razor:

@page "/call-javascript-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 2)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override void OnInitialized()
    {
        message = Interop.GetWelcomeMessage();
    }
}
@page "/call-javascript-2"
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop 
    (Call JS Example 2)
</h1>

@(message is not null ? message : string.Empty)

@code {
    private string? message;

    protected override void OnInitialized()
    {
        message = Interop.GetWelcomeMessage();
    }
}

CallDotNet2.razor:

@page "/call-dotnet-2"
@rendermode InteractiveWebAssembly
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop  
    (Call .NET Example 2)
</h1>

<p>
    <span id="result">.NET method not executed</span>
</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Interop.SetWelcomeMessage();
        }
    }
}
@page "/call-dotnet-2"
@using BlazorSample.JavaScriptInterop

<h1>
    JS <code>[JSImport]</code>/<code>[JSExport]</code> Interop  
    (Call .NET Example 2)
</h1>

<p>
    <span id="result">.NET method not executed</span>
</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Interop.SetWelcomeMessage();
        }
    }
}

Important

이 섹션의 예제 JS 에서 interop는 구성 요소가 렌더링된 OnAfterRender후 데모 목적으로만 DOM 요소를 변경하는 데 사용됩니다. 일반적으로 개체가 Blazor와 상호 작용하지 않는 경우에만 DOM을 JS으로 변경해야 합니다. 이 섹션에 표시된 접근 방식은 Razor 구성 요소에서 타사 JS 라이브러리가 사용되는 경우와 유사합니다. 여기서 구성 요소는 JS interop을 통해 JS 라이브러리와 상호 작용하고, 타사 JS 라이브러리는 DOM의 일부와 상호 작용하며, Blazor은 DOM의 해당 부분에 대한 DOM 업데이트와 직접 관련되지 않습니다. 자세한 내용은 ASP.NET Core Blazor JavaScript 상호 운용성(JS)을 참조하세요.

추가 리소스