示例#1
0
        public static CircuitHost Create(
            CircuitId?circuitId            = null,
            IServiceScope serviceScope     = null,
            RemoteRenderer remoteRenderer  = null,
            CircuitHandler[] handlers      = null,
            CircuitClientProxy clientProxy = null)
        {
            serviceScope = serviceScope ?? Mock.Of <IServiceScope>();
            clientProxy  = clientProxy ?? new CircuitClientProxy(Mock.Of <IClientProxy>(), Guid.NewGuid().ToString());
            var jsRuntime = new RemoteJSRuntime(Options.Create(new CircuitOptions()), Mock.Of <ILogger <RemoteJSRuntime> >());

            if (remoteRenderer == null)
            {
                remoteRenderer = new RemoteRenderer(
                    serviceScope.ServiceProvider ?? Mock.Of <IServiceProvider>(),
                    NullLoggerFactory.Instance,
                    new CircuitOptions(),
                    clientProxy,
                    NullLogger.Instance);
            }

            handlers = handlers ?? Array.Empty <CircuitHandler>();
            return(new TestCircuitHost(
                       circuitId is null ? new CircuitId(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()) : circuitId.Value,
                       serviceScope,
                       new CircuitOptions(),
                       clientProxy,
                       remoteRenderer,
                       new List <ComponentDescriptor>(),
                       jsRuntime,
                       handlers,
                       NullLogger <CircuitHost> .Instance));
        }
示例#2
0
        public CircuitHost(
            string circuitId,
            IServiceScope scope,
            CircuitClientProxy client,
            RendererRegistry rendererRegistry,
            RemoteRenderer renderer,
            IList <ComponentDescriptor> descriptors,
            IDispatcher dispatcher,
            RemoteJSRuntime jsRuntime,
            CircuitHandler[] circuitHandlers,
            ILogger logger)
        {
            CircuitId        = circuitId;
            _scope           = scope ?? throw new ArgumentNullException(nameof(scope));
            Dispatcher       = dispatcher;
            Client           = client;
            RendererRegistry = rendererRegistry ?? throw new ArgumentNullException(nameof(rendererRegistry));
            Descriptors      = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
            Renderer         = renderer ?? throw new ArgumentNullException(nameof(renderer));
            JSRuntime        = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime));
            _logger          = logger;

            Services = scope.ServiceProvider;

            Circuit          = new Circuit(this);
            _circuitHandlers = circuitHandlers;

            Renderer.UnhandledException += Renderer_UnhandledException;
            Renderer.UnhandledSynchronizationException += SynchronizationContext_UnhandledException;
        }
        public override CircuitHost CreateCircuitHost(HttpContext httpContext, IClientProxy client)
        {
            if (!_options.StartupActions.TryGetValue(httpContext.Request.Path, out var config))
            {
                var message = $"Could not find an ASP.NET Core Components startup action for request path '{httpContext.Request.Path}'.";
                throw new InvalidOperationException(message);
            }

            var scope                  = _scopeFactory.CreateScope();
            var jsRuntime              = new RemoteJSRuntime(client);
            var rendererRegistry       = new RendererRegistry();
            var synchronizationContext = new CircuitSynchronizationContext();
            var renderer               = new RemoteRenderer(scope.ServiceProvider, rendererRegistry, jsRuntime, client, synchronizationContext);

            var circuitHandlers = scope.ServiceProvider.GetServices <CircuitHandler>()
                                  .OrderBy(h => h.Order)
                                  .ToArray();

            var circuitHost = new CircuitHost(
                scope,
                client,
                rendererRegistry,
                renderer,
                config,
                jsRuntime,
                synchronizationContext,
                circuitHandlers);

            // Initialize per-circuit data that services need
            (circuitHost.Services.GetRequiredService <IJSRuntimeAccessor>() as DefaultJSRuntimeAccessor).JSRuntime = jsRuntime;
            (circuitHost.Services.GetRequiredService <ICircuitAccessor>() as DefaultCircuitAccessor).Circuit       = circuitHost.Circuit;

            return(circuitHost);
        }
示例#4
0
        public CircuitHost(
            string circuitId,
            IServiceScope scope,
            CircuitOptions options,
            CircuitClientProxy client,
            RemoteRenderer renderer,
            IReadOnlyList <ComponentDescriptor> descriptors,
            RemoteJSRuntime jsRuntime,
            CircuitHandler[] circuitHandlers,
            ILogger logger)
        {
            CircuitId = circuitId ?? throw new ArgumentNullException(nameof(circuitId));

            _scope           = scope ?? throw new ArgumentNullException(nameof(scope));
            _options         = options ?? throw new ArgumentNullException(nameof(options));
            Client           = client ?? throw new ArgumentNullException(nameof(client));
            Renderer         = renderer ?? throw new ArgumentNullException(nameof(renderer));
            Descriptors      = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
            JSRuntime        = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime));
            _circuitHandlers = circuitHandlers ?? throw new ArgumentNullException(nameof(circuitHandlers));
            _logger          = logger ?? throw new ArgumentNullException(nameof(logger));

            Services = scope.ServiceProvider;

            Circuit = new Circuit(this);
            Handle  = new CircuitHandle()
            {
                CircuitHost = this,
            };

            Renderer.UnhandledException += Renderer_UnhandledException;
            Renderer.UnhandledSynchronizationException += SynchronizationContext_UnhandledException;
        }
        public static async Task <bool> ReceiveData(RemoteJSRuntime runtime, long streamId, long chunkId, byte[] chunk, string error)
        {
            if (!runtime.RemoteJSDataStreamInstances.TryGetValue(streamId, out var instance))
            {
                // There is no data stream with the given identifier. It may have already been disposed.
                // We notify JS that the stream has been cancelled/disposed.
                return(false);
            }

            return(await instance.ReceiveData(chunkId, chunk, error));
        }
示例#6
0
        /// <summary>
        /// Creates a new <see cref="RemoteRenderer"/>.
        /// </summary>
        public RemoteRenderer(
            IServiceProvider serviceProvider,
            ILoggerFactory loggerFactory,
            CircuitOptions options,
            CircuitClientProxy client,
            ILogger logger,
            RemoteJSRuntime jsRuntime,
            CircuitJSComponentInterop jsComponentInterop)
            : base(serviceProvider, loggerFactory, jsRuntime.ReadJsonSerializerOptions(), jsComponentInterop)
        {
            _client  = client;
            _options = options;
            _logger  = logger;

            ElementReferenceContext = jsRuntime.ElementReferenceContext;
        }
示例#7
0
        public CircuitHost(
            CircuitId circuitId,
            AsyncServiceScope scope,
            CircuitOptions options,
            CircuitClientProxy client,
            RemoteRenderer renderer,
            IReadOnlyList <ComponentDescriptor> descriptors,
            RemoteJSRuntime jsRuntime,
            CircuitHandler[] circuitHandlers,
            ILogger logger)
        {
            CircuitId = circuitId;
            if (CircuitId.Secret is null)
            {
                // Prevent the use of a 'default' secret.
                throw new ArgumentException($"Property '{nameof(CircuitId.Secret)}' cannot be null.", nameof(circuitId));
            }

            _scope           = scope;
            _options         = options ?? throw new ArgumentNullException(nameof(options));
            Client           = client ?? throw new ArgumentNullException(nameof(client));
            Renderer         = renderer ?? throw new ArgumentNullException(nameof(renderer));
            Descriptors      = descriptors ?? throw new ArgumentNullException(nameof(descriptors));
            JSRuntime        = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime));
            _circuitHandlers = circuitHandlers ?? throw new ArgumentNullException(nameof(circuitHandlers));
            _logger          = logger ?? throw new ArgumentNullException(nameof(logger));

            Services = scope.ServiceProvider;

            Circuit = new Circuit(this);
            Handle  = new CircuitHandle()
            {
                CircuitHost = this,
            };

            // An unhandled exception from the renderer is always fatal because it came from user code.
            Renderer.UnhandledException += ReportAndInvoke_UnhandledException;
            Renderer.UnhandledSynchronizationException += SynchronizationContext_UnhandledException;

            JSRuntime.UnhandledException += ReportAndInvoke_UnhandledException;
        }
示例#8
0
        public static CircuitHost Create(
            CircuitId?circuitId            = null,
            AsyncServiceScope?serviceScope = null,
            RemoteRenderer remoteRenderer  = null,
            IReadOnlyList <ComponentDescriptor> descriptors = null,
            CircuitHandler[] handlers      = null,
            CircuitClientProxy clientProxy = null)
        {
            serviceScope = serviceScope ?? new AsyncServiceScope(Mock.Of <IServiceScope>());
            clientProxy  = clientProxy ?? new CircuitClientProxy(Mock.Of <IClientProxy>(), Guid.NewGuid().ToString());
            var jsRuntime       = new RemoteJSRuntime(Options.Create(new CircuitOptions()), Options.Create(new HubOptions()), Mock.Of <ILogger <RemoteJSRuntime> >());
            var serviceProvider = new Mock <IServiceProvider>();

            serviceProvider
            .Setup(services => services.GetService(typeof(IJSRuntime)))
            .Returns(jsRuntime);

            if (remoteRenderer == null)
            {
                remoteRenderer = new RemoteRenderer(
                    serviceProvider.Object,
                    NullLoggerFactory.Instance,
                    new CircuitOptions(),
                    clientProxy,
                    NullLogger.Instance,
                    jsRuntime,
                    new CircuitJSComponentInterop(new CircuitOptions()));
            }

            handlers ??= Array.Empty <CircuitHandler>();
            return(new TestCircuitHost(
                       circuitId is null ? new CircuitId(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()) : circuitId.Value,
                       serviceScope.Value,
                       new CircuitOptions(),
                       clientProxy,
                       remoteRenderer,
                       descriptors ?? new List <ComponentDescriptor>(),
                       jsRuntime,
                       handlers,
                       NullLogger <CircuitHost> .Instance));
        }
        private RemoteJSDataStream(
            RemoteJSRuntime runtime,
            long streamId,
            long totalLength,
            long maxBufferSize,
            TimeSpan jsInteropDefaultCallTimeout,
            CancellationToken cancellationToken)
        {
            _runtime     = runtime;
            _streamId    = streamId;
            _totalLength = totalLength;
            _jsInteropDefaultCallTimeout = jsInteropDefaultCallTimeout;
            _streamCancellationToken     = cancellationToken;

            _lastDataReceivedTime = DateTimeOffset.UtcNow;
            _ = ThrowOnTimeout();

            _runtime.RemoteJSDataStreamInstances.Add(_streamId, this);

            _pipe             = new Pipe(new PipeOptions(pauseWriterThreshold: maxBufferSize, resumeWriterThreshold: maxBufferSize / 2));
            _pipeReaderStream = _pipe.Reader.AsStream();
        }
示例#10
0
        private RemoteJSDataStream(
            RemoteJSRuntime runtime,
            long streamId,
            long totalLength,
            TimeSpan jsInteropDefaultCallTimeout,
            CancellationToken cancellationToken)
        {
            _runtime     = runtime;
            _streamId    = streamId;
            _totalLength = totalLength;
            _jsInteropDefaultCallTimeout = jsInteropDefaultCallTimeout;
            _streamCancellationToken     = cancellationToken;

            _lastDataReceivedTime = DateTimeOffset.UtcNow;
            _ = ThrowOnTimeout();

            _runtime.RemoteJSDataStreamInstances.Add(_streamId, this);

            _pipe             = new Pipe();
            _pipeReaderStream = _pipe.Reader.AsStream();
            PipeReader        = _pipe.Reader;
        }
示例#11
0
        public static async ValueTask <RemoteJSDataStream> CreateRemoteJSDataStreamAsync(
            RemoteJSRuntime runtime,
            IJSStreamReference jsStreamReference,
            long totalLength,
            long signalRMaximumIncomingBytes,
            TimeSpan jsInteropDefaultCallTimeout,
            CancellationToken cancellationToken = default)
        {
            // Enforce minimum 1 kb, maximum 50 kb, SignalR message size.
            // We budget 512 bytes overhead for the transfer, thus leaving at least 512 bytes for data
            // transfer per chunk with a 1 kb message size.
            // Additionally, to maintain interactivity, we put an upper limit of 50 kb on the message size.
            var chunkSize = signalRMaximumIncomingBytes > 1024 ?
                            Math.Min(signalRMaximumIncomingBytes, 50 * 1024) - 512 :
                            throw new ArgumentException($"SignalR MaximumIncomingBytes must be at least 1 kb.");

            var streamId           = runtime.RemoteJSDataStreamNextInstanceId++;
            var remoteJSDataStream = new RemoteJSDataStream(runtime, streamId, totalLength, jsInteropDefaultCallTimeout, cancellationToken);
            await runtime.InvokeVoidAsync("Blazor._internal.sendJSDataStream", jsStreamReference, streamId, chunkSize);

            return(remoteJSDataStream);
        }
示例#12
0
        public static CircuitHost Create(
            string circuitId               = null,
            IServiceScope serviceScope     = null,
            RemoteRenderer remoteRenderer  = null,
            CircuitHandler[] handlers      = null,
            CircuitClientProxy clientProxy = null)
        {
            serviceScope = serviceScope ?? Mock.Of <IServiceScope>();
            clientProxy  = clientProxy ?? new CircuitClientProxy(Mock.Of <IClientProxy>(), Guid.NewGuid().ToString());
            var renderRegistry = new RendererRegistry();
            var jsRuntime      = new RemoteJSRuntime(Options.Create(new CircuitOptions()));
            var dispatcher     = Rendering.Renderer.CreateDefaultDispatcher();

            if (remoteRenderer == null)
            {
                remoteRenderer = new RemoteRenderer(
                    serviceScope.ServiceProvider ?? Mock.Of <IServiceProvider>(),
                    NullLoggerFactory.Instance,
                    new RendererRegistry(),
                    jsRuntime,
                    clientProxy,
                    dispatcher,
                    HtmlEncoder.Default,
                    NullLogger.Instance);
            }

            handlers = handlers ?? Array.Empty <CircuitHandler>();
            return(new TestCircuitHost(
                       circuitId ?? Guid.NewGuid().ToString(),
                       serviceScope,
                       clientProxy,
                       renderRegistry,
                       remoteRenderer,
                       new List <ComponentDescriptor>(),
                       dispatcher,
                       jsRuntime,
                       handlers,
                       NullLogger <CircuitHost> .Instance));
        }
示例#13
0
 private TestCircuitHost(string circuitId, IServiceScope scope, CircuitClientProxy client, RendererRegistry rendererRegistry, RemoteRenderer renderer, IReadOnlyList <ComponentDescriptor> descriptors, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger)
     : base(circuitId, scope, client, rendererRegistry, renderer, descriptors, jsRuntime, circuitHandlers, logger)
 {
 }
示例#14
0
 private TestCircuitHost(CircuitId circuitId, AsyncServiceScope scope, CircuitOptions options, CircuitClientProxy client, RemoteRenderer renderer, IReadOnlyList <ComponentDescriptor> descriptors, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger)
     : base(circuitId, scope, options, client, renderer, descriptors, jsRuntime, circuitHandlers, logger)
 {
 }
示例#15
0
 private TestCircuitHost(IServiceScope scope, CircuitClientProxy client, RendererRegistry rendererRegistry, RemoteRenderer renderer, IList <ComponentDescriptor> descriptors, IDispatcher dispatcher, RemoteJSRuntime jsRuntime, CircuitHandler[] circuitHandlers, ILogger logger)
     : base(scope, client, rendererRegistry, renderer, descriptors, dispatcher, jsRuntime, circuitHandlers, logger)
 {
 }