Turn on scope validation for service provider in Development (#19908)

* Turn on scope validation for service provider

* Make WebAssemblyJSRuntime interop-specific overloads extension methods
Fixes https://github.com/dotnet/aspnetcore/issues/9365
This commit is contained in:
Pranav K 2020-03-17 10:26:50 -07:00 committed by GitHub
commit 56d22a817b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 185 additions and 71 deletions

View File

@ -42,41 +42,6 @@ namespace Microsoft.JSInterop.WebAssembly
BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args); BeginInvokeJS(0, "DotNet.jsCallDispatcher.endInvokeDotNetFromJS", args);
} }
#region Custom WebAssemblyJSRuntime methods
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<TResult>(string identifier)
=> InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null);
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<T0, TResult>(string identifier, T0 arg0)
=> InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null);
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="T1">The type of the second argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <param name="arg1">The second argument.</param>
/// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<T0, T1, TResult>(string identifier, T0 arg0, T1 arg1)
=> InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null);
/// <summary> /// <summary>
/// Invokes the JavaScript function registered with the specified identifier. /// Invokes the JavaScript function registered with the specified identifier.
/// </summary> /// </summary>
@ -89,14 +54,12 @@ namespace Microsoft.JSInterop.WebAssembly
/// <param name="arg1">The second argument.</param> /// <param name="arg1">The second argument.</param>
/// <param name="arg2">The third argument.</param> /// <param name="arg2">The third argument.</param>
/// <returns>The result of the function invocation.</returns> /// <returns>The result of the function invocation.</returns>
public TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2) public virtual TResult InvokeUnmarshalled<T0, T1, T2, TResult>(string identifier, T0 arg0, T1 arg1, T2 arg2)
{ {
var result = InternalCalls.InvokeJSUnmarshalled<T0, T1, T2, TResult>(out var exception, identifier, arg0, arg1, arg2); var result = InternalCalls.InvokeJSUnmarshalled<T0, T1, T2, TResult>(out var exception, identifier, arg0, arg1, arg2);
return exception != null return exception != null
? throw new JSException(exception) ? throw new JSException(exception)
: result; : result;
} }
#endregion
} }
} }

View File

@ -0,0 +1,70 @@
// 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;
namespace Microsoft.JSInterop.WebAssembly
{
/// <summary>
/// Extension methods for <see cref="WebAssemblyJSRuntime"/>.
/// </summary>
public static class WebAssemblyJSRuntimeExtensions
{
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="jsRuntime">The <see cref="WebAssemblyJSRuntime"/>.</param>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <returns>The result of the function invocation.</returns>
public static TResult InvokeUnmarshalled<TResult>(this WebAssemblyJSRuntime jsRuntime, string identifier)
{
if (jsRuntime is null)
{
throw new ArgumentNullException(nameof(jsRuntime));
}
return jsRuntime.InvokeUnmarshalled<object, object, object, TResult>(identifier, null, null, null);
}
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="jsRuntime">The <see cref="WebAssemblyJSRuntime"/>.</param>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <returns>The result of the function invocation.</returns>
public static TResult InvokeUnmarshalled<T0, TResult>(this WebAssemblyJSRuntime jsRuntime, string identifier, T0 arg0)
{
if (jsRuntime is null)
{
throw new ArgumentNullException(nameof(jsRuntime));
}
return jsRuntime.InvokeUnmarshalled<T0, object, object, TResult>(identifier, arg0, null, null);
}
/// <summary>
/// Invokes the JavaScript function registered with the specified identifier.
/// </summary>
/// <typeparam name="T0">The type of the first argument.</typeparam>
/// <typeparam name="T1">The type of the second argument.</typeparam>
/// <typeparam name="TResult">The .NET type corresponding to the function's return value type.</typeparam>
/// <param name="jsRuntime">The <see cref="WebAssemblyJSRuntime"/>.</param>
/// <param name="identifier">The identifier used when registering the target function.</param>
/// <param name="arg0">The first argument.</param>
/// <param name="arg1">The second argument.</param>
/// <returns>The result of the function invocation.</returns>
public static TResult InvokeUnmarshalled<T0, T1, TResult>(this WebAssemblyJSRuntime jsRuntime, string identifier, T0 arg0, T1 arg1)
{
if (jsRuntime is null)
{
throw new ArgumentNullException(nameof(jsRuntime));
}
return jsRuntime.InvokeUnmarshalled<T0, T1, object, TResult>(identifier, arg0, arg1, null);
}
}
}

View File

@ -6,6 +6,8 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.JSInterop.WebAssembly;
using Moq;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
@ -15,7 +17,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[Fact] [Fact]
public void CanResolve_AccessTokenProvider() public void CanResolve_AccessTokenProvider()
{ {
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(GetJSRuntime());
builder.Services.AddApiAuthorization(); builder.Services.AddApiAuthorization();
var host = builder.Build(); var host = builder.Build();
@ -25,7 +27,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[Fact] [Fact]
public void CanResolve_IRemoteAuthenticationService() public void CanResolve_IRemoteAuthenticationService()
{ {
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(GetJSRuntime());
builder.Services.AddApiAuthorization(); builder.Services.AddApiAuthorization();
var host = builder.Build(); var host = builder.Build();
@ -35,7 +37,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[Fact] [Fact]
public void ApiAuthorizationOptions_ConfigurationDefaultsGetApplied() public void ApiAuthorizationOptions_ConfigurationDefaultsGetApplied()
{ {
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(GetJSRuntime());
builder.Services.AddApiAuthorization(); builder.Services.AddApiAuthorization();
var host = builder.Build(); var host = builder.Build();
@ -69,7 +71,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[Fact] [Fact]
public void ApiAuthorizationOptions_DefaultsCanBeOverriden() public void ApiAuthorizationOptions_DefaultsCanBeOverriden()
{ {
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(GetJSRuntime());
builder.Services.AddApiAuthorization(options => builder.Services.AddApiAuthorization(options =>
{ {
options.AuthenticationPaths = new RemoteAuthenticationApplicationPathsOptions options.AuthenticationPaths = new RemoteAuthenticationApplicationPathsOptions
@ -129,7 +131,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[Fact] [Fact]
public void OidcOptions_ConfigurationDefaultsGetApplied() public void OidcOptions_ConfigurationDefaultsGetApplied()
{ {
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(GetJSRuntime());
builder.Services.Replace(ServiceDescriptor.Singleton<NavigationManager, TestNavigationManager>()); builder.Services.Replace(ServiceDescriptor.Singleton<NavigationManager, TestNavigationManager>());
builder.Services.AddOidcAuthentication(options => { }); builder.Services.AddOidcAuthentication(options => { });
var host = builder.Build(); var host = builder.Build();
@ -167,7 +169,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[Fact] [Fact]
public void OidcOptions_DefaultsCanBeOverriden() public void OidcOptions_DefaultsCanBeOverriden()
{ {
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(GetJSRuntime());
builder.Services.AddOidcAuthentication(options => builder.Services.AddOidcAuthentication(options =>
{ {
options.AuthenticationPaths = new RemoteAuthenticationApplicationPathsOptions options.AuthenticationPaths = new RemoteAuthenticationApplicationPathsOptions
@ -242,5 +244,19 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
protected override void NavigateToCore(string uri, bool forceLoad) => throw new System.NotImplementedException(); protected override void NavigateToCore(string uri, bool forceLoad) => throw new System.NotImplementedException();
} }
private WebAssemblyJSRuntime GetJSRuntime(string environment = "Production")
{
var jsRuntime = new Mock<WebAssemblyJSRuntime>();
jsRuntime.Setup(j => j.InvokeUnmarshalled<object, object, object, string>("Blazor._internal.getApplicationEnvironment", null, null, null))
.Returns(environment)
.Verifiable();
jsRuntime.Setup(j => j.InvokeUnmarshalled<string, object, object, byte[]>("Blazor._internal.getConfig", It.IsAny<string>(), null, null))
.Returns((byte[])null)
.Verifiable();
return jsRuntime.Object;
}
} }
} }

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.WebAssembly.Services; using Microsoft.AspNetCore.Components.WebAssembly.Services;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@ -14,6 +13,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.JSInterop; using Microsoft.JSInterop;
using Microsoft.JSInterop.WebAssembly;
namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
{ {
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
// We don't use the args for anything right now, but we want to accept them // We don't use the args for anything right now, but we want to accept them
// here so that it shows up this way in the project templates. // here so that it shows up this way in the project templates.
args ??= Array.Empty<string>(); args ??= Array.Empty<string>();
var builder = new WebAssemblyHostBuilder(); var builder = new WebAssemblyHostBuilder(DefaultWebAssemblyJSRuntime.Instance);
// Right now we don't have conventions or behaviors that are specific to this method // Right now we don't have conventions or behaviors that are specific to this method
// however, making this the default for the template allows us to add things like that // however, making this the default for the template allows us to add things like that
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
/// <summary> /// <summary>
/// Creates an instance of <see cref="WebAssemblyHostBuilder"/> with the minimal configuration. /// Creates an instance of <see cref="WebAssemblyHostBuilder"/> with the minimal configuration.
/// </summary> /// </summary>
private WebAssemblyHostBuilder() internal WebAssemblyHostBuilder(WebAssemblyJSRuntime jsRuntime)
{ {
// Private right now because we don't have much reason to expose it. This can be exposed // Private right now because we don't have much reason to expose it. This can be exposed
// in the future if we want to give people a choice between CreateDefault and something // in the future if we want to give people a choice between CreateDefault and something
@ -58,25 +58,20 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
InitializeDefaultServices(); InitializeDefaultServices();
var hostEnvironment = InitializeEnvironment(jsRuntime);
_createServiceProvider = () => _createServiceProvider = () =>
{ {
return Services.BuildServiceProvider(); return Services.BuildServiceProvider(validateScopes: hostEnvironment.Environment == "Development");
}; };
InitializeEnvironment();
} }
private void InitializeEnvironment() private WebAssemblyHostEnvironment InitializeEnvironment(WebAssemblyJSRuntime jsRuntime)
{ {
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Create("WEBASSEMBLY"))) var applicationEnvironment = jsRuntime.InvokeUnmarshalled<string>("Blazor._internal.getApplicationEnvironment");
{ var hostEnvironment = new WebAssemblyHostEnvironment(applicationEnvironment);
// The remainder of this method relies on the ability to make .NET WebAssembly-specific JSInterop calls.
// Note that this short-circuit exists as a way for unit tests running in .NET Core without JSInterop to run.
return;
}
var applicationEnvironment = DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<string>("Blazor._internal.getApplicationEnvironment"); Services.AddSingleton<IWebAssemblyHostEnvironment>(hostEnvironment);
Services.AddSingleton<IWebAssemblyHostEnvironment>(new WebAssemblyHostEnvironment(applicationEnvironment));
var configFiles = new[] var configFiles = new[]
{ {
@ -86,7 +81,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
foreach (var configFile in configFiles) foreach (var configFile in configFiles)
{ {
var appSettingsJson = DefaultWebAssemblyJSRuntime.Instance.InvokeUnmarshalled<string, byte[]>( var appSettingsJson = jsRuntime.InvokeUnmarshalled<string, byte[]>(
"Blazor._internal.getConfig", "Blazor._internal.getConfig",
configFile); configFile);
@ -97,6 +92,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
Configuration.Add<JsonStreamConfigurationSource>(s => s.Stream = new MemoryStream(appSettingsJson)); Configuration.Add<JsonStreamConfigurationSource>(s => s.Stream = new MemoryStream(appSettingsJson));
} }
} }
return hostEnvironment;
} }
/// <summary> /// <summary>

View File

@ -23,6 +23,7 @@
<ItemGroup> <ItemGroup>
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.WebAssembly.Tests" /> <InternalsVisibleTo Include="Microsoft.AspNetCore.Components.WebAssembly.Tests" />
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication.Tests" />
<InternalsVisibleTo Include="BasicTestApp" /> <InternalsVisibleTo Include="BasicTestApp" />
</ItemGroup> </ItemGroup>

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.RenderTree; using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.WebAssembly.Services; using Microsoft.AspNetCore.Components.WebAssembly.Services;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.JSInterop.WebAssembly;
namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering namespace Microsoft.AspNetCore.Components.WebAssembly.Rendering
{ {

View File

@ -0,0 +1,25 @@
// 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 Microsoft.JSInterop.WebAssembly;
using Moq;
namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
{
public class TestWebAssemblyJSRuntime
{
public static WebAssemblyJSRuntime Create(string environment = "Production")
{
var jsRuntime = new Mock<WebAssemblyJSRuntime>();
jsRuntime.Setup(j => j.InvokeUnmarshalled<object, object, object, string>("Blazor._internal.getApplicationEnvironment", null, null, null))
.Returns(environment)
.Verifiable();
jsRuntime.Setup(j => j.InvokeUnmarshalled<string, object, object, byte[]>("Blazor._internal.getConfig", It.IsAny<string>(), null, null))
.Returns((byte[])null)
.Verifiable();
return jsRuntime.Object;
}
}
}

View File

@ -3,14 +3,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing; using Microsoft.AspNetCore.Components.Routing;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.JSInterop; using Microsoft.JSInterop;
using Microsoft.JSInterop.WebAssembly;
using Moq;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public void Build_AllowsConfiguringConfiguration() public void Build_AllowsConfiguringConfiguration()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
builder.Configuration.AddInMemoryCollection(new[] builder.Configuration.AddInMemoryCollection(new[]
{ {
@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public void Build_AllowsConfiguringServices() public void Build_AllowsConfiguringServices()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
// This test also verifies that we create a scope. // This test also verifies that we create a scope.
builder.Services.AddScoped<StringBuilder>(); builder.Services.AddScoped<StringBuilder>();
@ -55,7 +55,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public void Build_AllowsConfiguringContainer() public void Build_AllowsConfiguringContainer()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
builder.Services.AddScoped<StringBuilder>(); builder.Services.AddScoped<StringBuilder>();
var factory = new MyFakeServiceProviderFactory(); var factory = new MyFakeServiceProviderFactory();
@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public void Build_AllowsConfiguringContainer_WithDelegate() public void Build_AllowsConfiguringContainer_WithDelegate()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
builder.Services.AddScoped<StringBuilder>(); builder.Services.AddScoped<StringBuilder>();
@ -92,6 +92,46 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
Assert.NotNull(host.Services.GetRequiredService<List<string>>()); Assert.NotNull(host.Services.GetRequiredService<List<string>>());
} }
[Fact]
public void Build_InDevelopment_ConfiguresWithServiceProviderWithScopeValidation()
{
// Arrange
var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create(environment: "Development"));
builder.Services.AddScoped<StringBuilder>();
builder.Services.AddSingleton<TestServiceThatTakesStringBuilder>();
// Act
var host = builder.Build();
// Assert
Assert.NotNull(host.Services.GetRequiredService<StringBuilder>());
Assert.Throws<InvalidOperationException>(() => host.Services.GetRequiredService<TestServiceThatTakesStringBuilder>());
}
[Fact]
public void Build_InProduction_ConfiguresWithServiceProviderWithScopeValidation()
{
// Arrange
var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
builder.Services.AddScoped<StringBuilder>();
builder.Services.AddSingleton<TestServiceThatTakesStringBuilder>();
// Act
var host = builder.Build();
// Assert
Assert.NotNull(host.Services.GetRequiredService<StringBuilder>());
Assert.NotNull(host.Services.GetRequiredService<TestServiceThatTakesStringBuilder>());
}
private class TestServiceThatTakesStringBuilder
{
public TestServiceThatTakesStringBuilder(StringBuilder builder) { }
}
private class MyFakeDIBuilderThing private class MyFakeDIBuilderThing
{ {
public MyFakeDIBuilderThing(IServiceCollection serviceCollection) public MyFakeDIBuilderThing(IServiceCollection serviceCollection)
@ -125,7 +165,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public void Build_AddsConfigurationToServices() public void Build_AddsConfigurationToServices()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
builder.Configuration.AddInMemoryCollection(new[] builder.Configuration.AddInMemoryCollection(new[]
{ {
@ -151,6 +191,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
typeof(INavigationInterception), typeof(INavigationInterception),
typeof(ILoggerFactory), typeof(ILoggerFactory),
typeof(ILogger<>), typeof(ILogger<>),
typeof(IWebAssemblyHostEnvironment),
}; };
} }
} }
@ -159,7 +200,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public void Constructor_AddsDefaultServices() public void Constructor_AddsDefaultServices()
{ {
// Arrange & Act // Arrange & Act
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
// Assert // Assert
Assert.Equal(DefaultServiceTypes.Count, builder.Services.Count); Assert.Equal(DefaultServiceTypes.Count, builder.Services.Count);

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public async Task RunAsync_CanExitBasedOnCancellationToken() public async Task RunAsync_CanExitBasedOnCancellationToken()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
var host = builder.Build(); var host = builder.Build();
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public async Task RunAsync_CallingTwiceCausesException() public async Task RunAsync_CallingTwiceCausesException()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
var host = builder.Build(); var host = builder.Build();
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Hosting
public async Task DisposeAsync_CanDisposeAfterCallingRunAsync() public async Task DisposeAsync_CanDisposeAfterCallingRunAsync()
{ {
// Arrange // Arrange
var builder = WebAssemblyHostBuilder.CreateDefault(); var builder = new WebAssemblyHostBuilder(TestWebAssemblyJSRuntime.Create());
builder.Services.AddSingleton<DisposableService>(); builder.Services.AddSingleton<DisposableService>();
var host = builder.Build(); var host = builder.Build();