Blazor API Review: Design concept for Dispatcher (#11930)
* Design concept for Dispatcher Part of: #11610 This change brings forward the Dispatcher as a more primary and more expandable concept. - Dispatcher shows up in more places - Dispatcher is an abstract class for horizontal scalability - Dispatcher has parallels with S.Windows.Threading.Dispatcher where possible Looking for feedback on this approach. I feel pretty strongly that making this an abstract class is the right choice, I want to see opinions on how much to push it into people's faces. * WIP * PR feedback
This commit is contained in:
parent
62f00a77e6
commit
a27b9fc335
|
|
@ -59,6 +59,7 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
||||||
public partial class WebAssemblyRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer
|
public partial class WebAssemblyRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer
|
||||||
{
|
{
|
||||||
public WebAssemblyRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { }
|
public WebAssemblyRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { }
|
||||||
|
public override Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } }
|
||||||
public System.Threading.Tasks.Task AddComponentAsync(System.Type componentType, string domElementSelector) { throw null; }
|
public System.Threading.Tasks.Task AddComponentAsync(System.Type componentType, string domElementSelector) { throw null; }
|
||||||
public System.Threading.Tasks.Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
|
public System.Threading.Tasks.Task AddComponentAsync<TComponent>(string domElementSelector) where TComponent : Microsoft.AspNetCore.Components.IComponent { throw null; }
|
||||||
public override System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo eventFieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
public override System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo eventFieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// 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.Components;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Blazor.Rendering
|
||||||
|
{
|
||||||
|
internal class NullDispatcher : Dispatcher
|
||||||
|
{
|
||||||
|
public static readonly Dispatcher Instance = new NullDispatcher();
|
||||||
|
|
||||||
|
private NullDispatcher()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CheckAccess() => true;
|
||||||
|
|
||||||
|
public override Task InvokeAsync(Action workItem)
|
||||||
|
{
|
||||||
|
if (workItem is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
workItem();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task InvokeAsync(Func<Task> workItem)
|
||||||
|
{
|
||||||
|
if (workItem is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return workItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<TResult> InvokeAsync<TResult>(Func<TResult> workItem)
|
||||||
|
{
|
||||||
|
if (workItem is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(workItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> workItem)
|
||||||
|
{
|
||||||
|
if (workItem is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return workItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,6 +37,8 @@ namespace Microsoft.AspNetCore.Blazor.Rendering
|
||||||
_webAssemblyRendererId = RendererRegistry.Current.Add(this);
|
_webAssemblyRendererId = RendererRegistry.Current.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher => NullDispatcher.Instance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attaches a new root component to the renderer,
|
/// Attaches a new root component to the renderer,
|
||||||
/// causing it to be displayed in the specified DOM element.
|
/// causing it to be displayed in the specified DOM element.
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
protected private RenderTreeFrame[] GetRenderTree(TestRenderer renderer, IComponent component)
|
protected private RenderTreeFrame[] GetRenderTree(TestRenderer renderer, IComponent component)
|
||||||
{
|
{
|
||||||
renderer.AttachComponent(component);
|
renderer.AttachComponent(component);
|
||||||
var task = renderer.InvokeAsync(() => component.SetParametersAsync(ParameterCollection.Empty));
|
var task = renderer.Dispatcher.InvokeAsync(() => component.SetParametersAsync(ParameterCollection.Empty));
|
||||||
// we will have to change this method if we add a test that does actual async work.
|
// we will have to change this method if we add a test that does actual async work.
|
||||||
Assert.True(task.Status.HasFlag(TaskStatus.RanToCompletion) || task.Status.HasFlag(TaskStatus.Faulted));
|
Assert.True(task.Status.HasFlag(TaskStatus.RanToCompletion) || task.Status.HasFlag(TaskStatus.Faulted));
|
||||||
if (task.IsFaulted)
|
if (task.IsFaulted)
|
||||||
|
|
@ -442,10 +442,12 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
|
|
||||||
protected class TestRenderer : Renderer
|
protected class TestRenderer : Renderer
|
||||||
{
|
{
|
||||||
public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, CreateDefaultDispatcher())
|
public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
public RenderTreeFrame[] LatestBatchReferenceFrames { get; private set; }
|
public RenderTreeFrame[] LatestBatchReferenceFrames { get; private set; }
|
||||||
|
|
||||||
public void AttachComponent(IComponent component)
|
public void AttachComponent(IComponent component)
|
||||||
|
|
|
||||||
|
|
@ -332,7 +332,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
// Trigger the change event to show it updates the property
|
// Trigger the change event to show it updates the property
|
||||||
//
|
//
|
||||||
// This should always complete synchronously.
|
// This should always complete synchronously.
|
||||||
var task = renderer.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = "Modified value", }));
|
var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = "Modified value", }));
|
||||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||||
await task;
|
await task;
|
||||||
|
|
||||||
|
|
@ -367,7 +367,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
// Trigger the change event to show it updates the property
|
// Trigger the change event to show it updates the property
|
||||||
//
|
//
|
||||||
// This should always complete synchronously.
|
// This should always complete synchronously.
|
||||||
var task = renderer.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = "Modified value", }));
|
var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = "Modified value", }));
|
||||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||||
await task;
|
await task;
|
||||||
|
|
||||||
|
|
@ -404,7 +404,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
//
|
//
|
||||||
// This should always complete synchronously.
|
// This should always complete synchronously.
|
||||||
var newDateValue = new DateTime(2018, 3, 5, 4, 5, 6);
|
var newDateValue = new DateTime(2018, 3, 5, 4, 5, 6);
|
||||||
var task = renderer.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = newDateValue.ToString(), }));
|
var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = newDateValue.ToString(), }));
|
||||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||||
await task;
|
await task;
|
||||||
|
|
||||||
|
|
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
// Trigger the change event to show it updates the property
|
// Trigger the change event to show it updates the property
|
||||||
//
|
//
|
||||||
// This should always complete synchronously.
|
// This should always complete synchronously.
|
||||||
var task = renderer.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = new DateTime(2018, 3, 5).ToString(testDateFormat), }));
|
var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = new DateTime(2018, 3, 5).ToString(testDateFormat), }));
|
||||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||||
await task;
|
await task;
|
||||||
|
|
||||||
|
|
@ -559,7 +559,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
// Trigger the change event to show it updates the property
|
// Trigger the change event to show it updates the property
|
||||||
//
|
//
|
||||||
// This should always complete synchronously.
|
// This should always complete synchronously.
|
||||||
var task = renderer.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs() { Value = false, }));
|
var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs() { Value = false, }));
|
||||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||||
await task;
|
await task;
|
||||||
|
|
||||||
|
|
@ -595,7 +595,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
||||||
// Trigger the change event to show it updates the property
|
// Trigger the change event to show it updates the property
|
||||||
//
|
//
|
||||||
// This should always complete synchronously.
|
// This should always complete synchronously.
|
||||||
var task = renderer.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = MyEnum.SecondValue.ToString(), }));
|
var task = renderer.Dispatcher.InvokeAsync(() => setter.InvokeAsync(new UIChangeEventArgs { Value = MyEnum.SecondValue.ToString(), }));
|
||||||
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
Assert.Equal(TaskStatus.RanToCompletion, task.Status);
|
||||||
await task;
|
await task;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,10 +88,12 @@ namespace Microsoft.AspNetCore.Components.Performance
|
||||||
private class FakeRenderer : Renderer
|
private class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
public FakeRenderer()
|
public FakeRenderer()
|
||||||
: base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
: base(new TestServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
protected override void HandleException(Exception exception)
|
protected override void HandleException(Exception exception)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,17 @@ namespace Microsoft.AspNetCore.Components
|
||||||
public Microsoft.AspNetCore.Components.UIDataTransferItem[] Items { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public Microsoft.AspNetCore.Components.UIDataTransferItem[] Items { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
public string[] Types { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public string[] Types { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||||
}
|
}
|
||||||
|
public abstract partial class Dispatcher
|
||||||
|
{
|
||||||
|
protected Dispatcher() { }
|
||||||
|
public abstract bool CheckAccess();
|
||||||
|
public static Microsoft.AspNetCore.Components.Dispatcher CreateDefault() { throw null; }
|
||||||
|
public abstract System.Threading.Tasks.Task InvokeAsync(System.Action workItem);
|
||||||
|
public abstract System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> workItem);
|
||||||
|
public abstract System.Threading.Tasks.Task<TResult> InvokeAsync<TResult>(System.Func<System.Threading.Tasks.Task<TResult>> workItem);
|
||||||
|
public abstract System.Threading.Tasks.Task<TResult> InvokeAsync<TResult>(System.Func<TResult> workItem);
|
||||||
|
protected void OnUnhandledException(System.UnhandledExceptionEventArgs e) { }
|
||||||
|
}
|
||||||
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
|
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
|
||||||
public readonly partial struct ElementRef
|
public readonly partial struct ElementRef
|
||||||
{
|
{
|
||||||
|
|
@ -303,13 +314,6 @@ namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
bool IsConnected { get; }
|
bool IsConnected { get; }
|
||||||
}
|
}
|
||||||
public partial interface IDispatcher
|
|
||||||
{
|
|
||||||
System.Threading.Tasks.Task InvokeAsync(System.Action workItem);
|
|
||||||
System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> workItem);
|
|
||||||
System.Threading.Tasks.Task<TResult> InvokeAsync<TResult>(System.Func<System.Threading.Tasks.Task<TResult>> workItem);
|
|
||||||
System.Threading.Tasks.Task<TResult> InvokeAsync<TResult>(System.Func<TResult> workItem);
|
|
||||||
}
|
|
||||||
public partial interface IHandleAfterRender
|
public partial interface IHandleAfterRender
|
||||||
{
|
{
|
||||||
System.Threading.Tasks.Task OnAfterRenderAsync();
|
System.Threading.Tasks.Task OnAfterRenderAsync();
|
||||||
|
|
@ -406,9 +410,8 @@ namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
private readonly object _dummy;
|
private readonly object _dummy;
|
||||||
private readonly int _dummyPrimitive;
|
private readonly int _dummyPrimitive;
|
||||||
|
public Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get { throw null; } }
|
||||||
public bool IsInitialized { get { throw null; } }
|
public bool IsInitialized { get { throw null; } }
|
||||||
public System.Threading.Tasks.Task InvokeAsync(System.Action workItem) { throw null; }
|
|
||||||
public System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> workItem) { throw null; }
|
|
||||||
public void Render(Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
|
public void Render(Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
|
||||||
}
|
}
|
||||||
[System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
|
[System.AttributeUsageAttribute(System.AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
|
||||||
|
|
@ -656,7 +659,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
}
|
}
|
||||||
public partial class HtmlRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer
|
public partial class HtmlRenderer : Microsoft.AspNetCore.Components.Rendering.Renderer
|
||||||
{
|
{
|
||||||
public HtmlRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.Components.IDispatcher dispatcher, System.Func<string, string> htmlEncoder) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { }
|
public HtmlRenderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, System.Func<string, string> htmlEncoder) : base (default(System.IServiceProvider), default(Microsoft.Extensions.Logging.ILoggerFactory)) { }
|
||||||
|
public override Microsoft.AspNetCore.Components.Dispatcher Dispatcher { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||||
protected override void HandleException(System.Exception exception) { }
|
protected override void HandleException(System.Exception exception) { }
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
public System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.Rendering.ComponentRenderedText> RenderComponentAsync(System.Type componentType, Microsoft.AspNetCore.Components.ParameterCollection initialParameters) { throw null; }
|
public System.Threading.Tasks.Task<Microsoft.AspNetCore.Components.Rendering.ComponentRenderedText> RenderComponentAsync(System.Type componentType, Microsoft.AspNetCore.Components.ParameterCollection initialParameters) { throw null; }
|
||||||
|
|
@ -675,18 +679,15 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
public abstract partial class Renderer : System.IDisposable
|
public abstract partial class Renderer : System.IDisposable
|
||||||
{
|
{
|
||||||
public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { }
|
||||||
public Renderer(System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.Components.IDispatcher dispatcher) { }
|
public abstract Microsoft.AspNetCore.Components.Dispatcher Dispatcher { get; }
|
||||||
public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } }
|
public event System.UnhandledExceptionEventHandler UnhandledSynchronizationException { add { } remove { } }
|
||||||
protected internal virtual void AddToRenderQueue(int componentId, Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
|
protected internal virtual void AddToRenderQueue(int componentId, Microsoft.AspNetCore.Components.RenderFragment renderFragment) { }
|
||||||
protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; }
|
protected internal int AssignRootComponentId(Microsoft.AspNetCore.Components.IComponent component) { throw null; }
|
||||||
public static Microsoft.AspNetCore.Components.IDispatcher CreateDefaultDispatcher() { throw null; }
|
|
||||||
public virtual System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo fieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
public virtual System.Threading.Tasks.Task DispatchEventAsync(int eventHandlerId, Microsoft.AspNetCore.Components.Rendering.EventFieldInfo fieldInfo, Microsoft.AspNetCore.Components.UIEventArgs eventArgs) { throw null; }
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
protected virtual void Dispose(bool disposing) { }
|
protected virtual void Dispose(bool disposing) { }
|
||||||
protected abstract void HandleException(System.Exception exception);
|
protected abstract void HandleException(System.Exception exception);
|
||||||
protected Microsoft.AspNetCore.Components.IComponent InstantiateComponent(System.Type componentType) { throw null; }
|
protected Microsoft.AspNetCore.Components.IComponent InstantiateComponent(System.Type componentType) { throw null; }
|
||||||
public virtual System.Threading.Tasks.Task InvokeAsync(System.Action workItem) { throw null; }
|
|
||||||
public virtual System.Threading.Tasks.Task InvokeAsync(System.Func<System.Threading.Tasks.Task> workItem) { throw null; }
|
|
||||||
protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId) { throw null; }
|
protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId) { throw null; }
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId, Microsoft.AspNetCore.Components.ParameterCollection initialParameters) { throw null; }
|
protected System.Threading.Tasks.Task RenderRootComponentAsync(int componentId, Microsoft.AspNetCore.Components.ParameterCollection initialParameters) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItem">The work item to execute.</param>
|
/// <param name="workItem">The work item to execute.</param>
|
||||||
protected Task InvokeAsync(Action workItem)
|
protected Task InvokeAsync(Action workItem)
|
||||||
=> _renderHandle.InvokeAsync(workItem);
|
=> _renderHandle.Dispatcher.InvokeAsync(workItem);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes the supplied work item on the associated renderer's
|
/// Executes the supplied work item on the associated renderer's
|
||||||
|
|
@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItem">The work item to execute.</param>
|
/// <param name="workItem">The work item to execute.</param>
|
||||||
protected Task InvokeAsync(Func<Task> workItem)
|
protected Task InvokeAsync(Func<Task> workItem)
|
||||||
=> _renderHandle.InvokeAsync(workItem);
|
=> _renderHandle.Dispatcher.InvokeAsync(workItem);
|
||||||
|
|
||||||
void IComponent.Configure(RenderHandle renderHandle)
|
void IComponent.Configure(RenderHandle renderHandle)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,34 +10,66 @@ namespace Microsoft.AspNetCore.Components
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispatches external actions to be executed on the context of a <see cref="Renderer"/>.
|
/// Dispatches external actions to be executed on the context of a <see cref="Renderer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDispatcher
|
public abstract class Dispatcher
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a default instance of <see cref="Dispatcher"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="Dispatcher"/> instance.</returns>
|
||||||
|
public static Dispatcher CreateDefault() => new RendererSynchronizationContextDispatcher();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides notifications of unhandled exceptions that occur within the dispatcher.
|
||||||
|
/// </summary>
|
||||||
|
internal event UnhandledExceptionEventHandler UnhandledException;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value that determines whether using the dispatcher to invoke a work item is required
|
||||||
|
/// from the current context.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns><c>true</c> if invoking is required, otherwise <c>false</c>.</returns>
|
||||||
|
public abstract bool CheckAccess();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes the given <see cref="Action"/> in the context of the associated <see cref="Renderer"/>.
|
/// Invokes the given <see cref="Action"/> in the context of the associated <see cref="Renderer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItem">The action to execute.</param>
|
/// <param name="workItem">The action to execute.</param>
|
||||||
/// <returns>A <see cref="Task"/> that will be completed when the action has finished executing.</returns>
|
/// <returns>A <see cref="Task"/> that will be completed when the action has finished executing.</returns>
|
||||||
Task InvokeAsync(Action workItem);
|
public abstract Task InvokeAsync(Action workItem);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
|
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItem">The asynchronous action to execute.</param>
|
/// <param name="workItem">The asynchronous action to execute.</param>
|
||||||
/// <returns>A <see cref="Task"/> that will be completed when the action has finished executing.</returns>
|
/// <returns>A <see cref="Task"/> that will be completed when the action has finished executing.</returns>
|
||||||
Task InvokeAsync(Func<Task> workItem);
|
public abstract Task InvokeAsync(Func<Task> workItem);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
|
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItem">The function to execute.</param>
|
/// <param name="workItem">The function to execute.</param>
|
||||||
/// <returns>A <see cref="Task{TResult}"/> that will be completed when the function has finished executing.</returns>
|
/// <returns>A <see cref="Task{TResult}"/> that will be completed when the function has finished executing.</returns>
|
||||||
Task<TResult> InvokeAsync<TResult>(Func<TResult> workItem);
|
public abstract Task<TResult> InvokeAsync<TResult>(Func<TResult> workItem);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
|
/// Invokes the given <see cref="Func{TResult}"/> in the context of the associated <see cref="Renderer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="workItem">The asynchronous function to execute.</param>
|
/// <param name="workItem">The asynchronous function to execute.</param>
|
||||||
/// <returns>A <see cref="Task{TResult}"/> that will be completed when the function has finished executing.</returns>
|
/// <returns>A <see cref="Task{TResult}"/> that will be completed when the function has finished executing.</returns>
|
||||||
Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> workItem);
|
public abstract Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> workItem);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called to notify listeners of an unhandled exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="UnhandledExceptionEventArgs"/>.</param>
|
||||||
|
protected void OnUnhandledException(UnhandledExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
if (e is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
UnhandledException?.Invoke(this, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,13 +2,12 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Components.Rendering;
|
using Microsoft.AspNetCore.Components.Rendering;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Components
|
namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allows a component to notify the renderer that it should be rendered.
|
/// Allows a component to interact with its renderer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly struct RenderHandle
|
public readonly struct RenderHandle
|
||||||
{
|
{
|
||||||
|
|
@ -21,9 +20,25 @@ namespace Microsoft.AspNetCore.Components
|
||||||
_componentId = componentId;
|
_componentId = componentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="Microsoft.AspNetCore.Components.Dispatcher" /> associated with the component.
|
||||||
|
/// </summary>
|
||||||
|
public Dispatcher Dispatcher
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_renderer == null)
|
||||||
|
{
|
||||||
|
ThrowNotInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _renderer.Dispatcher;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value that indicates whether the <see cref="RenderHandle"/> has been
|
/// Gets a value that indicates whether the <see cref="RenderHandle"/> has been
|
||||||
/// initialised and is ready to use.
|
/// initialized and is ready to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsInitialized
|
public bool IsInitialized
|
||||||
=> _renderer != null;
|
=> _renderer != null;
|
||||||
|
|
@ -36,38 +51,15 @@ namespace Microsoft.AspNetCore.Components
|
||||||
{
|
{
|
||||||
if (_renderer == null)
|
if (_renderer == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("The render handle is not yet assigned.");
|
ThrowNotInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderer.AddToRenderQueue(_componentId, renderFragment);
|
_renderer.AddToRenderQueue(_componentId, renderFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static void ThrowNotInitialized()
|
||||||
/// Executes the supplied work item on the renderer's
|
|
||||||
/// synchronization context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="workItem">The work item to execute.</param>
|
|
||||||
public Task InvokeAsync(Action workItem)
|
|
||||||
{
|
{
|
||||||
if (_renderer == null)
|
throw new InvalidOperationException("The render handle is not yet assigned.");
|
||||||
{
|
|
||||||
throw new InvalidOperationException("The render handle is not yet assigned.");
|
|
||||||
}
|
|
||||||
return _renderer.InvokeAsync(workItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the supplied work item on the renderer's
|
|
||||||
/// synchronization context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="workItem">The work item to execute.</param>
|
|
||||||
public Task InvokeAsync(Func<Task> workItem)
|
|
||||||
{
|
|
||||||
if (_renderer == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("The render handle is not yet assigned.");
|
|
||||||
}
|
|
||||||
return _renderer.InvokeAsync(workItem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components.RenderTree;
|
using Microsoft.AspNetCore.Components.RenderTree;
|
||||||
|
|
@ -28,14 +29,15 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> to use to instantiate components.</param>
|
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> to use to instantiate components.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <param name="dispatcher">The <see cref="IDispatcher"/> to be for invoking user actions into the <see cref="Renderer"/> context.</param>
|
|
||||||
/// <param name="htmlEncoder">A <see cref="Func{T, TResult}"/> that will HTML encode the given string.</param>
|
/// <param name="htmlEncoder">A <see cref="Func{T, TResult}"/> that will HTML encode the given string.</param>
|
||||||
public HtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, IDispatcher dispatcher, Func<string, string> htmlEncoder)
|
public HtmlRenderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, Func<string, string> htmlEncoder)
|
||||||
: base(serviceProvider, loggerFactory, dispatcher)
|
: base(serviceProvider, loggerFactory)
|
||||||
{
|
{
|
||||||
_htmlEncoder = htmlEncoder;
|
_htmlEncoder = htmlEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
|
protected override Task UpdateDisplayAsync(in RenderBatch renderBatch)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder();
|
private readonly RenderBatchBuilder _batchBuilder = new RenderBatchBuilder();
|
||||||
private readonly Dictionary<int, EventCallback> _eventBindings = new Dictionary<int, EventCallback>();
|
private readonly Dictionary<int, EventCallback> _eventBindings = new Dictionary<int, EventCallback>();
|
||||||
private readonly Dictionary<int, int> _eventHandlerIdReplacements = new Dictionary<int, int>();
|
private readonly Dictionary<int, int> _eventHandlerIdReplacements = new Dictionary<int, int>();
|
||||||
private readonly IDispatcher _dispatcher;
|
|
||||||
private readonly ILogger<Renderer> _logger;
|
private readonly ILogger<Renderer> _logger;
|
||||||
|
|
||||||
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
|
private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
|
||||||
|
|
@ -37,19 +36,11 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
{
|
{
|
||||||
add
|
add
|
||||||
{
|
{
|
||||||
if (!(_dispatcher is RendererSynchronizationContext rendererSynchronizationContext))
|
Dispatcher.UnhandledException += value;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rendererSynchronizationContext.UnhandledException += value;
|
|
||||||
}
|
}
|
||||||
remove
|
remove
|
||||||
{
|
{
|
||||||
if (!(_dispatcher is RendererSynchronizationContext rendererSynchronizationContext))
|
Dispatcher.UnhandledException -= value;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rendererSynchronizationContext.UnhandledException -= value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,25 +63,13 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
|
|
||||||
_componentFactory = new ComponentFactory(serviceProvider);
|
_componentFactory = new ComponentFactory(serviceProvider);
|
||||||
_logger = loggerFactory.CreateLogger<Renderer>();
|
_logger = loggerFactory.CreateLogger<Renderer>();
|
||||||
|
_componentFactory = new ComponentFactory(serviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an instance of <see cref="Renderer"/>.
|
/// Gets the <see cref="Microsoft.AspNetCore.Components.Dispatcher" /> associated with this <see cref="Renderer" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="serviceProvider">The <see cref="IServiceProvider"/> to be used when initializing components.</param>
|
public abstract Dispatcher Dispatcher { get; }
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
|
||||||
/// <param name="dispatcher">The <see cref="IDispatcher"/> to be for invoking user actions into the <see cref="Renderer"/> context.</param>
|
|
||||||
public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory, IDispatcher dispatcher)
|
|
||||||
: this(serviceProvider, loggerFactory)
|
|
||||||
{
|
|
||||||
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an <see cref="IDispatcher"/> that can be used with one or more <see cref="Renderer"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The <see cref="IDispatcher"/>.</returns>
|
|
||||||
public static IDispatcher CreateDefaultDispatcher() => new RendererSynchronizationContext();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new component of the specified type.
|
/// Constructs a new component of the specified type.
|
||||||
|
|
@ -272,58 +251,6 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
return GetErrorHandledTask(task);
|
return GetErrorHandledTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the supplied work item on the renderer's
|
|
||||||
/// synchronization context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="workItem">The work item to execute.</param>
|
|
||||||
public virtual Task InvokeAsync(Action workItem)
|
|
||||||
{
|
|
||||||
// This is for example when we run on a system with a single thread, like WebAssembly.
|
|
||||||
if (_dispatcher == null)
|
|
||||||
{
|
|
||||||
workItem();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SynchronizationContext.Current == _dispatcher)
|
|
||||||
{
|
|
||||||
// This is an optimization for when the dispatcher is also a syncronization context, like in the default case.
|
|
||||||
// No need to dispatch. Avoid deadlock by invoking directly.
|
|
||||||
workItem();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return _dispatcher.InvokeAsync(workItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the supplied work item on the renderer's
|
|
||||||
/// synchronization context.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="workItem">The work item to execute.</param>
|
|
||||||
public virtual Task InvokeAsync(Func<Task> workItem)
|
|
||||||
{
|
|
||||||
// This is for example when we run on a system with a single thread, like WebAssembly.
|
|
||||||
if (_dispatcher == null)
|
|
||||||
{
|
|
||||||
return workItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SynchronizationContext.Current == _dispatcher)
|
|
||||||
{
|
|
||||||
// This is an optimization for when the dispatcher is also a syncronization context, like in the default case.
|
|
||||||
// No need to dispatch. Avoid deadlock by invoking directly.
|
|
||||||
return workItem();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return _dispatcher.InvokeAsync(workItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void InstantiateChildComponentOnFrame(ref RenderTreeFrame frame, int parentComponentId)
|
internal void InstantiateChildComponentOnFrame(ref RenderTreeFrame frame, int parentComponentId)
|
||||||
{
|
{
|
||||||
if (frame.FrameType != RenderTreeFrameType.Component)
|
if (frame.FrameType != RenderTreeFrameType.Component)
|
||||||
|
|
@ -448,17 +375,16 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
|
|
||||||
private void EnsureSynchronizationContext()
|
private void EnsureSynchronizationContext()
|
||||||
{
|
{
|
||||||
// When the IDispatcher is a synchronization context
|
// Render operations are not thread-safe, so they need to be serialized by the dispatcher.
|
||||||
// Render operations are not thread-safe, so they need to be serialized.
|
|
||||||
// Plus, any other logic that mutates state accessed during rendering also
|
// Plus, any other logic that mutates state accessed during rendering also
|
||||||
// needs not to run concurrently with rendering so should be dispatched to
|
// needs not to run concurrently with rendering so should be dispatched to
|
||||||
// the renderer's sync context.
|
// the renderer's sync context.
|
||||||
if (_dispatcher is SynchronizationContext synchronizationContext && SynchronizationContext.Current != synchronizationContext)
|
if (!Dispatcher.CheckAccess())
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"The current thread is not associated with the renderer's synchronization context. " +
|
"The current thread is not associated with the Dispatcher. " +
|
||||||
"Use Invoke() or InvokeAsync() to switch execution to the renderer's synchronization " +
|
"Use Invoke() or InvokeAsync() to switch execution to the Dispatcher when " +
|
||||||
"context when triggering rendering or modifying any state accessed during rendering.");
|
"triggering rendering or modifying any state accessed during rendering.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||||
namespace Microsoft.AspNetCore.Components.Rendering
|
namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("{_state,nq}")]
|
[DebuggerDisplay("{_state,nq}")]
|
||||||
internal class RendererSynchronizationContext : SynchronizationContext, IDispatcher
|
internal class RendererSynchronizationContext : SynchronizationContext
|
||||||
{
|
{
|
||||||
private static readonly ContextCallback ExecutionContextThunk = (object state) =>
|
private static readonly ContextCallback ExecutionContextThunk = (object state) =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// 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;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
|
{
|
||||||
|
internal class RendererSynchronizationContextDispatcher : Dispatcher
|
||||||
|
{
|
||||||
|
private readonly RendererSynchronizationContext _context;
|
||||||
|
|
||||||
|
public RendererSynchronizationContextDispatcher()
|
||||||
|
{
|
||||||
|
_context = new RendererSynchronizationContext();
|
||||||
|
_context.UnhandledException += (sender, e) =>
|
||||||
|
{
|
||||||
|
OnUnhandledException(e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CheckAccess() => SynchronizationContext.Current == _context;
|
||||||
|
|
||||||
|
public override Task InvokeAsync(Action workItem)
|
||||||
|
{
|
||||||
|
if (CheckAccess())
|
||||||
|
{
|
||||||
|
workItem();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _context.InvokeAsync(workItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task InvokeAsync(Func<Task> workItem)
|
||||||
|
{
|
||||||
|
if (CheckAccess())
|
||||||
|
{
|
||||||
|
return workItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _context.InvokeAsync(workItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<TResult> InvokeAsync<TResult>(Func<TResult> workItem)
|
||||||
|
{
|
||||||
|
if (CheckAccess())
|
||||||
|
{
|
||||||
|
return Task.FromResult(workItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
return _context.InvokeAsync<TResult>(workItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> workItem)
|
||||||
|
{
|
||||||
|
if (CheckAccess())
|
||||||
|
{
|
||||||
|
return workItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _context.InvokeAsync<TResult>(workItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -386,7 +386,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
supplierParams.Add("Name", name);
|
supplierParams.Add("Name", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.InvokeAsync((Action)(() => supplier.SetParametersAsync(ParameterCollection.FromDictionary(supplierParams))));
|
renderer.Dispatcher.InvokeAsync((Action)(() => supplier.SetParametersAsync(ParameterCollection.FromDictionary(supplierParams))));
|
||||||
return supplier;
|
return supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
public void DisplaysComponentInsideLayout()
|
public void DisplaysComponentInsideLayout()
|
||||||
{
|
{
|
||||||
// Arrange/Act
|
// Arrange/Act
|
||||||
_renderer.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
_renderer.Dispatcher.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ nameof(PageDisplay.Page), typeof(ComponentWithLayout) }
|
{ nameof(PageDisplay.Page), typeof(ComponentWithLayout) }
|
||||||
})));
|
})));
|
||||||
|
|
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
public void DisplaysComponentInsideNestedLayout()
|
public void DisplaysComponentInsideNestedLayout()
|
||||||
{
|
{
|
||||||
// Arrange/Act
|
// Arrange/Act
|
||||||
_renderer.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
_renderer.Dispatcher.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ nameof(PageDisplay.Page), typeof(ComponentWithNestedLayout) }
|
{ nameof(PageDisplay.Page), typeof(ComponentWithNestedLayout) }
|
||||||
})));
|
})));
|
||||||
|
|
@ -111,13 +111,13 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
public void CanChangeDisplayedPageWithSameLayout()
|
public void CanChangeDisplayedPageWithSameLayout()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_renderer.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
_renderer.Dispatcher.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ nameof(PageDisplay.Page), typeof(ComponentWithLayout) }
|
{ nameof(PageDisplay.Page), typeof(ComponentWithLayout) }
|
||||||
})));
|
})));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
_renderer.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
_renderer.Dispatcher.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ nameof(PageDisplay.Page), typeof(DifferentComponentWithLayout) }
|
{ nameof(PageDisplay.Page), typeof(DifferentComponentWithLayout) }
|
||||||
})));
|
})));
|
||||||
|
|
@ -162,13 +162,13 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
public void CanChangeDisplayedPageWithDifferentLayout()
|
public void CanChangeDisplayedPageWithDifferentLayout()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
_renderer.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
_renderer.Dispatcher.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ nameof(PageDisplay.Page), typeof(ComponentWithLayout) }
|
{ nameof(PageDisplay.Page), typeof(ComponentWithLayout) }
|
||||||
})));
|
})));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
_renderer.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
_renderer.Dispatcher.InvokeAsync(() => _pageDisplayComponent.SetParametersAsync(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ nameof(PageDisplay.Page), typeof(ComponentWithNestedLayout) }
|
{ nameof(PageDisplay.Page), typeof(ComponentWithNestedLayout) }
|
||||||
})));
|
})));
|
||||||
|
|
|
||||||
|
|
@ -1795,10 +1795,12 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
private class TestRenderer : Renderer
|
private class TestRenderer : Renderer
|
||||||
{
|
{
|
||||||
public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
public TestRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
protected override void HandleException(Exception exception)
|
protected override void HandleException(Exception exception)
|
||||||
=> throw new NotImplementedException();
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2208,10 +2208,12 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
private class FakeRenderer : Renderer
|
private class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
public FakeRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
public FakeRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
protected override void HandleException(Exception exception)
|
protected override void HandleException(Exception exception)
|
||||||
=> throw new NotImplementedException();
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var componentId = renderer.AssignRootComponentId(component);
|
var componentId = renderer.AssignRootComponentId(component);
|
||||||
var renderTask = renderer.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId));
|
var renderTask = renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(renderTask.IsCompleted);
|
Assert.False(renderTask.IsCompleted);
|
||||||
|
|
@ -239,7 +239,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
var componentId = renderer.AssignRootComponentId(component);
|
var componentId = renderer.AssignRootComponentId(component);
|
||||||
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
||||||
await renderer.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
||||||
{
|
{
|
||||||
|
|
@ -283,7 +283,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
var componentId = renderer.AssignRootComponentId(component);
|
var componentId = renderer.AssignRootComponentId(component);
|
||||||
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
||||||
await renderer.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
||||||
{
|
{
|
||||||
|
|
@ -327,7 +327,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
var componentId = renderer.AssignRootComponentId(component);
|
var componentId = renderer.AssignRootComponentId(component);
|
||||||
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
||||||
await renderer.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
||||||
{
|
{
|
||||||
|
|
@ -371,7 +371,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
var componentId = renderer.AssignRootComponentId(component);
|
var componentId = renderer.AssignRootComponentId(component);
|
||||||
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
var log = new ConcurrentQueue<(int id, NestedAsyncComponent.EventType @event)>();
|
||||||
await renderer.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
await renderer.Dispatcher.InvokeAsync(() => renderer.RenderRootComponentAsync(componentId, ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
[EventActionsName] = new Dictionary<int, IList<NestedAsyncComponent.ExecutionAction>>
|
||||||
{
|
{
|
||||||
|
|
@ -2017,7 +2017,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
// Act/Assert: If a disposed component requests a render, it's a no-op
|
// Act/Assert: If a disposed component requests a render, it's a no-op
|
||||||
var renderHandle = ((FakeComponent)childComponent3).RenderHandle;
|
var renderHandle = ((FakeComponent)childComponent3).RenderHandle;
|
||||||
renderHandle.InvokeAsync(() => renderHandle.Render(builder
|
renderHandle.Dispatcher.InvokeAsync(() => renderHandle.Render(builder
|
||||||
=> throw new NotImplementedException("Should not be invoked")));
|
=> throw new NotImplementedException("Should not be invoked")));
|
||||||
Assert.Equal(2, renderer.Batches.Count);
|
Assert.Equal(2, renderer.Batches.Count);
|
||||||
}
|
}
|
||||||
|
|
@ -2906,7 +2906,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
var asyncExceptionTcs = new TaskCompletionSource<object>();
|
var asyncExceptionTcs = new TaskCompletionSource<object>();
|
||||||
taskToAwait = asyncExceptionTcs.Task;
|
taskToAwait = asyncExceptionTcs.Task;
|
||||||
await renderer.InvokeAsync(component.TriggerRender);
|
await renderer.Dispatcher.InvokeAsync(component.TriggerRender);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exception = new InvalidOperationException();
|
var exception = new InvalidOperationException();
|
||||||
|
|
@ -3373,10 +3373,12 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
private class NoOpRenderer : Renderer
|
private class NoOpRenderer : Renderer
|
||||||
{
|
{
|
||||||
public NoOpRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
public NoOpRenderer() : base(new TestServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
public new int AssignRootComponentId(IComponent component)
|
public new int AssignRootComponentId(IComponent component)
|
||||||
=> base.AssignRootComponentId(component);
|
=> base.AssignRootComponentId(component);
|
||||||
|
|
||||||
|
|
@ -3410,7 +3412,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
|
|
||||||
public void TriggerRender()
|
public void TriggerRender()
|
||||||
{
|
{
|
||||||
var t = _renderHandle.InvokeAsync(() => _renderHandle.Render(_renderFragment));
|
var t = _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(_renderFragment));
|
||||||
// This should always be run synchronously
|
// This should always be run synchronously
|
||||||
Assert.True(t.IsCompleted);
|
Assert.True(t.IsCompleted);
|
||||||
if (t.IsFaulted)
|
if (t.IsFaulted)
|
||||||
|
|
@ -3660,7 +3662,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
{
|
{
|
||||||
foreach (var renderHandle in _renderHandles)
|
foreach (var renderHandle in _renderHandles)
|
||||||
{
|
{
|
||||||
renderHandle.InvokeAsync(() => renderHandle.Render(builder =>
|
renderHandle.Dispatcher.InvokeAsync(() => renderHandle.Render(builder =>
|
||||||
{
|
{
|
||||||
builder.AddContent(0, $"Hello from {nameof(MultiRendererComponent)}");
|
builder.AddContent(0, $"Hello from {nameof(MultiRendererComponent)}");
|
||||||
}));
|
}));
|
||||||
|
|
@ -3821,7 +3823,7 @@ namespace Microsoft.AspNetCore.Components.Test
|
||||||
return TriggerRenderAsync();
|
return TriggerRenderAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task TriggerRenderAsync() => _renderHandle.InvokeAsync(() => _renderHandle.Render(RenderFragment));
|
public Task TriggerRenderAsync() => _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(RenderFragment));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertStream(int expectedId, (int id, NestedAsyncComponent.EventType @event)[] logStream)
|
private void AssertStream(int expectedId, (int id, NestedAsyncComponent.EventType @event)[] logStream)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
public abstract class HtmlRendererTestBase
|
public abstract class HtmlRendererTestBase
|
||||||
{
|
{
|
||||||
protected readonly Func<string, string> _encoder = (string t) => HtmlEncoder.Default.Encode(t);
|
protected readonly Func<string, string> _encoder = (string t) => HtmlEncoder.Default.Encode(t);
|
||||||
protected readonly IDispatcher Dispatcher = Renderer.CreateDefaultDispatcher();
|
|
||||||
|
|
||||||
protected abstract HtmlRenderer GetHtmlRenderer(IServiceProvider serviceProvider);
|
protected abstract HtmlRenderer GetHtmlRenderer(IServiceProvider serviceProvider);
|
||||||
|
|
||||||
|
|
@ -33,7 +32,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -43,7 +42,6 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
public void RenderComponentAsync_CanRenderSimpleComponent()
|
public void RenderComponentAsync_CanRenderSimpleComponent()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var dispatcher = Renderer.CreateDefaultDispatcher();
|
|
||||||
var expectedHtml = new[] { "<", "p", ">", "Hello world!", "</", "p", ">" };
|
var expectedHtml = new[] { "<", "p", ">", "Hello world!", "</", "p", ">" };
|
||||||
var serviceProvider = new ServiceCollection().AddSingleton(new RenderFragment(rtb =>
|
var serviceProvider = new ServiceCollection().AddSingleton(new RenderFragment(rtb =>
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +52,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -64,7 +62,6 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
public void RenderComponentAsync_HtmlEncodesContent()
|
public void RenderComponentAsync_HtmlEncodesContent()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var dispatcher = Renderer.CreateDefaultDispatcher();
|
|
||||||
var expectedHtml = new[] { "<", "p", ">", "<Hello world!>", "</", "p", ">" };
|
var expectedHtml = new[] { "<", "p", ">", "<Hello world!>", "</", "p", ">" };
|
||||||
var serviceProvider = new ServiceCollection().AddSingleton(new RenderFragment(rtb =>
|
var serviceProvider = new ServiceCollection().AddSingleton(new RenderFragment(rtb =>
|
||||||
{
|
{
|
||||||
|
|
@ -75,7 +72,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -96,7 +93,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -119,7 +116,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -153,7 +150,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -175,7 +172,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -196,7 +193,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -217,7 +214,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -240,7 +237,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -270,7 +267,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -299,7 +296,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -329,7 +326,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -360,7 +357,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
Action<UIChangeEventArgs> change = (UIChangeEventArgs changeArgs) => throw new InvalidOperationException();
|
Action<UIChangeEventArgs> change = (UIChangeEventArgs changeArgs) => throw new InvalidOperationException();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<ComponentWithParameters>(
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<ComponentWithParameters>(
|
||||||
new ParameterCollection(new[] {
|
new ParameterCollection(new[] {
|
||||||
RenderTreeFrame.Element(0,string.Empty),
|
RenderTreeFrame.Element(0,string.Empty),
|
||||||
RenderTreeFrame.Attribute(1,"update",change),
|
RenderTreeFrame.Attribute(1,"update",change),
|
||||||
|
|
@ -391,7 +388,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -418,7 +415,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
var result = GetResult(htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<TestComponent>(ParameterCollection.Empty)));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedHtml, result);
|
Assert.Equal(expectedHtml, result);
|
||||||
|
|
@ -468,7 +465,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<AsyncComponent>(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
var result = await htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<AsyncComponent>(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
["Value"] = 10
|
["Value"] = 10
|
||||||
})));
|
})));
|
||||||
|
|
@ -481,8 +478,8 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
public async Task CanRender_NestedAsyncComponents()
|
public async Task CanRender_NestedAsyncComponents()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var dispatcher = Renderer.CreateDefaultDispatcher();
|
var expectedHtml = new[]
|
||||||
var expectedHtml = new[] {
|
{
|
||||||
"<", "p", ">", "20", "</", "p", ">",
|
"<", "p", ">", "20", "</", "p", ">",
|
||||||
"<", "p", ">", "80", "</", "p", ">"
|
"<", "p", ">", "80", "</", "p", ">"
|
||||||
};
|
};
|
||||||
|
|
@ -492,7 +489,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
var htmlRenderer = GetHtmlRenderer(serviceProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<NestedAsyncComponent>(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
var result = await htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync<NestedAsyncComponent>(ParameterCollection.FromDictionary(new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
["Nested"] = false,
|
["Nested"] = false,
|
||||||
["Value"] = 10
|
["Value"] = 10
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
|
||||||
{
|
{
|
||||||
protected override HtmlRenderer GetHtmlRenderer(IServiceProvider serviceProvider)
|
protected override HtmlRenderer GetHtmlRenderer(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
return new HtmlRenderer(serviceProvider, NullLoggerFactory.Instance, Dispatcher, _encoder);
|
return new HtmlRenderer(serviceProvider, NullLoggerFactory.Instance, _encoder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,12 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
RendererRegistry rendererRegistry,
|
RendererRegistry rendererRegistry,
|
||||||
RemoteRenderer renderer,
|
RemoteRenderer renderer,
|
||||||
IList<ComponentDescriptor> descriptors,
|
IList<ComponentDescriptor> descriptors,
|
||||||
IDispatcher dispatcher,
|
|
||||||
RemoteJSRuntime jsRuntime,
|
RemoteJSRuntime jsRuntime,
|
||||||
CircuitHandler[] circuitHandlers,
|
CircuitHandler[] circuitHandlers,
|
||||||
ILogger logger)
|
ILogger logger)
|
||||||
{
|
{
|
||||||
CircuitId = circuitId;
|
CircuitId = circuitId;
|
||||||
_scope = scope ?? throw new ArgumentNullException(nameof(scope));
|
_scope = scope ?? throw new ArgumentNullException(nameof(scope));
|
||||||
Dispatcher = dispatcher;
|
|
||||||
Client = client;
|
Client = client;
|
||||||
RendererRegistry = rendererRegistry ?? throw new ArgumentNullException(nameof(rendererRegistry));
|
RendererRegistry = rendererRegistry ?? throw new ArgumentNullException(nameof(rendererRegistry));
|
||||||
Descriptors = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
|
Descriptors = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
|
||||||
|
|
@ -96,11 +94,9 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
|
|
||||||
public IServiceProvider Services { get; }
|
public IServiceProvider Services { get; }
|
||||||
|
|
||||||
public IDispatcher Dispatcher { get; }
|
|
||||||
|
|
||||||
public Task<ComponentRenderedText> PrerenderComponentAsync(Type componentType, ParameterCollection parameters)
|
public Task<ComponentRenderedText> PrerenderComponentAsync(Type componentType, ParameterCollection parameters)
|
||||||
{
|
{
|
||||||
return Dispatcher.InvokeAsync(async () =>
|
return Renderer.Dispatcher.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
var result = await Renderer.RenderComponentAsync(componentType, parameters);
|
var result = await Renderer.RenderComponentAsync(componentType, parameters);
|
||||||
|
|
||||||
|
|
@ -137,12 +133,12 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
// Dispatch any buffered renders we accumulated during a disconnect.
|
// Dispatch any buffered renders we accumulated during a disconnect.
|
||||||
// Note that while the rendering is async, we cannot await it here. The Task returned by ProcessBufferedRenderBatches relies on
|
// Note that while the rendering is async, we cannot await it here. The Task returned by ProcessBufferedRenderBatches relies on
|
||||||
// OnRenderCompleted to be invoked to complete, and SignalR does not allow concurrent hub method invocations.
|
// OnRenderCompleted to be invoked to complete, and SignalR does not allow concurrent hub method invocations.
|
||||||
var _ = Renderer.InvokeAsync(() => Renderer.ProcessBufferedRenderBatches());
|
var _ = Renderer.Dispatcher.InvokeAsync(() => Renderer.ProcessBufferedRenderBatches());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitializeAsync(CancellationToken cancellationToken)
|
public async Task InitializeAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await Renderer.InvokeAsync(async () =>
|
await Renderer.Dispatcher.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -180,7 +176,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Renderer.InvokeAsync(() =>
|
await Renderer.Dispatcher.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
SetCurrentCircuitHost(this);
|
SetCurrentCircuitHost(this);
|
||||||
DotNetDispatcher.BeginInvoke(callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson);
|
DotNetDispatcher.BeginInvoke(callId, assemblyName, methodIdentifier, dotNetObjectId, argsJson);
|
||||||
|
|
@ -291,7 +287,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
{
|
{
|
||||||
Log.DisposingCircuit(_logger, CircuitId);
|
Log.DisposingCircuit(_logger, CircuitId);
|
||||||
|
|
||||||
await Renderer.InvokeAsync(async () =>
|
await Renderer.Dispatcher.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
{
|
{
|
||||||
if (DisconnectCore(circuitHost, connectionId))
|
if (DisconnectCore(circuitHost, connectionId))
|
||||||
{
|
{
|
||||||
circuitHandlerTask = circuitHost.Dispatcher.InvokeAsync(() => circuitHost.OnConnectionDownAsync(default));
|
circuitHandlerTask = circuitHost.Renderer.Dispatcher.InvokeAsync(() => circuitHost.OnConnectionDownAsync(default));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
|
|
||||||
// Dispatch the circuit handlers inside the sync context to ensure the order of execution. CircuitHost executes circuit handlers inside of
|
// Dispatch the circuit handlers inside the sync context to ensure the order of execution. CircuitHost executes circuit handlers inside of
|
||||||
//
|
//
|
||||||
circuitHandlerTask = circuitHost.Dispatcher.InvokeAsync(async () =>
|
circuitHandlerTask = circuitHost.Renderer.Dispatcher.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
if (previouslyConnected)
|
if (previouslyConnected)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,12 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
}
|
}
|
||||||
|
|
||||||
var rendererRegistry = new RendererRegistry();
|
var rendererRegistry = new RendererRegistry();
|
||||||
var dispatcher = Renderer.CreateDefaultDispatcher();
|
|
||||||
var renderer = new RemoteRenderer(
|
var renderer = new RemoteRenderer(
|
||||||
scope.ServiceProvider,
|
scope.ServiceProvider,
|
||||||
_loggerFactory,
|
_loggerFactory,
|
||||||
rendererRegistry,
|
rendererRegistry,
|
||||||
jsRuntime,
|
jsRuntime,
|
||||||
client,
|
client,
|
||||||
dispatcher,
|
|
||||||
encoder,
|
encoder,
|
||||||
_loggerFactory.CreateLogger<RemoteRenderer>());
|
_loggerFactory.CreateLogger<RemoteRenderer>());
|
||||||
|
|
||||||
|
|
@ -93,7 +91,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
rendererRegistry,
|
rendererRegistry,
|
||||||
renderer,
|
renderer,
|
||||||
components,
|
components,
|
||||||
dispatcher,
|
|
||||||
jsRuntime,
|
jsRuntime,
|
||||||
circuitHandlers,
|
circuitHandlers,
|
||||||
_loggerFactory.CreateLogger<CircuitHost>());
|
_loggerFactory.CreateLogger<CircuitHost>());
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,9 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
|
||||||
RendererRegistry rendererRegistry,
|
RendererRegistry rendererRegistry,
|
||||||
IJSRuntime jsRuntime,
|
IJSRuntime jsRuntime,
|
||||||
CircuitClientProxy client,
|
CircuitClientProxy client,
|
||||||
IDispatcher dispatcher,
|
|
||||||
HtmlEncoder encoder,
|
HtmlEncoder encoder,
|
||||||
ILogger logger)
|
ILogger logger)
|
||||||
: base(serviceProvider, loggerFactory, dispatcher, encoder.Encode)
|
: base(serviceProvider, loggerFactory, encoder.Encode)
|
||||||
{
|
{
|
||||||
_rendererRegistry = rendererRegistry;
|
_rendererRegistry = rendererRegistry;
|
||||||
_jsRuntime = jsRuntime;
|
_jsRuntime = jsRuntime;
|
||||||
|
|
@ -56,6 +55,8 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
|
||||||
|
|
||||||
internal ConcurrentQueue<PendingRender> PendingRenderBatches = new ConcurrentQueue<PendingRender>();
|
internal ConcurrentQueue<PendingRender> PendingRenderBatches = new ConcurrentQueue<PendingRender>();
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Components.Web.Rendering;
|
using Microsoft.AspNetCore.Components.Web.Rendering;
|
||||||
using Microsoft.AspNetCore.Components.Rendering;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
@ -27,7 +26,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var serviceScope = new Mock<IServiceScope>();
|
var serviceScope = new Mock<IServiceScope>();
|
||||||
var remoteRenderer = GetRemoteRenderer(Renderer.CreateDefaultDispatcher());
|
var remoteRenderer = GetRemoteRenderer();
|
||||||
var circuitHost = TestCircuitHost.Create(
|
var circuitHost = TestCircuitHost.Create(
|
||||||
Guid.NewGuid().ToString(),
|
Guid.NewGuid().ToString(),
|
||||||
serviceScope.Object,
|
serviceScope.Object,
|
||||||
|
|
@ -50,7 +49,7 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
handler
|
handler
|
||||||
.Setup(h => h.OnCircuitClosedAsync(It.IsAny<Circuit>(), It.IsAny<CancellationToken>()))
|
.Setup(h => h.OnCircuitClosedAsync(It.IsAny<Circuit>(), It.IsAny<CancellationToken>()))
|
||||||
.Throws<InvalidTimeZoneException>();
|
.Throws<InvalidTimeZoneException>();
|
||||||
var remoteRenderer = GetRemoteRenderer(Renderer.CreateDefaultDispatcher());
|
var remoteRenderer = GetRemoteRenderer();
|
||||||
var circuitHost = TestCircuitHost.Create(
|
var circuitHost = TestCircuitHost.Create(
|
||||||
Guid.NewGuid().ToString(),
|
Guid.NewGuid().ToString(),
|
||||||
serviceScope.Object,
|
serviceScope.Object,
|
||||||
|
|
@ -77,13 +76,13 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var serviceScope = new Mock<IServiceScope>();
|
var serviceScope = new Mock<IServiceScope>();
|
||||||
var remoteRenderer = GetRemoteRenderer(Renderer.CreateDefaultDispatcher());
|
var remoteRenderer = GetRemoteRenderer();
|
||||||
var circuitHost = TestCircuitHost.Create(
|
var circuitHost = TestCircuitHost.Create(
|
||||||
Guid.NewGuid().ToString(),
|
Guid.NewGuid().ToString(),
|
||||||
serviceScope.Object,
|
serviceScope.Object,
|
||||||
remoteRenderer);
|
remoteRenderer);
|
||||||
|
|
||||||
var component = new DispatcherComponent(circuitHost.Dispatcher);
|
var component = new DispatcherComponent(circuitHost.Renderer.Dispatcher);
|
||||||
circuitHost.Renderer.AssignRootComponentId(component);
|
circuitHost.Renderer.AssignRootComponentId(component);
|
||||||
var original = SynchronizationContext.Current;
|
var original = SynchronizationContext.Current;
|
||||||
SynchronizationContext.SetSynchronizationContext(null);
|
SynchronizationContext.SetSynchronizationContext(null);
|
||||||
|
|
@ -229,20 +228,19 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
handler2.VerifyAll();
|
handler2.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TestRemoteRenderer GetRemoteRenderer(IDispatcher dispatcher)
|
private static TestRemoteRenderer GetRemoteRenderer()
|
||||||
{
|
{
|
||||||
return new TestRemoteRenderer(
|
return new TestRemoteRenderer(
|
||||||
Mock.Of<IServiceProvider>(),
|
Mock.Of<IServiceProvider>(),
|
||||||
new RendererRegistry(),
|
new RendererRegistry(),
|
||||||
dispatcher,
|
|
||||||
Mock.Of<IJSRuntime>(),
|
Mock.Of<IJSRuntime>(),
|
||||||
Mock.Of<IClientProxy>());
|
Mock.Of<IClientProxy>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestRemoteRenderer : RemoteRenderer
|
private class TestRemoteRenderer : RemoteRenderer
|
||||||
{
|
{
|
||||||
public TestRemoteRenderer(IServiceProvider serviceProvider, RendererRegistry rendererRegistry, IDispatcher dispatcher, IJSRuntime jsRuntime, IClientProxy client)
|
public TestRemoteRenderer(IServiceProvider serviceProvider, RendererRegistry rendererRegistry, IJSRuntime jsRuntime, IClientProxy client)
|
||||||
: base(serviceProvider, NullLoggerFactory.Instance, rendererRegistry, jsRuntime, new CircuitClientProxy(client, "connection"), dispatcher, HtmlEncoder.Default, NullLogger.Instance)
|
: base(serviceProvider, NullLoggerFactory.Instance, rendererRegistry, jsRuntime, new CircuitClientProxy(client, "connection"), HtmlEncoder.Default, NullLogger.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,12 +255,12 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
|
|
||||||
private class DispatcherComponent : ComponentBase, IDisposable
|
private class DispatcherComponent : ComponentBase, IDisposable
|
||||||
{
|
{
|
||||||
public DispatcherComponent(IDispatcher dispatcher)
|
public DispatcherComponent(Dispatcher dispatcher)
|
||||||
{
|
{
|
||||||
Dispatcher = dispatcher;
|
Dispatcher = dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDispatcher Dispatcher { get; }
|
public Dispatcher Dispatcher { get; }
|
||||||
public bool Called { get; private set; }
|
public bool Called { get; private set; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,6 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
|
||||||
new RendererRegistry(),
|
new RendererRegistry(),
|
||||||
jsRuntime.Object,
|
jsRuntime.Object,
|
||||||
circuitClientProxy,
|
circuitClientProxy,
|
||||||
Dispatcher,
|
|
||||||
HtmlEncoder.Default,
|
HtmlEncoder.Default,
|
||||||
NullLogger.Instance);
|
NullLogger.Instance);
|
||||||
}
|
}
|
||||||
|
|
@ -313,7 +312,7 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
|
||||||
|
|
||||||
public void TriggerRender()
|
public void TriggerRender()
|
||||||
{
|
{
|
||||||
var task = _renderHandle.InvokeAsync(() => _renderHandle.Render(_renderFragment));
|
var task = _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(_renderFragment));
|
||||||
Assert.True(task.IsCompletedSuccessfully);
|
Assert.True(task.IsCompletedSuccessfully);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -342,7 +341,7 @@ namespace Microsoft.AspNetCore.Components.Web.Rendering
|
||||||
|
|
||||||
public void TriggerRender()
|
public void TriggerRender()
|
||||||
{
|
{
|
||||||
var task = _renderHandle.InvokeAsync(() => _renderHandle.Render(Content));
|
var task = _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(Content));
|
||||||
Assert.True(task.IsCompletedSuccessfully);
|
Assert.True(task.IsCompletedSuccessfully);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
// Assert
|
// Assert
|
||||||
AssertBinaryContents(bytes, /* startIndex */ 0,
|
AssertBinaryContents(bytes, /* startIndex */ 0,
|
||||||
0, // Length of UpdatedComponents
|
0, // Length of UpdatedComponents
|
||||||
0, // Length of ReferenceFrames
|
0, // Length of ReferenceFrames
|
||||||
3, 123, int.MaxValue, int.MinValue, // DisposedComponentIds as length-prefixed array
|
3, 123, int.MaxValue, int.MinValue, // DisposedComponentIds as length-prefixed array
|
||||||
0, // Length of DisposedEventHandlerIds
|
0, // Length of DisposedEventHandlerIds
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
2, // Length of UpdatedComponents
|
2, // Length of UpdatedComponents
|
||||||
0, // Index of UpdatedComponents[0]
|
0, // Index of UpdatedComponents[0]
|
||||||
8, // Index of UpdatedComponents[1]
|
8, // Index of UpdatedComponents[1]
|
||||||
|
|
||||||
0, // Length of ReferenceFrames
|
0, // Length of ReferenceFrames
|
||||||
0, // Length of DisposedComponentIds
|
0, // Length of DisposedComponentIds
|
||||||
0, // Length of DisposedEventHandlerIds
|
0, // Length of DisposedEventHandlerIds
|
||||||
|
|
@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
var bytes = Serialize(new RenderBatch(
|
var bytes = Serialize(new RenderBatch(
|
||||||
new ArrayRange<RenderTreeDiff>(new[]
|
new ArrayRange<RenderTreeDiff>(new[]
|
||||||
{
|
{
|
||||||
new RenderTreeDiff(123, editsSegment)
|
new RenderTreeDiff(123, editsSegment)
|
||||||
}, 1),
|
}, 1),
|
||||||
default,
|
default,
|
||||||
default,
|
default,
|
||||||
|
|
@ -360,7 +360,7 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
shift += 7;
|
shift += 7;
|
||||||
numBytesRead++;
|
numBytesRead++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -376,10 +376,12 @@ namespace Microsoft.AspNetCore.Components.Server
|
||||||
class FakeRenderer : Renderer
|
class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
public FakeRenderer()
|
public FakeRenderer()
|
||||||
: base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
: base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
protected override void HandleException(Exception exception)
|
protected override void HandleException(Exception exception)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,19 @@ using System.Runtime.ExceptionServices;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Components.Web.Rendering;
|
using Microsoft.AspNetCore.Components.Web.Rendering;
|
||||||
using Microsoft.AspNetCore.Components.Rendering;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Moq;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Components.Server.Circuits
|
namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
{
|
{
|
||||||
internal class TestCircuitHost : CircuitHost
|
internal class TestCircuitHost : CircuitHost
|
||||||
{
|
{
|
||||||
private TestCircuitHost(string circuitId, IServiceScope scope, CircuitClientProxy client, RendererRegistry rendererRegistry, RemoteRenderer renderer, IList<ComponentDescriptor> descriptors, IDispatcher dispatcher, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger)
|
private TestCircuitHost(string circuitId, IServiceScope scope, CircuitClientProxy client, RendererRegistry rendererRegistry, RemoteRenderer renderer, IList<ComponentDescriptor> descriptors, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger)
|
||||||
: base(circuitId, scope, client, rendererRegistry, renderer, descriptors, dispatcher, jsRuntime, circuitHandlers, logger)
|
: base(circuitId, scope, client, rendererRegistry, renderer, descriptors, jsRuntime, circuitHandlers, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +39,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
clientProxy = clientProxy ?? new CircuitClientProxy(Mock.Of<IClientProxy>(), Guid.NewGuid().ToString());
|
clientProxy = clientProxy ?? new CircuitClientProxy(Mock.Of<IClientProxy>(), Guid.NewGuid().ToString());
|
||||||
var renderRegistry = new RendererRegistry();
|
var renderRegistry = new RendererRegistry();
|
||||||
var jsRuntime = new RemoteJSRuntime(Options.Create(new CircuitOptions()));
|
var jsRuntime = new RemoteJSRuntime(Options.Create(new CircuitOptions()));
|
||||||
var dispatcher = Rendering.Renderer.CreateDefaultDispatcher();
|
|
||||||
|
|
||||||
if (remoteRenderer == null)
|
if (remoteRenderer == null)
|
||||||
{
|
{
|
||||||
|
|
@ -50,7 +48,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
new RendererRegistry(),
|
new RendererRegistry(),
|
||||||
jsRuntime,
|
jsRuntime,
|
||||||
clientProxy,
|
clientProxy,
|
||||||
dispatcher,
|
|
||||||
HtmlEncoder.Default,
|
HtmlEncoder.Default,
|
||||||
NullLogger.Instance);
|
NullLogger.Instance);
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +60,6 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
||||||
renderRegistry,
|
renderRegistry,
|
||||||
remoteRenderer,
|
remoteRenderer,
|
||||||
new List<ComponentDescriptor>(),
|
new List<ComponentDescriptor>(),
|
||||||
dispatcher,
|
|
||||||
jsRuntime,
|
jsRuntime,
|
||||||
handlers,
|
handlers,
|
||||||
NullLogger<CircuitHost>.Instance);
|
NullLogger<CircuitHost>.Instance);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
using Microsoft.AspNetCore.Components.RenderTree;
|
using Microsoft.AspNetCore.Components.RenderTree;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -29,7 +28,7 @@ namespace Microsoft.AspNetCore.Components.Test.Helpers
|
||||||
// We do it this way so that we don't have to be doing renderer.Invoke on each and every test.
|
// We do it this way so that we don't have to be doing renderer.Invoke on each and every test.
|
||||||
public void TriggerRender()
|
public void TriggerRender()
|
||||||
{
|
{
|
||||||
var t = _renderHandle.InvokeAsync(() => _renderHandle.Render(BuildRenderTree));
|
var t = _renderHandle.Dispatcher.InvokeAsync(() => _renderHandle.Render(BuildRenderTree));
|
||||||
// This should always be run synchronously
|
// This should always be run synchronously
|
||||||
Assert.True(t.IsCompleted);
|
Assert.True(t.IsCompleted);
|
||||||
if (t.IsFaulted)
|
if (t.IsFaulted)
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,18 @@ namespace Microsoft.AspNetCore.Components.Test.Helpers
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestRenderer(IDispatcher dispatcher) : base(new TestServiceProvider(), NullLoggerFactory.Instance, dispatcher)
|
public TestRenderer(Dispatcher dispatcher) : base(new TestServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
|
Dispatcher = dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestRenderer(IServiceProvider serviceProvider) : base(serviceProvider, NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
public TestRenderer(IServiceProvider serviceProvider) : base(serviceProvider, NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
|
Dispatcher = Dispatcher.CreateDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; }
|
||||||
|
|
||||||
public Action OnExceptionHandled { get; set; }
|
public Action OnExceptionHandled { get; set; }
|
||||||
|
|
||||||
public Action<RenderBatch> OnUpdateDisplay { get; set; }
|
public Action<RenderBatch> OnUpdateDisplay { get; set; }
|
||||||
|
|
@ -46,21 +50,21 @@ namespace Microsoft.AspNetCore.Components.Test.Helpers
|
||||||
|
|
||||||
public void RenderRootComponent(int componentId, ParameterCollection? parameters = default)
|
public void RenderRootComponent(int componentId, ParameterCollection? parameters = default)
|
||||||
{
|
{
|
||||||
var task = InvokeAsync(() => base.RenderRootComponentAsync(componentId, parameters ?? ParameterCollection.Empty));
|
var task = Dispatcher.InvokeAsync(() => base.RenderRootComponentAsync(componentId, parameters ?? ParameterCollection.Empty));
|
||||||
UnwrapTask(task);
|
UnwrapTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new Task RenderRootComponentAsync(int componentId)
|
public new Task RenderRootComponentAsync(int componentId)
|
||||||
=> InvokeAsync(() => base.RenderRootComponentAsync(componentId));
|
=> Dispatcher.InvokeAsync(() => base.RenderRootComponentAsync(componentId));
|
||||||
|
|
||||||
public new Task RenderRootComponentAsync(int componentId, ParameterCollection parameters)
|
public new Task RenderRootComponentAsync(int componentId, ParameterCollection parameters)
|
||||||
=> InvokeAsync(() => base.RenderRootComponentAsync(componentId, parameters));
|
=> Dispatcher.InvokeAsync(() => base.RenderRootComponentAsync(componentId, parameters));
|
||||||
|
|
||||||
public Task DispatchEventAsync(int eventHandlerId, UIEventArgs args)
|
public Task DispatchEventAsync(int eventHandlerId, UIEventArgs args)
|
||||||
=> InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, null, args));
|
=> Dispatcher.InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, null, args));
|
||||||
|
|
||||||
public new Task DispatchEventAsync(int eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs args)
|
public new Task DispatchEventAsync(int eventHandlerId, EventFieldInfo eventFieldInfo, UIEventArgs args)
|
||||||
=> InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, eventFieldInfo, args));
|
=> Dispatcher.InvokeAsync(() => base.DispatchEventAsync(eventHandlerId, eventFieldInfo, args));
|
||||||
|
|
||||||
private static Task UnwrapTask(Task task)
|
private static Task UnwrapTask(Task task)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests
|
||||||
appElement.FindElement(By.Id("run-without-dispatch")).Click();
|
appElement.FindElement(By.Id("run-without-dispatch")).Click();
|
||||||
|
|
||||||
Browser.Contains(
|
Browser.Contains(
|
||||||
$"{typeof(InvalidOperationException).FullName}: The current thread is not associated with the renderer's synchronization context",
|
$"{typeof(InvalidOperationException).FullName}: The current thread is not associated with the Dispatcher. Use Invoke() or InvokeAsync() to switch execution to the Dispatcher when triggering rendering or modifying any state accessed during rendering.",
|
||||||
() => result.Text);
|
() => result.Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -335,10 +335,12 @@ namespace Ignitor
|
||||||
class FakeRenderer : Renderer
|
class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
public FakeRenderer()
|
public FakeRenderer()
|
||||||
: base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
: base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
protected override void HandleException(Exception exception)
|
protected override void HandleException(Exception exception)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -289,10 +289,12 @@ namespace Ignitor
|
||||||
public class FakeRenderer : Renderer
|
public class FakeRenderer : Renderer
|
||||||
{
|
{
|
||||||
public FakeRenderer()
|
public FakeRenderer()
|
||||||
: base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance, new RendererSynchronizationContext())
|
: base(new ServiceCollection().BuildServiceProvider(), NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Dispatcher Dispatcher { get; } = Dispatcher.CreateDefault();
|
||||||
|
|
||||||
protected override void HandleException(Exception exception)
|
protected override void HandleException(Exception exception)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -30,16 +30,14 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.RazorComponents
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
Type componentType)
|
Type componentType)
|
||||||
{
|
{
|
||||||
var dispatcher = Renderer.CreateDefaultDispatcher();
|
|
||||||
|
|
||||||
InitializeUriHelper(httpContext);
|
InitializeUriHelper(httpContext);
|
||||||
var loggerFactory = (ILoggerFactory)httpContext.RequestServices.GetService(typeof (ILoggerFactory));
|
var loggerFactory = (ILoggerFactory)httpContext.RequestServices.GetService(typeof (ILoggerFactory));
|
||||||
using (var htmlRenderer = new HtmlRenderer(httpContext.RequestServices, loggerFactory, dispatcher, _encoder.Encode))
|
using (var htmlRenderer = new HtmlRenderer(httpContext.RequestServices, loggerFactory, _encoder.Encode))
|
||||||
{
|
{
|
||||||
ComponentRenderedText result = default;
|
ComponentRenderedText result = default;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = await dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync(
|
result = await htmlRenderer.Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync(
|
||||||
componentType,
|
componentType,
|
||||||
parameters));
|
parameters));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue