// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Blazor.Components; using Microsoft.AspNetCore.Blazor.Rendering; using Microsoft.AspNetCore.SignalR; using Microsoft.JSInterop; namespace Microsoft.AspNetCore.Blazor.Browser.Rendering { internal class RemoteRenderer : Renderer { private readonly int _id; private readonly IClientProxy _client; private readonly IJSRuntime _jsRuntime; private readonly RendererRegistry _rendererRegistry; /// /// Notifies when a rendering exception occured. /// public event EventHandler UnhandledException; /// /// Creates a new . /// /// The . /// The . /// The . /// The . public RemoteRenderer( IServiceProvider serviceProvider, RendererRegistry rendererRegistry, IJSRuntime jsRuntime, IClientProxy client) : base(serviceProvider) { _rendererRegistry = rendererRegistry; _jsRuntime = jsRuntime; _client = client; _id = _rendererRegistry.Add(this); } /// /// Attaches a new root component to the renderer, /// causing it to be displayed in the specified DOM element. /// /// The type of the component. /// A CSS selector that uniquely identifies a DOM element. public void AddComponent(string domElementSelector) where TComponent: IComponent { AddComponent(typeof(TComponent), domElementSelector); } /// /// Associates the with the , /// causing it to be displayed in the specified DOM element. /// /// The type of the component. /// A CSS selector that uniquely identifies a DOM element. public void AddComponent(Type componentType, string domElementSelector) { var component = InstantiateComponent(componentType); var componentId = AssignComponentId(component); var attachComponentTask = _jsRuntime.InvokeAsync( "Blazor._internal.attachRootComponentToElement", _id, domElementSelector, componentId); CaptureAsyncExceptions(attachComponentTask); component.SetParameters(ParameterCollection.Empty); } /// /// Disposes the instance. /// public void Dispose() { _rendererRegistry.TryRemove(_id); } /// protected override void UpdateDisplay(in RenderBatch batch) { var task = _client.SendAsync("JS.RenderBatch", _id, batch); CaptureAsyncExceptions(task); } private void CaptureAsyncExceptions(Task task) { task.ContinueWith(t => { if (t.IsFaulted) { UnhandledException?.Invoke(this, t.Exception); } }); } } }